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. Request one by email and we send it over a secure channel. 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.

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.
  • 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.

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.
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.

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.