---
title: "Code Demo Case"
method: POST
path: "/api/v1/demo/code"
tags: ["demo"]
---

# Code Demo Case

`POST /api/v1/demo/code`

## Request

- Base URL: `https://api.accurecord.io` (the document declares no server; this is the origin it was published from)
- URL: `https://api.accurecord.io/api/v1/demo/code`
- Auth: none declared

Run one synthetic chart through the production coding pipeline.

Same engine as ``POST /api/v1/code`` — the same ``CodingAgentService``, the same
verification passes — so what a prospect sees here is what they would buy.

Three deliberate differences from ``/code``, each of which reads as a missing gate until
you know what this endpoint can and cannot receive:

* **No ``ai_coding_enabled`` check.** That flag gates the *capability being sold*: coding
  text the customer supplies. This endpoint cannot code customer text at all, so gating it
  on the paid flag would make the free tier undemonstrable, which is the whole problem.
* **No BAA gate.** ``/code`` is BAA-gated because it ingests PHI. This corpus is fabricated
  and the request carries no text, so there is no PHI to be a business associate for.
  Requiring a BAA to look at fictional charts would invert the policy it enforces.
* **No PHI audit event and no trace persistence.** ``/code`` writes a
  ``PHI_CREATE``/``phi_accessed=True`` audit row that feeds HIPAA accounting-of-disclosures.
  Writing one here would file records that contain no PHI into the disclosure trail and
  make it less useful, not more. The usage meter still records the call.

## Request body

- DemoCodeRequest: ⚠ Deliberately carries NO free-text field — see this module's docstring. `extra="forbid"` rather than Pydantic's default `ignore`, deliberately. Ignoring an unexpected `condition` is safe for us — the engine never sees it — but it answers 200 with a coded result for a DIFFERENT chart, so someone who pasted a real patient note would reasonably conclude it had been processed. On a boundary whose whole purpose is "no real patient data here", the caller has to be told no, not quietly handed a plausible answer. A 422 naming the rejected field is that refusal.
  - `case_id` string, required: Id of a case from GET /api/v1/demo/cases, e.g. 'DEMO-2026-001'.
  - `include_hcc` boolean: Include HCC/RAF risk-adjustment output. Requires an HCC-enabled (paid) key.

## Response `200`

Successful Response

- object

## Other responses

- `400`: Malformed or out-of-bounds request — a batch over 50 codes, a file over the upload limit, an unparseable identifier, or a surface that is switched off in this environment (the `cpt_*_disabled` gates are 400, not 403). ⚠ Not interchangeable with 422: 400 is raised BY the handler, 422 by request validation.
- `401`: Missing, malformed, revoked or expired credential. Send the key as `X-API-Key` or `Authorization: Bearer`. `detail` is a string, except the MFA challenge on `/auth/login`, which is `{code: 'mfa_required', message}`.
- `403`: Authenticated but not permitted: the tier does not include the feature, the role is insufficient, or the free tier is paused. Gate-specific bodies use the `{code, message}` shape (`tier_required`, `insufficient_role`). ⚠ The free-tier pause is the ONE error in the service that does not use `detail` at all — its body is `{error: 'free_tier_paused', message}` at the top level. ⚠ Preconditions the caller CAN satisfy (no org, no BAA, PHI mode off) are 412, not 403 — see below.
- `404`: Resource, code, or org-scoped record not found. Note that a record belonging to ANOTHER organization is also a 404, never a 403 — existence is not disclosed across tenants.
- `412`: A precondition on the calling principal is unmet and the caller can fix it: no organization linked to the key (`org_required`), no signed BAA (`baa_required`), PHI mode not activated (`phi_not_activated`), reviewer mode off (`review_mode_disabled`), or the session was never second-factored (`mfa_required`). All use the `{code, message}` shape.
- `422`: Request body or query failed validation. FastAPI's own failures are a LIST of `{loc, msg, type}`; semantic refusals raised by the service are an object (the risk-adjustment endpoints use `{status, ...}`).
- `429`: Rate limit, quota or concurrency cap exceeded. The tier limiter, the per-key chart-review job cap, the anonymous demo cap and the auth/signup limiters all land here; only the tier limiter sets the `X-RateLimit-*` headers.
- `500`: Unhandled server error. The body is `{detail: 'Internal server error', request_id: <id>}` and the same id is on the `X-Request-ID` response header.
- `503`: A dependency this request needed is unavailable — the database, an upstream model provider, or reference data that is present but not READY. Retry is reasonable, except for the risk-adjustment `blocked_pack_not_ready` refusals, which stay 503 until the coefficient pack is actually loaded.

---

[API](https://skmtc.dev/accurecord/apis/icd-10-coding-api.md) · [All operations](https://skmtc.dev/accurecord/apis/icd-10-coding-api/llms.txt) · [OpenAPI document](https://skmtc.dev/accurecord/apis/icd-10-coding-api/revisions/b1e12ce06ba5?raw)
