AnpherosAnpheros PlatformDevelopers

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

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

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:

  1. Register an application: POST /admin/projects/{id}/applications with your redirect URI (public for mobile/web apps with PKCE, confidential for servers; the secret is shown once).
  2. 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=ro They 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.
  3. 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.
  4. 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 answer 403, 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.