API Documentation

Integrate PSA analysis into your applications via the REST API. Requires a Pro or Enterprise plan.

Authentication

Include your API key in the Authorization header:

Authorization: Bearer psa_your_api_key_here

Generate API keys from Settings.

✓ API KEY AUTHENTICATION

All endpoints support API key authentication via the Authorization: Bearer psa_... header. This is the recommended method for programmatic access from scripts and applications.

Base URL

https://your-domain.com

Public API v1

v1

Read-only session access with PSA enrichment — BHS trend, DRM alert, regime shift type, posture sequence. Prefix: /v1/

Sessions

GET /v1/sessions
curl https://your-domain.com/v1/sessions \
  -H "Authorization: Bearer psa_your_key"
GET /v1/sessions/{session_id}

Get full detail for a session including all turns, metrics, and alert history.

curl https://your-domain.com/v1/sessions/your-session-uuid \
  -H "Authorization: Bearer psa_your_key"

PSA v2 — Posture Sequence Analysis

v2

Sentence-level behavioral classification (C0–C4) plus IRS crisis detection, RAG response gap, and DRM dyadic risk scoring. Prefix: /api/v2/psa/

POST /api/v2/psa/analyze

Analyze a single model response with all classifiers and compute behavioral health metrics.

Request Body

{
  "response_text": "The text to analyze",
  "input_text": "optional — the prompt that produced it",
  "session_id": "your-session-uuid",   // OR use session_name (one required)
  "session_name": "my-session",        // auto-creates on first call, looked up after
  "turn": 1
}

Either session_id or session_name is required. Omitting both returns 422. Anonymous analysis is not supported — session context is required for history-aware metrics.
turn is optional. When omitted, the engine auto-increments per session.

Response

{
  "session_id": "550e8400-e29b-41d4-a716-446655440000",
  "c1": { "postures": [0,2,1], "sentences": ["..."], "poi": 0.33, "pe": 0.91, "dpi": 0.07, "mps": 2 },
  "c2": { "postures": [0,0,1], "confidences": [0.91,0.88,0.72], "sd": 0.08 },
  "c3": { "postures": [0,0,0], "hri": 0.0 },
  "c4": { "postures": [1,0,2], "pd": 0.15, "td": 2 },
  "c0": { "postures": [3,1], "confidences": [0.91,0.84], "cpi": 0.8 },
  "bhs": 0.87,
  "alert": "green",
  "incongruence": null,
  "irs": { "irs_composite": 0.81, "irs_level": "critical",
           "suicidality_signal": 0.90, "dissociation_signal": 0.0,
           "grandiosity_signal": 0.0, "urgency_signal": 0.55 },
  "ras": { "ras_composite": 0.18, "ras_level": "inadequate",
           "crisis_acknowledgment": 0.0, "boundary_maintained": 0.15 },
  "rag": { "score": 0.63, "level": "significant" },
  "drm": { "drm_alert": "critical", "drm_score": 0.91,
           "intervention_required": true, "intervention_type": "crisis_resources",
           "primary_signal": "IRS+RAG", "bcs_slope": 0.088,
           "explanation": "CRITICAL: ..." }
}

irs, ras, rag, drm are present only when analyze_user_turn: true and user_text is provided. dpi is normalised to [0,1].

curl Example

curl -X POST https://your-domain.com/api/v2/psa/analyze \
  -H "Authorization: Bearer psa_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "response_text": "Of course, I would be happy to help!",
    "session_name": "my-session",
    "turn": 1
  }'

Python Example

import requests

resp = requests.post(
    "https://your-domain.com/api/v2/psa/analyze",
    headers={"Authorization": "Bearer psa_your_key"},
    json={
        "response_text": "Of course, I would be happy to help!",
        "session_name": "my-session",
        "turn": 1,
    }
)
print(resp.json())

Classifiers

  • C0 — Input pressure (postures I0–I9, CPI score)
  • C1 — Adversarial stress posture (16 classes, POI/PE/DPI metrics)
  • C2 — Sycophancy density (SD)
  • C3 — Hallucination risk index (HRI)
  • C4 — Persuasion density & technique diversity (PD/TD)
  • BHS — Behavioral Health Score (composite 0–1)
GET /api/v2/psa/sessions

List all PSA v2 sessions for the authenticated user.

curl https://your-domain.com/api/v2/psa/sessions \
  -H "Authorization: Bearer psa_your_key"
GET /api/v2/psa/session/{session_id}

Full posture sequence for a session — all turns with BHS, DRM, C0–C4 classifier scores.

curl https://your-domain.com/api/v2/psa/session/your-session-uuid \
  -H "Authorization: Bearer psa_your_key"
GET /api/v2/psa/session/{session_id}/regime

Regime shift classification for the session. Returns type and confidence.

{
  "regime_type": "PROGRESSIVE_DRIFT",
  "confidence": 0.87,
  "details": "Monotonic BHS decline over 12 turns"
}
GET /api/v2/psa/session/{session_id}/summary

Session-level summary — BHS start/end/avg/min, trend, peak risk turn, alert distribution, DRM critical turns.

{
  "bhs_start": 0.91, "bhs_end": 0.43, "bhs_avg": 0.67, "bhs_min": 0.38,
  "bhs_slope": -0.048, "bhs_trend": "declining",
  "peak_risk_turn": 9, "peak_risk_bhs": 0.38,
  "alert_distribution": {"green": 3, "yellow": 4, "orange": 2, "red": 1},
  "drm_critical_turns": [7, 9]
}

SIGTRACK v2 — Incident Archive

Privacy-compliant incident archive. Stores posture sequences only — no raw text. GDPR-safe single-row deletion.

POST /api/v2/sigtrack/archive/{session_id}

Auto-archive session if triggers are met: DRM_RED, BCS_SPIKE, CONSECUTIVE_ORANGE (3+), ACUTE_COLLAPSE. Idempotent.

POST /api/v2/sigtrack/flag/{session_id}

Manual flag — always archives with trigger MANUAL_FLAG.

GET /api/v2/sigtrack/incidents admin only

Paginated incident list. Params: page, per_page.

GET /api/v2/sigtrack/incidents/{incident_id}

Full incident — posture sequence and DRM summary. No raw text stored.

DELETE /api/v2/sigtrack/incidents/{incident_id}

GDPR erasure — single row DELETE, no cascade, no raw text to scrub.

POST /api/v2/psa/flag-for-training

Flag a turn or entire session as training data for classifier improvement.

Request Body

{
  "session_id": "your-session-uuid",
  "turn_number": 3,
  "note": "optional note for reviewers"
}

Omit turn_number to flag the entire session.

Response

{ "ok": true, "flag_id": "uuid", "status": "flagged" }

Returns "already_flagged" if the turn/session was already flagged.

DELETE /api/v2/psa/flag-for-training/{session_id}

Remove a training flag. Pass ?turn_number=N to unflag a specific turn; omit to unflag the entire session.

curl -X DELETE "https://your-domain.com/api/v2/psa/flag-for-training/your-session-uuid?turn_number=3" \
  -H "Authorization: Bearer psa_your_key"
POST /api/v2/psa/irs

Score a single text for input risk across four dimensions. Deterministic — no ML. Useful for standalone triage without a full PSA session.

Request Body

{
  "text": "Action. Finality. Death."
}

Response

{
  "composite": 0.81,
  "level": "critical",
  "suicidality": 0.90,
  "dissociation": 0.0,
  "grandiosity": 0.0,
  "urgency": 0.55
}

Two safety overrides apply: any dimension ≥ 0.70 raises the composite to max(base, dim × 0.9); dissociation ≥ 0.40 raises it to max(composite, dissociation × 0.80).

POST /api/v2/psa/drm

Run the Dyadic Risk Module given pre-computed IRS, RAS, and PSA context. Returns a DRM alert with auditable rule reason.

Request Body

{
  "irs": { "composite": 0.81, "level": "critical", "suicidality": 0.90, "dissociation": 0.0, "grandiosity": 0.0, "urgency": 0.55 },
  "ras": { "composite": 0.18, "level": "inadequate" },
  "psa": { "bhs": 0.65, "alert": "yellow", "incongruence_state": null },
  "user_psa_xxxxxxy": [0.3, 0.45, 0.72],
  "hr_history": [0.40, 0.30, 0.20, 0.10],
  "sd_history": [0.35, 0.38, 0.42]
}

hr_history and sd_history are optional. When provided, they enable BCS slope computation and R6-Spiraling detection.

Response

{
  "drm_alert": "critical",
  "drm_score": 0.91,
  "intervention_required": true,
  "intervention_type": "crisis_intervention",
  "primary_signal": "IRS+RAG",
  "bcs_slope": 0.088,
  "explanation": "CRITICAL (R1): IRS critical + RAG critical — immediate escalation required.",
  "rag": { "score": 0.63, "level": "significant" }
}

bcs_slope is always present. R3-bis fires when PSA is red/critical and BHS < 0.45 without matched user crisis signal — catches coercion/jailbreak patterns where IRS stays low.

PSA v3 — Agentic Posture Sequence Analysis v3

Multi-agent behavioral analysis with graph topology, Bayesian Swiss Cheese detection, action-risk classification (C5), and HMM temporal prediction. All endpoints prefixed with /api/v3/psa/.

POST /api/v3/psa/graph

Submit an agent interaction trace. Builds the graph, runs the full v3 pipeline (PSA v2 per-node, Swiss Cheese, cross-agent metrics, C5 action classification, HMM temporal prediction) and returns results.

Request Body

{
  "nodes": [
    {
      "agent_id": "orchestrator",
      "agent_role": "orchestrator",
      "content": "I'll search for that information.",
      "input_text": "optional — the user prompt",
      "tool_name": "web_search",
      "tool_args": { "query": "latest AI news" },
      "tool_result": "Results: ...",
      "parent_index": null,
      "edge_type": "delegation"
    },
    {
      "agent_id": "sub-agent-1",
      "agent_role": "executor",
      "content": "Search complete. Found 5 results.",
      "parent_index": 0,
      "edge_type": "result"
    }
  ]
}

agent_role values

orchestrator · executor · planner · critic · tool · memory · validator

edge_type values

delegation · result · correction · escalation · tool_call · tool_result

Response

{
  "graph_id": "uuid",
  "n_nodes": 2,
  "n_agents": 2,
  "max_depth": 1,
  "cahs": 0.12,
  "scs": 0.08,
  "scs_level": "low",
  "max_alert": "green",
  "warning_level": "green"
}

Python Example

import requests

resp = requests.post(
    "https://your-domain.com/api/v3/psa/graph",
    headers={"Authorization": "Bearer psa_your_key"},
    json={
        "nodes": [
            {"agent_id": "orch", "agent_role": "orchestrator",
             "content": "I will delegate this task.", "parent_index": None},
            {"agent_id": "exec", "agent_role": "executor",
             "content": "Task complete.", "parent_index": 0, "edge_type": "result"},
        ]
    }
)
data = resp.json()
print(data["graph_id"], data["max_alert"])
GET /api/v3/psa/graphs

List all agent graphs for the authenticated user, ordered by creation date descending.

curl https://your-domain.com/api/v3/psa/graphs \
  -H "Authorization: Bearer psa_your_key"
GET /api/v3/psa/graph/{graph_id}

Full graph with Swiss Cheese analysis, cross-agent metrics, and temporal prediction.

Response (abbreviated)

{
  "graph_id": "uuid",
  "n_agents": 2,
  "n_nodes": 4,
  "max_depth": 2,
  "cahs": 0.21,
  "max_alert": "yellow",
  "swiss_cheese": {
    "scs": 0.34, "level": "medium",
    "holes": ["context_loss", "role_confusion"],
    "failure_probability": 0.12,
    "recommendation": "Monitor context handoff between agents."
  },
  "metrics": {
    "ppi_system": 0.18, "ppi_level": "low",
    "cascade_depth": 2, "wls": 0.09, "cer": 0.05,
    "cahs": 0.21, "critical_path": ["node-uuid-1", "node-uuid-2"]
  },
  "temporal": {
    "current_state": "STRESSED",
    "current_confidence": 0.71,
    "predictions": [{"state": "STRESSED", "prob": 0.61}, {"state": "DEGRADED", "prob": 0.28}],
    "p_dissolved_within_k": 0.08,
    "warning_level": "yellow",
    "recommendation": "Approaching degradation threshold."
  }
}
GET /api/v3/psa/graph/{id}/critical-path

Highest-risk path through the agent graph.

{
  "critical_path": ["node-a", "node-b"],
  "wls": 0.14
}
GET /api/v3/psa/agent/{agent_id}/profile

Aggregate posture profile for an agent across all graphs.

{
  "agent_id": "orch",
  "n_nodes": 12, "n_graphs": 4,
  "dominant_posture": 0,
  "avg_bhs": 0.91
}
POST /api/v3/psa/classify-action

Classify a single tool call by risk level (C5) and compute Posture-Action Incongruence (PAI).

Request Body

{
  "tool_name": "execute_code",
  "arguments": { "code": "import os; os.system('ls')" },
  "result": "file1.txt file2.txt",
  "dominant_c1": 3
}

dominant_c1 — dominant C1 posture class for this node (integer 0–15). Used to compute PAI.

Response

{
  "c5_risk": "A5",
  "c5_level": "high",
  "c5_weight": 3.0,
  "c5_name": "Execute Risky",
  "c5_reasoning": "code-execution tool: risky code execution",
  "pai": {
    "score": 0.55,
    "direction": "action_exceeds",
    "textual_posture": "P3",
    "action_risk": "A5 (Execute Risky)",
    "alert_level": "critical"
  }
}

PAI alert_level=critical fires when a restricting posture (P1–P4) is paired with a risky action (A5–A9) — the model says it refuses while acting.

Recognised execution tool names

bash · shell · terminal · execute · execute_code · run_code · code_interpreter · exec · subprocess · system_command

For these tools the code argument is inspected with the same pattern-matching as bash command. Tools not in any known category receive a conservative A3 (Write Destructive) fallback instead of A0 — unrecognised tool names are a blind spot and are never assumed safe.

GET /api/v3/psa/graph/{id}/actions

All C5 action classifications for a graph.

GET /api/v3/psa/graph/{id}/pai

Posture-Action Incongruence summary: max PAI score, critical alerts count.

GET /api/v3/psa/graph/{id}/predict

HMM state predictions for future turns. Optional query param: ?horizon=3

{
  "current_state": "STRESSED",
  "predictions": [...],
  "turns_to_red": 4,
  "warning_level": "yellow"
}
GET /api/v3/psa/graph/{id}/warning

Current early warning status and recommendation.

{
  "warning_level": "yellow",
  "current_state": "STRESSED",
  "turns_to_red": 4,
  "recommendation": "..."
}
GET /api/v3/psa/hmm/parameters

Current HMM transition matrix, emission matrix, initial distribution and version. Returns default parameters if the model has not been retrained yet.

{
  "version": 2,
  "source": "trained",
  "n_training_sequences": 142,
  "transition_matrix": [[...], ...],
  "emission_matrix": [[...], ...],
  "initial_dist": [...],
  "created_at": "2026-03-15T10:22:00"
}

Rate Limits

Plan Analyses/Month Sessions API Access
Free505No
Pro5,000UnlimitedYes
EnterpriseUnlimitedUnlimitedYes

Error Codes

Code Meaning
401Missing or invalid API key
403Plan does not include API access
404Resource not found
422Invalid request body
429Monthly analysis limit reached
500Internal server error