One intake. Three calls. A clinician-ready result.

The Auddax API runs a governed clinical intake. You create an intake, you send each patient message as a turn, and you read the clinician handoff when the intake completes. The engine decides the questions, the safety status, and the disposition. Your application owns the surface.

The model is simple. An intake is one patient conversation. A turn is one patient message and the engine's reply. The handoff is the structured clinical summary the intake produces. Send patient language in. Get structured clinical state out.

Base URL sandbox
https://api.auddax.ai

Three rules keep your integration safe. Relay assistant_message to the patient without edits. Never override safety_status or disposition. Stop sending turns when terminal is true.

From key to handoff in three calls.

You need an API key. Create an account in the developer console and generate one in a few clicks, or request one by email. Export it before you run the examples.

Step 1 · Create an intake

Create the encounter first. The response gives you the encounter_id you use on every later call. The optional fields seed clinical context before the first turn.

request
$ curl -X POST https://api.auddax.ai/v1/intakes \
  -H "Authorization: Bearer $AUDDAX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "demographics": { "age_years": 58, "sex": "male" },
    "patient_history": "Allergies: penicillin. Current medications: lisinopril."
  }'
response201 Created
{
  "encounter_id": "enc_auddax-sandbox_91a81eb05e4c58fa",
  "status": "open",
  "created_at": "2026-08-21T16:31:04.118Z",
  "expires_at": "2026-08-21T18:31:04.000Z"
}
Step 2 · Send a turn

Send each patient message as one turn. The engine returns the next patient-facing message and the current clinical state. This example triggers a cannot-miss pathway, so the turn is terminal and the handoff is included.

request
$ curl -X POST https://api.auddax.ai/v1/intakes/$ENCOUNTER_ID/turns \
  -H "Authorization: Bearer $AUDDAX_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: turn-1-$ENCOUNTER_ID" \
  -d '{
    "message": "Chest pressure for the last hour, sweating and short of breath."
  }'
response200 OK
{
  "encounter_id": "enc_auddax-sandbox_91a81eb05e4c58fa",
  "turn_index": 1,
  "assistant_message": "I need you to call 911 right now or have someone take you
    to the emergency room immediately. [...]",
  "choices": [],
  "terminal": true,
  "urgent": true,
  "safety_status": "cannot_miss_positive",
  "disposition": "urgent_escalation",
  "disposition_label": "Emergency evaluation",
  "handoff": { "soap": { "...": "..." }, "provenance": { "...": "..." } }
}

A benign message behaves differently. The engine asks the next question, terminal stays false, and choices can carry quick replies you can render as buttons.

Step 3 · Read the handoff

The handoff stays readable by encounter_id after the intake closes and after the session expires. Store the id, not the payload, if you want to fetch it later.

request
$ curl https://api.auddax.ai/v1/intakes/$ENCOUNTER_ID/handoff \
  -H "Authorization: Bearer $AUDDAX_API_KEY"

The full handoff shape is documented in the handoff object.

Typed clients for Python and TypeScript.

The official SDKs cover the full API surface with typed requests, responses, and errors. Streaming, retries, idempotency keys, and webhook signature verification are built in, so what you test is the contract, not your HTTP plumbing. Both clients read AUDDAX_API_KEY from the environment.

install
$ pip install auddax        # Python 3.10+
$ npm install auddax        # Node 20+, zero dependencies

The whole quickstart above, through the SDK. A blocking turn attaches an Idempotency-Key automatically, streaming is an iterator, and terminal turns embed the typed handoff.

request
from auddax import Auddax

client = Auddax()

intake = client.intakes.create(demographics={"age_years": 58, "sex": "male"})

with client.intakes.stream_turn(intake.encounter_id, "I have chest pressure and I'm sweating.") as stream:
    for fragment in stream.text():
        print(fragment, end="", flush=True)

if stream.turn.terminal:
    print(stream.turn.handoff.soap.assessment)

Batch evaluation is two calls: batches.create(scenarios) then batches.wait(batch_id) for the full typed transcripts. Webhook deliveries verify with one function, verify_signature(body, signature, secret). Errors raise typed exceptions: RateLimitedError carries retry_after, IntakeClosedError means stop sending turns. The raw HTTP examples throughout these docs remain valid; the SDKs are the same contract with the plumbing handled.

One key. One header.

Every request except GET /v1/health needs your API key in the Authorization header. Sandbox keys start with adx_sb_.

header
Authorization: Bearer adx_sb_0123456789abcdef0123456789abcdef01234567

Keep the key on your server. Do not put it in a browser, a mobile app, or a repository. A request with a missing, wrong, or revoked key returns 401 unauthorized. If your key leaks, email team@auddax.ai and we rotate it. Revocation takes effect within one minute.

Your key sees only its own intakes. A request for another key's encounter_id returns 404 not_found.

The full surface.

  • POST /v1/intakes Create an intake
  • POST /v1/intakes/{encounter_id}/turns Send one patient message. Blocking or streaming.
  • GET /v1/intakes/{encounter_id} Status summary
  • GET /v1/intakes/{encounter_id}/handoff Clinician handoff. Works after close and expiry.
  • POST /v1/webhooks Register an event endpoint. Also GET to list, DELETE to remove.
  • POST /v1/batches Run scripted scenarios as a background job. GET for status.
  • GET /v1/usage Today's usage against your quotas
  • GET /v1/health Liveness and release identity. No auth.
  • GET /v1/openapi.yaml The machine-readable spec

All request and response bodies are JSON in snake_case. Request bodies have a 64 KB limit. Every response carries an x-auddax-release header with the release tag and build.

Create an intake · request fields

FieldTypeRules
demographics.age_years integer Optional. 0 to 130.
demographics.sex string Optional. One of female, male, intersex.
patient_history string Optional. Up to 4,000 characters. Free-text context such as allergies and current medications.

Send a turn · request fields

FieldTypeRules
message string Required. 1 to 8,000 characters. The patient's message, unmodified.
stream boolean Optional. Default false. True returns Server-Sent Events. See streaming.

Open, then closed or expired.

An intake opens when you create it. It closes when the engine reaches a terminal state. It expires when its session reaches the two-hour limit before a terminal state. The handoff stays readable in every state.

open turns accepted POST turns closed turns return 409 expired turns return 410 terminal turn 2 h session limit handoff readable
The handoff endpoint answers in every state. Only open intakes accept turns.
StatusMeaningTurnsHandoff
openThe intake accepts turns.AcceptedReadable
closedThe engine reached a terminal state.409 intake_closedReadable
expiredThe session passed the two-hour limit.410 intake_expiredReadable

Check the state at any time with GET /v1/intakes/{encounter_id}. The summary includes the turn count, the expiry time, and the last known safety status and disposition.

Every turn returns the clinical state.

A turn response always carries the same fields, terminal or not. The engine is authoritative. Show its message, honor its status, and do not soften its escalations.

FieldTypeMeaning
encounter_idstringThe intake this turn belongs to.
turn_indexintegerThe position of this turn, starting at 1.
assistant_messagestringThe next patient-facing message. Relay it without edits.
choicesstring[]Engine-suggested quick replies. Render them as buttons if you want.
terminalbooleanTrue when the intake reached a terminal state. Stop sending turns.
urgentbooleanTrue when the engine requires immediate clinician review. Surface it prominently.
safety_statusstring | nullThe deterministic safety state. Values include no_red_flags_yet, cannot_miss_negative, cannot_miss_positive.
dispositionstring | nullThe engine's disposition. Values include continue_intake, clinician_review, self_care, urgent_escalation.
disposition_labelstring | nullA display label for the disposition.
handoffobjectPresent when terminal is true. The full handoff object.
Treat enumerations as open sets. New safety statuses and dispositions can appear as the engine's coverage grows. Branch on the values you know. Pass unknown values through to your clinician surface.

The safety fields can be null on a turn in one rare case: the turn completed but the snapshot read behind it failed. The turn is still delivered. Read GET /v1/intakes/{encounter_id}/handoff to get the state. Do not resend the turn.

Stream anything a patient can see.

A turn drives a real model turn inside the engine. The complete result takes 20 to 40 seconds. Streaming removes the wait a patient would feel. The reply arrives token by token within seconds, and your interface stays alive while the engine compiles the clinical snapshot behind it.

Set "stream": true on the turns endpoint. The response is text/event-stream. Each event has an event: name and one data: line of JSON.

request
$ curl -N -X POST https://api.auddax.ai/v1/intakes/$ENCOUNTER_ID/turns \
  -H "Authorization: Bearer $AUDDAX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "message": "It hurts when I swallow.", "stream": true }'

Events

EventDataMeaning
message.delta{ "text" }The next fragment of the patient-facing reply. Append it.
message.completed{ "elapsed_ms" }The reply text is complete. You may send the next turn now.
handoff.compiling{ "terminal" }The engine compiles the clinical snapshot. Terminal tells you the intake is closing.
handoff.progress{ "chars" }Compile progress. Useful for a subtle activity indicator.
turn.completedturn objectThe same object the blocking response returns, handoff included when terminal.
error{ "code", "message" }The turn failed after the stream started. Read the handoff before you retry anything.

This is a recorded sandbox turn, replayed with its real timing compressed. Press play to see the event order.

POST /v1/intakes/{encounter_id}/turns · stream

Recorded sandbox events. Timing compressed for the demo.

You do not have to wait for the tail. When message.completed arrives, the patient can answer. Send the next turn immediately. The engine accepts it while the previous turn's snapshot still compiles. This is verified behavior, not an accident.

If a stream drops, do not resend the message blindly. The turn may have been delivered. Read the handoff to see the current state, then continue.

Plan for the latency budget.

Each turn runs a governed clinical reasoning pass. It is slower than a chat completion, and it is supposed to be. Design for the budget instead of hiding from it.

MilestoneTypical, warmWhat to show
First message.deltaA few secondsThe reply, appearing as it streams.
Complete patient message20 to 40 secondsThe full reply. The patient can answer now.
Snapshot and handoffShortly afterNothing. It compiles in the background.

The gateway holds a turn open for up to 240 seconds before it fails the call. Set your client timeout at 240 seconds or higher. Use streaming for every patient-facing surface. Use blocking calls for server-side and batch work where nobody watches a spinner.

Get told when an intake ends.

Register an https endpoint and the API calls you when an intake reaches a terminal state. No polling. A webhook problem never fails or slows a turn.

register
$ curl -X POST https://api.auddax.ai/v1/webhooks \
  -H "Authorization: Bearer $AUDDAX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "url": "https://example.com/auddax/hook" }'
response201 Created
{
  "id": "wh_9f2a51c07d3e44b1",
  "url": "https://example.com/auddax/hook",
  "events": ["intake.completed", "intake.escalated"],
  "secret": "whsec_...shown once, store it...",
  "created_at": "2026-08-21T18:20:11.312Z"
}

GET /v1/webhooks lists your endpoints (without secrets). DELETE /v1/webhooks/{id} removes one. Each key holds up to 3 endpoints. The target must be a public https URL.

Events

EventFires when
intake.completedAn intake reaches a terminal state without an urgent escalation.
intake.escalatedAn intake ends with an urgent escalation. Treat it with priority.
batch.completedA batch run finishes. Arrives with the batch API.

The delivery body is { id, event, created_at, data }. For intake events, data is the same object the terminal turn returned, handoff included. Headers: auddax-event, auddax-delivery, and auddax-signature.

Verify the signature

The signature header is t=<unix>,v1=<hex>. Compute HMAC-SHA256 over t + "." + raw_body with your endpoint secret and compare. Reject stale timestamps.

node
const [, t, v1] = /t=(\d+),v1=([a-f0-9]+)/.exec(req.headers["auddax-signature"]);
const expected = crypto.createHmac("sha256", WEBHOOK_SECRET)
  .update(`${t}.${rawBody}`)
  .digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
  && Math.abs(Date.now() / 1000 - Number(t)) < 300;

Answer with a 2xx within 10 seconds. Anything else retries: 3 attempts with backoff from 30 seconds to 5 minutes. Deliveries are at-least-once, so make your handler idempotent on the auddax-delivery id.

Evaluate the engine with scripted scenarios.

A batch runs synthetic patient conversations for you in the background. Send up to 20 scenarios with up to 12 messages each. The engine drives every scenario as a real intake, stops a scenario early when it reaches a terminal state, and stores the transcript. Use batches for benchmarking and regression checks.

create
$ curl -X POST https://api.auddax.ai/v1/batches \
  -H "Authorization: Bearer $AUDDAX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "label": "regression-aug",
    "scenarios": [
      { "label": "benign", "messages": ["Sore throat since yesterday.", "It hurts when I swallow."] },
      { "label": "urgent", "messages": ["Chest pressure for an hour, sweating."],
        "demographics": { "age_years": 58, "sex": "male" } }
    ]
  }'
response202 Accepted
{ "batch_id": "bat_5f0c33a1b2d4e6f8", "status": "queued", "scenario_count": 2 }

Poll GET /v1/batches/{batch_id} for status and per-scenario results, or register a webhook for batch.completed and skip polling. Each scenario result carries its encounter_id; fetch the full handoff with the normal handoff endpoint. GET /v1/batches lists your recent batches.

The rules that keep batches safe: batch turns draw from the same daily turn quota as interactive calls, one batch runs at a time per key (a second create returns 409 batch_running), scenarios run with limited concurrency, and a quota-starved scenario is marked failed with its partial transcript kept. Batch statuses: queued, running, completed, completed_with_failures.

Evaluate a conversation you did not drive.

The intake endpoints drive the interview: the engine asks the questions and reaches a disposition. Evaluate is the other shape. When a clinician runs the conversation and your product only records and analyzes it, you do not want the engine asking questions. You want the part that has to be right: catch the red flags and emergencies, evaluate the protocol, and decide the disposition over whatever the conversation has surfaced so far. That is POST /v1/evaluate.

The division of labor is the whole point. Your model does perception only: it turns the live transcript into the typed facts the engine needs, or you simply hand over the transcript text. MedCanon is the authority: it, not your model, sets every red-flag state, the emergency findings, and the disposition. No model runs inside the evaluate path, so the result is deterministic: the same input gives the same output, and every response is stamped provenance.deterministic: true.

Beta. The evaluate lane is in active development. The request and response shapes below are stable; fields marked coming populate in later phases. Send synthetic data only, as with the rest of the sandbox.

The scribe loop

A scribe records a growing clinician–patient conversation. On each new batch of speech, and once more at the end of the consult, you send the current state to evaluate and render what it returns.

1. Your model reads the transcript so far and extracts the protocol's typed fields (or you pass the raw transcript text).
2. POST /v1/evaluate with the facts and/or the transcript.
3. The engine returns the emergency screen, coverage, the protocol result, and the disposition.
4. Render the alerts and the disposition. Draft the note separately; the note is never the source of clinical truth. The orders and red-flag states come only from evaluate.

Call it about every 15 seconds while the consult is live, and once over the final transcript. It is fast because it is deterministic: no model turn, typically well under a second. It has its own generous rate class (at least 120 requests per minute) and does not draw from the intake turn quota.

Request

Send transcript_text, facts, or both. transcript_text is the fastest way to integrate and drives the emergency screen; facts (with a protocol_id) gives the precise rule verdict.

request
$ curl -X POST https://api.auddax.ai/v1/evaluate \
  -H "Authorization: Bearer $AUDDAX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "correlation_id": "consult-8f3a",
    "input": {
      "transcript_text": [
        { "speaker": "clinician", "text": "What brings you in today?" },
        { "speaker": "patient",   "text": "The worst headache of my life, it hit like a thunderclap a minute ago." }
      ]
    }
  }'

Request fields

FieldTypeRules
correlation_idstringOptional. For your own audit correlation only. The server keeps no state for it, so evaluate is fully stateless.
input.transcript_textarrayThe conversation so far, as { "speaker": "clinician" | "patient", "text": "..." }. Read by the deterministic emergency screen. No model reads it.
input.factsobjectThe extracted typed field values, as { field_id: value }. Deterministic protocol evaluation runs on these.
input.protocol_idstringRequired when facts is sent. May be omitted with transcript_text; the engine detects the protocol.
input.demographicsobjectOptional. { "age": 47, "sex": "M" }. Feeds age- and sex-gated rules.

Send at least one of transcript_text or facts. An empty input returns 400 invalid_request.

Response

response200 OK
{
  "correlation_id": "consult-8f3a",
  "coverage_state": "covered",
  "active_protocol": { "id": "headache" },
  "emergency": {
    "urgent": true,
    "findings": [
      { "id": "stroke_pattern",       "provenance": "deterministic_emergency_canon" },
      { "id": "thunderclap_headache", "provenance": "deterministic_protocol" }
    ]
  },
  "protocol_result": {
    "matched": true,
    "rule_id": "red_flag_urgent_referral",
    "diagnosis": { "label": "Urgent Referral Required", "disposition": "urgent" },
    "derived_values": { "has_red_flags": true, "has_nausea_or_vomiting": true }
  },
  "disposition": "urgent",
  "safety_status": "cannot_miss_positive",
  "provenance": {
    "deterministic": true,
    "engine_release": "2026.08",
    "audit_ref": "audit_f0812c423021"
  }
}
FieldWhat it means
coverage_statecovered when a protocol applies to the conversation, else uncovered or none.
active_protocolThe protocol the engine selected, or null. You did not choose it; the engine did.
emergencyurgent plus the deterministic findings. Runs independent of protocol selection, so a cannot-miss emergency is caught even when no protocol matches. Each finding names its source.
protocol_resultThe rule that fired: matched, rule_id, diagnosis (with disposition), and the derived_values the rules computed.
dispositionThe engine's routing decision, e.g. urgent.
safety_statuscannot_miss_positive, screening, or clear. Set by the engine; your model cannot set, clear, or delete it.
provenancedeterministic is true whenever no model ran (the facts and transcript paths). Carries the engine release and an audit_ref you can quote when reporting an issue.
cannot_miss, missing_fields, suggested_verificationsComing. Three-valued red-flag states, the fields still worth extracting, and clinician prompts for unknown high-risk items.

Determinism and safety

The shape is designed so the model cannot be the clinical authority, by construction:

GuaranteeHow
The model never decidesRed-flag states, emergency, and disposition come only from the engine. Your model fills in the blanks; it does not set the flags.
Emergencies are always screenedThe emergency block runs even when no protocol is detected, so a heart attack or anaphylaxis is caught regardless of routing.
Deterministic and replayableNo model in the path. The same facts and transcript give the same result, and provenance.deterministic proves it.
Stateless and idempotentSend the full current state each call. The server stores nothing per correlation_id; retries are safe.
Degradation path (required). If evaluate fails or times out, show “analysis pending.” Never show a false all-clear, and never compute a disposition or a gate on your side. The authority is the engine's response, or nothing.

Extracting against typed fields (the facts path) needs the per-protocol field schema, which tells your model exactly what to look for. A machine-readable schema endpoint is coming; until then, the transcript_text path gives you the full emergency screen and protocol result with no schema required. Reply to your onboarding contact with an audit_ref if any result looks wrong.

Configure the engine per request.

Set engine behavior with a config object on an intake, a batch scenario, or an evaluate call. Pass a profile to apply a named bundle, and a config object to override individual flags on top. Every result echoes the resolved configuration and a config_hash, so two runs are comparable exactly when their hashes match.

Read the catalog

GET /v1/config lists the profiles and flags available to your key. Each flag gives its allowed values and default.

request
$ curl https://api.auddax.ai/v1/config \
  -H "Authorization: Bearer $AUDDAX_API_KEY"
response200 OK
{
  "catalog_version": "2026-09-04",
  "profiles": [ { "id": "default", "description": "Engine defaults." } ],
  "flags": [
    { "key": "locale", "values": ["en-US", "es-AR", "pt-BR"], "default": "en-US",
      "description": "Language of the patient-facing dialogue." }
  ]
}

Apply configuration

Send config when you create an intake. The response echoes the resolved config and its hash. The same config applies to every turn in that encounter.

request
$ curl -X POST https://api.auddax.ai/v1/intakes \
  -H "Authorization: Bearer $AUDDAX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "config": { "locale": "es-AR" } }'
response201 Created
{
  "encounter_id": "enc_...",
  "status": "open",
  "config": { "locale": "es-AR" },
  "config_hash": "722a56cd1465f74c"
}

Batch scenarios take their own config, so one batch runs the same scenario under several configurations for a side-by-side comparison. The evaluate call takes config and echoes it in provenance. Both the Python and TypeScript SDKs expose the catalog through client.config() and take config on the same calls.

Available flags

FlagValuesControls
localeen-US, es-AR, pt-BRThe language of the patient dialogue. Default en-US.

More flags are on the way, including the model that drives the encounter, the clinician-handoff language, the interview cadence, and the handoff format. Each one appears in GET /v1/config as it goes live, so your integration reads the current catalog rather than a fixed list.

Safety invariants are not configuration. No flag value lets the engine deliver a prescription decision to a patient or suppress an urgent escalation. An unknown flag, an invalid value, or an unknown profile returns 400 invalid_request.

A delivered turn is never re-driven.

Turns are long calls, so client timeouts happen. A naive retry would drive a second clinical turn with the same message. The Idempotency-Key header prevents that.

CallSafe to retryRule
POST /v1/intakes Yes A duplicate creates a second empty intake. Use the newest encounter_id.
Blocking turn with Idempotency-Key Yes A repeated key returns the stored response and consumes no quota. The replay carries the header x-auddax-idempotent-replay: true.
Blocking turn without a key No A retry drives a second turn. Always send the header.
Streaming turn No Idempotency does not apply to streams. If a stream drops, read the handoff first.
GET requests Yes All reads are safe to repeat.

Choose one key per logical turn, for example turn-3-enc_abc. Replayed responses stay available for about 24 hours.

Stable codes. Clear next steps.

Every error uses one envelope. Branch on error.code, not on the message text.

error envelope409 Conflict
{
  "error": {
    "code": "intake_closed",
    "message": "The intake reached a terminal state and takes no more turns.",
    "encounter_id": "enc_auddax-sandbox_91a81eb05e4c58fa"
  }
}
HTTPCodeMeaningWhat to do
400invalid_requestBad JSON, a missing field, or an out-of-range value.Fix the request. Do not retry as-is.
401unauthorizedThe key is missing, unknown, or revoked.Check the header and the key.
404not_foundThe intake does not exist for this key.Check the encounter_id.
409intake_closedThe intake reached a terminal state.Stop sending turns. Read the handoff.
410intake_expiredThe session passed the two-hour limit.Create a new intake. The handoff stays readable.
409batch_runningA batch is already running for this key.Wait for it, or poll its status.
429rate_limitedToo many requests this minute.Wait for Retry-After seconds.
429quota_exceededThe daily turn quota is used up.Resume tomorrow, or ask us to raise the quota.
502upstream_errorThe engine failed on this call.Retry once with the same Idempotency-Key.
503unavailableThe engine is unreachable.Retry with backoff.
500internal_errorA gateway fault.Retry once. Report it if it repeats.

Sandbox limits are per key.

LimitDefaultOn breach
Requests per minute6429 rate_limited with Retry-After
Turns per day100429 quota_exceeded
Intakes per day100429 quota_exceeded

Every turn runs real clinical inference, so the sandbox caps spend per key. The daily window resets at 00:00 UTC. Need more for a serious evaluation? Email team@auddax.ai and we raise your quota.

Check where you stand at any time. Every turn response also carries an x-auddax-turns-remaining header, so your client can watch the budget without an extra call.

GET /v1/usage200 OK
{
  "date": "2026-08-21",
  "turns": { "used": 12, "quota": 100, "remaining": 88 },
  "intakes": { "used": 3, "quota": 100, "remaining": 97 },
  "rpm_limit": 6
}

The clinician-ready result.

The handoff is the structured output of the intake. It arrives inside a terminal turn and from GET /v1/intakes/{encounter_id}/handoff at any time.

handoff · abridged real sandbox response200 OK
{
  "encounter_id": "enc_auddax-sandbox_91a81eb05e4c58fa",
  "captured_at": "2026-08-21T16:32:41.902Z",
  "terminal": true,
  "urgent": true,
  "intake_status": "complete",
  "safety_status": "cannot_miss_positive",
  "safety_notes": ["Cannot-miss pathway triggered."],
  "disposition": "urgent_escalation",
  "disposition_label": "Emergency evaluation",
  "soap": {
    "subjective": "58-year-old male with chief complaint of chest pressure...",
    "objective": "No examination performed. Intake interview only.",
    "assessment": "Presentation concerning for acute coronary syndrome...",
    "plan": "Immediate emergency evaluation. 911 activation advised..."
  },
  "captured_facts": { "age": "58", "sex": "male", "pregnancy": null },
  "active_protocol": "CERT-ACS-061",
  "candidate_protocols": ["CERT-ACS-061", "CERT-CARD-060"],
  "scores": [
    { "key": "rfs", "total": "6/6", "band": "strong", "components": "2/2/2" }
  ],
  "conversation": [
    { "role": "patient", "text": "Chest pressure for the last hour..." },
    { "role": "assistant", "text": "I need you to call 911 right now..." }
  ],
  "provenance": {
    "release": "release_staging_runtime_v1",
    "server_model": "claude-sonnet-4-5",
    "prompt_hash": "sha256:1f8c...",
    "source_commit": "b9c502d1...",
    "directory_hash": "sha256:77aa...",
    "runtime_profile": "pure_llm_studio_v1",
    "prompt_profile": "protocolos_studio_may11_v1",
    "voice_profile": "warm_concise_clinician_led_v1",
    "audit_ref": "req_a7393c1094d7",
    "latency_ms": 21408,
    "protocol_count": 151
  }
}
FieldMeaning
terminal · urgentThe intake's end state. Urgent means immediate clinician review.
intake_statusWhat the intake still needs, or complete.
safety_status · safety_notesThe deterministic safety state and its notes.
disposition · disposition_labelThe engine's disposition and its display label.
soapThe clinician summary: subjective, objective, assessment, plan.
captured_factsStructured demographics captured during the intake.
active_protocol · candidate_protocolsThe committed protocol and the differential considered.
scoresQuality scores. Populated on terminal intakes. Bands are strong, mid, weak.
conversationThe patient-facing dialogue. Clinician-only content never appears here.
provenanceThe attested run identity. See provenance.

Attested, not asserted.

Every handoff carries the identity of the run that produced it, reported by the engine itself. Pin these values in your evaluation records. Compare them across releases.

FieldMeaning
server_modelThe model the engine actually ran.
release · source_commitThe engine release and its source commit.
prompt_hash · directory_hashContent hashes of the prompt and the pinned protocol library.
runtime_profile · prompt_profile · voice_profileThe pinned engine configuration for this tenant.
audit_refThe engine's audit reference for this run. Quote it in any support request.
protocol_countThe size of the pinned protocol library.

A research preview. Not for care.

Do not use the sandbox for real patient care. The sandbox exists for development and evaluation. It is not a medical device. Clinical decisions belong to clinicians.

Send no real patient data. Do not send personal health information, names, contact details, or record numbers. Use synthetic scenarios. Test messages persist in the engine's encounter store and inform engine evaluation.

The sandbox moves. It runs against the staging engine. Behavior can change and encounters can reset without notice. Provenance fields tell you exactly which release served each response.

Keys are personal. One key per developer or service. Do not share keys. We revoke on request, and revocation lands within one minute.

Support and incidents: team@auddax.ai. Include the encounter_id and the audit_ref when you have them.

Machine-readable, versioned.

The OpenAPI 3.1 spec is served by the API itself at /v1/openapi.yaml. Generate clients from it, or load it into your API tooling.

Every response carries the release in a header. GET /v1/health returns the same identity as JSON.

release identity200 OK
$ curl -sI https://api.auddax.ai/v1/health | grep x-auddax-release
x-auddax-release: 2026.08+bd1ee4f

$ curl -s https://api.auddax.ai/v1/health
{"ok":true,"release":"2026.08","build_sha":"bd1ee4f0f2d33c36db815e607cb51ee26a53df44"}

Typed SDKs and webhooks are planned and not yet available. A reference client is available on request. For anything else, email team@auddax.ai.