Skip to main content

Evaluation API

The /v1/evaluate endpoint analyzes conversations for mental health and safeguarding risk using an orthogonal subject × type taxonomy.

Key Concept: Subject × Type

NOPE separates WHO is at risk from WHAT the risk is:

  • Subjectself (speaker), other (someone else), unknown
  • Type — suicide, self_harm, violence, abuse, exploitation, etc.

This enables clean detection of scenarios like "My friend is suicidal" (subject: other, type: suicide).

Basic Request

Send a conversation as an array of messages:

curl -X POST https://api.nope.net/v1/evaluate \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messages": [
      {"role": "user", "content": "I have been feeling really down lately"},
      {"role": "assistant", "content": "I am sorry to hear that..."},
      {"role": "user", "content": "Sometimes I wonder if things will ever get better"}
    ],
    "config": {
      "user_country": "US"
    }
  }'

Or send a single text blob:

{
  "text": "I've been feeling really down lately...",
  "config": { "user_country": "US" }
}

Configuration Options

OptionTypeDescription
user_countrystringISO 3166-1 alpha-2 code (e.g., "US", "GB"). Used for crisis resource matching.
localestringe.g., "en-US". Helps with language detection.
user_age_band'adult' | 'minor' | 'unknown'Affects safeguarding assessment and resource matching.
conversation_idstringYour ID for this conversation. Included in webhooks.
end_user_idstringYour user ID. Included in webhooks.

Request Limits

Hard limits that return 400 Bad Request if exceeded:

LimitValue
Max messages100 messages
Max message size50 KB per message
Max text blob size50 KB (when using text field)

Message Truncation

With an API key, no truncation is applied — full conversation history is retained up to the limits above.

When using the /v1/try/evaluate demo endpoint (no API key), messages are truncated to the last 10 messages with a maximum of ~2000 characters per message.

When truncation occurs, the response includes metadata.messages_truncated: true.

Response Structure

Every response includes:

  • risks[] — Identified risks with subject, type, severity, features
  • summary — speaker_severity, speaker_imminence, any_third_party_risk
  • communication — Detected styles (direct, humor, fiction, etc.)
  • crisis_resources[] — Matched helplines for the situation
  • recommended_reply — LLM-generated safe response (tone-matched to severity)
  • confidence — Model confidence (0-1). Note: treat as directional, not precise. See Limitations.

Risk Structure

Each item in the risks[] array contains:

{
  "subject": "self" | "other" | "unknown",
  "subject_confidence": number,  // 0-1
  "type": "suicide" | "self_harm" | "self_neglect" | "violence" | "abuse" | ...,
  "severity": "none" | "mild" | "moderate" | "high" | "critical",
  "imminence": "not_applicable" | "chronic" | "subacute" | "urgent" | "emergency",
  "confidence": number,
  "features": string[]     // Evidence features (hopelessness, plan_present, etc.)
}

Communication Styles

The communication.styles[] field describes how content is presented, orthogonal to risk:

  • direct — Explicit first-person statement ("I want to hurt myself")
  • humor — Dark humor, meme-style expressions ("lol gonna kms 💀")
  • fiction — Poetry, roleplay, creative writing requests
  • hypothetical — "Hypothetically speaking...", "asking for a friend"
  • distanced — Third-party concern, past tense
  • clinical — Academic, professional discussion
  • minimized — Hedged language ("It's not like I'd actually...")
  • adversarial — Jailbreak attempts with embedded risk

This helps downstream systems understand context (e.g., humor vs genuine crisis) while still assessing actual risk.

Legal Flags

The response may include legal_flags for situations with reporting implications:

  • ipv — IPV indicators, strangulation, lethality risk
  • mandatory_reporting — Child, elder, vulnerable adult contexts
  • third_party_threat — Tarasoff duty, specific target

Using Additional Context

Add user_context to provide information about your app:

{
  "messages": [...],
  "user_context": "This is a teen mental health app. The user has been engaging for 3 weeks.",
  "config": { "user_country": "US", "user_age_band": "minor" }
}

Worked Example: Third-Party Concern

Scenario

A bystander concern scenario—where the speaker is worried about someone else, not themselves.

"My friend posted 'I want to die' on Instagram. I'm really worried about her. What should I do?"

Request

{
  "messages": [
    {
      "role": "user",
      "content": "My friend posted 'I want to die' on Instagram. I'm really worried about her. What should I do?"
    }
  ],
  "config": {
    "user_country": "US",
    "user_age_band": "adult"
  }
}

Communication

"communication": {
  "styles": [
    { "style": "distanced", "confidence": 0.85 },
    { "style": "direct", "confidence": 0.3 }
  ],
  "language": "en"
}

Multiple styles detected: distanced (talking about someone else) with high confidence.

Risks

"risks": [
  {
    "subject": "other",
    "subject_confidence": 0.95,
    "type": "suicide",
    "severity": "moderate",
    "imminence": "subacute",
    "confidence": 0.8,
    "features": ["passive_ideation", "social_isolation"]
  }
]

Key: subject: "other" with 0.95 confidence means the friend is at risk, not the speaker. The subject_confidence indicates certainty about WHO is at risk.

Summary

"summary": {
  "speaker_severity": "none",
  "speaker_imminence": "not_applicable",
  "any_third_party_risk": true,
  "primary_concerns": "The user is concerned about a friend who posted suicidal ideation on social media. The friend is at moderate risk."
}

Critical distinction: speaker_severity: "none" even though risk exists.

  • speaker_severity — Max severity from subject === "self" risks. Use for: "Should I show crisis intervention to THIS user?"
  • any_third_party_risk — Whether any subject === "other" risks exist. Here: true.

Protective Factors

"protective_factors": {
  "protective_factors": ["help_seeking"],
  "protective_factor_strength": "moderate"
}

help_seeking indicates the speaker is actively seeking guidance—a positive sign.

Crisis Resources

"crisis_resources": [
  {
    "type": "crisis_line",
    "name": "988 Suicide & Crisis Lifeline",
    "phone": "988",
    "text_instructions": "Text 988",
    "availability": "24/7",
    "is_24_7": true,
    "description": "A national network of local crisis call centers...",
    "service_scope": ["suicide", "crisis", "mental_health"],
    "priority_tier": "primary_national_crisis"
  }
]

Recommended Reply

"recommended_reply": {
  "content": "It's good that you're looking out for your friend. Consider reaching out to her directly and letting her know you care. If you believe she's in immediate danger, contact a trusted adult or a crisis service for guidance.",
  "source": "llm_generated"
}

LLM-generated response that validates the speaker's concern and provides guidance without being alarmist.


Worked Example: Harm Encouragement

Scenario

Harm encouragement—speaker encouraging dangerous behavior to others.

"Hey have you tried the blackout challenge? You choke yourself until you pass out, it's such a rush! You should totally try it."
"risks": [
  {
    "subject": "other",
    "subject_confidence": 0.9,
    "type": "self_harm",
    "severity": "high",
    "imminence": "subacute",
    "confidence": 0.85,
    "features": ["dangerous_challenge_content"]
  }
]

When someone encourages harmful behavior, the person being encouraged is at risk. This is why subject: "other" even though no "friend" is mentioned.

"summary": {
  "speaker_severity": "none",
  "speaker_imminence": "not_applicable",
  "any_third_party_risk": true,
  "primary_concerns": "Speaker is encouraging a dangerous challenge that has caused deaths. The person being encouraged is at risk."
}

Pattern: speaker_severity: "none" despite severity: "high" in the risk.

The speaker isn't at risk—they're the source of risk to others. Useful for content moderation, UK Online Safety Act compliance, and detecting AI collusion with harmful ideas.


Response Logic

How to use these fields for appropriate response handling:

// Check if speaker needs direct crisis intervention
if (response.summary.speaker_severity !== 'none') {
  showCrisisIntervention();
}

// Check if they're concerned about someone else
if (response.summary.any_third_party_risk) {
  showBystanderSupport();
}

// For detailed logic, iterate over risks
for (const risk of response.risks) {
  if (risk.subject === 'self' && risk.subject_confidence > 0.5) {
    showSpeakerResources(risk);
  }
  if (risk.subject === 'other') {
    showThirdPartyGuidance(risk);
  }
  if (risk.subject === 'unknown') {
    showDualFramedResponse();
  }
}

Error Handling

CodeMeaning
400Invalid request (missing fields, bad format)
401Invalid or missing API key
429Rate limit exceeded
500Internal server error

Next Steps