Developer guide
The clinical-loop simulator and certification (sandbox)
Run your sandbox patients through the real loop: the sandbox's synthetic clinician, pharmacy and clock act through the real commands and your receiver gets the real events.
Open the Developer CenterNever send patient information to a sandbox key.
On this deployment: Headless clinical API (patient data): Not available · Webhooks to your receivers: Sandbox only
- Headless clinical API (patient data): Not available. What runs now: Nothing for a real patient: the headless patient API is written and has run only against a local synthetic stack; no brand's patient data access is approved in any environment, and the Developer Center's clinical-loop simulator is a script with synthetic ids.
- Webhooks to your receivers: Sandbox only. What runs now: Signing, retries (19 attempts over at least about 74 hours; every 4xx but 410 retried, 410 disables the receiver), dead letters, replay and delivery receipts against the in-process synthetic receiver (.demo.invalid) on synthetic deployments; a self-serve developer connection for brands with no partner integration; and, built but not yet exercised on a deployed sandbox, sandbox delivery of synthetic events to a developer's own https receiver while the developer_webhooks sandbox rail is open; and, written and unit-tested but with its migration not yet applied and its pgTAP suite not yet run, lifecycle event producers with refs-only payloads carrying the enrollment id and externalReference (enrollment.created, subscription.created, subscription.canceled, payment.failed, and enrollment.status_changed produced only under the brand-to-entity BAA and downstream-systems attestation and re-checked at every send).
What it is
The developer sandbox has no real clinician or pharmacy. Its synthetic actors stand in: a test clinician, a test pharmacy and the sandbox clock, each labelled synthetic. With your sandbox phi_server key (or from Developers > Clinical loop simulator) you ask them to act on one of your own sandbox patients, and they run the REAL commands under every real gate: the decision, the prescription rail, the pharmacy's authenticated status callbacks, the lab sign-off. The real clinical.* events reach your verified sandbox receiver, with livemode: false. Nothing here exists on the live plane: a live key, a brand that is not synthetic, or the production deployment is refused.
Your own backend does its part first, exactly as on live: create the patient, accept consents with render receipts, submit intake, verify identity (vendor sandbox_fixture) and contact. A synthetic brand on the sandbox reaches its synthetic patients before its patient data access is approved (GET /phi-access/status says phiAccess: sandbox); live keys always need the full gate.
Limits: 60 loops (patients) and 600 simulations per brand per hour. Each simulation is idempotent by its Idempotency-Key and logged; each Developer Center view of a sandbox patient is recorded in the access log.
The simulate operations
| Call | Action | Who | What runs, and the events |
|---|---|---|---|
| POST /sandbox/patients/{patientId}/cases/{caseId}/simulate | approve | Test clinician | The decision, then the prescription written, signed and routed: clinical.case.approved, clinical.prescription.signed, clinical.order.created. 409 labs_required while labs wait. |
| needs_info, decline | Test clinician | clinical.case.needs_info; clinical.case.declined (with refundExpected in merchant-of-record programs). | |
| POST /sandbox/patients/{patientId}/lab-results/{labResultId}/simulate | sign_off | Test clinician | The real sign-off: clinical.lab.reviewed; a critical value records the synthetic contact confirmation. |
| POST /sandbox/patients/{patientId}/prescriptions/{prescriptionId}/simulate | acknowledge, accept, ship, deliver, exception | Test pharmacy | Authenticated status callbacks once the order was transmitted: clinical.order.acknowledged, .accepted, .in_production, .shipped, .delivered, .exception. 409 order_not_transmitted before. |
| policy_withdrawn | Sandbox clock | For a regulated substance: the real regulatory hold on this prescription (clinical.prescription.held) and formulary.policy_changed to you only. 409 regulated_product_required otherwise. | |
| renewal_due | Sandbox clock | The check-in falls due now (clinical.checkin.due) and the renewal notice is requested (clinical.notification.requested). | |
| POST /sandbox/patients/{patientId}/fills/{fillId}/simulate | refill_due | Sandbox clock | A fill held refill_too_soon is decided again with the supply treated as used; the real refill order: clinical.fill.requested, then clinical.fill.transmitted. |
| POST /sandbox/patients/{patientId}/notifications/simulate | notification_unacked | Sandbox clock | A clinically required notice passes its deadline; Ambition's content-free fallback is sent from your domain: clinical.notification.fallback_sent. |
The SDK has the same calls: headless(options).patients(id, context).sandbox.decideCase, signOffLabResult, pharmacy, withdrawPolicy, renewalDue, refillDue and notificationUnacked; headless(options).sandbox.certification() and sendSignatureProbes().
No email is delivered on the sandbox: contact codes and sign-in links are caught by the sandbox mail catcher. GET /sandbox/patients/{patientId}/messages (patients.read; the SDK's sandbox.messages()) answers the newest ten Ambition sent your sandbox patient, with subject, text, sender and time, so a test can read the code or the link and confirm it. Only your own patient's mail is answered.
Certification
GET /sandbox/certification (and the panel under the simulator) computes, from your real sandbox activity, the checklist Ambition reviews before live patient data keys: a verified clinical receiver; signature checked (POST /sandbox/webhook-signature-probes sends your receiver a delivery signed wrongly on purpose, and it must answer 4xx); a render receipt accepted; consent and intake complete; identity verification; verified contact; the labs path, brand release, refundExpected and policy_withdrawn where your programs use them; fills; renewals; and Idempotency-Key on your writes. Counts and times only, never a patient.