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
v1Read-only session access with PSA enrichment — BHS trend, DRM alert, regime shift type, posture sequence. Prefix: /v1/
Sessions
/v1/sessions
curl https://your-domain.com/v1/sessions \ -H "Authorization: Bearer psa_your_key"
/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
v2Sentence-level behavioral classification (C0–C4) plus IRS crisis detection, RAG response gap, and DRM dyadic risk scoring. Prefix: /api/v2/psa/
/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)
/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"
/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"
/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"
}
/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.
/api/v2/sigtrack/archive/{session_id}
Auto-archive session if triggers are met: DRM_RED, BCS_SPIKE, CONSECUTIVE_ORANGE (3+), ACUTE_COLLAPSE. Idempotent.
/api/v2/sigtrack/flag/{session_id}
Manual flag — always archives with trigger MANUAL_FLAG.
/api/v2/sigtrack/incidents
admin only
Paginated incident list. Params: page, per_page.
/api/v2/sigtrack/incidents/{incident_id}
Full incident — posture sequence and DRM summary. No raw text stored.
/api/v2/sigtrack/incidents/{incident_id}
GDPR erasure — single row DELETE, no cascade, no raw text to scrub.
/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.
/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"
/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).
/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/.
/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"])
/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"
/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."
}
}
/api/v3/psa/graph/{id}/critical-path
Highest-risk path through the agent graph.
{
"critical_path": ["node-a", "node-b"],
"wls": 0.14
}
/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
}
/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.
/api/v3/psa/graph/{id}/actions
All C5 action classifications for a graph.
/api/v3/psa/graph/{id}/pai
Posture-Action Incongruence summary: max PAI score, critical alerts count.
/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"
}
/api/v3/psa/graph/{id}/warning
Current early warning status and recommendation.
{
"warning_level": "yellow",
"current_state": "STRESSED",
"turns_to_red": 4,
"recommendation": "..."
}
/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 |
|---|---|---|---|
| Free | 50 | 5 | No |
| Pro | 5,000 | Unlimited | Yes |
| Enterprise | Unlimited | Unlimited | Yes |
Error Codes
| Code | Meaning |
|---|---|
| 401 | Missing or invalid API key |
| 403 | Plan does not include API access |
| 404 | Resource not found |
| 422 | Invalid request body |
| 429 | Monthly analysis limit reached |
| 500 | Internal server error |