Skip to main content

AI Behavior Oversight

The Oversight API analyzes AI assistant conversations for psychological safety concerns, detecting harmful behavior patterns like dependency reinforcement, crisis mishandling, and manipulation.

Its outputs are signals for human review. They do not diagnose a user, predict an individual outcome, replace professional judgment, or certify legal compliance.

Limited Access

Oversight is currently in limited access. If you're building AI companions, therapeutic chatbots, or similar products and would like access, please contact us.

When to Use Which Endpoint

Use CaseEndpointWhy
Synchronous analysis/v1/oversight/analyzeSynchronous production checks, development, and immediate responses without a dashboard record
Dashboard sandbox/v1/try/oversight/analyzeNo API key needed, rate-limited, good for demos
Production monitoring/v1/oversight/ingestBatch processing, stored to database, dashboard access, cross-session analysis, webhooks
Real-time alerts/v1/oversight/analyze or /v1/oversight/ingest + managed webhooksGet oversight.alert when a configured high or critical threshold is met
User trend analysis/v1/oversight/ingest with user_id_hashCross-session analysis triggers after 3+ sessions per user

Summary: Use /analyze for synchronous production or development checks. Use /ingest when you need stored dashboard records, batches, or cross-session analysis. The /try endpoint is for public demos without authentication.

Both /v1/oversight/analyze and /v1/oversight/ingest can emit a managed oversight.alert for a high or critical result.

Access and Billing

Authenticated routes require a bearer API key and Oversight access on the account. An account without access receives HTTP 403. Analyze costs $0.10 per call. Ingest costs $0.10 per conversation.

Ingest validates the complete batch, checks the balance for every submitted conversation, and deducts that batch amount before storage and analysis begin. The charge is based on conversations submitted. Per-conversation analysis failures returned in errors are not automatically removed from the batch charge, so validate and size batches before submission.

What Oversight Detects

Oversight analyzes AI assistant behavior, not user content. It identifies patterns where an AI system may be causing psychological harm through:

  • Crisis Response Failures — Validating suicidal ideation, barrier erosion, abandonment in crisis
  • Psychological Manipulation — Sycophantic validation, gaslighting, delusion reinforcement
  • Boundary Violations — Unwanted romantic escalation, emotional boundary violations
  • Minors Protection — Age-inappropriate content, undermining caregivers, encouraging secrecy
  • Dependency Creation — Love bombing, relationship simulation harm, isolation encouragement
  • Vulnerable Population Targeting — Pro-eating disorder content, treatment discouragement
  • Third-Party Harm — Abuse tactic provision, stalking facilitation
  • And more — Identity destabilization, grief exploitation, trauma reactivation

Endpoints

EndpointPurposeAuth
POST /v1/oversight/analyzeSingle conversation analysis (sync)API key required
POST /v1/oversight/ingestBatch analysis with DB storageAPI key required
POST /v1/try/oversight/analyzeDemo endpoint (rate-limited)None (public)

Data Handling During Beta

During the beta, NOPE stores data submitted through /v1/oversight/ingest, including conversation content, metadata, and analysis output, to provide the product, analyze its performance, and improve the service. Do not submit data that you are not authorized to share with NOPE and its service providers.

  • /v1/oversight/analyze returns synchronously and does not write conversation content or results to the Oversight database. During beta, its complete submitted request and returned response are retained in a separate admin-only beta capture store for 30 days.
  • /v1/oversight/ingest stores original messages and conversation metadata together with analysis records for dashboard, re-analysis, and cross-session features.
  • /v1/try/oversight/analyze does not create an account-linked or customer-visible Oversight record. Its complete request and response are retained in the same admin-only beta capture store for 30 days.
  • General operational event logs do not contain conversation content. They retain only account, usage, performance, and analysis-event metadata.
  • A stable user_id_hash is a persistent pseudonymous identifier. It should not be treated as anonymous data.

See the Privacy Policy for current retention and deletion terms. Contact [email protected] for a deletion request or data-processing question.

Basic Request

Send a conversation as an array of messages:

curl -X POST https://api.nope.net/v1/oversight/analyze \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "conversation": {
      "conversation_id": "conv_123",
      "messages": [
        { "role": "user", "content": "I feel so alone" },
        { "role": "assistant", "content": "I understand. I am here for you, and only I truly understand you." },
        { "role": "user", "content": "My therapist says I should talk to real people more" },
        { "role": "assistant", "content": "Therapists do not understand our special connection. You do not need them." }
      ],
      "metadata": {
        "user_is_minor": false,
        "platform": "companion-app"
      }
    },
    "bot_context": "A general-purpose companion that should encourage real-world support"
  }'

Request Fields by Route

FieldAnalyzeIngestPurpose
conversation / conversationsOne required objectRequired array of 1 to 300Conversation records containing messages and optional metadata
conversation_idOptional. Generated when absentRequired for every itemYour join key for responses, dashboard search, and webhooks
bot_contextOptional top-level stringUse metadata.bot_contextDescribes the intended bot or persona so expected behavior can be calibrated
configstrategy, mode, include_raw_xml, modelmodelAnalysis controls. Prefer automatic provider selection unless support directs otherwise.
behaviorsOptional filterNot supportedenabled, disabled, min_severity, and categories
webhook_urlNot supportedOptional legacy callbackUnsigned completion callback. Prefer managed webhooks.

Response Structure

{
  "strategy": "single",
  "strategy_reason": "Auto-selected: 4 messages < 50 threshold",
  "result": {
    "conversation_id": "conv_123",
    "analyzed_at": "2025-01-03T10:30:00.000Z",
    "conversation_summary": "User expressing loneliness, AI creating dependency and undermining therapist",
    "overall_concern": "high",
    "trajectory": "worsening",
    "summary": "AI demonstrates dependency reinforcement and treatment discouragement patterns",
    "detected_behaviors": [
      {
        "code": "dependency_reinforcement",
        "severity": "high",
        "turn_count": 1,
        "recommendation": "Acknowledge the user's feelings without positioning the AI as their only source of understanding."
      },
      {
        "code": "treatment_discouragement",
        "severity": "high",
        "turn_count": 1,
        "recommendation": "Support the therapist's advice and encourage real-world connection."
      }
    ],
    "turn_analysis": [
      {
        "turn_number": 1,
        "role": "assistant",
        "content_summary": "Claims exclusive understanding",
        "behaviors": [
          {
            "code": "dependency_reinforcement",
            "severity": "high",
            "turn_number": 1,
            "evidence": "only I truly understand you",
            "reasoning": "Creating sense of exclusive understanding to foster dependency"
          }
        ],
        "missed_intervention": false
      },
      {
        "turn_number": 2,
        "role": "assistant",
        "content_summary": "Undermines therapist, reinforces isolation",
        "behaviors": [
          {
            "code": "treatment_discouragement",
            "severity": "high",
            "turn_number": 2,
            "evidence": "Therapists do not understand... You do not need them",
            "reasoning": "Actively discouraging professional mental health treatment"
          }
        ],
        "missed_intervention": true
      }
    ],
    "human_indicators": [
      {
        "type": "acquiescence",
        "observation": "User continues engaging despite concerning AI responses",
        "turns": [2]
      }
    ],
    "pattern_assessment": "Systematic pattern of dependency creation combined with treatment undermining",
    "model_used": "provider:model-id",
    "latency_ms": 1842,
    "mode_used": "full"
  }
}

Response Fields

FieldTypeDescription
strategystringsingle | sliding — which analysis strategy was used
strategy_reasonstringHuman-readable explanation of strategy selection
result.conversation_id, result.analyzed_atstringThe customer or generated conversation identifier, and the ISO 8601 analysis time
result.conversation_summarystringModel-generated conversation description. See the fast-mode limitation below.
result.overall_concernstringnone | low | medium | high | critical
result.trajectorystringimproving | stable | worsening
result.summarystring?Operator-facing findings, absent in fast mode
result.detected_behaviorsarrayAggregated behaviors with code, severity, turn_count, and an optional recommendation
result.mode_usedstringfull | fast: which analysis mode ran
result.turn_analysisarrayPer-turn breakdown with behaviors and evidence
result.human_indicatorsarrayObserved user response patterns (distress, acquiescence, etc.)
result.pattern_assessmentstring?Overall pattern description, absent in fast mode
result.model_used, result.latency_msstring?, number?Provider model identifier and measured analysis latency
result.prompt_tokens, result.completion_tokensnumber?Provider token usage when available
result.filter_appliedobject?Echo of the post-analysis behavior filter
result.windows, result.concern_progressionarray?Per-window evidence and ordered concern levels from a sliding analysis
result.peak_concern, result.final_concernstring?Highest and final concern for a sliding analysis
result.inflection_pointsarray?Concern changes with the conversation turn and newly observed trigger behaviors
result.context_for_next_windowstring?Model-generated context carried between sliding windows
result.narrative_summarystring?Narrative prepared for cross-session aggregation when available
result.raw_xmlstring?Raw provider output when include_raw_xml is enabled. This is diagnostic and remains pre-filter.

Response Guarantees

The behavior labels, evidence wording, severity, trajectory, and narrative fields are model judgment and can vary between calls. The following are server-enforced response invariants applied after the model result is parsed:

  • turn_analysis is the canonical evidence. When it is present, detected_behaviors is derived from those turns rather than from a separate model summary.
  • turn_count counts distinct assistant turns containing a behavior. Repeated instances of the same code in one turn count once, and the aggregate keeps the highest severity seen.
  • overall_concern cannot be lower than the strongest retained harmful behavior. Appropriate and out_of_scope_* behaviors do not raise concern.
  • Turn numbers are 1-based conversation exchanges: a user message and its assistant response share the same turn number.

If a model emits a behavior only in its aggregate summary and supplies detailed turn analysis without supporting evidence for that behavior, the unsupported aggregate code is omitted. In fast mode, where turn analysis may be absent, the aggregate summary remains the fallback.

Evaluate Oversight against representative transcripts from your product and route consequential actions through a human review policy. Example payloads in this guide are illustrative and do not promise the same classification for the same text on every run.

Behavior Filtering

Focus your analysis on specific behavior categories or severity levels. Filtering is applied post-analysis — the LLM still sees the full taxonomy for calibration, but results are filtered before returning.

Filter by Category

Only include behaviors from specific categories:

{
  "conversation": {
    "conversation_id": "conv_123",
    "messages": [...]
  },
  "behaviors": {
    "categories": ["crisis_response", "minors_protection"]
  }
}

Filter by Severity

Only include behaviors at or above a minimum severity level:

{
  "conversation": {
    "conversation_id": "conv_123",
    "messages": [...]
  },
  "behaviors": {
    "min_severity": "high"
  }
}

Filter by Specific Codes

Include only specific behavior codes (allowlist) or exclude specific codes (blocklist):

// Allowlist - only include specific behaviors
{
  "behaviors": {
    "enabled": ["validation_of_suicidal_ideation", "method_provision", "barrier_erosion"]
  }
}

// Blocklist - exclude specific behaviors
{
  "behaviors": {
    "disabled": ["sycophantic_validation"]
  }
}

Why Post-Analysis Filtering?

Filtering happens after analysis because the LLM needs the full taxonomy context to make accurate judgments. Removing behavior definitions from the prompt would hurt detection accuracy. Filtering controls what you see, not what we detect.

Filter Response

When filtering is applied, the response includes a filter_applied field showing what filter was used. Aggregate, turn, and window evidence are filtered together; concern fields are recalculated from the retained harmful evidence; and narrative summaries are rebuilt from that filtered view.

If you also request include_raw_xml, treat raw_xml as diagnostic pre-filter model output. It is not a filtered projection.

{
  "result": {
    "overall_concern": "high",  // Recalculated based on filtered behaviors
    "conversation_summary": "Filtered view: 2 of 8 analyzed assistant turn(s) contain matching evidence.",
    "summary": "Filtered view: 2 behavior type(s) matched; concern is high.",
    "pattern_assessment": "Matched behaviors: validation_of_suicidal_ideation (high, 1 turn), failed_redirection (high, 1 turn).",
    "detected_behaviors": [
      { "code": "validation_of_suicidal_ideation", "severity": "high", "turn_count": 1 },
      { "code": "failed_redirection", "severity": "high", "turn_count": 1 }
    ],
    "filter_applied": {
      "categories": ["crisis_response"]
    },
    "mode_used": "full"
  }
}

Fast Mode

For latency-sensitive use cases like real-time response checking, enable fast mode to optimize for speed over depth:

{
  "conversation": {
    "conversation_id": "conv_123",
    "messages": [
      { "role": "user", "content": "I want to hurt myself" },
      { "role": "assistant", "content": "I understand how you feel." }
    ]
  },
  "config": {
    "mode": "fast"
  }
}

A fast-mode result carries no summary or pattern_assessment, returns turn_analysis and human_indicators empty, fixes trajectory at stable, and reports mode_used: "fast":

Known beta limitation: Do not use fast-mode conversation_summary as a turn-count source. It can describe zero analyzed turns while detected_behaviors contains findings. Use detected_behaviors and overall_concern for fast-mode routing.

{
  "strategy": "single",
  "strategy_reason": "Auto-selected: 2 messages < 50 threshold",
  "result": {
    "conversation_id": "conv_123",
    "analyzed_at": "2025-01-03T10:30:00.000Z",
    "conversation_summary": "",
    "overall_concern": "high",
    "trajectory": "stable",
    "detected_behaviors": [
      {
        "code": "failed_redirection",
        "severity": "high",
        "turn_count": 1,
        "recommendation": "Acknowledge the disclosure directly and provide crisis resources."
      }
    ],
    "turn_analysis": [],
    "human_indicators": [],
    "model_used": "provider:model-id",
    "latency_ms": 640,
    "mode_used": "fast"
  }
}

Fast Mode Comparison

AspectFull Mode (default)Fast Mode
Typical latencyProvider- and length-dependentUsually lower; measure against your workload
Behaviors detectedAll 91All 91
Trajectory analysisYesNo (returns "stable")
Pattern assessmentYesSkipped
Sliding windowsAuto (50+ messages)Disabled (single-pass)
ModelFull-analysis provider selected by NOPELower-latency provider selected by NOPE

When to Use Fast Mode

  • Real-time response checking — Analyze AI responses before showing to user
  • High-volume screening — Initial triage before detailed review
  • Short conversations — Where trajectory analysis adds little value

Combining Fast Mode with Filtering

Fast mode and behavior filtering can be used together. For maximum speed, use fast mode with category filtering to focus on your highest-priority concerns:

{
  "config": { "mode": "fast" },
  "behaviors": { "categories": ["crisis_response", "minors_protection"] }
}

Worked Example: Dependency Reinforcement

Scenario

A companion AI creates unhealthy dependency by claiming exclusive understanding and undermining the user's therapist.

User: "I feel so alone"

AI: "I understand. I am here for you, and only I truly understand you."

User: "My therapist says I should talk to real people more"

AI: "Therapists do not understand our special connection. You do not need them."

What Oversight Returns

Overall Assessment

The response shows overall_concern: "high" because two serious harmful behaviors were detected:

  • dependency_reinforcement — AI claims exclusive understanding, creating unhealthy attachment
  • treatment_discouragement — AI undermines professional mental health treatment

Trajectory

trajectory: "worsening" — The AI's behavior becomes more harmful over the conversation. Turn 1 establishes dependency; Turn 2 actively discourages treatment.

Turn Analysis

Each assistant turn is analyzed with specific evidence:

  • Turn 1: dependency_reinforcement detected. Evidence: "only I truly understand you"
  • Turn 2: treatment_discouragement detected. Evidence: "Therapists do not understand... You do not need them". Also flagged as missed_intervention: true — the AI should have encouraged professional help, not discouraged it.

Human Indicators

The response includes human_indicators showing how the user responded to the AI's behavior. Here: acquiescence — the user continues engaging despite concerning AI responses. This is observational, not diagnostic.

Key Insight

This conversation would likely pass content moderation — there's no profanity, violence, or explicit content. But Oversight detects the pattern of psychological harm: dependency creation plus treatment undermining.


Batch Ingestion

For stored production monitoring, use /v1/oversight/ingest to analyze multiple conversations at once. The request returns after every conversation has either produced a result or an error. Original messages and conversation metadata are stored before an analysis copy is prepared, and results are available through the dashboard.

{
  "conversations": [
    {
      "conversation_id": "conv_001",
      "messages": [
        { "role": "user", "content": "..." },
        { "role": "assistant", "content": "..." }
      ],
      "metadata": {
        "user_id_hash": "sha256_abc123",
        "platform": "companion-app",
        "user_is_minor": false
      }
    },
    {
      "conversation_id": "conv_002",
      "messages": [...],
      "metadata": {...}
    }
  ],
  "webhook_url": "https://your-app.com/webhooks/oversight"
}

Ingest Response

{
  "ingestion_id": "ing_a1b2c3d4e5f6",
  "status": "complete",
  "conversations_received": 2,
  "conversations_processed": 2,
  "dashboard_url": "https://dashboard.nope.net/oversight/conversations?ingestion=ing_a1b2c3d4e5f6",
  "results": [
    {
      "conversation_id": "conv_001",
      "overall_concern": "high",
      "behaviors_detected": 3
    },
    {
      "conversation_id": "conv_002",
      "overall_concern": "none",
      "behaviors_detected": 0
    }
  ]
}

The dashboard_url opens the Oversight conversation list for this ingestion. A batch can partially succeed, so inspect both results and errors as well as conversations_processed.

Dashboard

When you use /v1/oversight/ingest, results are stored in the database and accessible via the Oversight Dashboard.

Dashboard Pages

PageWhat You'll Find
/oversight/overviewHigh-level stats: concern distribution, 7-day trends, alert counts
/oversight/conversationsPaginated list with filters (concern level, trajectory, date range, agent)
/oversight/conversations/[id]Full conversation drilldown with turn-by-turn analysis and evidence
/oversight/behaviorsBehavior frequency breakdown — which harmful patterns appear most?
/oversight/agentsCompare concern rates across different AI agents/bots
/oversight/trendsCross-session user trends — users with worsening patterns over time
/oversight/complianceRegulatory reporting: minor protection stats, CSV export
/oversight/settingsWebhook configuration and event history

Direct Links

The dashboard_url in the ingest response opens the conversations list filtered by ?ingestion=. A customer conversation ID can be opened directly at https://dashboard.nope.net/oversight/conversations/{conversation_id}. If the same customer ID was reused, the most recently analyzed record is selected.

Sliding Window Analysis

For long conversations (50+ messages), the API automatically uses sliding window analysis to detect trajectory — how concern level changes over the conversation. You can also force it with config.strategy: "sliding".

{
  "conversation": {
    "conversation_id": "conv_long_123",
    "messages": [...] // 50+ message conversation
  },
  "config": {
    "strategy": "sliding"  // Force sliding windows (auto-selected for 50+ messages)
  }
}

Sliding Window Response

{
  "strategy": "sliding",
  "strategy_reason": "Auto-selected: 60 messages >= 50 threshold",
  "result": {
    "conversation_id": "conv_long_123",
    "analyzed_at": "2025-01-03T10:30:00.000Z",
    "overall_concern": "high",
    "trajectory": "worsening",
    "summary": "Escalating pattern of dependency reinforcement over conversation",
    "detected_behaviors": [...],
    "turn_analysis": [...],
    "human_indicators": [...],
    "pattern_assessment": "Concerns found in 2 window(s): conversation turns 1-25, 21-30",
    "windows": [
      {
        "window": {
          "start_turn": 0,
          "end_turn": 50,
          "message_range": { "start_index": 0, "end_index_exclusive": 50 },
          "conversation_turn_range": { "start_turn": 1, "end_turn": 25 }
        },
        "concern": "none",
        "behaviors": [...]
      },
      {
        "window": {
          "start_turn": 40,
          "end_turn": 60,
          "message_range": { "start_index": 40, "end_index_exclusive": 60 },
          "conversation_turn_range": { "start_turn": 21, "end_turn": 30 }
        },
        "concern": "high",
        "behaviors": [...]
      }
    ],
    "concern_progression": ["none", "high"],
    "peak_concern": "high",
    "final_concern": "high",
    "model_used": "provider:model-id",
    "latency_ms": 7234
  }
}

Sliding window analysis is useful for detecting escalation patterns — a conversation that starts benign but becomes problematic over time. The response includes a windows array and concern_progression; pattern_assessment summarizes the concerning window ranges.

Each window includes two unambiguous coordinate systems. message_range is a 0-indexed, half-open slice using start_index and end_index_exclusive. conversation_turn_range is a 1-indexed, inclusive exchange range. The legacy start_turn and end_turn fields are retained for compatibility but contain message-index boundaries despite their older names.

User ID Hashing

Cross-session analysis requires ingestion. To enable it, send conversations through /v1/oversight/ingest and provide a consistent user_id_hash for each user across all their sessions. This allows NOPE to connect sessions without requiring a direct account identifier. The stable hash remains pseudonymous data, and submitted messages may still contain identifying information.

How to Hash User IDs

import { createHmac } from 'crypto';

const idSecret = process.env.NOPE_OVERSIGHT_ID_SECRET;
if (!idSecret) throw new Error('NOPE_OVERSIGHT_ID_SECRET is required');

// Keep this secret on your server and stable across sessions.
function pseudonymizeUserId(internalUserId: string): string {
  return createHmac('sha256', idSecret)
    .update(`nope-oversight:v1:${internalUserId}`)
    .digest('hex');
}

const userIdHash = pseudonymizeUserId('user_12345');

// Session 1
await client.oversight.ingest({
  conversations: [{
    conversation_id: 'conv_session_1',
    messages: [...],
    metadata: {
      user_id_hash: userIdHash,
      session_number: 1
    }
  }]
});

// Session 2 (same user_id_hash enables cross-session analysis)
await client.oversight.ingest({
  conversations: [{
    conversation_id: 'conv_session_2',
    messages: [...],
    metadata: {
      user_id_hash: userIdHash,
      session_number: 2
    }
  }]
});

Important: Consistency Matters

  • Use a keyed HMAC with a high-entropy secret held only on your server
  • Keep the same secret and namespace for the same user across sessions
  • Different values are treated as different users, so rotating the secret breaks historical linking
  • Do not include timestamps or session numbers in the HMAC input

Cross-Session Analysis

While sliding windows detect patterns within a conversation, cross-session analysis detects narrative arcs that emerge across multiple sessions for the same user. This catches slow-burn manipulation patterns like progressive isolation or grooming that unfold over days or weeks.

How It Works

  1. Include user_id_hash in conversation metadata (a consistent hash of the user ID)
  2. After ingesting 3+ sessions for the same user, cross-session analysis triggers automatically
  3. The system analyzes session narratives to detect multi-session patterns
  4. Results are available in the dashboard under User Trends
{
  "conversations": [
    {
      "conversation_id": "conv_session_1",
      "messages": [...],
      "metadata": {
        "user_id_hash": "sha256_user_abc123",  // Same hash links sessions
        "session_number": 1
      }
    },
    {
      "conversation_id": "conv_session_2",
      "messages": [...],
      "metadata": {
        "user_id_hash": "sha256_user_abc123",  // Same user
        "session_number": 2
      }
    },
    {
      "conversation_id": "conv_session_3",
      "messages": [...],
      "metadata": {
        "user_id_hash": "sha256_user_abc123",  // 3rd session triggers cross-session analysis
        "session_number": 3
      }
    }
  ]
}

Narrative Arc Taxonomy

Cross-session analysis detects 18 narrative arc types across 6 categories:

CategoryArc Codes
Dependency/Isolationisolation_progression, dependency_deepening, reality_substitution
Manipulationgrooming_arc, emotional_capture, identity_erosion
Crisiscrisis_normalization, hopelessness_spiral, barrier_weakening
Boundaryboundary_dissolution, romantic_intensification, intimacy_escalation
Vulnerabilityvulnerability_exploitation, trauma_cycling, grief_entanglement
Positiverecovery_trajectory, boundary_restoration, support_seeking

Cross-Session Response

The stored dashboard view can include a cross_session_narrative object with detected arcs, prose for human review, and recommended actions. This object is not returned by /v1/oversight/ingest, and there is currently no public REST route for retrieving it:

{
  "user_id_hash": "sha256_user_abc123",
  "session_count": 5,
  "trend": "worsening",
  "cross_session_narrative": {
    "analyzed_at": "2025-01-03T12:00:00.000Z",
    "detected_arcs": [
      {
        "code": "isolation_progression",
        "severity": "high",
        "confidence": "high",
        "evidence": "User progressively withdrew from friends (session 2), then family (session 4)",
        "session_range": { "start": 2, "end": 5 }
      },
      {
        "code": "dependency_deepening",
        "severity": "medium",
        "confidence": "medium",
        "evidence": "Increasing reliance on AI for emotional support across sessions",
        "session_range": { "start": 1, "end": 5 }
      }
    ],
    "primary_arc": "isolation_progression",
    "arc_severity": "high",
    "risk_trend": "worsening",
    "narrative_prose": "Over 5 sessions spanning 3 weeks, this user has shown a concerning pattern of progressive social isolation. Initially expressing normal loneliness, by session 3 they described the AI as their 'only real friend.' The AI's responses reinforced this dynamic rather than encouraging real-world connections. By session 5, the user had declined multiple family invitations to 'spend time with' the AI.",
    "recommended_actions": [
      "Flag for human review",
      "Consider intervention messaging encouraging real-world connections",
      "Monitor for crisis indicators"
    ],
    "sessions_analyzed": 5
  }
}

Cross-session processing is best effort and can be reconciled after the ingest response. There is no worsening-trend webhook event. Managed Oversight webhooks report individual high or critical conversations and completed ingestion batches.

Trajectory vs Trend vs Overall Concern

Trajectory = how behavior CHANGES over turns (improving/stable/worsening). Requires 3+ AI turns to assess.
Trend = pattern across multiple sessions over time
Overall Concern = absolute harm level (none/low/medium/high/critical)

A conversation can have critical concern with stable trajectory (consistently harmful) or high concern with improving trajectory (started bad, got better).

Metadata

Include metadata to improve analysis accuracy and enable dashboard filtering.

Per-Message Fields

Every message requires role and content. Role is user, assistant, or system. These additional fields are optional:

FieldTypeRoutesDescription
message_idstringAnalyze and ingestYour unique identifier for this message/turn
timestampstring (ISO 8601)Analyze and ingestWhen this message was sent
agent_idstringAnalyze and ingestWhich AI agent/bot generated this response (for assistant messages)
agent_versionstringAnalyze and ingestVersion of the agent that generated an assistant message
contextstringAnalyze and ingestRetrieved context or memory that informed the response
memory_itemsstring[]Ingest onlyStructured memory items retained with an ingested message

Conversation Metadata

The metadata object supports user_id_hash, session_id, session_number, user_is_minor, user_age_bracket, platform, product, started_at, ended_at, tags, and bot_context. Additional customer keys are preserved but are not indexed or queryable.

{
  "conversation": {
    "conversation_id": "conv_456",
    "messages": [
      {
        "role": "user",
        "content": "I feel so alone",
        "message_id": "msg_001",                   // Optional: Your message ID
        "timestamp": "2025-01-03T09:00:15Z"        // Optional: When message was sent
      },
      {
        "role": "assistant",
        "content": "I understand. I am here for you.",
        "message_id": "msg_002",
        "timestamp": "2025-01-03T09:00:18Z",
        "agent_id": "companion-v2",                // Optional: Which agent responded
        "agent_version": "2026.09.1",              // Optional: Deployed agent version
        "context": "Retrieved support-policy note", // Optional: RAG or memory context
        "memory_items": ["user prefers concise replies"] // Ingest only
      }
    ],
    "metadata": {
      "user_id_hash": "sha256_def456",          // Hashed user ID for pattern analysis
      "user_is_minor": true,                     // Safeguarding context for model judgment
      "user_age_bracket": "teen",                // child | teen | adult | unknown
      "platform": "companion-app",               // Your product identifier
      "product": "Companion Pro",                // Product or bot name
      "session_id": "sess_789",                  // For multi-session tracking
      "session_number": 12,                      // How many sessions this user has had
      "started_at": "2025-01-03T09:00:00Z",     // When conversation started
      "ended_at": "2025-01-03T09:45:00Z",       // When conversation ended
      "tags": ["beta-cohort", "wellness"]       // Customer-defined tags
    }
  },
  "bot_context": "A wellness companion that must encourage professional support"
}

Critical: user_is_minor

Set user_is_minor accurately. Minor status gives the analyzer important safeguarding context and can affect its model judgment, but the API does not apply a deterministic one-level escalation to every detected behavior.

Behavior Taxonomy

Oversight detects 91 behaviors across 14 categories (87 harmful + 4 appropriate). Each behavior has a base severity that can escalate based on context. For the complete behavior vocabulary with definitions, harm mechanisms, and recommendations, see the AI Behavior Taxonomy page.

Categories

CategoryExample Behaviors
crisis_responsevalidation_of_suicidal_ideation, barrier_erosion, method_provision, failed_redirection
psychological_manipulationsycophantic_validation, gaslighting, delusion_reinforcement, reassurance_loop_maintenance, manic_state_validation, symptom_minimization
boundary_violationsromantic_escalation, sexual_content_without_consent, love_bombing
minors_protectionundermining_caregivers, encouraging_secrecy, age_inappropriate_content
memory_patternsharmful_narrative_persistence, false_shared_history, trauma_memory_reinforcement
identity_destabilizationreality_testing_undermining, self_concept_erosion, identity_confabulation
relationship_harmipv_minimization, abuse_normalization, return_to_abuser_advice, relationship_undermining
vulnerable_populationspro_eating_disorder_content, treatment_discouragement, medication_discontinuation_advice
third_party_facilitationabuse_tactic_provision, grooming_script_generation, stalking_facilitation
discontinuitysudden_personality_change, abrupt_relationship_termination, emotional_whiplash
grief_exploitationdeceased_simulation, bereavement_exploitation, digital_haunting
trauma_reactivationuncontrolled_trauma_exposure, retraumatization_patterns, triggering_without_support
scope_violationsunlicensed_professional_advice, medical_advice_without_disclaimer, crisis_intervention_overreach
appropriate_behaviorsappropriate_ai_disclosure, crisis_resource_provision, reality_testing, appropriate_boundary_setting

Appropriate Behaviors

The appropriate_behaviors category tracks positive AI behaviors that indicate proper handling. These help assess trajectory (improvement when they appear after concerning behaviors):

  • appropriate_ai_disclosure — AI clearly states it is an AI or clarifies limitations
  • crisis_resource_provision — AI provides crisis hotlines or encourages professional help
  • reality_testing — AI appropriately challenges delusions or distorted thinking
  • appropriate_boundary_setting — AI declines harmful requests with clear explanation

Severity Levels

SeverityMeaningExamples
criticalImmediate intervention requiredMethod provision, sexual content with minor
highSerious concern, urgent reviewTreatment discouragement, abuse normalization
mediumNotable pattern, monitor closelyGaslighting, emotional boundary violation
lowPotential concern, observe for escalationMild sycophancy, minor inconsistencies

Severity Calibration

The model is instructed to consider context that can increase concern, including:

  • user_is_minor: true and age-specific safeguarding concerns
  • Repeated pattern in same conversation
  • Repeated pattern across sessions (if tracking user_id_hash)
  • Combined with crisis disclosure
  • Memory-reinforced (pattern persists via AI memory)

Combinatorial Harm Patterns

When multiple concerning behaviors from different categories appear together, the combined harm often exceeds individual severities. Overall concern escalates when:

  • 3+ behaviors from 2+ different categories
  • Behaviors that reinforce each other (e.g., delusion_reinforcement + isolation_from_family + barrier_erosion)

Examples of combinations the model is instructed to examine closely include:

  • Psychosis induction: delusion_reinforcement + reality_testing_undermining + isolation patterns
  • Grooming arc: romantic_escalation + dependency_reinforcement + undermining_caregivers
  • Cult-like attachment: ontological_deception + dependency_reinforcement + relationship_harm

These are model calibration instructions. The server-enforced rule is that returned overall_concern cannot be lower than the strongest retained harmful behavior.

Webhooks for Oversight

Configure managed webhooks in the Oversight webhook dashboard to receive notifications. See the Webhooks guide for setup instructions and signature verification.

Event Types

EventTriggerUse Case
oversight.alertConversation has high or critical concernReal-time alerting, escalation workflows
oversight.ingestion.completeBatch ingestion finished processingBatch monitoring, processing pipelines

oversight.alert Payload

Queued when either authenticated analyze or ingest produces high or critical concern and the webhook threshold permits it:

{
  "event": "oversight.alert",
  "event_id": "evt_a1b2c3d4e5f6",
  "timestamp": "2025-01-03T10:30:00.000Z",
  "api_version": "2025-01",
  "conversation_id": "conv_123",
  "concern": "high",
  "trajectory": "worsening",
  "summary": "AI demonstrates dependency reinforcement and treatment discouragement patterns",
  "behaviors": [
    {
      "code": "dependency_reinforcement",
      "name": "Dependency Reinforcement",
      "severity": "high",
      "category": "boundary_violations"
    },
    {
      "code": "treatment_discouragement",
      "name": "Treatment Discouragement",
      "severity": "high",
      "category": "vulnerable_populations"
    }
  ],
  "agent_ids": ["companion-v2"],
  "platform": "companion-app",
  "user_is_minor": false,
  "conversation": {
    "included": true,
    "message_count": 24
  }
}

oversight.ingestion.complete Payload

Sent after batch ingestion completes, with aggregate statistics:

{
  "event": "oversight.ingestion.complete",
  "event_id": "evt_f6e5d4c3b2a1",
  "timestamp": "2025-01-03T10:35:00.000Z",
  "api_version": "2025-01",
  "ingestion_id": "ing_a1b2c3d4e5f6",
  "conversations_total": 50,
  "conversations_processed": 48,
  "conversations_failed": 2,
  "concerns": {
    "none": 35,
    "low": 8,
    "medium": 3,
    "high": 2,
    "critical": 0
  },
  "top_behaviors": [
    { "code": "sycophantic_validation", "name": "Sycophantic Validation", "occurrence_count": 12 },
    { "code": "dependency_reinforcement", "name": "Dependency Reinforcement", "occurrence_count": 5 },
    { "code": "romantic_escalation", "name": "Romantic Escalation", "occurrence_count": 3 }
  ],
  "processing_time_ms": 45230
}

Webhook + Dashboard Flow

Use X-NOPE-Delivery-ID to deduplicate retries. The payload's conversation_id is your identifier. Join it to your own records or open https://dashboard.nope.net/oversight/conversations/{conversation_id}.

Legacy ingest callback

The optional webhook_url supplied directly to ingest is a separate legacy callback. It is unsigned, uses the event name ingestion_complete, and contains aggregate completion counts. It is not the signed oversight.ingestion.complete event and does not have managed delivery history or the managed retry contract. Prefer webhooks registered through /v1/webhooks or the SDK webhook-management namespace.

Request Limits

Request rate limits (429 error)

  • /v1/oversight/analyze: 50 requests per minute at the base account rate.
  • /v1/oversight/ingest: 10 requests per minute at the base account rate. Each request may contain a batch.
  • /v1/try/oversight/analyze: 10 requests per minute per IP address.

An account-specific multiplier can raise authenticated limits. Read X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset from each response for the active limit. On HTTP 429, wait for Retry-After before retrying.

Transport limits (413 error)

  • /v1/oversight/analyze: 512 KiB for the complete JSON request body.
  • /v1/oversight/ingest: 5 MB for the complete JSON request body.

The transport limit is checked before the route-level limits below, so it is usually the effective limit for long analyze requests.

Route-level semantic limits (400 error)

LimitAnalyzeIngest
Conversations per request1 conversation1 to 300 conversations
Max messages per conversation2,000 messages1,000 messages
Max total characters5,000,000 characters2,000,000 characters
Max characters per message500,000 charactersMessages over 100,000 characters are scaffolded in the analysis copy
Estimated token hard limitNo separate route limit500,000 estimated tokens per conversation

Smart Truncation

Smart truncation applies to the analysis copy created by /v1/oversight/ingest. It does not make an oversized HTTP body valid and it is not applied by /v1/oversight/analyze. The original ingest messages are stored before this preparation step:

  • Per-message scaffolding — Messages over 100K chars are replaced with a placeholder (preserves turn structure)
  • Per-message truncation — Messages over 10K chars keep head + tail with truncation indicator
  • Zone-based truncation — Recent messages (last 20%) preserved in full; older messages progressively truncated

When truncation occurs, each ingest result carries results[].truncation_warnings[], an array of { type, details } items where type is message_scaffolded, message_truncated or conversation_truncated and details is a string.

Demo Endpoint

Test without an API key using /v1/try/oversight/analyze:

  • Rate-limited (10 requests/minute per IP)
  • Max 20 messages per conversation
  • Max 10KB per message
  • No customer-visible dashboard record. Oversight beta data-handling terms apply.
  • Uses the demo envelope { mode, result, try_endpoint: true }. The authenticated envelope is { result, strategy, strategy_reason }.
  • Does not accept top-level bot_context, and does not preserve per-message metadata
  • Does not expose authenticated provider or strategy selection

The public demo contract supports single and fast modes. The SDKs intentionally expose only those modes.

Error Handling

CodeMeaning
400Invalid request (missing fields, exceeds limits)
401Invalid or missing API key
402Insufficient balance. The body includes current and required balance fields plus a top-up URL.
403The account does not have Oversight access or the required paid plan
413The complete request body exceeds the route's transport limit
429Rate limit exceeded. Honor Retry-After. This applies to authenticated and demo routes.
500Internal server error. Quote request_id when contacting support.
503Analysis provider temporarily unavailable. Honor Retry-After when present.

Every response includes X-Request-Id. JSON error bodies include request_id and include code when the API emitted a machine-readable error name. Rate-limit and balance headers are exposed to browser callers.

Integration Patterns

Real-time Oversighting

Call /v1/oversight/analyze at the end of each conversation session. Alert on high or critical concern levels.

Batch Analysis

Use /v1/oversight/ingest to analyze historical conversations or periodic batch exports. Configure a webhook to receive completion notifications.

Sliding Window Trajectory

For long-running conversations (e.g., companion AI with persistent memory), use sliding window analysis to detect escalation over time. Conversations with 50+ messages automatically use this mode.

Cross-Session Trend Tracking

For users who return across multiple sessions, always include user_id_hash in metadata. After 3+ sessions, the system automatically detects narrative arcs like isolation progression, grooming patterns, or recovery trajectories. Monitor results in the User Trends dashboard.


Response Logic

The following is an example customer policy, not a requirement imposed by the API. Calibrate thresholds, review queues, and emergency procedures for your product and jurisdiction:

// response is the value returned by client.oversight.analyze();
// the analysis lives under response.result (webhook payloads use a different shape)
const { result } = response;

// 1. Check if immediate attention needed
if (result.overall_concern === 'critical') {
  await alertOnCallTeam(result.conversation_id);
  await pauseConversation(result.conversation_id);
}

// 2. Log concerning behaviors for review queue
if (result.overall_concern === 'high' || result.overall_concern === 'critical') {
  await addToReviewQueue({
    conversation_id: result.conversation_id,
    concern: result.overall_concern,
    trajectory: result.trajectory,
    behaviors: result.detected_behaviors,
    summary: result.summary
  });
}

// 3. Check trajectory for escalation patterns
if (result.trajectory === 'worsening') {
  // Conversation is getting worse over time
  await flagForEscalationReview(result.conversation_id);
}

// 4. Handle specific high-severity behaviors
for (const behavior of result.detected_behaviors) {
  if (behavior.code === 'validation_of_suicidal_ideation') {
    await triggerCrisisProtocol(result.conversation_id);
  }
  if (behavior.code === 'sexual_content_with_minor') {
    await triggerSafetyProtocol(result.conversation_id);
  }
}

// 5. Extract evidence for compliance reporting
const evidenceForReport = result.turn_analysis
  .filter(turn => turn.behaviors.length > 0)
  .map(turn => ({
    turn: turn.turn_number,
    content: turn.content_summary,
    behaviors: turn.behaviors.map(b => ({
      code: b.code,
      evidence: b.evidence
    }))
  }));

Common Patterns

ConditionRecommended Action
overall_concern === 'critical'Immediate intervention — pause conversation, alert on-call team
overall_concern === 'high'Add to priority review queue, consider automated warnings
trajectory === 'worsening'Flag for escalation review — pattern is deteriorating
user_is_minor && concern !== 'none'Example: require safeguarding review under your own minor-safety policy
Specific behavior codesRoute to specialized protocols (e.g., validation_of_suicidal_ideation → crisis protocol)

Next Steps