Getting started
From an API key to reading and writing a patient's FHIR R4 record in the sandbox: keys, first calls, writes with provenance, documents, AI context, IPS, consent, webhooks and lab reports.
Anpheros Platform is a health-data backend: a FHIR R4 record per patient, project isolation, provenance on every write, and a simple REST API on top of the same data. This guide takes you from nothing to reading and writing a patient's record in the sandbox.
Base URL (sandbox and production share it; the key decides the data plane):
https://platform.anpheros.com
Interactive reference: /docs (OpenAPI) and /fhir/R4/metadata (CapabilityStatement).
1. Get a key (1 minute)
The sandbox is self-service. Sign in to the dashboard (https://platform.anpheros.com/dashboard/)
with Google and press Get a sandbox key: you get an organization, a sandbox project with its own
synthetic patients, and a key — shown once. The same through the Admin API, with your Firebase user token:
curl -X POST $BASE/admin/sandbox/quickstart -H "Authorization: Bearer $FIREBASE_ID_TOKEN"
# {"organization": {…}, "project": {"id": "proj_…", "environment": "sandbox", …}, "key": {"key": "sk_test_…", …}, "sandbox": {…}}
Or step by step:
# 1. an organization (you become its owner)
curl -X POST $BASE/admin/organizations -H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
-H 'content-type: application/json' -d '{"name":"CardioAI SRL","kind":"developer","country":"RO"}'
# 2. a sandbox project (it comes with its own synthetic patients)
curl -X POST $BASE/admin/organizations/org_…/projects -H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
-H 'content-type: application/json' -d '{"name":"CardioAI dev","environment":"sandbox"}'
# 3. a key — the plain key is returned exactly once
curl -X POST $BASE/admin/projects/proj_…/keys -H "Authorization: Bearer $FIREBASE_ID_TOKEN" \
-H 'content-type: application/json' -d '{"name":"local dev","scopes":["read","write"]}'
You get sk_test_…. Sandbox keys only ever see sandbox data. Production keys (sk_live_…) are
issued to verified organizations with a signed DPA — write to [email protected]. The sandbox is free;
production starts at €49 a month and the first month is free (see Pricing).
2. First call (1 minute)
Your sandbox project already has its own copy of 30 synthetic patients, with six months of history
up to the day the project was created: adults, children and older people from across the EU, with
conditions (ICD-10), medications (ATC), allergies, lab results and vital signs (LOINC). The copy
belongs to your project: change or delete anything — no other project sees it. Reset test
patients in the dashboard (or POST /admin/projects/{id}/sandbox/reset) brings them back as they
were, with new ids; the patients you created yourself are not touched. Each synthetic patient keeps a
stable identifier across resets: Patient?identifier=https://anpheros.com/fhir/sid/sandbox-persona|p02
is always Elena Ionescu.
export KEY=sk_test_…
curl $BASE/v1/patients -H "Authorization: Bearer $KEY"
{"data":[{"id":"…","given":"Elena","family":"Ionescu","birth_date":"1985-09-03","gender":"female",…,"fhir":"Patient/…"}, …],"total":30,"next_cursor":null}
Sandbox limits are generous but finite: 10 000 resource writes a day per project, 500 patients of your own besides the synthetic ones, 250 MB of documents (see limits).
3. Read a record
# lab results, newest first
curl "$BASE/v1/patients/$PID/observations?category=laboratory&limit=10" -H "Authorization: Bearer $KEY"
# active medications
curl "$BASE/v1/patients/$PID/medications?status=active" -H "Authorization: Bearer $KEY"
# everything on one timeline
curl "$BASE/v1/patients/$PID/timeline?from=2026-06-01" -H "Authorization: Bearer $KEY"
# the same data, strict FHIR
curl "$BASE/fhir/R4/Observation?patient=$PID&code=http://loinc.org|4548-4&_sort=-date" -H "Authorization: Bearer $KEY"
Ids are identical in /v1 and /fhir/R4; every v1 object carries its fhir reference.
4. Write
Say who the author is. author_type is patient, practitioner, device, import or ai;
if you omit it the platform records import, never patient by assumption.
curl -X POST "$BASE/v1/patients/$PID/observations" -H "Authorization: Bearer $KEY" \
-H 'content-type: application/json' -H "Idempotency-Key: $(uuidgen)" -d '{
"code": "2339-0", "display": "Glucose", "category": "laboratory",
"value": 112, "unit": "mg/dL", "effective_at": "2026-09-19T08:10:00Z",
"author_type": "device"
}'
The response is the stored observation with id, fhir and updated_at. Repeating the exact
same request with the same Idempotency-Key returns the same response and creates nothing.
5. Documents
# 1. create the document → upload target
curl -X POST "$BASE/v1/patients/$PID/documents" -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \
-d '{"title":"Analize 2026-09-14","kind":"lab_report","content_type":"application/pdf","date":"2026-09-14"}'
# 2. upload the bytes to the returned url (direct to storage, or through the platform)
curl -X PUT "$BASE/v1/documents/$DOC/content" -H "Authorization: Bearer $KEY" -H 'content-type: application/pdf' --data-binary @analize.pdf
The original is never modified after that; sha256 and size are recorded, and any values you
later extract point back to the document via derived_from.
6. Provenance
curl "$BASE/v1/patients/$PID/provenance/Observation/$OBS" -H "Authorization: Bearer $KEY"
One entry per version: who (author type and project), when, from which source system.
Rules worth knowing
- Isolation: a project sees the patients it created (plus the shared sandbox patients). Anyone
else's patient does not exist for you:
404, never403. - Pairwise ids: the patient id you see is yours. Another project sees the same person under a different id. Store our ids freely; never try to correlate them.
- Provenance: every write leaves a Provenance resource. Nothing is silently overwritten;
history is available at
/fhir/R4/{Type}/{id}/_history. - Errors: FHIR endpoints return
OperationOutcome;/v1and/adminreturn{"error": {"type", "message", "field"}}. Every response carriesAnpheros-Request-Id; quote it when you write to us. - Limits: 600 requests/minute per key by default, 200 items per page, 25 MB per document.
7. Context for an AI model
Instead of pulling raw records and deciding what fits a prompt, ask the platform for a context:
curl -X POST "$BASE/v1/context" -H "Authorization: Bearer $KEY" -H 'content-type: application/json' -d '{
"patient": "'$PID'",
"task": "medication review before a cardiology visit",
"question": "How did blood pressure evolve over the last 3 months?",
"budget_tokens": 1500,
"format": "text"
}'
You get sections (summary card, conditions, medications, allergies, labs, vitals with weekly
trends and before/after treatment markers, symptoms, timeline, documents), each item labelled
with author_type and source, a list of what was omitted to fit the budget, warnings, and a
manifest_id that ties the call to the audit log. Values produced by AI are never mixed with
facts: they appear only under ai_notes. Explicit needs are also accepted:
"needs": ["labs:4548-4", "vitals:trend:85354-9", "timeline:180d"].
8. Standards
GET /fhir/R4/Patient/{id}/$summaryreturns an International Patient Summary document Bundle.POST /fhir/R4/Observation/$validate?profile=eu-labreports how a lab result measures up to the European laboratory report profile (errors, warnings, information).GET /v1/terminology/loinc?q=hba1cand/v1/terminology/atc?q=metforminsearch the bundled code subsets; observations created without a display name get the LOINC name automatically.
9. Patient consent (OAuth 2.1 + SMART on FHIR)
API keys see the patients your project created. To reach a person's existing record, ask them:
- Register an application:
POST /admin/projects/{id}/applicationswith your redirect URI (publicfor mobile/web apps with PKCE,confidentialfor servers; the secret is shown once). - Send the person to the consent page:
GET /oauth/authorize?response_type=code&client_id=…&redirect_uri=…&state=…&code_challenge=…&code_challenge_method=S256&scope=patient/Observation.rs?category=laboratory patient/MedicationStatement.r offline_access&purpose=treatment&lang=roThey sign in to Anpheros, see what you ask for in plain language, choose the record (their own, a dependent's, or the one your app created for them) and how long the access lasts. - Exchange the code:
POST /oauth/token(authorization_code+code_verifier). You receive an access token (30 min), a refresh token (30 days, rotated on use) and the patient id. - Call the API with
Authorization: Bearer at_…. You see only that patient, only the resource types and actions in the scopes; out-of-scope reads answer403, searches are filtered.
The person can revoke at any time from Anpheros; the next call answers 401. Every grant is
mirrored as a FHIR Consent resource, and every access under it is logged and visible to the
person. Discovery: /.well-known/smart-configuration.
10. Webhooks
Let the platform call you instead of polling:
curl -X POST $BASE/v1/webhooks -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"url": "https://your.app/anpheros/hook", "events": ["*"]}'
Keep the secret from the response and verify Anpheros-Signature on every delivery
(verifyWebhookSignature in both SDKs). Events carry ids and versions, not clinical data.
Details, retries and examples: webhooks.md.
11. Organisations and practitioners
Clinics, labs and the people who work there are first-class resources: Organization,
Practitioner, PractitionerRole. They are directory resources: no patient, readable by
every project in the same environment, changeable only by the project that created them.
curl -X POST $BASE/fhir/R4/Practitioner -H "Authorization: Bearer $KEY" -H "Content-Type: application/fhir+json" \
-d '{"resourceType":"Practitioner","active":true,"name":[{"family":"Popescu","given":["Ana"],"prefix":["Dr."]}]}'
Name the practitioner behind a write with X-Anpheros-Author-Ref: Practitioner/<id> (or a
PractitionerRole, Organization, Device): the server-generated Provenance then carries
agent.who.reference, and GET /fhir/R4/Provenance?agent=Practitioner/<id> lists everything
that person recorded. Search: Organization?name=, ?identifier=, ?type=, Practitioner?name=,
?family=, ?given=, PractitionerRole?practitioner=, ?organization=, ?role=, ?specialty=, ?active=.
Who is working behind your app? Send X-Anpheros-Acting-As: PractitionerRole/<id> (or
Practitioner/<id>) on any /v1 or /fhir/R4 request made with a project key. The person must
exist in the directory and be active. The reference is written to the access log, becomes the
author of that request's writes (unless you set X-Anpheros-Author-Ref) and is shown to the
patient by name in their connections ("Dr. Ana Popescu · Clinica Dente read your lab results").
12. Lab reports in one call
Send a whole lab report (CSV, HL7 v2 ORU^R01 or JSON) and get laboratory Observations with LOINC and reference ranges; re-sending is safe. Details: lab-connector.md.
curl -X POST "$BASE/v1/patients/$PATIENT/labs/import" -H "Authorization: Bearer $KEY" -H "Content-Type: text/csv" --data-binary @report.csv
Conformance feedback on writes
Every POST/PUT of a clinical resource is checked against the IPS profile of its section and, for
laboratory observations, the HL7 Europe laboratory report rules. The write is never rejected for
profile reasons (structural FHIR errors still are); when something is missing the response carries
Anpheros-Conformance: warnings=2; IPS Condition: Condition without code | ...
Fix what it names and the resource will be included in the patient's $summary. Resource types added
on 22 September 2026: Immunization, MedicationAdministration (search statement=MedicationStatement/{id}),
RelatedPerson, QuestionnaireResponse, Basic. Writes made by other projects into a record you can
see arrive as webhook events with data.external = true — see docs/webhooks.md.