Sandbox & testing
nk_sandbox_ keys resolve to synthetic patients and a mock pharmacy, so you can build and verify the whole integration before going live.
Sandbox lets you exercise the entire rail — orders, intake, provider approval, routing, webhooks — against synthetic data, then go live by swapping one key. The API behaves identically in both environments; only what a key resolves to changes.
Sandbox vs. live#
A key's prefix decides the environment. Nothing else about your code needs to change.
| Prefix | Environment | Resolves to |
|---|---|---|
nk_sandbox_… |
Sandbox | Synthetic patients + a mock pharmacy |
nk_live_… |
Live | Real patients and pharmacies (requires an active agreement) |
Because a sandbox key can never touch a real patient or a real pharmacy, you can build and run your whole integration end to end with zero risk — no shipment ever leaves, no PHI is ever involved. See Authentication for how keys, scopes, and prefixes work.
Identical behavior#
Sandbox is not a stub. It runs the same request validation, the same state machine, the same idempotency guarantees, and emits the same PHI-free events as live. That means the things you test in sandbox are the things that happen in production:
- Submitting an unapproved order is refused in sandbox exactly as it is in live.
- A missing scope returns
403; a bad key returns401. - A replayed
Idempotency-Keyreturns the stored response withIdempotent-Replayed: true. submitted→ downstream fulfillment status transitions arrive over webhooks as PHI-free{ id, status }payloads.
The mock pharmacy accepts routed orders and advances them through fulfillment status so you can watch a complete lifecycle without a real pharmacy connection.
Switching = swap the key#
Going live is a one-line change. Keep the key in an environment variable and point it at a live key when you're ready:
# .env — sandbox
NEOLIFE_API_KEY=nk_sandbox_…
# .env — live
NEOLIFE_API_KEY=nk_live_…
Your code never mentions the environment:
import { Neolife } from "@neolifehealth/sdk";
const neolife = new Neolife({ apiKey: process.env.NEOLIFE_API_KEY! });
The SDK infers the environment from the key prefix, so there is no separate flag to flip.
Testing webhooks locally#
Fulfillment status flows back over webhooks, and your callback endpoint usually isn't reachable from the internet while you develop. The CLI forwards live sandbox events to a local URL:
neolife listen --forward-to http://localhost:3000/webhooks/neolife
listen streams sandbox events as they happen and replays them to your handler, printing each delivery so you can confirm your endpoint parses the { id, status } shape and verifies signatures. Trigger events by running real sandbox flows — submit an order and watch the transitions arrive — so your reconciliation logic is exercised against the same payloads live will send.
Ready for live — a checklist#
Before you swap in a live key, confirm your integration handles the whole rail in sandbox:
- You create orders, capture the returned
id, and never assume a status client-side. - Every mutation sends a stable
Idempotency-Key(UUID), and your retries reuse it — see Idempotency. - You handle the refusal to submit an unapproved order rather than treating it as an error to swallow.
- Your webhook endpoint verifies signatures, is idempotent on redelivery, and returns
2xxquickly. - You reconcile on the PHI-free
{ id, status }payload and hydrate detail over authenticatedGETs only when needed (the PHI boundary). -
401/403/409responses are handled distinctly, not as one generic failure. - Your live key is server-side only, scoped to what this integration needs, and stored as a secret.
When those hold in sandbox, they hold in live. Walk through the full sequence in the go-live guide.