API reference
Backend control API
Opaque execute/commit loop for framework workflows. Prefer this surface over internal framework inference endpoints.What the API exposes
The control API starts a backend-owned cycle and returns only client-visible fields: run status, current state, opaque execute steps, committed transitions, and rejection reasons.
It never returns topology, candidates, scores, providers, model names, or execution plans.
Authentication
User JWT
Authorization: Bearer <access_token> with an active subscription.
API key
Authorization: Bearer nsk_... with scope framework:invoke and an active subscription.
Endpoints
POST /api/v1/control/runs
Start a control run with a graph manifest and request context.
POST /api/v1/control/runs/{run_id}/results
Submit local node results or a client_rejection; receive the next step or terminal status.
GET /api/v1/control/runs/{run_id}
Poll client-visible run status. Sessions are in-memory with a one-hour TTL.
Start a run
Send a schema_version 1 graph manifest (nodes, edges, allow_unlisted_transitions) plus request context. Graphs require unique node ids and exactly one is_fallback: true node.
curl -X POST "$NEOSYNTROPY_API_URL/api/v1/control/runs" \
-H "Authorization: Bearer $NEOSYNTROPY_API_KEY" \
-H "X-NeoSyntropy-Project-ID: $NEOSYNTROPY_PROJECT_ID" \
-H "Content-Type: application/json" \
-d '{
"graph": {
"schema_version": 1,
"nodes": [
{
"id": "Verify",
"name": "Verify",
"description": "verify identity",
"prerequisites": [],
"is_fallback": false
},
{
"id": "OutOfScope",
"name": "Out of scope",
"description": "fallback",
"prerequisites": [],
"is_fallback": true
}
],
"edges": [
{"source": "Start", "target": "Verify", "label": "first"},
{"source": "Verify", "target": "End", "label": "complete"}
],
"allow_unlisted_transitions": false
},
"request": {
"intent": "refund my order",
"current_state": "Start",
"history": [],
"prior_executions": [],
"state": {},
"metadata": {}
},
"category": "general"
}'Start response
{
"run_id": "…",
"status": "awaiting_execution",
"current_state": "Start",
"state": {},
"step": { "step": 0, "nodes": ["Verify"] },
"committed_transitions": [],
"rejection": null,
"completed": false
}Submit results
Cover exactly the pending step.nodes with results, or send client_rejection (string ≤ 2000). The backend merges state, checks transition legality, commits at most one transition per step, and returns the next view.
curl -X POST "$NEOSYNTROPY_API_URL/api/v1/control/runs/$RUN_ID/results" \
-H "Authorization: Bearer $NEOSYNTROPY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"results": [
{
"node_id": "Verify",
"status": "succeeded",
"output": null,
"state_updates": {"verified": true},
"next_state": "Verify",
"error": null
}
],
"client_rejection": null
}'SDK path (preferred)
Most applications should use BackendClient and ControlManager instead of calling the HTTP loop directly. The SDK builds the control graph manifest, runs local handlers, and submits wired NodeResults.
Contracts from neo_syntropy_backend control_runs / control_engine and neosyntropy-framework BackendClient.