Simulix

API v1

API Reference

Stable as of v1. All endpoints are versioned in the path; breaking changes ship as a new prefix with a deprecation window.

Endpoints

POST/v1/simulationsCreate a simulation with an explicit workflow_id. Returns 202 with poll URL. See /docs/simulations.
POST/v1/simulations/autoAuto-route a natural-language question to the best calibrated workflow. Returns 202 + meta.routed_via; falls back to 422 routing_low_confidence with alternatives.
GET/v1/simulationsList your organization's simulations. Cursor-paginated.
GET/v1/simulations/:idGet simulation status. Honors Retry-After while running.
GET/v1/simulations/:id/resultsGet full per-agent results. 409 if simulation not yet complete.
POST/v1/api-keys/{key_id}/rotateRotate an API key. See /docs/api-keys for full lifecycle.
GET/v1/statusPublic health probe: API + DB + Redis components, plus link-outs for Stripe + Resend. 30s Redis cache.
GET/v1/usageCurrent-period consumption + plan-tier caps. Returns simulations-this-period, lifetime count, agent-count ceiling, and per-minute rate limit. No scope required — the data is the caller's own.
POST/v1/auth/password/signupCreate a new organization + user with a chosen password and start a session. Public; per-IP rate-limited (5 req/min). Body: {email, password (10-200 chars), name, organization_name}. Returns 201 + SessionResponse with Set-Cookie.
POST/v1/training/uploadsMint a training run row in QUEUED state + return a signed R2 PUT URL for the calibration CSV. Body: {workflow_name (1-120), description? (≤1000)}. Returns 201 + {training_id, upload_url, upload_url_expires_at}. Scope: training:write.
POST/v1/training/:id/startTransition a QUEUED training run to RUNNING + (v1) sync-complete with mock results. 202 + TrainingRunResponse. 409 if not QUEUED. Scope: training:write.
GET/v1/training/:idPoll a training run's status. results_available is true iff status is terminal. Scope: training:read.
GET/v1/training/:id/resultsTerminal-only: MAPE + by-segment breakdown + preview_only flag (always true in v1 — mock-label discipline per ADR-028 § 3). 409 training_not_complete if non-terminal. Scope: training:read.
POST/v1/webhooksRegister a webhook endpoint. Body: {url, events[], description?, custom_headers?}. Returns 201 + WebhookResponse with the generated signing secret shown ONCE in plaintext. Scope: webhooks:write.
GET/v1/webhooksList your organization's webhook endpoints. Cursor-paginated. Scope: webhooks:read.
GET/v1/webhooks/:idGet a single webhook endpoint's metadata (no secret). Scope: webhooks:read.
POST/v1/webhooks/:idUpdate a webhook endpoint (url, events, description, custom_headers). PATCH semantics over the listed fields. Scope: webhooks:write.
DELETE/v1/webhooks/:idHard-delete a webhook endpoint + cancel pending deliveries. Scope: webhooks:write.
POST/v1/webhooks/:id/rotate-secretIssue a new signing secret for an existing webhook endpoint. Old secret remains valid for 24h overlap. Returns the new plaintext secret ONCE. Scope: webhooks:write.
GET/v1/webhooks/:id/deliveriesCursor-paginated delivery history for a webhook endpoint. Each entry includes status, response code, retry count, latency_ms, error_message. Scope: webhooks:read.
POST/v1/webhooks/:id/testTrigger a synthetic webhook.test event delivery. Useful for verifying signatures + endpoint reachability in the console. Scope: webhooks:write.

POST/v1/simulations

Create a new simulation. The response is asynchronous (per ADR-006): all simulations are queued and delivered via webhook on completion. See /docs/simulations for the full endpoint family + webhook signature verification.

Body

workflow_idstringrequired

Workflow slug identifying which calibrated YAML aggregator to run.

agent_countintegerrequired

Number of agents to simulate. 1—10,000.

scenario_contextobjectrequired

Workflow-specific parameters. See workflow docs.

questionstring

Optional. Per ADR-029 (v1.0.7c): your customer's literal question, asked verbatim of every agent in the matched methodology's population. Omitting the field falls back to the legacy behavior (agents see the methodology's calibrated KPI question); the legacy branch is deprecated for 12 months per I-12.

seedinteger

Optional deterministic seed.

webhook_urlstring

Override default webhook for this sim.

Example request

POST /v1/simulations HTTP/1.1
Authorization: Bearer sk_test_...
Idempotency-Key: 01HXZ...

{
  "workflow_id": "cdc_nhis_adult_smoking",
  "agent_count": 200,
  "scenario_context": { "region": "US" },
  "seed": 7
}

Response — 201

{
  "id": "sim_01HXA6QC2F",
  "status": "queued",
  "created_at": "2026-04-22T18:34:12Z"
}

POST/v1/simulations/auto

Take a natural-language question and match it to the closest methodology grounded in real demographics, then create the simulation. Same async contract as /v1/simulations (202 + poll URL), with meta.routed_via describing the matched methodology + confidence. Per ADR-029 (v1.0.7c), the matched methodology supplies the population, segments, and sample profile; the agents are asked your literal question, not the methodology's calibrated KPI question. When the match confidence is below the routing floor (default 0.65), responds 422 routing_low_confidence with the top alternatives in meta.alternatives so you can pick explicitly and re-submit against /v1/simulations with an explicit workflow_id plus your literal question field.

Body

questionstringrequired

Natural-language question. 10—2,000 chars. The auto-router scores every published workflow against this text.

agent_countinteger

Optional. Defaults to the matched workflow's recommended sample size. Subject to your plan tier's ceiling.

scenario_contextobject

Optional. Workflow-specific overrides applied after routing.

Example request

POST /v1/simulations/auto HTTP/1.1
Authorization: Bearer sk_test_...
Idempotency-Key: 01HXZ...

{
  "question": "Will families take a summer vacation this year despite high prices?",
  "agent_count": 500
}

Response — 202 (routed)

{
  "data": {
    "id": "sim_01HXA6QC2F",
    "status": "queued"
  },
  "meta": {
    "routed_via": {
      "workflow_id": "aaa_summer_travel_intent",
      "workflow_name": "AAA Summer Travel — At Least One Overnight Trip",
      "confidence": 0.84,
      "kpi_question": "Will you take at least one overnight leisure trip this summer?"
    }
  }
}

meta.routed_via.methodology_label names the matched methodology (the population, segments, and sample profile that will be applied). Your customer's literal question is what the agents are asked, and it's preserved verbatim on the results envelope as data.customer_question (returned from GET /v1/simulations/{id}/results). The legacy meta.routed_via.kpi_question field stays for one deprecation cycle (12-month I-12 window); it carries the methodology's own calibrated KPI text, which the agents are no longer asked.

Calibration boundary tiers (v1.0.7c)

Every result envelope (from GET /v1/simulations/{id}/results) carries an additive calibration_boundary field that discloses which of three tiers the verdict respects. Read the disclaimer string verbatim above the verdict on your dashboard.

calibrated_matchsage-tier

Your literal question matched the methodology's calibrated KPI question closely (cosine similarity >= 0.85). The verdict is calibrated against the published benchmark on /benchmarks. The accuracy_pct + confirm_mean_pct fields render here. Only here.

methodology_matchdefault

Your literal question fit the methodology's topic but was phrased differently from the calibrated KPI. The methodology's demographically grounded population was applied; the agents were asked your literal question. The verdict shows what this population said about your question. The methodology's published accuracy claim does not apply on this tier; accuracy_pct is null.

no_matchamber-tier

No published methodology fit your question closely. A generic demographically grounded U.S. population was used. There is no calibration claim on this run. methodology_id is null.

The verdict aggregate also gains a 4th n_a bucket — “the question doesn't fit this segment of the population.” Pre-v1.0.7c rows carry n_a = null and render as 3-way (yes / maybe / no) as before. Read more in methodology vs question.

Response — 422 (routing_low_confidence)

{
  "error": "routing_low_confidence",
  "meta": {
    "alternatives": [
      { "workflow_id": "cdc_nhis_adult_smoking", "confidence": 0.42 },
      { "workflow_id": "aaa_summer_travel_intent", "confidence": 0.38 }
    ]
  }
}

Errors

CodeTypeDescription
400invalid_workflowWorkflow slug does not exist or is deprecated.
402insufficient_quotaAccount has reached its monthly simulation limit.
429rate_limitedToo many requests. Back off per Retry-After.