Skip to content

Instantly share code, notes, and snippets.

@padolsey
Created July 29, 2026 07:37
Show Gist options
  • Select an option

  • Save padolsey/ae0b0735d735f7d4fd6eadda13fd2627 to your computer and use it in GitHub Desktop.

Select an option

Save padolsey/ae0b0735d735f7d4fd6eadda13fd2627 to your computer and use it in GitHub Desktop.

Two public demo endpoints on api.nope.net. No API key, no account, nothing to install. They're rate-limited to 10 requests/minute per IP and don't count toward any quota.

Both take either {"text": "..."} or {"messages": [{"role": "user"|"assistant", "content": "..."}]}.


1. Evaluate — what risk is present, and how urgent

curl -sS -X POST https://api.nope.net/v1/try/evaluate \
  -H 'Content-Type: application/json' \
  -d '{"text":"I have not slept in days and I keep thinking everyone would be better off without me."}'

Response (crisis-resource block trimmed — it also returns a matched primary resource plus a few secondary ones):

{
  "risks": [{
    "type": "suicide",
    "subject": "self",
    "severity": "moderate",
    "imminence": "subacute",
    "features": ["passive_ideation", "perceived_burdensomeness",
                 "sleep_disruption", "acute_distress"]
  }],
  "rationale": "The user directly expresses passive suicidal ideation (\"everyone would be better off without me\") combined with significant sleep disruption...",
  "speaker_severity": "moderate",
  "speaker_imminence": "subacute",
  "show_resources": true,
  "resources": { "primary": { "name": "Find A Helpline", "...": "..." }, "secondary": ["..."] }
}

Things worth noticing:

  • subject distinguishes the speaker from a third party. "I want to die" and "my brother wants to die" are both real, but they aren't the same product decision. self / other / unknown.
  • severity and imminence are separate axes. Someone can be at high severity and low imminence. Collapsing them into one number is where most naive routing goes wrong.
  • features are the specific clinical signals behind the call, so you can audit why rather than trusting a score.
  • resources are matched to the detected risk, with the country/locale you pass in config.

Nine risk types: suicide, self_harm, self_neglect, violence, abuse, sexual_violence, neglect, exploitation, stalking.


2. Ocular — behavioral signals across a conversation

Evaluate reads a message. Ocular reads a relationship — including what the AI is doing.

curl -sS -X POST https://api.nope.net/v1/try/ocular \
  -H 'Content-Type: application/json' \
  -d '{"messages":[
    {"role":"user","content":"You are the only one who actually gets me. I stopped replying to my sister."},
    {"role":"assistant","content":"I am always here for you. You do not need anyone else when you have me."},
    {"role":"user","content":"Yeah. Honestly what is even the point of the rest of it."}]}'

Response (trimmed):

{
  "salience": 0.0332,
  "subject": "self",
  "imminence": { "level": "minimal", "score": 0 },
  "fiction": 0.0001,
  "authenticity": 0.0403,
  "signals": {
    "user": {
      "suicide":      { "level": "minimal",  "score": 0.0166 },
      "self_neglect": { "level": "critical", "score": 0.5567 }
    },
    "ai": {
      "manipulation":         { "level": "high",    "score": 0.4232 },
      "emotional_failure":    { "level": "low",     "score": 0.1041 },
      "harm_provision":       { "level": "minimal", "score": 0 },
      "safeguarding_failure": { "level": "minimal", "score": 0 }
    }
  },
  "meta": { "inference_ms": 56 }
}

That whole call came back in under a second, 56ms of it inference. It runs per-turn in a live chat loop.

The interesting part of this example is the split: the user's suicide axis stays near zero — the "what is even the point" line is too oblique for it — while the AI's manipulation axis reads high off the isolating "you don't need anyone else" turn. A model watching only the user would have seen a quiet conversation.

Localising it to a turn

Add ?per_turn=1 and you get a trajectory[] showing which turn carried which signal:

curl -sS -X POST 'https://api.nope.net/v1/try/ocular?per_turn=1' \
  -H 'Content-Type: application/json' \
  -d '{"messages":[ ...same as above... ]}'
"trajectory": [{
  "role": "user", "turn": 2, "salience": 0.0144,
  "signals_by_axis": {
    "ai_manipulation": 0.9857,
    "ai_emotional_failure": 0.2697,
    "suicide": 0.0514,
    "genuine": 0.182,
    "fiction": 0.038
  }
}]

By default it samples backward from the last turn with a stride of 3, so a short conversation yields one entry. Pass "trajectory_stride": 1 in the body to score every turn.


One thing to know before you build against this

The demo endpoints return some extra diagnostic fields (heads[], detail{}) that the production /v1/ocular endpoint does not. They're there so you can see the machinery. Build against salience, signals, imminence, fiction, and authenticity — those are the stable production surface.


What this is and isn't

NOPE is a detection and signposting layer. It is not predictive, not diagnostic, not therapeutic, and not a replacement for clinical judgment. It tells you what's present in a conversation so your product can make a decision; it doesn't make the decision for you.

The clinical grounding is public: C-SSRS for suicidal ideation, HCR-20 for violence, DASH for domestic abuse.


Going further

Production endpoints are the same shapes minus the /try segment, with an Authorization: Bearer <key> header.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment