Production access is free and self-serve with an account. · Synthetic demo · no account needed

FinchNode

Sandbox

Scenario Sandbox: named synthetic patients and failure cases for testing an integration.

Named synthetic patients and deterministic failure cases, on the public demo and inside your sandbox.

Named synthetic scenarios, from ordinary records to consent, rate-limit, and source failures. On the public demo, their records, FHIR resources, and MCP tools answer with no account or key. In your sandbox, a sandbox key completes a Connect session with a record or behavior scenario’s synthetic patient, which goes through the same consent, import, completion, receipts, webhooks, record reads, and change feed as a real one, and the sandbox controls then advance its records, end its consent, or fail its source.

What it is

Built for: Developers and agents testing an integration against deterministic synthetic patients and failure cases before a real patient connects.

Base URL: https://api.finchnode.com/demo/v1 (public demo, no key) and https://api.finchnode.com/api/v1 (simulation and controls, sandbox key)

Authentication: The public demo (https://api.finchnode.com/demo/v1 and https://api.finchnode.com/demo/mcp) takes no account or key and serves synthetic data only. Simulation and the sandbox controls, on https://api.finchnode.com/api/v1 and https://api.finchnode.com/api/mcp, take a sandbox key as a Bearer token from your backend: Authorization: Bearer ck_test_... A live key (ck_live_...) receives 403 sandbox_only. Keys are hashed at rest, revocable, and must never be embedded in browser or mobile code.

Create a free account to get sandbox keys: https://finchnode.com/signup

At a glance

Status
Available
Auth
None for the demo scenarios; sandbox key for simulation and controls
Contract
OpenAPI 3.1
Public demo MCP endpoint (no key, synthetic)
https://api.finchnode.com/demo/mcp
Authenticated MCP endpoint (API key)
https://api.finchnode.com/api/mcp

Documents for this product

Try it in 30 seconds

List the named synthetic scenarios

curl https://api.finchnode.com/demo/v1/scenarios

No account or key. Each entry names the scenario’s id, kind, subject, what it exercises, and the sandbox controls it supports, with links to its demo routes.

Expected response: 200 with a list of demo_scenario objects: id, kind, title, summary, subject, sources, categories, exercises, controls, the behavior or session outcome, and links. No clinical data.

Synthetic data only. Not for clinical use.

For coding agents

Three ways in for a coding agent: connect the MCP endpoints below, load the OpenAPI document (https://finchnode.com/openapi.yaml), or fetch this page as markdown (https://finchnode.com/products/scenario-sandbox.md). https://finchnode.com/llms.txt lists every product’s markdown twin.

Public demo MCP endpoint (no key, synthetic)

MCP endpoint
https://api.finchnode.com/demo/mcp
Transport
Streamable HTTP (JSON-RPC over POST)
Auth
None
Clients
ChatGPT, Codex, Claude, and other MCP clients, with no key
MCP Registry name
com.finchnode/health-records-demo

Tools at https://api.finchnode.com/demo/mcp

  • list_demo_scenarios
  • get_demo_health_record
  • search_demo_fhir
  • simulate_demo_connect

Claude Code: Public demo MCP endpoint (no key, synthetic)

claude mcp add --transport http finchnode-demo https://api.finchnode.com/demo/mcp

Codex CLI: Public demo MCP endpoint (no key, synthetic)

codex mcp add finchnode-demo --url https://api.finchnode.com/demo/mcp

Cursor (.cursor/mcp.json): Public demo MCP endpoint (no key, synthetic)

{
  "mcpServers": {
    "finchnode-demo": {
      "url": "https://api.finchnode.com/demo/mcp"
    }
  }
}

Claude.ai: Public demo MCP endpoint (no key, synthetic)

  • Where your plan offers custom connectors: on a Free, Pro, or Max plan, open Customize > Connectors, click Add custom connector, enter https://api.finchnode.com/demo/mcp as the remote MCP server URL, and click Add. If the dialog asks how people connect, choose No sign-in: the demo takes no key. Turn the connector on for a chat from the + button, under Connectors.
  • Where your plan offers custom connectors: on a Team or Enterprise plan, an Owner adds https://api.finchnode.com/demo/mcp under Organization settings > Connectors (Add, then Custom, then Web if asked), and each member clicks Connect on it under Customize > Connectors.

ChatGPT: Public demo MCP endpoint (no key, synthetic)

  • Where your plan offers custom connectors: turn on Developer mode under Settings > Security and login, then open ChatGPT Plugins (chatgpt.com/plugins), select the plus button, and create a developer-mode app for the remote MCP server https://api.finchnode.com/demo/mcp with no authentication.
  • Where your plan offers custom connectors: in a conversation, choose Developer mode from the Plus menu and select the app you created for https://api.finchnode.com/demo/mcp.

Authenticated MCP endpoint (API key)

MCP endpoint
https://api.finchnode.com/api/mcp
Transport
Streamable HTTP (JSON-RPC over POST)
Auth
Authorization: Bearer ck_test_... (sandbox keys) or Authorization: Bearer ck_live_... (live keys)
Clients
Server-side and desktop MCP clients only; the endpoint is not CORS-enabled
MCP Registry name
com.finchnode/health-records

Tools at https://api.finchnode.com/api/mcp

  • simulate_connect_session
  • trigger_sandbox_event

Set FINCHNODE_API_KEY once in the shell that runs these commands or starts your agent client (replace ck_test_... with your sandbox key; it is the only key value to substitute)

export FINCHNODE_API_KEY=ck_test_...

Claude Code: Authenticated MCP endpoint (API key)

claude mcp add --scope project --transport http finchnode https://api.finchnode.com/api/mcp --header 'Authorization: Bearer ${FINCHNODE_API_KEY}'

Claude Code writes this server to the project's .mcp.json, which is meant to be checked into version control and shared with the project, and expands ${FINCHNODE_API_KEY} when it connects, so the file never holds the key: set FINCHNODE_API_KEY in the shell that runs Claude Code.

Codex CLI: Authenticated MCP endpoint (API key)

codex mcp add finchnode --url https://api.finchnode.com/api/mcp --bearer-token-env-var FINCHNODE_API_KEY

Cursor (.cursor/mcp.json): Authenticated MCP endpoint (API key)

{
  "mcpServers": {
    "finchnode": {
      "url": "https://api.finchnode.com/api/mcp",
      "headers": {
        "Authorization": "Bearer ${env:FINCHNODE_API_KEY}"
      }
    }
  }
}

Machine-readable resources

How it works

  1. List the scenarios

    Every scenario has an id and a kind, and record and behavior scenarios have a subject. GET /scenarios/{scenarioId} returns one entry. Its exercises and controls fields describe the authenticated sandbox; the public demo lists them for reference.

    curl https://api.finchnode.com/demo/v1/scenarios/polypharmacy-senior
  2. Read a scenario subject on the demo

    Read a subject’s records with no key. A behavior subject answers with the production codes: patient-demo-rate-limited answers 429 rate_limited with Retry-After in alternating time slots, so a client that waits the stated seconds succeeds on its next attempt. The demo OpenAPI document gives the slot length.

    curl 'https://api.finchnode.com/demo/v1/users/patient-demo-rate-limited/records'
  3. Simulate a sandbox session with a scenario

    With a sandbox key, create a sandbox Connect session (POST https://api.finchnode.com/api/v1/connect/sessions; the body is optional, so the bare first request below works); its id is SESSION_ID. A session from the public demo cannot be simulated. Then complete the session with a scenario’s synthetic patient instead of sending a person to the hosted page. The response is 202 with the session and its simulation. Repeating the request with the same scenario resumes the simulation and never creates a second patient. A session scenario returns 400 invalid_scenario, and a scenario whose consent covers none of the session’s categories returns 400 invalid_categories. A session that is no longer pending or has expired, already has a patient, or was simulated with another scenario returns 409 session_not_simulatable: use a new session for each simulation.

    curl -X POST "https://api.finchnode.com/api/v1/connect/sessions" -H "Authorization: Bearer $FINCHNODE_API_KEY"
    curl -X POST https://api.finchnode.com/api/v1/connect/sessions/$SESSION_ID/simulate -H "Authorization: Bearer $FINCHNODE_API_KEY" -H "Content-Type: application/json" -d '{"scenario":"polypharmacy-senior"}'
  4. Poll to completed and read the records

    Poll GET /connect/sessions/{sessionId} until simulation.state is completed or failed. Poll simulation.state rather than status: for the two-source scenarios and consent-revoked, status reads completed first. Once simulation.state is completed, the session exposes the synthetic patient’s app-scoped subject (its id is SUBJECT). Read its records and receipts as for any other user; its webhooks reach your application’s webhook URL as a real patient’s do.

    curl "https://api.finchnode.com/api/v1/users/$SUBJECT/records" -H "Authorization: Bearer $FINCHNODE_API_KEY"
  5. Drive lifecycle events

    POST /sandbox/subjects/{subject}/events with a control the scenario lists. records.advance imports the scenario’s new and changed records into the change feed (records.updated for continuous consent), consent.revoke and consent.expire end the consent (consent.revoked, consent.expired), and source.fail makes the next import fail (sync.failed for continuous consent). The response is 202; a control the scenario does not list returns 409 control_unsupported, and records.advance or source.fail for a user whose source is not connected yet returns 409 subject_not_connected.

    curl -X POST https://api.finchnode.com/api/v1/sandbox/subjects/$SUBJECT/events -H "Authorization: Bearer $FINCHNODE_API_KEY" -H "Content-Type: application/json" -d '{"type":"records.advance"}'

The scenarios

12 scenarios: 6 record, 4 behavior, 2 session
ScenarioKindWhat it exercisesControls
Baseline adult, age 38recordthe default record every quickstart uses; one source, one encounter, no paginationrecords.advance, consent.revoke, consent.expire, source.fail
Polypharmacy, age 78recordcursor pagination past 25 records in medications and labs; MedicationDispense alongside MedicationRequest; reference ranges on every lab; a record change that removes a medicationrecords.advance, consent.revoke, consent.expire, source.fail
Pediatric asthma, age 9recordimmunization schedules with repeated vaccine codes; growth vitals as time series; pediatric dosing textrecords.advance, consent.revoke, consent.expire, source.fail
Two sources with overlapping records, age 40recordsource attribution on every record; deduplication of the same code across sources; a unit difference on the same lab (mIU/L vs uIU/mL); conflicting allergy statements between sourcesrecords.advance, consent.revoke, consent.expire, source.fail
Sparse record, age 30recordmissingCategories in the envelope; empty category pages with hasMore false; a record change that adds the first vital signrecords.advance, consent.revoke, consent.expire, source.fail
Messy coding, age 63recordmedications with text but no coding; observations with no value or a coded value; zero reference-range bounds; ICD-10-CM without SNOMED; non-default unitsrecords.advance, consent.revoke, consent.expire, source.fail
Rate limited readsbehaviorhonoring Retry-After; bounded retries; RateLimit headersconsent.revoke, consent.expire, source.fail
Consent revokedbehaviorfailing closed on 410; not retrying a revoked subjectconsent.revoke, consent.expire, source.fail
Partial consentbehaviorreading consent.receipts before requesting categories; handling 403 consent_scope_exceededconsent.revoke, consent.expire, source.fail
One source unavailablebehaviormeta.syncStatus partial; per-source lastSyncedAt; a source_unavailable warning in meta.warningsconsent.revoke, consent.expire, source.fail
Connect session cancelledsessioncancelled session state; no subject on incomplete sessionsnone
Connect session failedsessionfailed session state; failure_code handling; offering the user a retrynone

Scenario ids: record scenarios baseline-adult, polypharmacy-senior, pediatric-asthma, multi-source-overlap, sparse-record, messy-coding; behavior scenarios rate-limited, consent-revoked, consent-partial, source-unavailable; session scenarios connect-cancelled, connect-failed. Record and behavior scenarios run on the public demo and simulate in your sandbox. Session scenarios run only in the public demo, where they end its simulated Connect session cancelled or failed.

Simulated in your sandbox, consent-partial grants only medications and allergies, consent-revoked revokes consent right after the session completes, and source-unavailable leaves its second source failing every later import. The timed 429 responses of rate-limited exist only in the public demo; simulated, it is an ordinary small record.

Reference

The demo routes on https://api.finchnode.com/demo/v1 take no key; the https://api.finchnode.com/api/v1 routes take sandbox keys. Create the session you simulate on https://api.finchnode.com/api/v1: a demo session cannot be simulated. Each row names its full URL.

Endpoints
MethodPathOpenAPI operationId
GEThttps://api.finchnode.com/demo/v1/scenarioslistDemoScenarios
GEThttps://api.finchnode.com/demo/v1/scenarios/{scenarioId}getDemoScenario
GEThttps://api.finchnode.com/demo/v1/users/{subject}/recordsgetDemoHealthRecord
POSThttps://api.finchnode.com/demo/v1/connect/sessionscreateDemoConnectSession
POSThttps://api.finchnode.com/api/v1/connect/sessionscreateConnectSession
POSThttps://api.finchnode.com/api/v1/connect/sessions/{sessionId}/simulatesimulateConnectSession
POSThttps://api.finchnode.com/api/v1/sandbox/subjects/{subject}/eventstriggerSandboxEvent
MCP tools
ToolEndpoint
list_demo_scenarioshttps://api.finchnode.com/demo/mcp (no key)
get_demo_health_recordhttps://api.finchnode.com/demo/mcp (no key)
search_demo_fhirhttps://api.finchnode.com/demo/mcp (no key)
simulate_demo_connecthttps://api.finchnode.com/demo/mcp (no key)
simulate_connect_sessionhttps://api.finchnode.com/api/mcp (sandbox keys)
trigger_sandbox_eventhttps://api.finchnode.com/api/mcp (sandbox keys)

What it does not do

  • Synthetic data only: every scenario patient and source is fictional. It never reaches production records or real patient accounts, and it is not for clinical use.
  • On the public demo, the behavior scenarios’ consent and rate-limit errors answer only record reads: /users/{subject}/records, /patients/{patientId}/records, and the demo MCP record tools get_demo_health_record and get_demo_record. The FHIR routes model the synthetic source itself.
  • The sandbox controls act only on synthetic users your application’s simulations created, never on the account a person used to complete a sandbox session by hand; any other subject returns 404 not_found.
  • Session scenarios (connect-cancelled, connect-failed) run only in the public demo; simulate returns 400 invalid_scenario for them.
  • Simulation and the sandbox controls take sandbox keys; a live key receives 403 sandbox_only.
  • The sandbox holds at most 25 active synthetic patients per application by default, each purged 7 days after it is created; a simulation over the limit returns 409 sandbox_limit_reached with nothing created. If the sandbox is unavailable, simulate and the controls answer 503 sandbox_unavailable and change nothing.

Frequently asked questions

Are the scenarios deterministic?

Yes. Each scenario’s records come from one fixed synthetic Bundle, so a scenario always starts from the same fictional data, and records.advance applies one fixed set of changes. On the public demo, rate-limited alternates fixed time slots: reads answer 429 rate_limited with Retry-After in one slot and succeed in the next, so a client that waits the stated seconds succeeds on its next attempt. The demo OpenAPI document gives the slot length.

What does source-unavailable mean?

Two connected sources that each synced once, of which Quillhaven Medical Group (Synthetic) now fails every sync. Reads report meta.syncStatus partial, a source_unavailable warning in meta.warnings, and an older lastSyncedAt for that source. Simulated in your sandbox, it connects both sources and leaves the second failing every later import, so its reads report the partial status from the moment simulation.state is completed.

How does the sandbox differ from the public demo?

The public demo takes no account or key; its Connect sessions are simulated and non-persistent, and it cannot perform the sandbox controls. The sandbox takes a sandbox key: simulate completes one of your application’s sandbox Connect sessions with the scenario’s synthetic patient, through the same consent, import, completion, receipts, webhooks, record reads, and change feed as a real patient, and the sandbox controls then advance its records, revoke or expire its consent, or fail its source.

Can I complete a sandbox session by hand instead?

Yes. The hosted Connect page of a sandbox session lists the FinchNode Scenario Sandbox organizations above its search, and choosing one connects without a hospital sign-in; the account and consent steps are unchanged. Production sessions never list them. The sandbox controls act only on patients created by simulate, not on the account a person used.