# Anpheros Platform — developer documentation > Anpheros is infrastructure for interoperable medical data and for integrating that data into healthcare applications, software and AI services. Each patient has one HL7 FHIR R4 record that they control; applications, clinics, laboratories and AI agents read and write it through a FHIR R4 or REST API, only with the patient's consent and with provenance on every write. Developers use it as the medical data layer — a managed FHIR backend and healthcare database — of healthcare applications and AI services. Anpheros' own patient app uses the same API. The sandbox is free; production starts at €49 a month with the first month free; the platform is in private beta. # Medical data infrastructure > What medical data infrastructure is and where Anpheros fits: a patient-controlled HL7 FHIR R4 record, an API, consent, provenance and audit as shared building blocks for healthcare applications and AI. Source: https://developers.anpheros.com/guides/medical-data-infrastructure **Medical data infrastructure is the layer that stores patient health data in a structured, standard form and makes it available to applications under rules the patient controls.** Anpheros is interoperable medical-data infrastructure: it keeps one HL7 FHIR R4 record per patient and exposes it through an API, with consent, provenance and an audit built in, so that healthcare applications, medical software and AI services can be built on top of it instead of each one building its own medical database. In practice, developers use Anpheros as the medical data layer of their product — the FHIR backend and patient-record store of a healthcare app, a clinic integration or an AI application. It is reached through an API (REST and FHIR R4), not as a general-purpose SQL database, and it does not host AI models. ## Why it is a separate layer Every application that handles health data needs the same foundations, and none of them are the application's actual product: - a **data model** for observations, diagnoses, medications, documents and the rest of a medical record; - **identity and isolation**, so one application cannot see another's patients; - **consent**, so a patient decides which application sees what, and for how long; - **provenance and history**, so every value can be traced to who recorded it and nothing is silently overwritten; - **integration** with laboratories, clinics, devices and other applications; - **standards**, so the data can leave the application and still be understood; - and, increasingly, a safe way to hand the right part of a record to an **AI model**. When each application builds these on its own, patient data ends up fragmented across incompatible silos. Medical data infrastructure turns them into shared, tested building blocks. ## The chain Anpheros implements ``` Medical data measurements, lab results, diagnoses, medications, documents, visits ↓ HL7 FHIR R4 stored as standard resources — 26 types, versioned ↓ API /fhir/R4 (strict FHIR) and /v1 (simplified REST), same ids ↓ Patient record one record per person, isolated per application (pairwise ids) ↓ Consent OAuth 2.1 / SMART on FHIR grants: scopes, duration, revocation ↓ Applications patient apps, clinic and lab systems, third-party apps ↓ AI context API: the relevant part of the record for a model, with sources ``` ## The building blocks, and where each is documented | Building block | In Anpheros | Read more | |---|---|---| | Data model | 26 HL7 FHIR R4 resource types; LOINC, ICD-10, ATC, UCUM | [FHIR platform](https://developers.anpheros.com/guides/fhir) | | Record | one FHIR record per patient; family members have their own records | [Patient medical record](https://developers.anpheros.com/guides/patient-medical-record) | | Storage and history | every update is a new version; documents immutable, encrypted with a customer-managed key in the EU | [Digital medical record infrastructure](https://developers.anpheros.com/guides/digital-medical-record) | | Access | API keys per project, OAuth tokens per patient, `404` for anything outside your scope | [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) | | Consent | grants for 30–365 days, per resource type and category, revocable at once | [Consent and access model](https://developers.anpheros.com/guides/consent) | | Provenance and audit | every write records its author and source; every read is visible to the patient | [Security, privacy and data residency](https://developers.anpheros.com/guides/security) | | Integration | FHIR transactions, lab report import, signed webhooks, SDKs | [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations) | | Interoperability | FHIR R4, International Patient Summary, SMART on FHIR, HL7 v2 lab messages | [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability) | | AI context | a budgeted, source-labelled context for any model you choose | [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) | ## Infrastructure versus application Anpheros separates the two on purpose. **Anpheros Daily** is an application — screens, reminders, an assistant — for patients and families. **Anpheros Platform** is the infrastructure underneath. Daily writes to the record through the same public API as any other application, which is what makes the record portable: an application built by someone else can read what Daily wrote, with the patient's consent, in the same FHIR form. ## What infrastructure does not decide for you Anpheros holds and governs the data; it does not make clinical decisions, design your user experience or cover your regulatory obligations. Anpheros does not claim medical-device certification or other regulatory approvals. Production use requires a verified organisation and a signed data processing agreement, and the platform is in private beta (single zone, no contractual SLA). ## Related - [What is Anpheros?](https://developers.anpheros.com/guides/what-is-anpheros) - [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) - [Healthcare software development](https://developers.anpheros.com/guides/healthcare-software) - [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) - [Build with Anpheros](https://developers.anpheros.com/guides/build-with-anpheros) --- # What is Anpheros? > Anpheros is infrastructure for interoperable medical data: a patient-controlled HL7 FHIR R4 record and an API for building healthcare applications, software and AI services on it. Source: https://developers.anpheros.com/guides/what-is-anpheros **Anpheros is infrastructure for interoperable medical data and for integrating that data into healthcare applications, software and AI services.** For a patient it is a digital medical record they control; for a developer it is an API over that record, stored as standard HL7 FHIR R4 data. Anpheros has two parts that share one record per patient: - **Anpheros Daily** — the patient app (Android, macOS, web) where people and families record symptoms, vital signs, medications, lab results, documents and appointments. - **Anpheros Platform** — the API and data store behind it. Applications, clinics, laboratories and AI agents read and write the same record through it, and each of them reaches a patient only with that patient's consent. Anpheros Daily is itself a client of the public API: what the app records is available to other authorised applications in exactly the same form. The platform is in private beta; data is hosted in the European Union. ## The problem it addresses A healthcare application usually has to solve the same things before it can do anything useful: a data model for medical records, storage, identity, consent, an audit trail, integration with labs and clinics, and a way to hand the right part of a record to an AI model. Most of that work is not specific to the application. Anpheros provides that layer once, on open standards, so that an application can concentrate on its own experience while the record stays portable between applications and under the patient's control. ## What the platform provides | Capability | What it is | Where it is documented | |---|---|---| | FHIR R4 store | One record per patient made of standard FHIR resources — 26 resource types, search, version history, transactions, `Patient/$everything` | [FHIR platform](https://developers.anpheros.com/guides/fhir) | | REST API | `/v1`: patients, observations, conditions, medications, documents, timeline, provenance — the same data and ids as the FHIR API | [Getting started](https://developers.anpheros.com/guides/getting-started) | | Patient consent | OAuth 2.1 with PKCE, SMART on FHIR standalone launch, scopes per resource type and category, revocation that takes effect on the next request | [Authentication and OAuth](https://developers.anpheros.com/guides/authentication), [Consent and access model](https://developers.anpheros.com/guides/consent) | | Provenance and audit | Every write records who wrote it, for whom and from which system; every read is logged and visible to the patient | [Security, privacy and data residency](https://developers.anpheros.com/guides/security) | | AI context API | `POST /v1/context` assembles the relevant part of a record for an AI model, within a token budget, with every item labelled by source | [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) | | International Patient Summary | `Patient/$summary` returns an IPS document, validated with the official HL7 validator | [FHIR platform](https://developers.anpheros.com/guides/fhir) | | Webhooks | Signed, retried events for writes, consent changes and documents | [Webhooks](https://developers.anpheros.com/guides/webhooks) | | Lab connector | A whole lab report (CSV, HL7 v2 ORU^R01, JSON) becomes FHIR Observations in one call | [Lab connector](https://developers.anpheros.com/guides/lab-connector) | | SDKs | Dart / Flutter (`anpheros_sdk` on pub.dev) and TypeScript (`@anpheros/sdk` on npm) | [SDKs](https://developers.anpheros.com/guides/sdks) | | Sandbox | Self-service; a separate database where each project has its own 30 synthetic patients; `sk_test_` keys cannot reach real data | [Getting started](https://developers.anpheros.com/guides/getting-started) | ## Who it is for - **Developers and startups** building a healthcare or medical application that needs to store patient data without designing a medical data model, consent system and audit trail from scratch. - **Clinics and laboratories** that want to deliver results and documents into a patient's record with the patient's consent. - **Teams building AI assistants and agents** that need a patient's structured medical context, with consent and an audit of what the AI read. - **Patients and families**, through Anpheros Daily, who want one record they control and can share. ## What Anpheros is not - It is not a hospital EHR or a practice-management system; it holds the patient's own record and connects applications to it. - It does not ship integrations with specific AI vendors. The context API returns JSON or text that your code passes to whichever model you use. - It does not provide a Model Context Protocol (MCP) server today. - It is not generally available yet: the platform is in private beta, single-zone, without a contractual SLA. Production keys are issued to verified organisations with a signed data processing agreement. ## Frequently asked questions ### Is Anpheros a FHIR server? Yes, among other things. `/fhir/R4` is a FHIR R4 (4.0.1) interface with a CapabilityStatement at `/fhir/R4/metadata`. It also adds what a plain FHIR server does not: per-project isolation, patient consent, provenance on every write, an audit visible to the patient, a simpler REST API over the same data and an AI context API. ### Can I use Anpheros as the backend of my healthcare app? That is its purpose. Your app stores and reads patient data through the REST or FHIR API; your patients' records stay portable and can be shared with other applications when the patient consents. Start with [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app). ### Can I use Anpheros as the database of my AI healthcare application? For the patient medical data, yes: Anpheros is a managed healthcare database built on HL7 FHIR R4, with an API, patient consent and an AI context API — a FHIR backend your application calls instead of designing its own medical tables. It is not a general-purpose SQL database and it does not run AI models; your application keeps its own users and non-medical data and calls the model of your choice. See [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare). ### Can an AI model read patient data through Anpheros? Only through your application and only within a patient's consent (or the patients your project created). The context API prepares the data for a model and records what was used. See [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data). ### Where is the data stored? In the European Union. Documents are kept in an EU storage bucket encrypted with a customer-managed key. See [Security, privacy and data residency](https://developers.anpheros.com/guides/security). ### How do I get access? The sandbox is self-service: sign in with Google on the dashboard (`https://platform.anpheros.com/dashboard/`) and get a key in one click. Production access is by request during the private beta (`contact@anpheros.com`): production keys are issued to verified organisations with a signed data processing agreement. ### Is Anpheros free? The sandbox is free: each sandbox project gets its own 30 synthetic patients and up to 10 000 writes a day. Production starts at €49 a month for 2,500 patients, with the first month free; production access is for verified organisations with a signed data processing agreement. See [Pricing](https://developers.anpheros.com/guides/pricing). ## Related - [Medical data infrastructure](https://developers.anpheros.com/guides/medical-data-infrastructure) - [Anpheros for developers](https://developers.anpheros.com/guides/developers) - [Healthcare application architecture](https://developers.anpheros.com/guides/architecture) - [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) --- # Patient medical record > What a patient medical record contains, how it differs from EHRs and EMRs, and how patient, data, applications and consent relate in Anpheros — including families, portability and deletion. Source: https://developers.anpheros.com/guides/patient-medical-record **A patient medical record is the complete, structured history of one person's health — measurements, results, diagnoses, medications, documents and encounters — kept over time.** In Anpheros every patient has exactly one such record, stored as HL7 FHIR R4 resources. The record belongs to the patient's care, not to one application: applications write into it and read from it, and a patient decides, through consent, which applications may do so. ## EHR, EMR and patient-held records | Kind | Who keeps it | Typical scope | |---|---|---| | Electronic medical record (EMR) | one clinic or practice | what that provider recorded | | Electronic health record (EHR) | a hospital or health system | what the organisation's providers recorded | | Personal / patient-held record | the patient | everything the patient collects: results from many labs, home measurements, documents, medications | Anpheros is closest to the third kind, with an important difference: it is not an app-specific diary. It is **infrastructure**: the same record can be written by the patient's own app, by a laboratory, by a clinic and by an AI assistant, each through the API and each within the limits the patient allows. Anpheros is not a hospital EHR and does not replace one. ## What the record contains | Part of the record | FHIR resources in Anpheros | |---|---| | The person and the people close to them | `Patient`, `RelatedPerson` | | Measurements and results | `Observation` (vital signs, laboratory, symptoms, wellbeing, daily activity and sleep), `DiagnosticReport` | | Problems and their course | `Condition`, `EpisodeOfCare` (for example a pregnancy or a long-term illness), `Procedure`, `FamilyMemberHistory` | | Treatment | `MedicationStatement`, `MedicationAdministration` (each dose taken or skipped), `Immunization`, `CarePlan`, `Goal`, `ServiceRequest` | | Safety | `AllergyIntolerance` | | Care | `Encounter`, `Appointment`, `CareTeam` | | Documents and questionnaires | `DocumentReference` (immutable originals), `QuestionnaireResponse` | | Governance | `Consent` (one per grant), `Provenance` (one per write) | Every item is coded where a standard exists — LOINC for measurements and lab results, ICD-10 for conditions, ATC for medications, UCUM for units — and keeps its original text as well. See [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems). ## The relationship between patient, data, applications and consent ``` ┌──────────────── consent: which app, which data, how long ───────────────┐ │ ▼ Patient ──► Anpheros Daily (or any patient app) ──► Anpheros API ──► the patient's FHIR record ◄── other apps, clinics, labs, AI │ access log visible to the patient ``` - **The application that created a record** can read and write it with its API key. - **Any other application** needs the patient's consent: an OAuth grant with explicit scopes (resource types and actions, optionally a category such as `laboratory`), for 30, 90, 180 or 365 days. - **Every write** is attributed: patient, practitioner, device, import or AI, with the organisation and source system. - **Every read** — including reads by the creating application and context built for AI models — appears in the patient's access log, per application. - **The patient can revoke** an application at any time; the next request is refused. ## Families and dependents A person can hold records for others — children, an elderly parent. Each dependent has their own `Patient` record, linked to the guardian's; the patient-side API lists "my records and my dependents'" (`GET /me/patients`), with who has access to each. Consent is always given per record. ## Portability Because the record is standard FHIR, it can leave Anpheros intact: `Patient/{id}/$everything` returns the whole compartment, and `Patient/{id}/$summary` returns an International Patient Summary, a document format designed to be read by clinicians elsewhere. ## Deletion Deleting a `Patient` deletes every resource of that record. Documents, once finalised, cannot be modified, only deleted. ## Related - [Digital medical record infrastructure](https://developers.anpheros.com/guides/digital-medical-record) - [Medical data infrastructure](https://developers.anpheros.com/guides/medical-data-infrastructure) - [Consent and access model](https://developers.anpheros.com/guides/consent) - [FHIR platform](https://developers.anpheros.com/guides/fhir) --- # Digital medical record infrastructure > The infrastructure a digital medical record needs — structure, history, documents, isolation, consent, audit, exchange — and why it is kept separate from the patient-facing application. Source: https://developers.anpheros.com/guides/digital-medical-record **A digital medical record needs two different things: a patient-facing application that people use every day, and the infrastructure underneath that stores, protects and shares the record.** Anpheros provides the second: the storage, versioning, identity, consent, audit and exchange of the record, through an API. The patient-facing application can be Anpheros Daily, or one you build. ## Application versus infrastructure | | Patient-facing application | Medical data infrastructure | |---|---|---| | What it is | screens, notifications, reminders, charts, an assistant | the record itself and the rules around it | | Changes often | yes — design, features, platforms | rarely — it must stay stable and compatible | | Examples of work | a symptom diary, a medication reminder, a family calendar | FHIR storage, version history, consent, provenance, audit, lab import, webhooks | | In Anpheros | Anpheros Daily (Android, macOS, web) | Anpheros Platform (`platform.anpheros.com`) | Keeping them apart is what lets a record outlive any single application and be shared between several. Anpheros Daily follows this split: what people record in the app is written to the platform through the same public API that any other application uses, so it is available — with the patient's consent — to other applications in the same FHIR form. ## What the infrastructure has to provide ### Structure A record is only useful if other software can understand it. Anpheros stores it as HL7 FHIR R4 resources — 26 types — with standard codes (LOINC, ICD-10, ATC, UCUM) and keeps the original text next to every code. [FHIR platform](https://developers.anpheros.com/guides/fhir) ### History Medical data is corrected, not overwritten. Every update creates a new version, readable through `/fhir/R4/{type}/{id}/_history`; conditional updates with `If-Match` prevent two writers from overwriting each other (a stale version answers `412`). ### Documents Scans and PDFs are stored as `DocumentReference` with the original file: uploaded through the platform or directly to storage, then finalised with a SHA-256 checksum and size. After finalisation the original cannot be changed; values extracted from it point back to it (`derived_from`). Files are kept in an EU storage bucket encrypted with a customer-managed key, up to 25 MiB each. ### Identity and isolation Each application works inside a project and sees only its own patients (plus those that granted it access), under its own pairwise identifiers. A record outside its reach does not exist for it (`404`). ### Consent A patient grants an application access for a period (30–365 days), to specific resource types and actions, optionally limited to a category. Grants are mirrored as FHIR `Consent` resources and can be revoked at any time. [Consent and access model](https://developers.anpheros.com/guides/consent) ### Provenance and audit Every write records who wrote it (patient, practitioner, device, import or AI), for which organisation and from which system. Every read is logged and shown to the patient per application. ### Exchange The record can be exported as a whole (`Patient/$everything`), summarised in the International Patient Summary format (`Patient/$summary`), fed by laboratories (CSV, HL7 v2 ORU^R01, JSON) and watched through signed webhooks. [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations) ### Residency and deletion Data is stored and processed in the European Union. Deleting a patient deletes every resource of the record. ## Building your own patient-facing application If you are building the application layer, you can concentrate on the experience and use Anpheros for the record: 1. create a patient for each user (`POST /v1/patients`) or ask an existing Anpheros user for consent; 2. write what the user records (`/v1/patients/{id}/observations`, `/conditions`, `/medications`, `/documents`); 3. read it back as lists or a timeline (`/v1/patients/{id}/timeline`); 4. subscribe to webhooks to refresh the screens when a lab or clinic adds something. The full walkthrough is in [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app). ## Related - [Patient medical record](https://developers.anpheros.com/guides/patient-medical-record) - [Medical app backend and database](https://developers.anpheros.com/guides/medical-app-backend) - [Security, privacy and data residency](https://developers.anpheros.com/guides/security) - [Medical data infrastructure](https://developers.anpheros.com/guides/medical-data-infrastructure) --- # Security, privacy and data residency > How patient data is protected: EU data residency, project isolation, pairwise ids, credentials, consent, provenance, an audit visible to the patient, and the limits of the private beta. Source: https://developers.anpheros.com/guides/security Medical data is the most sensitive data an application can hold. This page lists how Anpheros Platform protects it today — only what is implemented — and what is still limited during the private beta. ## Data residency - All platform data is stored and processed in the European Union: the service and its databases in Google Cloud `europe-west4` (Netherlands), the webhook delivery queue in `europe-west3` (Frankfurt) and the append-only export of the access log in the BigQuery EU location. - Documents are stored in an EU storage bucket encrypted with a customer-managed encryption key (CMEK). Originals are immutable after finalisation; their SHA-256 checksum and size are recorded. ## Isolation between applications - Every API key belongs to one **project**. A project sees only the patients it created — in the sandbox, including its own copy of synthetic patients, which no other project can see. - **Pairwise identifiers:** each project receives its own id for the same person; internal ids never leave the platform, so ids cannot be correlated between applications. - A record you cannot reach answers `404`, never `403`, so the existence of a patient cannot be probed. - **Sandbox and production are separate databases.** A sandbox key (`sk_test_`) physically cannot reach real patients. - With the patient's consent an organisation reads the whole record, including what other organisations wrote, but can change or delete only what it wrote itself. ## Credentials - API keys are shown once and stored only as a SHA-256 hash. Keys have `read` / `write` scopes and never cross their environment. - OAuth 2.1 with mandatory PKCE (S256); the `redirect_uri` must be registered exactly. Access tokens last 30 minutes, refresh tokens 30 days and rotate on every use. - **Refresh-token reuse detection:** presenting a refresh token that was already used revokes the whole token chain. - Token responses carry `Cache-Control: no-store`. OpenID Connect `id_token`s are signed with RS256; public keys are published at `/oauth/jwks`. ## Consent, provenance and audit - A patient grants an application access on a hosted consent page, choosing the record and the duration (30, 90, 180 or 365 days). Scopes are per resource type and action, optionally filtered by category. Every grant is mirrored as a FHIR `Consent` resource. - Revocation takes effect on the next request; the application cannot refresh back in. - **Every write** produces a `Provenance` resource: who wrote it (patient, practitioner, device, import or AI), for which organisation, from which source system. - **Every read is logged and visible to the patient**, including reads made with a project's own API key, and including context built for AI models. ## Transport and web security - HTTPS only, with HTTP Strict Transport Security. API responses carry a restrictive Content-Security-Policy, `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY` and a strict referrer policy. - Webhook deliveries are signed with HMAC-SHA256 over the timestamp and body; receivers should reject signatures older than 5 minutes. Events carry ids and versions, never clinical content. - Rate limits: 600 requests per minute per credential and per IP; JSON bodies up to 2 MiB; documents up to 25 MiB. ## Search engines and AI crawlers Public pages (anpheros.com, the platform presentation and this documentation) are open to search engines and AI crawlers. The API, the dashboard, the OAuth and consent pages and the patient app (`app.anpheros.com`) are excluded with `noindex` and `robots.txt` rules; none of them return patient data without authentication. ## Current limits (private beta) - Single-zone hosting without automatic failover; no contractual SLA yet. - Production keys are issued to verified organisations with a signed data processing agreement; beta partners start with synthetic data. - SMART EHR launch and the OpenID `nonce` parameter are not supported yet. ## Related - [Consent and access model](https://developers.anpheros.com/guides/consent) - [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) - [Limits and rate limits](https://developers.anpheros.com/guides/limits) - [Architecture](https://developers.anpheros.com/guides/architecture) --- # Free FHIR database and sandbox > A free HL7 FHIR R4 database to build against: the Anpheros sandbox with 30 synthetic patients per project, the production API, OAuth and webhooks, no card, EU-hosted — and how it differs from a self-hosted server. Source: https://developers.anpheros.com/guides/free-fhir-database **A free FHIR database is a place where you can store and query HL7 FHIR R4 resources without paying for infrastructure while you build and test.** Anpheros offers one as its sandbox: the same API as production, 30 synthetic patients per project with realistic records, your own test patients, an API key you create yourself, and no card or contract. It is free for as long as you build; you pay only when you go to production with real patients. ## What the sandbox gives you | | Sandbox | |---|---| | Price | Free, no time limit, no card | | FHIR | HL7 FHIR R4, 26 resource types, search, history, transactions, `$everything`, the International Patient Summary | | REST | the simpler REST v1 view of the same data | | Patients | 30 synthetic patients per project, plus up to 500 test patients you create | | Writes | 10,000 a day per project | | Storage | 250 MB per project (data and files) | | Auth | API keys and the full OAuth 2.1 / SMART on FHIR flow, with a test consent screen | | Events | signed webhooks, retried, with a local verification example | | SDKs | Dart / Flutter and TypeScript | | Region | hosted in the European Union, like production | | Reset | one click, the project returns to its 30 synthetic patients | The synthetic patients are generated with coherent histories: conditions, medications matched to them, laboratory results with LOINC codes and reference ranges, vitals over months, documents and an emergency summary. They look like real records to your code, so a dashboard, a chart or an AI prompt built against them works unchanged in production. ## Why not just run HAPI FHIR locally? You can, and for learning FHIR it is a fine choice. A self-hosted server gives you a FHIR endpoint; it does not give you patient consent, pairwise identifiers between applications, provenance on every write, an audit the patient can read, laboratory import from HL7 v2 or a hosted OAuth server. Those are the parts a healthcare product spends its first months on. The Anpheros sandbox has them from the first request, and they are the same code that runs in production. The trade-off is that Anpheros is a managed service with a defined data model, not a blank FHIR server. If your product needs resource types or extensions outside the 26 supported, check the [FHIR platform](https://developers.anpheros.com/guides/fhir) guide first. ## What you can build in the sandbox - A patient app that reads and writes its user's record with consent. - A clinic or laboratory integration that writes on behalf of an organisation. - An AI assistant or agent that reads a patient's context through the context API and writes back with AI provenance. - A migration test: import an existing dataset as FHIR transactions and check what your code sees. The [Getting started](https://developers.anpheros.com/guides/getting-started) guide goes from an API key to all of these in about an hour. ## From sandbox to production Production uses the same API, the same SDKs and the same consent flow. You create a production key, point your configuration at it and your sandbox code runs against real patients. The first month of production is free on every plan; after that the [pricing](https://developers.anpheros.com/guides/pricing) is a monthly price per organisation for a number of stored patients, with sandbox, test and synthetic patients never counted. ## Limits to know before you start - The sandbox is for building and testing. Real patient data must not be stored in it. - Rate limits are lower than in production; see [Limits and rate limits](https://developers.anpheros.com/guides/limits). - Resetting a project deletes everything you wrote in it, including test patients. ## Related - [FHIR MCP server for AI agents](https://developers.anpheros.com/guides/mcp) - [Getting started](https://developers.anpheros.com/guides/getting-started) - [FHIR platform](https://developers.anpheros.com/guides/fhir) - [Healthcare API with patient consent](https://developers.anpheros.com/guides/healthcare-api-patient-consent) - [How Anpheros compares with other FHIR servers](https://developers.anpheros.com/guides/fhir-server-comparison) - [Pricing](https://developers.anpheros.com/guides/pricing) --- # Healthcare API with patient consent > How access to a record is granted by the patient through OAuth 2.1 scopes and durations, logged and revocable, what it changes in an application's design, and how pairwise ids keep applications apart. Source: https://developers.anpheros.com/guides/healthcare-api-patient-consent **A healthcare API with patient consent is one where access to a record is granted by the patient, for a purpose, for a time, and can be seen and withdrawn by the patient, rather than decided once by the organisation that holds the data.** In Anpheros, consent is not a field you set; it is the mechanism through which an application reaches a record at all. This guide explains how that works for a developer and what it changes in an application's design. ## Two ways to reach a record | | Organisation access | Patient-granted access | |---|---|---| | Who authorises | your organisation, through an API key | the patient, through an OAuth 2.1 consent screen | | Typical use | a clinic or laboratory writing results, your own app writing on behalf of its users | a third-party app, an AI assistant, a doctor's tool, a family member | | Scope | the patients your organisation created or that were shared with it | the scopes the patient accepted (`patient/Observation.read`, …) | | Duration | while the key is valid | the duration the patient chose; renewable, revocable | | Visible to the patient | yes, in the access log | yes, with the ability to withdraw | Both paths go through the same API and the same FHIR record. The difference is who holds the key to the door. ## The consent flow, step by step 1. Your application sends the patient to the Anpheros authorisation endpoint with the scopes it needs and a reason in plain language. 2. The patient sees what you ask for, chooses a duration and accepts or declines. The screen is in the patient's language. 3. You receive an access token limited to those scopes and that patient. Tokens are short-lived; refresh tokens last as long as the consent. 4. Every read and write with that token is logged with your application's name. The patient sees the log in their app. 5. If the patient withdraws consent, the next request fails with a clear error. You receive a webhook so you can clean up. The flow is standard OAuth 2.1 with PKCE and SMART on FHIR scopes, so existing libraries work. The [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) guide has the exact parameters and the [Consent and access model](https://developers.anpheros.com/guides/consent) the rules behind it. ## What it changes in your application - **You ask for less.** Scopes are per resource type and per direction. An app that charts weight asks for `Observation.read`, not the whole record. - **You design for withdrawal.** Access can end at any time. Cache little, re-read when needed, and handle the revoked error as a normal state. - **You get trust for free.** Patients see your application's name, what it can reach and when it last read something. Applications that behave well are easier to accept. - **You write with provenance.** Everything you write carries your application as author and, when relevant, the person on whose behalf. The patient and other applications can tell your data from theirs. ## Identifiers that do not leak Each application sees a patient under a pairwise identifier: the same person has a different id in your application and in another one. Two applications cannot join their data about a person without the patient's consent, even if both are built on Anpheros. For your code this is invisible; for the patient it is the difference between consent and a formality. ## Families and carers Consent extends to people who manage records for others: a parent for a child, an adult child for an elderly parent. The record stays with the account that created it; other accounts receive access, which can be withdrawn. Your application sees the same consent mechanism, with the carer as the person who accepts. ## Related - [Consent and access model](https://developers.anpheros.com/guides/consent) - [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) - [SMART on FHIR backend](https://developers.anpheros.com/guides/smart-on-fhir-backend) - [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) - [Security, privacy and data residency](https://developers.anpheros.com/guides/security) --- # SMART on FHIR backend > What Anpheros implements of SMART on FHIR — discovery, standalone launch, PKCE, SMART v2 scopes, OpenID Connect, hosted consent — a launch in five requests, and what is not offered yet. Source: https://developers.anpheros.com/guides/smart-on-fhir-backend **SMART on FHIR is the standard way an application obtains a user's permission to reach a FHIR record: OAuth 2.0/2.1 for the authorisation, a defined set of scopes for what can be read or written, and a discovery document that tells the application where to go.** Anpheros is a SMART on FHIR backend: it hosts the authorisation server, the FHIR R4 server and the consent screen, so a SMART application built for it works with standard libraries and no custom login. ## What Anpheros implements | Part of SMART | In Anpheros | |---|---| | Discovery | `/.well-known/smart-configuration` on the FHIR base, with the endpoints, scopes and PKCE methods supported | | Launch | standalone launch (the application starts, then asks for access); EHR launch from within a clinical system is not offered | | Authorisation | OAuth 2.1 with PKCE required, authorisation code flow | | Scopes | SMART v2 patient scopes, `patient/.`, plus `openid` and `fhirUser` | | Identity | an OpenID Connect `id_token` naming the patient as a FHIR resource | | Consent | a hosted consent screen in the patient's language, with the duration chosen by the patient | | Tokens | short-lived access tokens, refresh tokens bound to the consent, revocation | | Conformance | the capability statement declares the SMART security service; the FHIR server passed the Inferno ONC test suite in September 2026 | ## A standalone launch in five requests ``` 1. GET /fhir/R4/.well-known/smart-configuration 2. GET {authorization_endpoint}?response_type=code&client_id=…&scope=openid fhirUser patient/Observation.rs&code_challenge=… 3. the patient accepts on the Anpheros consent screen 4. POST {token_endpoint} code + code_verifier → access_token, refresh_token, id_token, patient 5. GET /fhir/R4/Observation?patient={patient} with Authorization: Bearer … ``` The `patient` field in the token response is the pairwise id of the patient for your application. Use it in every query; it is the only id you will see for that person. ## Why a backend rather than a library A SMART client library handles the dance on your side. What it needs on the other side is an authorisation server that knows the patient, a consent screen the patient trusts, scopes enforced on every request and a FHIR server that honours them. Running those yourself means an identity provider, a FHIR server, a policy layer and an audit log, each kept consistent with the others. Anpheros provides them as one service, with the audit visible to the patient and provenance on every write. ## Writing through SMART Write scopes (`patient/Observation.c`, `.u`, `.d`) work the same way. Everything written carries your application as the author. Writes are idempotent when you send an idempotency key, so retries never duplicate a measurement. Deletions are soft and leave history, as the [Medical data API](https://developers.anpheros.com/guides/medical-data-api) guide describes. ## What is not there yet - EHR launch (the application opened from inside a hospital system with a launch context). - `system/` scopes for backend services; organisations use API keys instead. - Bulk Data export (`$export`); `$everything` on a patient is available. These are listed with the rest in [Versioning and deprecation](https://developers.anpheros.com/guides/versioning), and the capability statement is always the authoritative source. ## Related - [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) - [Healthcare API with patient consent](https://developers.anpheros.com/guides/healthcare-api-patient-consent) - [FHIR platform](https://developers.anpheros.com/guides/fhir) - [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) - [API reference (OpenAPI)](https://developers.anpheros.com/docs) --- # How Anpheros compares with other FHIR servers > Self-hosted FHIR servers, cloud FHIR stores, open-source healthcare platforms and Anpheros side by side: who authorises access, consent, provenance, residency, pricing, and when each is the right choice. Source: https://developers.anpheros.com/guides/fhir-server-comparison **Teams choosing a FHIR backend usually weigh four kinds of option: an open-source server they host themselves, a managed FHIR store from a cloud provider, an open-source healthcare platform with a hosted edition, or a managed healthcare database like Anpheros.** This guide describes what each kind is good at and where Anpheros sits, based on public documentation as of October 2026. For any product named here, check its own documentation; features change. ## The four kinds | | Self-hosted FHIR server (e.g. HAPI FHIR) | Cloud FHIR store (e.g. Google Cloud Healthcare API, Azure Health Data Services, AWS HealthLake) | Healthcare platform (e.g. Medplum) | Anpheros | |---|---|---|---|---| | What it is | a FHIR server you run | a FHIR data store inside a cloud account | a FHIR-native application platform with auth, workflows and a hosted edition | a managed healthcare database: FHIR R4 record per patient, consent, API, audit | | Who authorises access | whatever you build around it | the cloud's IAM, per project or dataset | the platform's access policies, configured by you | the patient (OAuth 2.1 consent) or the organisation (API key) | | Patient-facing consent and audit | no | no | buildable with its policy model | built in, visible to the patient | | Provenance on every write | if you add it | if you add it | supported by FHIR; you enforce it | required and automatic | | Identifier isolation between applications | no | no | no | pairwise ids per application | | Lab import (HL7 v2) | separate tooling | partial (v2 to FHIR mapping in some stores) | integrations you write | built in, one request | | Data residency | wherever you host it | the regions the provider offers | depends on hosting | European Union only | | Pricing | your infrastructure and time | usage-based (requests, storage) | per plan or self-hosted | per organisation, by stored patients | | Best for | learning, full control, unusual data models | teams already in that cloud who will build the healthcare layer themselves | teams who want to build on an open codebase and own the full stack | teams who want the healthcare layer done and the product as their work | ## Where Anpheros is the right choice - You are building a product for patients, clinics, laboratories or AI, and you want to write the product, not the record. - Patient consent and an audit the patient can read are requirements, not nice-to-haves (GDPR Article 9, EHDS). - Your data must stay in the European Union. - You want FHIR R4 but also a simpler REST view, SDKs and webhooks, from one vendor. - You want to start free, in a sandbox with realistic synthetic patients, and move to production without rewriting. ## Where another option is better - You need FHIR resource types, profiles or extensions outside the 26 that Anpheros supports, or a fully custom data model: a self-hosted server gives you that freedom. - Your organisation requires everything inside one cloud account for compliance reasons: a cloud FHIR store fits that policy. - You want to own and modify the entire stack, including the authorisation server and UI components: an open-source platform is designed for it. - You need EHR launch, Bulk Data export or `system/` scopes today: Anpheros does not offer them yet (see [SMART on FHIR backend](https://developers.anpheros.com/guides/smart-on-fhir-backend)). ## A fair way to decide Count the parts of the healthcare layer your product needs, consent, provenance, audit, identifiers, lab import, document storage, residency, and estimate the months to build and maintain each one on the option you prefer. Then compare that with the product work those months could have gone to. Anpheros is the right answer when the second number is larger. ## Related - [Free FHIR database and sandbox](https://developers.anpheros.com/guides/free-fhir-database) - [FHIR platform](https://developers.anpheros.com/guides/fhir) - [Medical app backend and database](https://developers.anpheros.com/guides/medical-app-backend) - [Healthcare startups](https://developers.anpheros.com/guides/healthcare-startups) - [Security, privacy and data residency](https://developers.anpheros.com/guides/security) --- # Healthcare API > What a healthcare API is, what to look for in one, and the Anpheros API at a glance: FHIR R4, REST v1, OAuth 2.1, patient-side endpoints, idempotent writes, errors, limits and events. Source: https://developers.anpheros.com/guides/healthcare-api **A healthcare API is a programmatic interface through which software reads and writes health data — patient records, observations, diagnoses, medications, documents — and through which access to that data is authorised.** The Anpheros Platform API is a healthcare API over a patient-controlled HL7 FHIR R4 record: applications use it to store and retrieve medical data, to obtain a patient's consent and to be notified of changes. ## Kinds of healthcare APIs | Kind | What it exchanges | Typical use | |---|---|---| | FHIR REST APIs | FHIR resources over HTTP (`GET /Observation?patient=…`) | the modern standard for clinical data exchange | | SMART on FHIR / OAuth | authorisation for FHIR APIs | letting third-party apps reach a record with the user's permission | | HL7 v2 messaging | pipe-delimited messages (`ORU^R01` for results, `ADT` for admissions) | laboratory and hospital systems, often over interfaces rather than HTTP | | Document exchange | clinical documents (PDF, CDA, FHIR document bundles) | summaries, discharge letters, referrals | | Proprietary REST APIs | vendor-specific JSON | a single product's own mobile app or integrations | Anpheros combines the first two as its core, accepts HL7 v2 laboratory results as input, stores documents with their originals and produces FHIR document bundles (the International Patient Summary). It also offers a simpler REST API over the same data for developers who do not want to work with FHIR directly. ## What to look for in a healthcare API - **A standard data model**, so data can move between systems without custom mapping. - **Authorisation that the patient controls**, not only credentials that the application controls. - **Provenance**: who wrote each value, on whose behalf, from which system. - **History**: versions instead of silent overwrites. - **Auditability** of reads, not only of writes. - **Safe retries** (idempotency) and **predictable errors**, because health data must not be duplicated or lost. - **Isolation** between the applications that share the same infrastructure. - **Data residency** that matches where the patients are. The rest of this page shows how each of these appears in the Anpheros API. ## The Anpheros API at a glance | Surface | Base path | Purpose | |---|---|---| | FHIR R4 | `/fhir/R4` | 26 resource types; read, search, create, update, delete, history, transactions, `$everything`, `$summary`, `$validate` | | REST v1 | `/v1` | patients, observations, conditions, medications, documents, timeline, provenance, AI context, lab import, terminology, webhooks | | OAuth 2.1 | `/oauth` | consent page, tokens (PKCE), revocation, OpenID Connect keys | | Patient side | `/me` | a person's own records, who has access, access log, revoke | | Discovery | `/fhir/R4/metadata`, `/fhir/R4/.well-known/smart-configuration`, `/openapi.json` | machine-readable descriptions of the API | Base URL: `https://platform.anpheros.com`. The sandbox and production share it; the key decides the data plane. ### Authentication - **API keys** (`sk_test_…`, `sk_live_…`) for your servers; they see the patients your project created. - **OAuth access tokens** (`at_…`) for an application acting for one patient under a consent. ```bash curl https://platform.anpheros.com/v1/patients -H "Authorization: Bearer $KEY" ``` ### Writing safely `POST` requests accept an `Idempotency-Key`: a retried request with the same key returns the original response and creates nothing. Every write gets a `Provenance`; the author type is sent in the body (`author_type`) or in headers such as `X-Anpheros-Author-Type`, `X-Anpheros-Source-System`, `X-Anpheros-Origin-Id` and `X-Anpheros-On-Behalf-Of`. ```bash curl -X POST https://platform.anpheros.com/v1/patients/$PID/observations \ -H "Authorization: Bearer $KEY" -H 'content-type: application/json' -H "Idempotency-Key: $(uuidgen)" \ -d '{"code": "29463-7", "display": "Body weight", "category": "vital-signs", "value": 71.4, "unit": "kg", "effective_at": "2026-09-28T07:30:00Z", "author_type": "patient"}' ``` ### Errors and limits FHIR endpoints answer with `OperationOutcome`; the others with `{"error": {"type", "message", "field"}}`. Every response carries `Anpheros-Request-Id`. The default limit is 600 requests per minute per key and per IP. [Errors](https://developers.anpheros.com/guides/errors) · [Limits](https://developers.anpheros.com/guides/limits) ### Events Signed webhooks for `resource.created`, `resource.updated`, `resource.deleted`, `consent.granted`, `consent.revoked`, `document.finalized` and `ping`. [Webhooks](https://developers.anpheros.com/guides/webhooks) ## Choosing between FHIR and REST v1 Use **FHIR** when you already work with FHIR, need resource types that `/v1` does not cover (for example `Immunization`, `Procedure` or `CarePlan`), or exchange data with other FHIR systems. Use **REST v1** for application code that wants flat JSON for the common cases. Both read and write the same resources with the same ids, so a project can mix them. [Medical data API](https://developers.anpheros.com/guides/medical-data-api) describes the data operations in detail. ## Related - [Healthcare API with patient consent](https://developers.anpheros.com/guides/healthcare-api-patient-consent) - [SMART on FHIR backend](https://developers.anpheros.com/guides/smart-on-fhir-backend) - [Medical data API](https://developers.anpheros.com/guides/medical-data-api) - [FHIR platform](https://developers.anpheros.com/guides/fhir) - [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability) - [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations) - [API reference (OpenAPI)](https://developers.anpheros.com/docs) · [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) --- # Medical data API > Where each kind of medical data goes in the Anpheros API, how it is coded, and how to write, filter, trace, correct and delete it — with working examples. Source: https://developers.anpheros.com/guides/medical-data-api **A medical data API gives software structured access to the contents of patient records: create a patient, record a blood-pressure reading, list active medications, attach a lab report, trace who wrote what.** This page describes the data operations of the Anpheros API — which kind of medical data goes where, how it is coded, and how to read it back — with examples that work against the sandbox. Applications use these operations to treat Anpheros as the medical database of their product: patient records live in the platform's HL7 FHIR R4 store, and the application reads and writes them through the API instead of keeping its own tables of medical data. For the broader picture (authentication, consent, events) see [Healthcare API](https://developers.anpheros.com/guides/healthcare-api). ## Where each kind of medical data goes | Medical data | REST v1 | FHIR resource | Coding | |---|---|---|---| | The person | `POST /v1/patients` | `Patient` | name, birth date, gender, identifiers | | Vital signs, lab results, symptoms, activity, surveys | `/v1/patients/{id}/observations` | `Observation` | LOINC (symptoms: ICD-10 chapter R); UCUM units | | Diagnoses and problems | `/v1/patients/{id}/conditions` | `Condition` | ICD-10 | | Medications | `/v1/patients/{id}/medications` | `MedicationStatement` | ATC, product name kept as text | | Documents (PDF, images) | `/v1/patients/{id}/documents` | `DocumentReference` | LOINC document kinds | | A whole lab report | `POST /v1/patients/{id}/labs/import` | `Observation` (laboratory) | LOINC where known, the lab's own code otherwise | | Doses taken or skipped, vaccinations, allergies, procedures, reports, care plans, goals, referrals, visits, appointments, care teams, family history, questionnaires | `/fhir/R4/{type}` | `MedicationAdministration`, `Immunization`, `AllergyIntolerance`, `Procedure`, `DiagnosticReport`, `CarePlan`, `Goal`, `ServiceRequest`, `Encounter`, `Appointment`, `CareTeam`, `FamilyMemberHistory`, `QuestionnaireResponse` | per [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems) | REST v1 objects and FHIR resources are the same records with the same ids; every v1 object carries its `fhir` reference. ## Writing medical data ```bash # a lab result with its reference range, linked to the report it came from curl -X POST https://platform.anpheros.com/v1/patients/$PID/observations \ -H "Authorization: Bearer $KEY" -H 'content-type: application/json' -H "Idempotency-Key: $(uuidgen)" -d '{ "code": "4548-4", "display": "Hemoglobin A1c", "category": "laboratory", "value": 6.4, "unit": "%", "effective_at": "2026-09-01T08:00:00Z", "reference_range": {"low": 4.0, "high": 5.6}, "derived_from": ["DocumentReference/'$DOC'"], "author_type": "import" }' ``` - **Observation categories:** `vital-signs`, `laboratory`, `symptom`, `activity`, `survey`, `exam`, `imaging`, `social-history`. - **Composite measurements** such as blood pressure use `components` (systolic `8480-6`, diastolic `8462-4` inside the panel `85354-9`). - **Author types:** `patient`, `practitioner`, `device`, `import`, `ai`. Without one, the platform records `import`. - **Codes you do not know by heart:** `GET /v1/terminology/loinc?q=hba1c` and `GET /v1/terminology/atc?q=metformin` search the bundled code subsets; an observation written without a display name gets the LOINC name automatically. ## Reading medical data ```bash curl "https://platform.anpheros.com/v1/patients/$PID/observations?category=laboratory&code=4548-4&from=2026-01-01" -H "Authorization: Bearer $KEY" curl "https://platform.anpheros.com/v1/patients/$PID/conditions?clinical_status=active" -H "Authorization: Bearer $KEY" curl "https://platform.anpheros.com/v1/patients/$PID/medications?status=active" -H "Authorization: Bearer $KEY" curl "https://platform.anpheros.com/v1/patients/$PID/timeline?from=2026-06-01" -H "Authorization: Bearer $KEY" ``` | Endpoint | Filters | |---|---| | observations | `category`, `code`, `from`, `to` | | conditions | `clinical_status` | | medications | `status` | | documents | `kind` | | timeline | `from`, `to`, `types` | Lists are paged with `limit` and `cursor`. The **timeline** merges observations, conditions, medications, documents, visits, appointments, vaccinations and episodes of care into one chronological list — the natural input for a patient history screen. For anything the REST filters do not cover, use FHIR search: `GET /fhir/R4/Observation?patient=$PID&code=http://loinc.org|4548-4&_sort=-date` ([FHIR platform](https://developers.anpheros.com/guides/fhir)). ## Tracing and correcting data - **Who wrote it:** `GET /v1/patients/{id}/provenance/{type}/{resourceId}` — one entry per version, with author type, project, organisation and source system. - **Every version:** `GET /fhir/R4/{type}/{id}/_history`; update with `If-Match` to avoid overwriting someone else's change. - **Ownership:** with consent you can read what other organisations wrote, but change or delete only what your project wrote (`403` otherwise). - **Deletion:** `DELETE /v1/{observations|conditions|medications}/{id}`; deleting a `Patient` deletes the whole record. ## Documents Create the document (you get an upload target), upload the bytes through the platform or directly to storage, then finalise. After finalisation the original is immutable; its SHA-256 and size are recorded. Up to 25 MiB per file. ## Related - [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) - [Patient medical record](https://developers.anpheros.com/guides/patient-medical-record) - [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) - [API reference (OpenAPI)](https://developers.anpheros.com/docs) · [Getting started](https://developers.anpheros.com/guides/getting-started) --- # FHIR platform > HL7 FHIR R4 explained and how Anpheros implements it as a managed FHIR database: 26 resource types, search, history, transactions, $everything, the International Patient Summary and the simpler REST view of the same data. Source: https://developers.anpheros.com/guides/fhir **Anpheros is a FHIR platform — a managed FHIR database (data store) that applications use as their FHIR backend: it stores every patient record natively as HL7 FHIR R4 (4.0.1) resources and exposes them at `https://platform.anpheros.com/fhir/R4`,** with consent, provenance and an audit added on top of the standard. Applications that already speak FHIR can use it directly; applications that do not can use the simpler REST API (`/v1`), which reads and writes the same resources with the same ids. For AI applications this makes Anpheros the FHIR backend a model's context comes from: see [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data). ## What is HL7 FHIR? FHIR (Fast Healthcare Interoperability Resources) is the HL7 standard for exchanging health data over the web. It defines: - **resources** — small, typed JSON (or XML) documents for each clinical concept: a `Patient`, an `Observation`, a `Condition`, a `MedicationStatement`; - **references** between them (`"subject": {"reference": "Patient/123"}`), so a record is a graph of resources around a patient; - a **REST API** for reading, searching, creating, updating and deleting resources, with standard search parameters; - **bundles** for sending several resources at once (transactions) or as a document (such as a patient summary); - **terminology bindings**, so values carry codes from systems such as LOINC or ICD-10; - **profiles** — constraints for a use case or a country, such as the International Patient Summary. R4 (version 4.0.1) is the release most widely implemented today. Using FHIR as the storage model — not only as an export format — means there is no translation layer between what an application writes and what another FHIR system reads. ```json { "resourceType": "Observation", "status": "final", "category": [{"coding": [{"system": "http://terminology.hl7.org/CodeSystem/observation-category", "code": "laboratory"}]}], "code": {"coding": [{"system": "http://loinc.org", "code": "4548-4", "display": "Hemoglobin A1c"}]}, "subject": {"reference": "Patient/…"}, "effectiveDateTime": "2026-09-01T08:00:00Z", "valueQuantity": {"value": 6.4, "unit": "%", "system": "http://unitsofmeasure.org", "code": "%"} } ``` ## Capability statement `GET /fhir/R4/metadata` returns the CapabilityStatement: the supported resource types, their search parameters and the operations. It is public and is the authoritative list; the table below reflects it on 28 September 2026. ## The 26 resource types | Area | Resource types | |---|---| | Patient and people | `Patient`, `RelatedPerson` | | Measurements and results | `Observation` (vital signs, laboratory, symptoms, wellbeing, daily activity and sleep), `DiagnosticReport` | | Problems and care | `Condition`, `EpisodeOfCare`, `Procedure`, `CarePlan`, `Goal`, `ServiceRequest`, `CareTeam`, `FamilyMemberHistory` | | Medication and prevention | `MedicationStatement`, `MedicationAdministration`, `Immunization`, `AllergyIntolerance` | | Documents and questionnaires | `DocumentReference`, `QuestionnaireResponse` | | Visits | `Encounter`, `Appointment` | | Directory | `Organization`, `Practitioner`, `PractitionerRole` | | Governance | `Consent`, `Provenance` | | Extension point | `Basic` | Every patient-scoped type belongs to the patient compartment, so `Patient/{id}/$everything`, patient-level OAuth scopes and consent filters apply to all of them. Directory resources (`Organization`, `Practitioner`, `PractitionerRole`) have no patient; they are readable across projects in the same environment and changeable only by the project that created them. ## Interactions and operations - **Read, search, create, update, delete** on every supported type; search parameters per type are listed in the CapabilityStatement. Unknown search parameters are refused with `400` rather than silently ignored. - **History**: `GET /fhir/R4/{type}/{id}/_history` returns every version; updates can be made conditional with `If-Match` (a version mismatch answers `412`). - **Transactions and batches**: `POST /fhir/R4` with a `Bundle` of type `transaction` or `batch`. - **`Patient/{id}/$everything`**: the whole compartment of one patient. - **`Patient/{id}/$summary`**: an International Patient Summary (IPS) document `Bundle`, in English or Romanian (`?lang=`). - **`Observation/$validate?profile=eu-lab`**: reports how a lab result measures up to the HL7 Europe laboratory report rules. - **Paging**: `_count` up to 200; `_revinclude` returns at most 1 000 resources. - **Idempotency**: `POST` requests accept an `Idempotency-Key`; repeating a request with the same key returns the same answer and creates nothing. ```bash # latest HbA1c results of one patient, strict FHIR curl "https://platform.anpheros.com/fhir/R4/Observation?patient=$PID&code=http://loinc.org|4548-4&_sort=-date" \ -H "Authorization: Bearer $KEY" # the patient's International Patient Summary curl "https://platform.anpheros.com/fhir/R4/Patient/$PID/\$summary?lang=en" -H "Authorization: Bearer $KEY" ``` ## FHIR and the simpler REST API `/v1` exists for developers who do not want to work with FHIR resources directly. It covers patients, observations, conditions, medications, documents, a chronological timeline and provenance, plus the platform features (context, lab import, webhooks, terminology). Every `/v1` object carries its `fhir` reference, so an application can start with `/v1` and switch to FHIR for the parts where it needs the full model. ## Standards around FHIR `$summary` produces an International Patient Summary validated with the official HL7 validator (0 errors); lab results are checked against the HL7 Europe laboratory rules (advisory today); third-party apps connect through SMART on FHIR standalone launch; HL7 v2 `ORU^R01` lab messages are accepted as input. The formats, levels and exchange patterns are described in [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability); the code systems per resource type in [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems). ## Related - [Free FHIR database and sandbox](https://developers.anpheros.com/guides/free-fhir-database) - [How Anpheros compares with other FHIR servers](https://developers.anpheros.com/guides/fhir-server-comparison) - [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability) - [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems) - [Medical data API](https://developers.anpheros.com/guides/medical-data-api) - [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) - [API reference (OpenAPI)](https://developers.anpheros.com/docs) --- # Healthcare data interoperability > The technical, syntactic, semantic and organisational levels of interoperability, the standards Anpheros uses (FHIR R4, IPS, SMART on FHIR, HL7 v2) and why provenance makes exchanged data trustworthy. Source: https://developers.anpheros.com/guides/interoperability **Healthcare data interoperability is the ability of different systems — apps, clinics, laboratories, hospitals, AI services — to exchange health data and use it without re-interpreting it by hand.** Anpheros approaches it by storing every record in the formats other systems already understand (HL7 FHIR R4 with standard code systems), by exchanging it through standard protocols (FHIR REST, SMART on FHIR, the International Patient Summary, HL7 v2 laboratory messages) and by keeping the context that makes exchanged data trustworthy: who wrote it, when, and with whose consent. ## Four levels of interoperability | Level | Question it answers | How Anpheros addresses it | |---|---|---| | Technical | Can the systems connect? | HTTPS APIs, OAuth 2.1, signed webhooks, SDKs in Dart and TypeScript | | Syntactic | Can they parse each other's data? | HL7 FHIR R4 (4.0.1) resources and bundles; CSV, HL7 v2 ORU^R01 and JSON accepted for lab results | | Semantic | Do they mean the same thing? | LOINC for measurements and results, ICD-10 for conditions, ATC for medications, UCUM for units; original text kept next to every code | | Organisational | May they exchange it, and can they trust it? | patient consent per application, provenance on every write, an access log visible to the patient | Most integration projects fail at the semantic and organisational levels, not the technical one. Coding at write time and recording provenance for every value are what make data from one source usable in another. ## Standards Anpheros uses - **HL7 FHIR R4.** Every record is made of FHIR resources — 26 types — searchable and versioned, with a CapabilityStatement at `/fhir/R4/metadata`. [FHIR platform](https://developers.anpheros.com/guides/fhir) - **International Patient Summary (IPS).** `Patient/{id}/$summary` returns an IPS document bundle, validated with the official HL7 validator against `hl7.fhir.uv.ips#1.1.0` with 0 errors. The IPS is the summary format intended for cross-border care in Europe. - **HL7 Europe laboratory report rules.** Lab results are checked on write; gaps are reported in the `Anpheros-Conformance` response header (advisory today). `Observation/$validate?profile=eu-lab` runs the check on demand. - **SMART on FHIR.** Third-party applications reach a record through OAuth 2.1 with PKCE and SMART v2 patient scopes; discovery at `/fhir/R4/.well-known/smart-configuration`. The standalone launch test group of the Inferno SMART App Launch STU2 suite passes; EHR launch is not supported yet. - **HL7 v2.** Laboratory results arrive as `ORU^R01` messages as well as CSV or JSON, and become FHIR Observations. [Lab connector](https://developers.anpheros.com/guides/lab-connector) - **European Health Data Space.** FHIR R4 and the IPS are the formats the EHDS relies on for patient summaries and laboratory results; Anpheros follows them. This is alignment with the formats, not a certification. ## Exchange patterns 1. **Consented application access** — an application asks the patient for scopes, reads and writes the record through FHIR or REST, and loses access when the patient revokes it. 2. **Document exchange** — the record, or its summary, leaves as a FHIR bundle (`$everything`, `$summary`). 3. **Inbound results** — laboratories and clinics write into the record on behalf of their organisation; the patient sees who wrote what. 4. **Events** — subscribers are told that something changed (ids only, never clinical content) and read what they are allowed to. ## Provenance: interoperability you can trust Data that travels between systems loses its context unless the context travels with it. In Anpheros every version of every resource records: - the **author type** — patient, practitioner, device, import or AI; - the **organisation** on whose behalf it was written and, when named, the **practitioner**; - the **source system** and the record's id there (`X-Anpheros-Source-System`, `X-Anpheros-Origin-Id`). Values produced by AI are labelled as such and are kept apart from clinical facts when a context is built for a model. ## Identity across applications Each application sees its own identifier for the same person (pairwise ids), so records cannot be correlated between applications behind the patient's back. References to people outside an application's scope are masked. Interoperability happens through consent, not through shared identifiers. ## Related - [FHIR platform](https://developers.anpheros.com/guides/fhir) - [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations) - [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems) - [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) - [Medical data infrastructure](https://developers.anpheros.com/guides/medical-data-infrastructure) --- # Healthcare integrations > Integration patterns supported today: lab reports in one call, clinics writing on behalf of an organisation, devices, consented third-party apps, webhooks and SDKs — and what is not available. Source: https://developers.anpheros.com/guides/healthcare-integrations **A healthcare integration connects a system that produces or needs health data — a laboratory, a clinic, a device, another application — to the patient's record.** With Anpheros every integration goes through the same API and the same rules: data is written as HL7 FHIR R4, attributed to its source, visible to the patient, and shared with other parties only under the patient's consent. This page describes the integration patterns the platform supports today. ## Laboratories: whole reports in one call A laboratory, or any system that holds lab reports, sends a complete report and the platform turns every result into a laboratory `Observation`: ```bash curl -X POST https://platform.anpheros.com/v1/patients/$PID/labs/import \ -H "Authorization: Bearer $KEY" -H "Content-Type: text/csv" \ -H "X-Anpheros-Source-System: labx" -H "Idempotency-Key: report-2026-0917-77" \ --data-binary @report.csv ``` - Formats: **CSV** (Romanian or English headers, decimal comma accepted), **HL7 v2 ORU^R01** and **JSON**. - Markers are mapped to **LOINC** when the report gives a code or the name matches the platform's terminology; others keep the lab's own code and are listed as `unmapped`. - Every row gets a stable identifier, so **re-sending the same report skips what was already imported**. - Up to 500 rows per request; each result carries provenance naming the source system and report. Details: [Lab connector](https://developers.anpheros.com/guides/lab-connector). ## Clinics: writing on behalf of an organisation Clinics and the people who work there are directory resources (`Organization`, `Practitioner`, `PractitionerRole`). A clinic's system can then say who is behind each request: - `X-Anpheros-Acting-As: PractitionerRole/` — the practitioner working through your application; written to the access log and shown to the patient by name; - `X-Anpheros-On-Behalf-Of: Organization/` — the organisation a write is made for; - `X-Anpheros-Author-Ref: Practitioner/` — the author recorded in `Provenance`. With the patient's consent the clinic reads the whole record, including what other organisations wrote, and changes only what it wrote itself. Several resources can be written atomically with a FHIR `transaction` bundle (`POST /fhir/R4`). The flow consent → lab `Observation` written by a clinic project → notification in the patient's app has been exercised end-to-end with a test clinic project. ## Devices and wearables Measurements from devices are `Observation`s with `author_type: "device"` and a LOINC code — heart rate, blood pressure, SpO₂, weight, glucose, steps, sleep duration and others ([FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems)). Anpheros Daily writes the daily summaries it reads from Apple Health and Health Connect as Observations in the same way. Anpheros does not connect directly to device vendors' clouds; your application or backend reads the device and writes the result. ## Third-party applications: consented access An application that wants data a person already keeps in Anpheros registers once and asks for consent through OAuth 2.1 with PKCE (SMART on FHIR standalone launch): 1. `GET /oauth/authorize?...&scope=patient/Observation.rs?category=laboratory offline_access` — the hosted consent page; 2. the person chooses the record and the duration (30, 90, 180 or 365 days); 3. `POST /oauth/token` exchanges the code for an access token (30 minutes) and a rotating refresh token (30 days); 4. the application sees only that patient, only within its scopes, under its own pairwise id. [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) ## Events: reacting to changes Instead of polling, register a webhook. Deliveries are signed with HMAC-SHA256, retried with backoff for up to 24 hours and carry ids, never clinical content. When another project writes into a record you have access to, the event says so (`data.external: true`, with the source). [Webhooks](https://developers.anpheros.com/guides/webhooks) ## SDKs The TypeScript (`@anpheros/sdk`) and Dart / Flutter (`anpheros_sdk`) SDKs implement all of the above — lab import (`labs.importCsv`, `labs.importHl7`, `labs.importItems`), OAuth with PKCE, webhooks management and signature verification. [SDKs](https://developers.anpheros.com/guides/sdks) ## What is not available - Ready-made connectors to specific hospital EHRs or laboratory information systems; integrations are built against the API. - SMART EHR launch (launching inside an EHR); only standalone launch is supported. - Direct device-vendor integrations. ## Related - [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability) - [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) - [Architecture](https://developers.anpheros.com/guides/architecture) - [Use cases](https://developers.anpheros.com/guides/use-cases) --- # Healthcare software development > What is different about building medical software and how a healthcare application is layered: your product on top, the Anpheros API, the FHIR record and patient consent underneath. Source: https://developers.anpheros.com/guides/healthcare-software **Healthcare software is software that creates, stores or acts on information about people's health — patient apps, clinic tools, laboratory systems, remote-monitoring services, AI assistants.** What sets it apart from other software is not the user interface but the data: it is sensitive, long-lived, standardised, shared between organisations and subject to consent. Anpheros is infrastructure for that data layer; this page explains the layers of a healthcare application and which of them Anpheros can provide. ## The general architecture ``` Healthcare application your product: UI, workflows, notifications, business rules ↓ Anpheros API REST v1 and FHIR R4, OAuth 2.1 / SMART on FHIR, webhooks, SDKs ↓ FHIR medical data one HL7 FHIR R4 record per patient, versioned, with provenance ↓ Consent / authorisation per-application grants chosen and revocable by the patient ``` Your application owns the experience; Anpheros owns the record and the rules around it. ## What is different about building medical software ### The data model is a standard, not a design choice Other software can invent its schema. Medical software that invents its own schema cannot exchange data with labs, clinics or other applications without a translation project. Using HL7 FHIR R4 resources and standard codes (LOINC, ICD-10, ATC, UCUM) from the first line of code avoids that. [FHIR platform](https://developers.anpheros.com/guides/fhir) ### Every value needs a source A glucose value typed by a patient, measured by a device, imported from a lab report or produced by an AI model means different things. Anpheros records the author type (patient, practitioner, device, import, AI), organisation and source system for every write, and keeps every version. ### Access is decided by the patient, not only by the application Beyond user login and roles, medical software needs consent: which application may read which part of which person's record, for how long, and an audit that the person can see. [Consent and access model](https://developers.anpheros.com/guides/consent) ### Data must survive the application Records are kept for years and move between providers. Separating the record (infrastructure) from the application means a redesign, a new app or a new partner does not require migrating medical data. [Digital medical record infrastructure](https://developers.anpheros.com/guides/digital-medical-record) ### Develop and test without real patients Real medical data should not be in development environments. Anpheros has a sandbox — a separate database with synthetic patients — and sandbox keys that physically cannot reach production data. ### AI needs the same rules as everyone else An AI feature is another reader of the record. It should get only what the patient allowed, with sources, and its outputs should be labelled as AI-generated. [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) ## What you build and what Anpheros provides | Layer | You build | Anpheros provides | |---|---|---| | User experience | screens, flows, notifications, clinical content | — | | Your users and accounts | sign-up, login, roles in your product | per-patient consent for data access; patient sign-in on the consent page | | Medical data storage | — | FHIR R4 record, 26 resource types, history, documents | | Coding | choosing what to record | standard code systems, bundled LOINC/ATC search | | Access control to records | which of your users sees which patient | project isolation, pairwise ids, OAuth scopes | | Audit | — | provenance on writes, access log visible to the patient | | Integration | your partners' specifics | lab import, FHIR transactions, webhooks, SDKs | | AI | prompts, model choice, safety of your feature | context API with token budgets and provenance labels | | Compliance | your regulatory obligations and clinical safety | EU data residency, encryption of documents with a customer-managed key, a data processing agreement for production | ## Where to go next - A step-by-step path from access to production: [Build with Anpheros](https://developers.anpheros.com/guides/build-with-anpheros) - A working tutorial: [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) - The responsibilities of a medical backend: [Medical app backend and database](https://developers.anpheros.com/guides/medical-app-backend) - Diagrams and data flows: [Architecture](https://developers.anpheros.com/guides/architecture) - For early-stage teams: [Healthcare startups](https://developers.anpheros.com/guides/healthcare-startups) ## Related - [Medical data infrastructure](https://developers.anpheros.com/guides/medical-data-infrastructure) - [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) - [Security, privacy and data residency](https://developers.anpheros.com/guides/security) --- # Anpheros for developers > What developers can build with Anpheros and where to start, by role: patient apps, medical backends, clinic and lab integrations, FHIR, AI features and AI-assisted development. Source: https://developers.anpheros.com/guides/developers **Anpheros gives developers interoperable medical-data infrastructure: a patient-controlled HL7 FHIR R4 record per person, a REST and FHIR API over it, OAuth-based consent, provenance, an audit visible to the patient, webhooks, a lab connector, an AI context API and SDKs for TypeScript and Dart.** You build the product; Anpheros keeps the medical record and the rules around it. This page answers "what can I build with Anpheros, and where do I start?" by role. ## What can I build? - **A patient or family health app** — symptoms, measurements, medications, documents, a timeline — without designing a medical database. - **The backend of a medical product** — remote monitoring, chronic-condition management, medication adherence — with consent and audit built in. - **A clinic or laboratory integration** that delivers results into the patient's record with the patient's consent. - **An AI assistant or agent** that answers questions about a person's record, with sources, within the patient's consent. - **A third-party app** that reaches data a person already keeps in Anpheros, through SMART on FHIR. Detailed scenarios: [Use cases](https://developers.anpheros.com/guides/use-cases). ## Start here, by role | If you are… | Start with | Then | |---|---|---| | a mobile or web developer building a patient app | [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) | [SDKs](https://developers.anpheros.com/guides/sdks), [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) | | a backend developer | [Medical app backend and database](https://developers.anpheros.com/guides/medical-app-backend) | [Medical data API](https://developers.anpheros.com/guides/medical-data-api), [Webhooks](https://developers.anpheros.com/guides/webhooks) | | an integration engineer at a clinic or lab | [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations) | [Lab connector](https://developers.anpheros.com/guides/lab-connector), [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability) | | a FHIR developer | [FHIR platform](https://developers.anpheros.com/guides/fhir) | [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems), [API reference](https://developers.anpheros.com/docs) | | building AI features or agents | [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) | [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data), [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) | | writing code with AI tools | [Anpheros for AI developers](https://developers.anpheros.com/guides/ai-developers) | [llms.txt](https://developers.anpheros.com/llms.txt), [OpenAPI](https://developers.anpheros.com/openapi.json) | | a founder or CTO evaluating infrastructure | [Healthcare startups](https://developers.anpheros.com/guides/healthcare-startups) | [Security, privacy and data residency](https://developers.anpheros.com/guides/security), [Architecture](https://developers.anpheros.com/guides/architecture) | ## Developer resources | Resource | Where | |---|---| | First calls, step by step | [Getting started](https://developers.anpheros.com/guides/getting-started) | | The whole path to production | [Build with Anpheros](https://developers.anpheros.com/guides/build-with-anpheros) | | Every endpoint | [API reference (OpenAPI)](https://developers.anpheros.com/docs) · [openapi.json](https://developers.anpheros.com/openapi.json) | | FHIR R4 | [FHIR platform](https://developers.anpheros.com/guides/fhir) · [CapabilityStatement](https://platform.anpheros.com/fhir/R4/metadata) | | OAuth and consent | [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) · [Consent and access model](https://developers.anpheros.com/guides/consent) | | Events | [Webhooks](https://developers.anpheros.com/guides/webhooks) | | Client libraries | [SDKs](https://developers.anpheros.com/guides/sdks): `@anpheros/sdk` on npm, `anpheros_sdk` on pub.dev | | AI | [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) | | Examples | runnable calls in [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app), [Medical data API](https://developers.anpheros.com/guides/medical-data-api) and [Webhooks](https://developers.anpheros.com/guides/webhooks) | | Architecture | [Healthcare application architecture](https://developers.anpheros.com/guides/architecture) | | Errors, limits, versioning | [Errors](https://developers.anpheros.com/guides/errors) · [Limits](https://developers.anpheros.com/guides/limits) · [Versioning](https://developers.anpheros.com/guides/versioning) | ## The platform in five facts 1. **Standard data:** 26 HL7 FHIR R4 resource types, coded with LOINC, ICD-10, ATC and UCUM. 2. **Two APIs, one record:** `/fhir/R4` and `/v1` read and write the same resources with the same ids. 3. **Consent by the patient:** OAuth 2.1 with PKCE and SMART on FHIR; grants of 30–365 days, revocable. 4. **Traceability:** every write has provenance, every version is kept, every read is visible to the patient. 5. **Safe development:** a self-service sandbox, separate from production, where each project has its own 30 synthetic patients. Anpheros Platform is in private beta. The sandbox is self-service on the [dashboard](https://platform.anpheros.com/dashboard/) (sign in with Google); production access is by request. ## Related - [What is Anpheros?](https://developers.anpheros.com/guides/what-is-anpheros) - [Medical data infrastructure](https://developers.anpheros.com/guides/medical-data-infrastructure) - [Build with Anpheros](https://developers.anpheros.com/guides/build-with-anpheros) --- # Build with Anpheros > The path from access to production in nine steps — authentication, API, medical data, consent, FHIR, webhooks, SDKs and going live — with the guide for each step. Source: https://developers.anpheros.com/guides/build-with-anpheros **Building on Anpheros means using it as the medical-data layer of your application: your product calls the Anpheros API to store and read patient records in HL7 FHIR R4, to obtain patient consent and to receive events.** This page is the map from first access to production; each step links to the guide that covers it in detail. ## 1. Get access Anpheros Platform is in private beta. The sandbox is self-service: sign in with Google on the dashboard (`https://platform.anpheros.com/dashboard/`) and press *Get a sandbox key* — you get an organisation, a sandbox project with its own 30 synthetic patients, and a key. Production access is by request (`contact@anpheros.com`). You create further projects and API keys in the dashboard or through the Admin API; OAuth applications are registered with `POST /admin/projects/{id}/applications` and webhooks with `POST /v1/webhooks`. A **project** is the unit of isolation: its keys see only the patients it created (and, with consent, those who granted it access). ## 2. Authenticate | Credential | For | Looks like | |---|---|---| | API key | your servers | `sk_test_…` (sandbox), `sk_live_…` (production) | | OAuth access token | an app acting for one patient | `at_…`, valid 30 minutes, refreshed with a rotating refresh token | Send it as `Authorization: Bearer `. Keys are shown once and never belong in a mobile or web app. → [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) ## 3. Connect to the API Base URL `https://platform.anpheros.com`; REST at `/v1`, FHIR R4 at `/fhir/R4`. The interactive reference and the OpenAPI specification describe every endpoint. ```bash curl https://platform.anpheros.com/v1/patients -H "Authorization: Bearer $KEY" ``` → [API reference](https://developers.anpheros.com/docs) · [Healthcare API](https://developers.anpheros.com/guides/healthcare-api) ## 4. Create and read medical data Create a patient for each of your users, write observations, conditions, medications and documents with an `Idempotency-Key`, and read them back as lists or a timeline. State the author of every write (`patient`, `practitioner`, `device`, `import`, `ai`). → [Getting started](https://developers.anpheros.com/guides/getting-started) · [Medical data API](https://developers.anpheros.com/guides/medical-data-api) · [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) ## 5. Add consent To reach a record a person already keeps in Anpheros, register an OAuth application with its redirect URI, send the person to the consent page with the scopes you need, and exchange the code (PKCE) for tokens. The person chooses the duration and can revoke access at any time; every read is visible to them. → [Consent and access model](https://developers.anpheros.com/guides/consent) · [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) ## 6. Use FHIR where you need the full model Resource types beyond the REST API — immunizations, procedures, care plans, allergies, encounters and others, 26 in all — are available through FHIR R4, together with search, history, transactions, `$everything` and the International Patient Summary (`$summary`). → [FHIR platform](https://developers.anpheros.com/guides/fhir) · [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems) · [Healthcare data interoperability](https://developers.anpheros.com/guides/interoperability) ## 7. React to events Register a webhook endpoint for `resource.*`, `consent.*` or `document.finalized` events and verify the `Anpheros-Signature` of every delivery. Laboratory reports can be sent in one call to the lab connector. → [Webhooks](https://developers.anpheros.com/guides/webhooks) · [Lab connector](https://developers.anpheros.com/guides/lab-connector) · [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations) ## 8. Use an SDK `@anpheros/sdk` (TypeScript: Node 18+, browsers, Deno, Bun) and `anpheros_sdk` (Dart / Flutter) cover the whole public API with the same shape, add idempotency keys to creates, retry on `429`/`5xx`, refresh tokens and implement the consent flow. ```bash npm install @anpheros/sdk # or: dart pub add anpheros_sdk ``` → [SDKs](https://developers.anpheros.com/guides/sdks) ## 9. Go to production - Production keys (`sk_live_`) are issued to verified organisations with a signed data processing agreement. - Plan for the limits of the private beta: single zone, no contractual SLA, 600 requests per minute per key and per IP. - Handle errors by type and keep `Anpheros-Request-Id` for support. - Review how data is protected and where it is stored. → [Security, privacy and data residency](https://developers.anpheros.com/guides/security) · [Limits](https://developers.anpheros.com/guides/limits) · [Errors](https://developers.anpheros.com/guides/errors) · [Versioning and deprecation](https://developers.anpheros.com/guides/versioning) ## Adding AI If your product includes an AI assistant or agent, the context API prepares the relevant part of a record for the model you use, within a token budget and with every item labelled by source. → [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) ## Related - [Anpheros for developers](https://developers.anpheros.com/guides/developers) - [Healthcare software development](https://developers.anpheros.com/guides/healthcare-software) - [Healthcare startups](https://developers.anpheros.com/guides/healthcare-startups) --- # Build a healthcare app > Tutorial: use Anpheros as the medical-data backend of a healthcare app — patients, measurements, conditions, medications, documents, labs, consent, webhooks and SDKs. Source: https://developers.anpheros.com/guides/build-a-healthcare-app This tutorial shows how a healthcare or medical application can use Anpheros Platform as its medical-data backend: where patient records are stored, how they are read and written, how other systems are connected and how the patient stays in control. Every call below is part of the public API ([reference](https://developers.anpheros.com/docs)). ## What you are building A typical patient-facing app — a chronic-condition tracker, a family health app, a remote-monitoring companion — needs to: 1. keep a record per patient: measurements, conditions, medications, documents; 2. show that record back as lists and a timeline; 3. accept data from other sources (devices, labs, clinics); 4. share parts of the record, with the patient's consent; 5. react when something changes. With Anpheros your app keeps its own users, screens and business logic, and delegates the medical record to the platform: ``` Mobile / web app ──► your backend ──► Anpheros Platform API ──► FHIR R4 record of each patient ▲ │ └──────────── signed webhooks ◄────────────────┘ ``` Your backend holds the API key; the app talks to your backend. (Apps that act for a patient who already has an Anpheros record use OAuth instead — see step 7.) ## 1. Get a sandbox key The sandbox is self-service: sign in with Google on the dashboard (`https://platform.anpheros.com/dashboard/`) and press *Get a sandbox key*. Sandbox keys start with `sk_test_` and can only reach the sandbox database, where your project already has its own copy of 30 synthetic patients. ```bash export BASE=https://platform.anpheros.com export KEY=sk_test_… curl $BASE/v1/patients -H "Authorization: Bearer $KEY" ``` ## 2. Create a patient Each user of your app gets a patient record owned by your project. ```bash curl -X POST $BASE/v1/patients -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"given": "Elena", "family": "Ionescu", "birth_date": "1985-09-03", "gender": "female"}' ``` The response contains the patient `id` (your own identifier for this person — other projects see a different one) and its `fhir` reference. ## 3. Write measurements, conditions and medications State who the data comes from with `author_type`: `patient`, `practitioner`, `device`, `import` or `ai`. If you omit it the platform records `import`, never `patient` by assumption. ```bash # a blood-pressure reading from a connected device (LOINC panel with two components) curl -X POST $BASE/v1/patients/$PID/observations -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \ -H "Idempotency-Key: $(uuidgen)" -d '{ "code": "85354-9", "display": "Blood pressure panel", "category": "vital-signs", "effective_at": "2026-09-28T08:00:00Z", "author_type": "device", "components": [ {"code": "8480-6", "display": "Systolic", "value": 128, "unit": "mm[Hg]"}, {"code": "8462-4", "display": "Diastolic", "value": 82, "unit": "mm[Hg]"} ]}' # a diagnosis (ICD-10 by default) curl -X POST $BASE/v1/patients/$PID/conditions -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \ -d '{"code": "I10", "display": "Essential hypertension", "onset": "2024-03-01", "author_type": "practitioner"}' # a medication (ATC by default) curl -X POST $BASE/v1/patients/$PID/medications -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \ -d '{"display": "Amlodipine 5 mg", "code": "C08CA01", "dosage": "1 tablet in the morning", "start": "2024-03-01", "author_type": "patient"}' ``` Observation categories: `vital-signs`, `laboratory`, `symptom`, `activity`, `survey`, `exam`, `imaging`, `social-history`. Each write is stored as a FHIR resource and gets a `Provenance` entry automatically. ## 4. Store documents ```bash # create the document, then upload the bytes curl -X POST $BASE/v1/patients/$PID/documents -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \ -d '{"title": "Blood tests 2026-09-14", "kind": "lab_report", "content_type": "application/pdf", "date": "2026-09-14"}' curl -X PUT $BASE/v1/documents/$DOC/content -H "Authorization: Bearer $KEY" -H 'content-type: application/pdf' --data-binary @report.pdf ``` The original is immutable after upload; values you extract from it can point back to it with `derived_from`. ## 5. Read the record back ```bash curl "$BASE/v1/patients/$PID/observations?category=vital-signs&limit=20" -H "Authorization: Bearer $KEY" curl "$BASE/v1/patients/$PID/medications?status=active" -H "Authorization: Bearer $KEY" curl "$BASE/v1/patients/$PID/timeline?from=2026-06-01" -H "Authorization: Bearer $KEY" # everything, chronologically ``` When you need the full FHIR model, the same data is available at `/fhir/R4` with the same ids ([FHIR R4 API](https://developers.anpheros.com/guides/fhir)). ## 6. Connect labs and devices - **Lab reports:** `POST /v1/patients/{id}/labs/import` with CSV, HL7 v2 ORU^R01 or JSON turns a whole report into laboratory Observations with LOINC codes ([Lab connector](https://developers.anpheros.com/guides/lab-connector)). - **Devices and wearables:** write Observations with `author_type: device` and the LOINC code of the measurement (heart rate, SpO₂, steps, sleep duration and others are listed in [FHIR code systems](https://developers.anpheros.com/guides/fhir-code-systems)). ## 7. Reach a record the patient already has (OAuth) If the person already keeps a record in Anpheros (for example through Anpheros Daily), your app can ask for access instead of creating a new patient: register an application, send the person to the consent page with the scopes you need, exchange the code for tokens and call the API with the access token. The patient chooses the duration and can revoke access at any time. Details: [Authentication and OAuth](https://developers.anpheros.com/guides/authentication). ## 8. React to changes with webhooks ```bash curl -X POST $BASE/v1/webhooks -H "Authorization: Bearer $KEY" -H 'content-type: application/json' \ -d '{"url": "https://your.app/anpheros/hook", "events": ["resource.created", "consent.revoked"]}' ``` Verify the `Anpheros-Signature` header of every delivery ([Webhooks](https://developers.anpheros.com/guides/webhooks)). ## 9. Use an SDK The same flow in TypeScript: ```ts import { Anpheros, apiKey } from '@anpheros/sdk'; const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) }); const { data: patients } = await anpheros.patients.list(); const vitals = await anpheros.observations.list(patients[0].id, { category: 'vital-signs', limit: 20 }); ``` A Dart / Flutter client with the same shape is available as `anpheros_sdk` ([SDKs](https://developers.anpheros.com/guides/sdks)). ## Before going to production - Production keys (`sk_live_`) are issued to verified organisations with a signed data processing agreement. - Read the [Security, privacy and data residency](https://developers.anpheros.com/guides/security) page and the [limits](https://developers.anpheros.com/guides/limits). - Handle errors by their type and quote the `Anpheros-Request-Id` header when you contact support ([Errors](https://developers.anpheros.com/guides/errors)). ## Related - [Build with Anpheros](https://developers.anpheros.com/guides/build-with-anpheros) - [Medical app backend and database](https://developers.anpheros.com/guides/medical-app-backend) - [Medical data API](https://developers.anpheros.com/guides/medical-data-api) - [Healthcare software development](https://developers.anpheros.com/guides/healthcare-software) --- # Medical app backend and database > What a medical app backend and its database must handle, which parts Anpheros provides as a managed healthcare database, what stays in your backend, three ways to connect, and how to stay in sync with webhooks. Source: https://developers.anpheros.com/guides/medical-app-backend **A medical app backend is the server side of a healthcare application: it stores patient data, enforces who may see it, keeps a history of changes and talks to labs, clinics and other services.** With Anpheros, the medical part of that backend — the healthcare database that holds each patient's record, with its history, consent, provenance, audit, lab import and events — is provided by the platform through an API, and your own backend keeps only what is specific to your product. ## What a medical backend has to handle | Responsibility | Why it is hard in healthcare | With Anpheros | |---|---|---| | A medical data model | dozens of kinds of data, each with standard codes | HL7 FHIR R4, 26 resource types, LOINC / ICD-10 / ATC / UCUM | | Versioning | medical data is corrected, never silently overwritten | every update is a new version; `If-Match` for conditional updates | | Documents | originals must stay unchanged and traceable | immutable originals with SHA-256, EU storage encrypted with a customer-managed key | | Access control | per patient, per application, per data type | project isolation, pairwise ids, OAuth scopes with category filters | | Consent | the patient decides, and can change their mind | grants for 30–365 days, revocable, mirrored as FHIR `Consent` | | Audit | patients and regulators ask who saw what | every read and write logged and visible to the patient | | Provenance | a value from a lab is not a value typed by a patient | author type, organisation, practitioner and source system on every write | | Integrations | labs send CSV, HL7 v2, JSON; apps need events | lab import, FHIR transactions, signed webhooks | | Safe retries | a duplicated medication or result is a clinical error | `Idempotency-Key` on every create | | Test data | real patients must never be in development | a sandbox database with synthetic patients | ## What stays in your backend - your **users and accounts**, and the mapping from each user to their Anpheros patient id (the pairwise id your project sees); - **product data** that is not medical: settings, subscriptions, content, reminders' schedules; - **business rules** — which of your staff may see which patient in your product; - the **API key**, which must never be shipped inside a mobile or web app. ## Three ways to connect **1. Your backend holds the API key (most common).** Your app calls your backend; your backend calls Anpheros with an `sk_live_` key and sees the patients your project created. ```ts import { Anpheros, apiKey } from '@anpheros/sdk'; const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) }); // GET /api/me/vitals in your backend, after your own authentication export async function myVitals(user: { anpherosPatientId: string }) { const page = await anpheros.observations.list(user.anpherosPatientId, { category: 'vital-signs', limit: 50 }); return page.data; } ``` **2. The app acts for the patient with OAuth.** For people who already have an Anpheros record, a mobile or web app is a *public* OAuth client with PKCE: the person consents on the hosted page and the app receives a 30-minute access token and a rotating refresh token for that one record. The SDKs implement the flow (`OAuthFlow`). **3. Server-to-server partners.** A confidential client (with a secret, kept on a server) can use the authorization-code flow, or `client_credentials`, which behaves like an API key for that project. ## Keeping your backend in sync Subscribe to webhooks instead of polling. Deliveries are signed (`Anpheros-Signature`, HMAC-SHA256 over timestamp and body), at-least-once and possibly out of order; de-duplicate by event id and ignore stale versions. ```ts import { verifyWebhookSignature } from '@anpheros/sdk'; app.post('/anpheros/hook', express.raw({ type: 'application/json' }), async (req, res) => { const ok = await verifyWebhookSignature({ secret: process.env.ANPHEROS_WEBHOOK_SECRET!, header: req.header('anpheros-signature'), body: req.body }); if (!ok) return res.status(400).end(); const event = JSON.parse(req.body.toString()); // ids and versions only — read the resource if you need it res.status(204).end(); }); ``` ## Handling errors and limits - Treat `404` as "not visible to you", never as proof that a record does not exist. - `403` means the credential exists but may not do this — a missing scope, or a resource written by another organisation. - `429` comes with `Retry-After`; the SDKs wait and retry automatically, as they do for `5xx`. - Keep the `Anpheros-Request-Id` of failed calls for support. [Errors](https://developers.anpheros.com/guides/errors) · [Limits and rate limits](https://developers.anpheros.com/guides/limits) ## Frequently asked questions ### What database should a medical app use? One that keeps medical data in a standard, versioned form and controls access per patient. Anpheros is a managed healthcare database built on HL7 FHIR R4: each patient's record is versioned and searchable, every write carries provenance, and an application sees a patient only if it created the record or the patient consented. Your own database keeps the rest of your product's data — accounts, billing, content. ### Is there a free database for medical apps? Yes. The Anpheros sandbox is free: sign in with Google, get a key in one click, and your project gets its own 30 synthetic patients and up to 10 000 writes a day. Production starts at €49 a month for 2,500 patients, with the first month free; production access is for verified organisations with a signed data processing agreement. See [Pricing](https://developers.anpheros.com/guides/pricing). ### Can I keep real patient data in the free sandbox? No. The sandbox is for synthetic data only: each sandbox project gets its own synthetic patients, and sandbox keys cannot reach production. Real patient records belong in a production project. ## Related - [Healthcare software development](https://developers.anpheros.com/guides/healthcare-software) - [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) - [Architecture](https://developers.anpheros.com/guides/architecture) - [Medical data API](https://developers.anpheros.com/guides/medical-data-api) - [SDKs](https://developers.anpheros.com/guides/sdks) --- # Healthcare application architecture > Diagrams and data flows: patient to application to Anpheros API to the FHIR record and external services, and AI agent to the context API to authorised data. Source: https://developers.anpheros.com/guides/architecture Anpheros is the medical-data layer between your application (or AI agent) and the patient's record. Your application keeps its own user interface and business logic; the medical record, consent, provenance and audit live in Anpheros and are reached through one API. ``` Your application, backend or AI agent (mobile app, web app, clinic system, lab system, LLM-based assistant) │ HTTPS · API key (sk_test_ / sk_live_) or OAuth token (at_…) ▼ Anpheros Platform API ├─ /v1 simplified REST: patients, observations, conditions, medications, │ documents, timeline, provenance, context, labs, webhooks ├─ /fhir/R4 strict FHIR R4: 26 resource types, search, history, transactions, │ $everything, $summary (IPS), $validate └─ /oauth OAuth 2.1 + PKCE, SMART on FHIR, OpenID Connect │ every request: project isolation · scopes · rate limits ▼ One FHIR R4 record per patient ├─ versions of every resource (history) ├─ Provenance for every write ├─ Consent resources for every grant └─ access log visible to the patient │ ▼ Events out: signed webhooks to your server (ids only, never clinical content) ``` ## The patient's view: from person to external services ``` Patient ↓ uses an app, chooses what to share, sees every access Healthcare application Anpheros Daily, or your own app ↓ REST v1 / FHIR R4 over HTTPS, API key or OAuth token Anpheros API ↓ isolation, scopes, idempotency, provenance FHIR medical data the patient's record: 26 resource types, every version kept ↓ only what the patient allowed, only for as long as allowed External healthcare services laboratories (lab import), clinics (directory, acting-as), other apps (OAuth / SMART), your backend (webhooks) ``` ## The AI view: from agent to authorised data ``` AI agent or LLM application runs the model you choose — hosted or local ↓ POST /v1/context {patient, task, question, budget_tokens} Medical context API plans which parts of the record matter, fits them into the budget, ↓ labels every item with author type and source, records a manifest Authorised medical data only records the project created or the patient granted; the read appears in the patient's access log ``` The model never receives credentials and never calls Anpheros itself; your application requests the context and decides what to send to the model. Two complete examples with the API calls: an AI healthcare application in [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) and a consented agent in [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data). Details: [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data), [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data). ## The record Every patient has one record made of FHIR R4 resources: `Observation` for vital signs, lab results, symptoms and daily activity summaries, `Condition` and `EpisodeOfCare`, `MedicationStatement` and `MedicationAdministration`, `DocumentReference`, `Immunization`, `AllergyIntolerance` and others — 26 types in all, listed live in the CapabilityStatement (`GET /fhir/R4/metadata`). There is no proprietary schema to learn: the REST API is a simpler view of the same resources, with the same ids. Nothing is silently overwritten. Each update creates a new version (`/fhir/R4/{type}/{id}/_history`), and each version records the project that wrote it and the organisation on whose behalf it was written. ## Two ways in | | API key | OAuth access token | |---|---|---| | Looks like | `sk_test_…` / `sk_live_…` | `at_…` | | Used by | your server | an application acting for one patient | | Sees | the patients your project created | exactly one patient, within the scopes the patient granted | | Typical use | your own app's backend, a lab system, a clinic integration | a third-party app or AI assistant reaching a record the patient already has | A project never sees another project's patients unless the patient grants access. Each project gets its own identifier for the same person (pairwise ids), so ids cannot be correlated across applications, and a record outside your reach answers `404`, never `403`. ## Two environments The sandbox and production are separate databases. A sandbox key (`sk_test_`) physically cannot reach real patients; each sandbox project gets its own copy of 30 synthetic patients, which it can change freely and reset. Production keys (`sk_live_`) are issued to verified organisations. ## Data flows **Your app writes.** `POST /v1/patients/{id}/observations` with an `Idempotency-Key`. The platform stores a FHIR `Observation`, writes a `Provenance` (author type: patient, practitioner, device, import or ai), logs the access and sends a `resource.created` webhook to subscribed endpoints. **Another application reads with consent.** The patient approves it on the hosted consent page (`/oauth/authorize`), choosing the record and the duration (30–365 days). The application exchanges the code for tokens and reads only what the scopes allow. The patient sees the application, its scopes and every read in their access log, and can revoke it at any time. **A lab delivers results.** `POST /v1/patients/{id}/labs/import` with a CSV, HL7 v2 ORU^R01 or JSON report; every result becomes a laboratory `Observation` with LOINC codes where known, and re-sending the same report is safe. **An AI model needs context.** `POST /v1/context` returns the parts of the record relevant to a task, within a token budget, each item labelled with its source; the call is recorded with a manifest id. The model itself runs wherever you choose. ## Where Anpheros fits compared with building it yourself | Concern | Building it yourself | With Anpheros | |---|---|---| | Medical data model | design tables for each kind of record | FHIR R4 resources, 26 types | | Interoperability | custom export formats | FHIR R4, International Patient Summary, SMART on FHIR | | Consent | build grant, scope, expiry and revocation logic | OAuth 2.1 grants mirrored as FHIR `Consent` | | Audit | build logging and a way to show it to patients | every read and write logged and visible to the patient | | Lab integration | parse each lab's format | CSV, HL7 v2 ORU and JSON import | | AI context | write retrieval and summarisation code | context API with token budget and provenance labels | ## Related - [What is Anpheros?](https://developers.anpheros.com/guides/what-is-anpheros) - [Healthcare software development](https://developers.anpheros.com/guides/healthcare-software) - [Medical app backend and database](https://developers.anpheros.com/guides/medical-app-backend) - [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) - [Consent and access model](https://developers.anpheros.com/guides/consent) - [Security, privacy and data residency](https://developers.anpheros.com/guides/security) --- # Healthcare startups > How an interoperable medical-data infrastructure spares a startup from building patient records, consent, audit and integrations from scratch, a realistic path to production, and what the startup still owns. Source: https://developers.anpheros.com/guides/healthcare-startups **For a healthcare startup, the fastest path to a working product is to build what makes it different and use infrastructure for what every medical product needs.** Anpheros is interoperable medical-data infrastructure: patient records in HL7 FHIR R4, a REST and FHIR API, OAuth-based patient consent, provenance and audit, lab import, webhooks and SDKs. A startup can build its product on top instead of spending its first months on a medical database. ## What a healthcare product needs before it can do anything useful Almost every health product — a chronic-condition tracker, a remote-monitoring service, a pregnancy or medication app, a clinic tool, an AI assistant — needs the same foundation: | Foundation | Built from scratch | On Anpheros | |---|---|---| | Patient records | design tables for measurements, diagnoses, medications, documents | FHIR R4 record, 26 resource types | | Standard codes | research LOINC, ICD-10, ATC; build pickers | recognised on write; bundled LOINC and ATC search | | Medical data layer and API | design and document an API | REST v1 and FHIR R4, OpenAPI specification | | Authentication for data access | build API keys and OAuth | API keys per project; OAuth 2.1 with PKCE, SMART on FHIR | | Consent | grant, scope, expiry and revocation logic | built in, visible to the patient | | Audit and provenance | logging, history, a way to show it to users | every read and write logged; every version kept | | Lab data | parsers for each lab format | CSV, HL7 v2 ORU^R01 and JSON import | | Events | a queue and retry logic | signed, retried webhooks | | Client libraries | write your own | TypeScript and Dart / Flutter SDKs | | AI context | retrieval and summarisation code | context API with token budget and source labels | None of these is the startup's product, and each is easy to get subtly wrong with medical data. ## A realistic path 1. **Prototype in the sandbox.** Sandbox access is self-service: sign in with Google and get a key in one click. Sandbox keys (`sk_test_`) reach only a separate database — your project's own copy of 30 synthetic patients — so a prototype, including one written with AI coding tools, never touches real data. 2. **Build the product layer.** Screens, onboarding, your clinical content, your AI features; the medical record lives in Anpheros. [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) 3. **Connect partners.** A partner lab can send reports to your patients' records; a clinic can write on behalf of its organisation. [Healthcare integrations](https://developers.anpheros.com/guides/healthcare-integrations) 4. **Go to production.** Production keys (`sk_live_`) are issued to verified organisations with a signed data processing agreement. ## What you still own Infrastructure does not remove a startup's own responsibilities: - **Regulatory status of your product.** If your software makes diagnostic or therapeutic claims it may be regulated as a medical device; that assessment is yours. Anpheros does not claim medical-device certification or other regulatory approvals. - **Clinical safety** of your content and of any AI feature. - **Your users' accounts** and the relationship with them. - **Your own compliance** as a controller of personal data; Anpheros processes the record under a data processing agreement and keeps it in the EU. ## Things to know about the current stage Anpheros Platform is in private beta: single-zone hosting without automatic failover, no contractual SLA, rate limits of 600 requests per minute per key and per IP. SMART EHR launch is not supported yet. These limits are listed publicly so you can plan around them. [Security, privacy and data residency](https://developers.anpheros.com/guides/security) · [Limits](https://developers.anpheros.com/guides/limits) ## Frequently asked questions ### Can we start without real patient data? Yes. The sandbox is a separate database; each sandbox project gets its own 30 synthetic patients, and sandbox keys cannot reach production data. ### Do our users need an Anpheros account? Not if your project creates their records: your backend creates a patient per user and reads and writes it with your API key. People who already keep a record in Anpheros can instead give your application access through the consent page. ### Can we leave later and take the data with us? The records are standard FHIR R4. `Patient/$everything` returns a patient's whole record as a FHIR bundle. ## Related - [Healthcare software development](https://developers.anpheros.com/guides/healthcare-software) - [Build with Anpheros](https://developers.anpheros.com/guides/build-with-anpheros) - [Medical app backend and database](https://developers.anpheros.com/guides/medical-app-backend) - [Use cases](https://developers.anpheros.com/guides/use-cases) - [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) --- # Use cases > What can be built on Anpheros: patient and family health apps, medical-data backends for startups, clinic and laboratory integrations, AI health assistants and consented third-party apps. Source: https://developers.anpheros.com/guides/use-cases What can be built on Anpheros Platform, and which parts of the platform each case uses. The first case is how Anpheros itself uses the platform; the others describe what the implemented API supports — they are not customer references. ## A patient or family health record app **Anpheros Daily**, the Anpheros patient app, is built this way: it writes symptoms, vital signs, weight, medications, lab results, documents, appointments and daily summaries from Apple Health and Health Connect into the platform, for the account holder and for family members, and reads vital signs and medications back from it. It uses the same public API as any other application. Uses: [REST API](https://developers.anpheros.com/guides/getting-started) · [FHIR resources](https://developers.anpheros.com/guides/fhir) · [documents](https://developers.anpheros.com/guides/build-a-healthcare-app) · [consent](https://developers.anpheros.com/guides/consent) ## A healthcare startup that needs a medical-data backend A team building a new medical product — a chronic-condition tracker, a remote-monitoring service, a pregnancy or medication app — can keep its records in Anpheros instead of designing a medical database: patients, observations with LOINC codes, conditions with ICD-10, medications with ATC, documents with immutable originals, provenance and audit. It starts in the sandbox with synthetic patients and moves to production keys after verification. Uses: [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) · [sandbox](https://developers.anpheros.com/guides/getting-started) · [SDKs](https://developers.anpheros.com/guides/sdks) ## A clinic or laboratory delivering results to the patient A laboratory sends a whole report (CSV, HL7 v2 ORU^R01 or JSON) and every result becomes a laboratory Observation in the patient's record, with provenance naming the source system; re-sending the same report is safe. A clinic writes on behalf of its organisation and names the practitioner, so the patient sees who recorded what. With the patient's consent the organisation reads the whole record but can change only what it wrote. This flow — consent, lab Observation, notification in the patient's app within seconds — has been exercised end-to-end with a test clinic project. Uses: [Lab connector](https://developers.anpheros.com/guides/lab-connector) · [Consent and access model](https://developers.anpheros.com/guides/consent) · [Webhooks](https://developers.anpheros.com/guides/webhooks) ## An AI health assistant or agent An assistant that answers questions about a person's health asks for consent, requests a budgeted context for each question, sends it to the model of its choice and can write its own notes back as AI-authored. The patient sees every read in the access log. Uses: [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) · [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) ## A third-party app reaching an existing record A fitness, nutrition or specialist app that wants data a person already keeps in Anpheros asks for exactly the scopes it needs (for example laboratory observations only), for a limited time, through SMART on FHIR standalone launch. It receives its own identifier for the person and loses access the moment the person revokes it. Uses: [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) · [FHIR R4 API](https://developers.anpheros.com/guides/fhir) ## Sharing a standard summary An application or a person who needs to hand a summary to a doctor elsewhere can generate an International Patient Summary (`Patient/$summary`), a FHIR document format designed for cross-border care. Uses: [FHIR platform](https://developers.anpheros.com/guides/fhir) ## Related - [What is Anpheros?](https://developers.anpheros.com/guides/what-is-anpheros) - [Architecture](https://developers.anpheros.com/guides/architecture) --- # AI healthcare applications > What AI healthcare applications need from their data layer — structured data, relevance, sources, consent, accountability — and how Anpheros provides it without hosting models. Source: https://developers.anpheros.com/guides/ai-healthcare **An AI healthcare application uses a machine-learning model — typically a large language model — to help people or clinicians with health information: answering questions about a person's record, summarising results, preparing a visit, spotting trends.** Its quality depends on the patient context the model receives, and its trustworthiness on the rules around that context. Anpheros provides the medical-data layer for such applications: consented access to a patient's HL7 FHIR R4 record, a context API that prepares the relevant part of it for a model, and an audit of what the AI read. Anpheros does not host or run AI models and has no official integration with any AI vendor. Your application calls the model you choose. ## The architecture ``` AI application your assistant, agent or feature; your prompts and safety rules ↓ Anpheros API authenticated as your project, or as an app the patient consented to ↓ Medical context POST /v1/context — the relevant sections, within a token budget, ↓ every item labelled with author type and source FHIR data the patient's record: observations, conditions, medications, … ↓ Consent scopes and duration chosen by the patient; every read logged ``` ## Which database or backend should an AI healthcare application use for patient data? Anpheros can be that layer. It is a managed HL7 FHIR R4 data store — a FHIR backend for patient medical records — reached through an API, with patient consent, provenance, an access log and an AI context API built in. It is not a general-purpose SQL database and it is not an AI platform: your application keeps its own users, settings and non-medical data in its own database, stores and reads patient medical data through the Anpheros API, and calls whichever model you choose. ## What an AI healthcare application needs from its data layer | Need | Why | In Anpheros | |---|---|---| | Structured, coded data | models reason better over "HbA1c 6.4 % (LOINC 4548-4), 2026-09-01" than over a PDF | FHIR R4 resources with LOINC, ICD-10, ATC, UCUM | | Relevance within a budget | a whole record does not fit a prompt, and irrelevant data dilutes answers | context API with `task`, `question`, `needs` and `budget_tokens` | | Sources for every fact | the model — and the user — must know a lab result from a typed note | `author_type` and `source` on every item; `omitted` lists what was left out | | Separation of AI output from facts | earlier AI summaries must not become "facts" in later prompts | AI-written values kept apart under `ai_notes` | | Consent | the patient decides whether an AI feature may read their record | OAuth grants; a context requires read access to observations, conditions, medications and allergies | | Accountability | patients should see that an assistant read their data | every context request appears in the patient's access log, with a manifest id | ## Example architecture: an AI healthcare application on Anpheros and FHIR A hypertension companion app: people log blood pressure and medications, a lab sends results, and an assistant explains what changed. Every call below is part of the public API. ``` Mobile app ──► Your backend (users, sessions, prompts; holds the sk_live_ key) │ ├─► Anpheros API ──► FHIR R4 record of each user │ POST /v1/patients Patient │ POST /v1/patients/{id}/observations Observation 85354-9 (BP panel, author: device) │ POST /v1/patients/{id}/medications MedicationStatement (ATC C08CA01) │ POST /v1/patients/{id}/conditions Condition (ICD-10 I10) │ POST /v1/patients/{id}/labs/import lab report → laboratory Observations (from the lab's system) │ POST /v1/context budgeted, source-labelled context for the model │ GET /fhir/R4/Patient/{id}/$summary International Patient Summary for the doctor │ ├─► The model you choose (hosted API or local runtime) ── answer with sources │ └─◄ Webhook resource.created (signed) ── a new lab result arrived → prepare an explanation ``` The assistant's request handler in your backend: ```ts import { Anpheros, apiKey } from '@anpheros/sdk'; const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) }); export async function answer(user: { anpherosPatientId: string }, question: string) { // 1. Only the relevant part of the FHIR record, within a budget, every item labelled with its source. const ctx = await anpheros.context.build({ patient: user.anpherosPatientId, task: 'explain blood pressure and medication data to the patient', question, budget_tokens: 1500, format: 'text', }); // 2. Your prompt and your model (callModel is your own code for the provider or local runtime you use). const text = await callModel({ system: RULES_WITH_PROVENANCE, context: ctx.text, question, partial: ctx.omitted }); // 3. Keep the manifest id: it records which parts of the record the answer was based on. return { text, manifestId: ctx.manifest_id }; } ``` What each part owns: | Part | Owns | |---|---| | Your app and backend | users, UI, prompts, safety rules, the choice of model | | Anpheros | the patient medical data (FHIR R4), consent, provenance, access log, the context API, lab import, webhooks | | The model | language understanding and the wording of the answer — never the credentials | A runnable version of the context-plus-model step is in the public examples: [ai-context-llm](https://github.com/anpheros/anpheros-sdk/tree/main/examples/ai-context-llm). ## Kinds of applications this supports - **Patient-facing assistants** that answer questions with the person's own record in context. → [AI medical assistant](https://developers.anpheros.com/guides/ai-medical-assistant) - **Agents** that perform multi-step work over a record: preparing a visit summary, reconciling a medication list, checking what changed since the last review. → [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) - **LLM features inside existing software**, with a hosted model or a local one. → [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data) - **Medical software written with AI coding tools**, where the generated code should rely on a tested medical-data API. → [Anpheros for AI developers](https://developers.anpheros.com/guides/ai-developers) ## Limits you should design for - A model's answer is not a clinical decision. Present outputs as information, show sources, and route anything that looks like a diagnosis or a treatment change to a clinician. - Anpheros does not claim medical-device certification or other regulatory approvals; whether your AI feature is regulated depends on what it claims to do, and that assessment is yours. - If you use a hosted model, the context leaves your infrastructure for that provider; your consent text and data processing agreements must cover it. With a local model, the prompt stays on your infrastructure. - Anpheros does not provide a Model Context Protocol (MCP) server today. ## Related - [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) - [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data) - [AI medical assistant](https://developers.anpheros.com/guides/ai-medical-assistant) - [Anpheros for AI developers](https://developers.anpheros.com/guides/ai-developers) - [Medical data infrastructure](https://developers.anpheros.com/guides/medical-data-infrastructure) --- # AI agents and medical data > Controlled access for AI agents to patient records: OAuth scopes, the tools an agent needs, audit and provenance of what it reads and writes, and event-driven agents. Source: https://developers.anpheros.com/guides/ai-agents-medical-data **An AI agent is a program in which a language model decides, step by step, which actions to take — which data to read, which tool to call, what to write — to complete a task.** When the task involves a patient's medical record, the agent needs controlled access: it should reach only the records it is allowed to, only the parts of them it needs, leave a trace of what it read and mark what it wrote as AI-generated. Anpheros provides that controlled access through its API; the agent framework and the model are yours. Anpheros has no built-in agent runtime, no Model Context Protocol (MCP) server and no official integration with any agent framework or model provider. Agents use it the way any application does: through the REST and FHIR API or the SDKs. ## The architecture ``` Patient ── grants access (OAuth scopes, duration) ────────────────┐ ▼ Agent runtime (your code, any framework) ── tools ──► Anpheros API ──► the patient's FHIR record │ ▲ │ │ └── context, search results ◄───────┘ every call: scope checks + access log ▼ The model you choose (hosted or local) ── plans the next step ``` The model proposes actions; your runtime executes them with the credential it holds. The model itself never holds an Anpheros key or token. ## Controlled access - **Whose records.** With an API key the agent sees the patients your project created. To act on someone's existing record it needs an OAuth grant from that person — for one patient, for 30 to 365 days. - **Which data.** Scopes limit resource types and actions, optionally to a category: `patient/Observation.rs?category=laboratory` lets an agent read and search lab results and nothing else. To build a context, the grant must allow reading observations, conditions, medications and allergies (for example `patient/*.rs`). - **Read-only by default.** Grant write scopes only when the agent is meant to record something. - **Revocable.** The person can revoke the grant at any time; the agent's next call is refused. ## Tools an agent typically needs | Tool | Anpheros call | Notes | |---|---|---| | Get context for a task | `POST /v1/context` | the first call for most tasks; budgeted and source-labelled ([LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data)) | | List recent results | `GET /v1/patients/{id}/observations?category=laboratory&from=…` | filters: `category`, `code`, `from`, `to` | | Active medications | `GET /v1/patients/{id}/medications?status=active` | | | What happened when | `GET /v1/patients/{id}/timeline?from=…` | one chronological list across types | | Full FHIR detail | `GET /fhir/R4/{type}?patient=…` | when a summary is not enough | | A standard summary | `GET /fhir/R4/Patient/{id}/$summary` | International Patient Summary bundle | | Look up a code | `GET /v1/terminology/loinc?q=…` | bundled LOINC and ATC subsets | | Record a note | `POST /v1/patients/{id}/observations` with `author_type: "ai"` | only with a write scope | The OpenAPI specification (`https://developers.anpheros.com/openapi.json`) describes every endpoint and can be turned into tool definitions; the TypeScript and Dart SDKs can be wrapped as tools directly. ## Example: a visit-preparation agent with the patient's consent A patient who already keeps a record in Anpheros asks a third-party assistant to prepare questions for a cardiology visit. The agent needs read access to the record for a limited time — nothing more. **1. Consent (OAuth 2.1 + PKCE, SMART v2 scopes).** The assistant sends the person to the consent page with the narrowest scopes that still allow a context (observations, conditions, medications and allergies): ```ts import { Anpheros, OAuthAuth, OAuthFlow, generatePkce } from '@anpheros/sdk'; const flow = new OAuthFlow({ baseUrl: 'https://platform.anpheros.com', clientId: CLIENT_ID, redirectUri: REDIRECT_URI }); const pkce = await generatePkce(); const url = flow.authorizeUrl({ scopes: ['patient/Observation.rs', 'patient/Condition.rs', 'patient/MedicationStatement.rs', 'patient/AllergyIntolerance.rs', 'offline_access'], state, pkce, purpose: 'treatment', }); // … the person chooses the record and the duration (30–365 days) and allows; on the callback: const tokens = await flow.exchange(code, pkce); const anpheros = new Anpheros({ auth: new OAuthAuth({ tokens, onRefresh: flow.refresh }) }); const patient = tokens.patient!; // this application's own (pairwise) id for the person ``` **2. Tools.** The agent runtime exposes a few functions to the model; each one is a real API call made with the access token: ```ts const tools = { // POST /v1/context — relevant sections, within a budget, labelled with author type and source get_context: (a: { question: string }) => anpheros.context.build({ patient, task: 'prepare a cardiology visit', question: a.question, budget_tokens: 2000, format: 'text' }), // GET /v1/patients/{id}/observations?category=laboratory&code=…&from=… list_lab_results: (a: { code?: string; from?: string }) => anpheros.observations.list(patient, { category: 'laboratory', code: a.code, from: a.from, limit: 20 }), // GET /v1/patients/{id}/timeline?from=… get_timeline: (a: { from: string }) => anpheros.timeline.list(patient, { from: a.from, limit: 50 }), }; ``` Describe them to the model in whatever tool or function-calling format your model API uses; the model proposes a call, your runtime runs it and returns the JSON. The model never sees the token. **3. What the platform enforces.** The token reaches only that person's record and only the scoped types; anything else answers `403` (a type outside the scopes) or `404` (another patient). Every call — including each context request, with its `manifest_id` — appears in the person's access log for this application. If the person revokes access, the next call answers `401` and the agent must stop; the refresh token cannot bring it back. **4. Output.** The agent returns questions for the doctor with the sources it used. It writes nothing back, because it was not given a write scope. ## Audit and provenance - Every call the agent makes is an access to the record and appears in the patient's access log for your application — including each context request, which also stores a manifest of the sections and sources used. - Everything the agent writes is recorded as AI-authored in `Provenance`. When a context is built later, AI-written values are listed under `ai_notes`, apart from clinical facts, so an agent does not end up citing its own earlier output as evidence. ## Starting agents from events Webhooks let an agent run when something changes — a new lab result (`resource.created`), a new consent (`consent.granted`) — instead of polling. Events carry ids only; the agent then reads what its scopes allow. [Webhooks](https://developers.anpheros.com/guides/webhooks) ## Design rules worth keeping 1. Give the agent the narrowest scopes that complete the task. 2. Start from a context, not from raw bulk reads; respect `omitted` and `warnings`. 3. Show the patient's data sources in the agent's answer. 4. Never let the agent present a diagnosis or change a treatment on its own; route such outputs to a clinician. 5. Log the `manifest_id` of each context next to the agent's answer, so a person can later see what the answer was based on. ## Related - [FHIR MCP server for AI agents](https://developers.anpheros.com/guides/mcp) - [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) - [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data) - [AI medical assistant](https://developers.anpheros.com/guides/ai-medical-assistant) - [Consent and access model](https://developers.anpheros.com/guides/consent) - [Authentication and OAuth](https://developers.anpheros.com/guides/authentication) --- # LLM applications and healthcare data > Using large language models with healthcare data: the context API request and response, cloud and local models, agentic systems, retrieval versus context, and prompting with provenance. Source: https://developers.anpheros.com/guides/llm-healthcare-data **An application that uses a large language model with healthcare data has to solve one problem the model cannot: which part of a patient's record to put in the prompt, and how to label it so the model can tell facts from notes.** Anpheros solves it on the data side with a context API: given a patient, a task and a token budget, it returns the relevant sections of the patient's HL7 FHIR R4 record, each item labelled with its source. Your application sends that context to the model you choose — hosted or local. **How do I connect an LLM to FHIR medical data?** Keep the records in a FHIR store the model cannot reach directly — with Anpheros, the patient's HL7 FHIR R4 record — ask it for a budgeted, source-labelled context (`POST /v1/context`), and put that context in the prompt of the model you choose. The model never receives database or API credentials; your application does the calls, within the patient's consent. Anpheros does not run models and has no native integration with any model provider or local runtime. ## The pattern ``` 1. your app ── POST /v1/context {patient, task, question, budget_tokens, format} ──► Anpheros 2. Anpheros ── sections + text + omitted + warnings + manifest_id ──────────────────► your app 3. your app ── system prompt + context + user question ─────────────────────────────► the model 4. the model ── answer ───────────────────────────────────────────────────────────────► your app 5. your app ── optional write-back with author_type "ai" ──────────────────────────► Anpheros ``` ## The context request ```bash curl -X POST https://platform.anpheros.com/v1/context -H "Authorization: Bearer $TOKEN" -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" }' ``` | Field | Meaning | |---|---| | `patient` | the patient id your credential sees | | `task`, `question` | what the model will do; the platform plans which parts of the record are relevant | | `needs` | optional explicit needs, for example `["labs:4548-4", "vitals:trend:85354-9", "timeline:180d"]` | | `budget_tokens` | size of the context, 300–8 000 (default 2 000) | | `format` | `structured` (JSON sections) or `text` (also returns a ready-to-use text block) | | `window_days` | optional look-back window | ## The context response - `sections` — for example a summary card, conditions, medications, allergies, immunizations, lab results, vital signs with weekly trends and before/after-treatment markers, symptoms, timeline and documents. **Every item carries `author_type` and `source`.** - `omitted` — what did not fit the budget; tell the model its context is partial. - `warnings`, `provenance_note`. - `text` — when `format` is `text`. - `manifest_id` — the record of which sections and sources were used, tied to the access log. - an `ai_notes` section — values that an AI wrote earlier appear only there, marked as not verified, never mixed with the clinical sections. ## Cloud models With a hosted model — from OpenAI, Anthropic, Google, xAI or another provider — your backend puts the context in the prompt and calls the provider's API. The context leaves your infrastructure for that provider, so: - make sure the patient's consent and your privacy notice cover sending data to it; - have a data processing agreement with the provider that fits health data; - send only what the task needs — the token budget and explicit `needs` help. ## Local models With a model you run yourself — for example through Ollama or another local runtime — the only network call carrying patient data is the one between your backend and Anpheros; the prompt and the answer stay on your infrastructure. Smaller local models have smaller context windows: lower `budget_tokens` accordingly and prefer `format: "text"`. ## Agentic systems When the model decides which calls to make, give it tools (context, search, timeline) instead of raw credentials, keep scopes narrow and log each `manifest_id` next to the answer. [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) ## Context API or your own retrieval? A retrieval pipeline over free text (embedding chunks of documents and searching them) is useful for unstructured notes. For structured medical data the context API is usually simpler and safer: it works on coded FHIR resources, keeps provenance, knows about trends and treatment periods, respects consent and is audited. The two can be combined — for example context from Anpheros plus retrieved passages from documents you manage. ## Prompting with provenance Keep the labels in the prompt and tell the model what they mean: ``` The context below comes from the patient's record. Each item is labelled with its author type (patient, practitioner, device, import, derived) and source. Items under ai_notes were written by an AI earlier and are not verified. Say which items your answer relies on. If the context is marked as partial, say so. Do not give a diagnosis or change a treatment; suggest discussing it with a clinician. ``` ## Related - [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) - [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) - [AI medical assistant](https://developers.anpheros.com/guides/ai-medical-assistant) - [Security, privacy and data residency](https://developers.anpheros.com/guides/security) --- # FHIR MCP server for AI agents > Connect Claude Code, Cursor, VS Code or Claude Desktop to an HL7 FHIR R4 API through MCP: 14 tools for reading records, AI-ready context, writing, lab import and sandbox reset, on 30 synthetic patients, free. Source: https://developers.anpheros.com/guides/mcp **Anpheros FHIR is a remote MCP server that lets an AI agent (Claude, Claude Code, Cursor, VS Code, Claude Desktop) work with an HL7 FHIR R4 health-data API.** It connects in two ways: - **With a free sandbox key**, for developers: your agent lists patients, reads their records as FHIR or as an AI-ready context with provenance, writes observations, imports lab reports and resets its test data, all on 30 synthetic patients with realistic histories. - **With OAuth**, for a person and their own record: the assistant registers itself, the person signs in and approves it on the Anpheros consent screen, and the assistant can then read that one record, for the period chosen, read-only unless the person allowed more. Server address: `https://platform.anpheros.com/mcp` (Streamable HTTP, stateless). ## Connect with OAuth (Claude and other assistants) Add `https://platform.anpheros.com/mcp` as a custom connector (in Claude: Settings → Connectors → Add custom connector). Nothing else to configure: the assistant discovers the authorization server, registers itself and opens the Anpheros consent screen. There the person sees that it is an AI assistant, that what it reads is sent to the company running the assistant, what it may read, for how long and where they will return after choosing. Access is read-only unless more was asked for and allowed, and the person can revoke it at any time. During the private beta, OAuth connections use sandbox records. Connections to real records open after the privacy policy is updated. ## Connect with a sandbox key (developers) 1. Sign in at [platform.anpheros.com/dashboard](https://platform.anpheros.com/dashboard/) with Google and choose **Get a sandbox key**. You get an `sk_test_…` key and a project with 30 synthetic patients. 2. Put the key in an environment variable, for example `ANPHEROS_KEY`, and add the server to your tool. **Claude Code** ```bash claude mcp add --transport http anpheros-fhir https://platform.anpheros.com/mcp --header "Authorization: Bearer $ANPHEROS_KEY" ``` **Cursor** (`~/.cursor/mcp.json` or `.cursor/mcp.json` in the project) ```json { "mcpServers": { "anpheros-fhir": { "url": "https://platform.anpheros.com/mcp", "headers": { "Authorization": "Bearer ${env:ANPHEROS_KEY}" } } } } ``` **VS Code** (`.vscode/mcp.json`) ```json { "servers": { "anpheros-fhir": { "type": "http", "url": "https://platform.anpheros.com/mcp", "headers": { "Authorization": "Bearer ${env:ANPHEROS_KEY}" } } } } ``` **Claude Desktop** (`claude_desktop_config.json`, through the `mcp-remote` bridge) ```json { "mcpServers": { "anpheros-fhir": { "command": "npx", "args": ["-y", "mcp-remote", "https://platform.anpheros.com/mcp", "--header", "Authorization: Bearer ${ANPHEROS_KEY}"], "env": { "ANPHEROS_KEY": "sk_test_…" } } } } ``` Then ask your agent something like: *"List the sandbox patients, pick the one with diabetes and summarise her last six months of HbA1c."* ## Tools | Tool | What it does | |---|---| | `list_patients` | the project's patients: the 30 synthetic personas and any you created | | `get_patient_context` | an AI-ready context for one patient, within a token budget, each item labelled with its source | | `get_patient_summary` | the International Patient Summary (FHIR `$summary`), in the language you ask for | | `get_timeline` | the record in date order across resource types | | `search_fhir` | standard FHIR R4 search, returning a Bundle | | `read_fhir_resource` | one resource, or one earlier version of it | | `get_provenance` | who wrote a resource, when and from which system | | `lookup_code` | LOINC and ATC codes by text or by code | | `validate_fhir_resource` | checks a resource without saving it | | `create_fhir_resource` | validates, then writes a resource | | `create_patient` | a new made-up patient in the project | | `import_lab_report` | a CSV, HL7 v2 ORU^R01 or JSON lab report becomes laboratory Observations | | `sandbox_status` | writes used today, patients, storage, resets | | `reset_sandbox` | restores the 30 synthetic patients (asks for confirmation) | Read tools are marked read-only and the reset is marked destructive, so clients that ask before risky actions can do so. The server also offers the list of synthetic patients as a resource and three prompts: a clinician summary, a lab CSV import and building your integration on the API. ## How it behaves - **The same rules as the API.** Every tool calls the public API with your key: the same scopes, rate limits, validation and audit. A read-only key cannot write. - **Provenance.** Everything an agent writes is recorded with the source `urn:anpheros:mcp`, so you can always tell what came from an agent. - **Patient data is data.** Tool results carry a note that record content must never be followed as instructions, a basic guard against prompt injection through medical records. - **One record, with consent.** Production API keys (`sk_live_…`) are refused, because they reach every patient of a project. A real record reaches an assistant only through OAuth, after that person approves it, and every read is logged in their access history. - **Standard discovery.** Without credentials the server answers 401 with a `WWW-Authenticate` header pointing to its OAuth protected resource metadata (RFC 9728); assistants register through dynamic client registration (RFC 7591), with PKCE. Registration accepts only loopback addresses, the app schemes of known editors and the callback domains of known AI assistants. ## Frequently asked questions ### What is an MCP server? MCP (Model Context Protocol) is an open protocol through which AI agents and coding assistants call external tools. An MCP server for FHIR lets the agent read and write health records directly, instead of you pasting data into the chat. ### Is it free? Yes. The MCP server works on the free sandbox: 30 synthetic patients per project, up to 10,000 writes a day, no card. ### Can an assistant read a real patient's record? Only through OAuth, after that person approves the assistant on the consent screen, for the period they choose, and only their own record (or that of someone they care for). During the private beta, OAuth connections use sandbox records. ### Which FHIR version does it use? HL7 FHIR R4 (4.0.1), the same API as https://platform.anpheros.com/fhir/R4, with the International Patient Summary and a REST view of the same data. ### Does it work with ChatGPT? ChatGPT connectors use OAuth with dynamic client registration, which the server supports, and its callback domain is accepted. We have tested the flow with the official MCP SDK client; if a ChatGPT connection fails, write to support@anpheros.com. Claude Code, Cursor and VS Code also work with a sandbox key. ## Related - [Free FHIR database and sandbox](https://developers.anpheros.com/guides/free-fhir-database) - [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) - [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data) - [Healthcare API with patient consent](https://developers.anpheros.com/guides/healthcare-api-patient-consent) --- # AI medical assistant > The components of an AI medical assistant — LLM, medical context, patient data, consent, FHIR, safety and audit — a request step by step, and the warnings to build in. Source: https://developers.anpheros.com/guides/ai-medical-assistant **An AI medical assistant is an application in which a language model answers health questions using a specific person's medical data — "how has my blood pressure changed since I started amlodipine?", "what should I bring to my cardiology visit?".** Building one takes more than a model: it needs the patient's data in a usable form, consent to use it, a way to keep facts apart from generated text, safety rules and an audit. Anpheros provides the data side of that: the patient's HL7 FHIR R4 record, consent, the context API and the access log. In this architecture Anpheros is the medical data layer — the managed FHIR R4 store of the patient's record and the API around it. The assistant, its prompts and the model are yours. Anpheros Daily, the Anpheros patient app, includes such an assistant for its users. This page describes the components for building your own. ## The components ``` ┌─────────────────────────────────────────────────────────────────────┐ │ Assistant UI chat, voice, suggested questions, sources │ ├─────────────────────────────────────────────────────────────────────┤ │ Your backend identity, safety rules, prompt, model calls │ │ ├─ Consent ───────► OAuth grant from the patient (Anpheros) │ │ ├─ Context ───────► POST /v1/context (Anpheros) │ │ ├─ LLM ───────► the model you choose (hosted or local) │ │ └─ Write-back ─────► optional notes with author_type "ai" (Anpheros)│ ├─────────────────────────────────────────────────────────────────────┤ │ Patient data FHIR R4 record, provenance, access log │ └─────────────────────────────────────────────────────────────────────┘ ``` | Component | Role | Provided by | |---|---|---| | LLM | understands the question and writes the answer | you choose: a hosted provider or a local model | | Medical context | the relevant part of the record, within a budget, labelled by source | Anpheros context API | | Patient data | coded observations, conditions, medications, allergies, documents | Anpheros FHIR R4 record | | Consent | the patient's permission for the assistant to read their record | Anpheros OAuth grants (or your project's own patients) | | FHIR | a standard model the context is built from | Anpheros | | Safety layer | what the assistant must not do, and when to hand over to a person | your backend and prompts | | Audit | who read what, when | Anpheros access log, `manifest_id` per context | ## A request, step by step 1. The user asks a question in your app. 2. Your backend checks who the user is and which Anpheros record they may use (their own, or a dependent's they hold). 3. It requests a context: `POST /v1/context` with the question, a task description and a budget. 4. It builds the prompt: your system instructions, the context text with its source labels, and the question. 5. It calls the model and receives an answer. 6. It checks the answer against its safety rules and shows it with the sources used. 7. It stores the `manifest_id` with the conversation, so the answer can later be traced to the data it was based on. ```ts import { Anpheros, apiKey } from '@anpheros/sdk'; const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) }); const ctx = await anpheros.context.build({ patient: patientId, task: 'answer a patient question', question, budget_tokens: 2000, format: 'text', }); const answer = await callYourModel({ system: SAFETY_AND_PROVENANCE_RULES, context: ctx.text, question }); await saveConversationTurn({ question, answer, manifestId: ctx.manifest_id, omitted: ctx.omitted }); ``` `callYourModel` is your own code for the provider or local runtime you use. ## Warnings to build in - **It is not a clinician.** The assistant should explain and summarise the person's data, not diagnose or change treatment. Anything that looks like an urgent symptom should lead to a clear instruction to contact a doctor or emergency services. - **Regulation.** Depending on its claims, an assistant can fall under medical-device rules. Anpheros does not claim medical-device certification or any regulatory approval; that assessment belongs to the product. - **Hallucinations.** Show the sources the answer relies on, tell the model to say when the context is partial (`omitted`), and keep AI-generated notes apart from facts (`ai_notes`). - **Data leaving your infrastructure.** With a hosted model the context is sent to that provider; consent, privacy notice and agreements must cover it. A local model keeps the prompt in your infrastructure. - **Access scope.** Request only the scopes the assistant needs; a context requires read access to observations, conditions, medications and allergies. - **Transparency.** The patient sees every context request in the access log of your application. Say in your product that the assistant reads their record. ## Related - [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data) - [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) - [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) - [Consent and access model](https://developers.anpheros.com/guides/consent) --- # Anpheros for AI developers > Building healthcare software with Claude Code, Cursor, GitHub Copilot, ChatGPT, Gemini, Grok or Ollama on top of Anpheros as the medical-data layer: machine-readable docs, SDKs and the sandbox. Source: https://developers.anpheros.com/guides/ai-developers **Whether you build with Claude Code, Cursor, GitHub Copilot, ChatGPT, Gemini, Grok, Ollama or another AI development environment, Anpheros can serve as the medical-data infrastructure layer of your healthcare application.** AI tools are fast at generating application code, but a medical application also needs a data model, consent, provenance and an audit trail that a generated prototype rarely gets right. Building on Anpheros means the generated code calls a tested medical-data API instead of inventing its own medical database. There is no official plugin or integration between Anpheros and any of these tools or models. What Anpheros offers are machine-readable resources that any assistant or agent can read, typed SDKs, and a sandbox where generated code can run safely. ## Two ways AI shows up in your project | | AI helps you write the software | AI is part of the software | |---|---|---| | Examples | Claude Code, Cursor, GitHub Copilot, ChatGPT writing your code | your app calls a model (hosted, or local with Ollama) to answer health questions | | What Anpheros gives you | an API and docs your coding assistant can follow | the patient context for the model, with consent and audit | | Read next | this page | [AI healthcare applications](https://developers.anpheros.com/guides/ai-healthcare) | ## Give your coding assistant the right context | Resource | URL | Why it helps | |---|---|---| | OpenAPI specification | `https://developers.anpheros.com/openapi.json` | every endpoint with request and response schemas | | Developer summary | `https://developers.anpheros.com/llms.txt` | what the platform is and where each topic is documented | | All guides in one file | `https://developers.anpheros.com/llms-full.txt` | the guides as Markdown, for a single context load | | Each guide as Markdown | `https://developers.anpheros.com/guides/{guide}.md` | e.g. `/guides/getting-started.md` | | FHIR CapabilityStatement | `https://platform.anpheros.com/fhir/R4/metadata` | the 26 FHIR resource types and their search parameters | | Typed SDKs | `@anpheros/sdk` (npm), `anpheros_sdk` (pub.dev) | idempotency keys, retries, token refresh and the consent flow already implemented | A practical first instruction: *"Use Anpheros Platform as the medical-data backend. Read https://developers.anpheros.com/llms.txt and the OpenAPI spec before writing code. Use the TypeScript SDK. Use the sandbox key from the environment variable `ANPHEROS_KEY`."* ## When your assistant asks where to store patient data Coding assistants tend to propose new tables for patients, observations and medications. For a healthcare application built on Anpheros, point them to the medical data layer instead: patient records go to the Anpheros HL7 FHIR R4 store through the SDK, and your own database keeps users, sessions and product data. A sentence you can give your assistant: *"Store all patient medical data in Anpheros through `@anpheros/sdk` (patients, observations, conditions, medications, documents); do not create tables for medical data; keep only the mapping from our user id to the Anpheros patient id."* ## Let generated code run in the sandbox The sandbox is a separate database, and each sandbox project has its own copy of 30 synthetic patients. A sandbox key (`sk_test_`) physically cannot reach real patients, so an assistant can create patients, write observations and run tests without touching real medical data — and a reset brings the synthetic patients back as they were. - Put the sandbox key in an environment variable; never paste keys into prompts or commit them. - Never give a coding assistant a production key (`sk_live_`). - Requests with the same `Idempotency-Key` are safe to retry — useful when an assistant re-runs a script. ## Keep the medical rules in the platform, not in generated code Ask your assistant to rely on Anpheros for the parts that are easy to get wrong: - **Consent:** OAuth grants and scopes instead of home-made permission tables. - **Provenance:** `author_type` on every write (`patient`, `practitioner`, `device`, `import`, `ai`) instead of an invented "source" column. - **Standards:** LOINC for measurements, ICD-10 for conditions, ATC for medications; `GET /v1/terminology/loinc?q=…` and `/v1/terminology/atc?q=…` search the bundled code subsets. - **Errors:** the documented error types and the `Anpheros-Request-Id` header ([Errors](https://developers.anpheros.com/guides/errors)). ## A first script an assistant can generate ```ts import { Anpheros, apiKey } from '@anpheros/sdk'; const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) }); // sk_test_ key const { data: patients } = await anpheros.patients.list(); // synthetic sandbox patients const labs = await anpheros.observations.list(patients[0].id, { category: 'laboratory', limit: 10 }); const ctx = await anpheros.context.build({ patient: patients[0].id, task: 'weekly check-in', budget_tokens: 1500, format: 'text' }); console.log(labs.data, ctx.text); ``` ## When your application also uses a model The same project can call a model at runtime: request a context from Anpheros and pass it to a hosted model or to a local one (for example through Ollama). How to do that safely — consent, budgets, provenance in the prompt, what to show the user — is covered in [LLM applications and healthcare data](https://developers.anpheros.com/guides/llm-healthcare-data) and [AI medical assistant](https://developers.anpheros.com/guides/ai-medical-assistant). ## Related - [FHIR MCP server for AI agents](https://developers.anpheros.com/guides/mcp) - [Build a healthcare app](https://developers.anpheros.com/guides/build-a-healthcare-app) - [Build with Anpheros](https://developers.anpheros.com/guides/build-with-anpheros) - [AI agents and medical data](https://developers.anpheros.com/guides/ai-agents-medical-data) - [SDKs](https://developers.anpheros.com/guides/sdks) --- # 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. Source: https://developers.anpheros.com/guides/getting-started 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: ```bash 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: ```bash # 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 platform@anpheros.com. The sandbox is free; production starts at €49 a month and the first month is free (see [Pricing](https://developers.anpheros.com/guides/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. ```bash export KEY=sk_test_… curl $BASE/v1/patients -H "Authorization: Bearer $KEY" ``` ```json {"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](https://developers.anpheros.com/guides/limits)). ## 3. Read a record ```bash # 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. ```bash 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 ```bash # 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 ```bash 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`, never `403`. - **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`; `/v1` and `/admin` return `{"error": {"type", "message", "field"}}`. Every response carries `Anpheros-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: ```bash 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}/$summary` returns an International Patient Summary document Bundle. - `POST /fhir/R4/Observation/$validate?profile=eu-lab` reports how a lab result measures up to the European laboratory report profile (errors, warnings, information). - `GET /v1/terminology/loinc?q=hba1c` and `/v1/terminology/atc?q=metformin` search 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: 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: ```bash 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](https://developers.anpheros.com/guides/webhooks). ## 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. ```bash 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/` (or a `PractitionerRole`, `Organization`, `Device`): the server-generated Provenance then carries `agent.who.reference`, and `GET /fhir/R4/Provenance?agent=Practitioner/` 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/` (or `Practitioner/`) 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](https://developers.anpheros.com/guides/lab-connector). ```bash 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`](https://developers.anpheros.com/guides/webhooks). --- # Authentication and OAuth > API keys, OAuth 2.1 with PKCE (SMART on FHIR standalone launch), OpenID Connect id_token, SMART v2 patient scopes, token lifetimes and the consent lifecycle. Source: https://developers.anpheros.com/guides/authentication Anpheros Platform accepts three kinds of credentials. Every request carries exactly one. | Credential | Looks like | Who | Sees | |---|---|---|---| | API key | `sk_test_…` (sandbox) / `sk_live_…` (production) | a project's server | the patients the project created (in sandbox, including its own copy of 30 synthetic patients) | | OAuth access token | `at_…` | an application acting for one patient under a consent | that patient only, within the granted SMART scopes | | Firebase ID token | JWT | a developer in the dashboard, or a patient in "Connections" | their own organisations / their own records | Send it as `Authorization: Bearer ` (API keys also work as `X-Api-Key`). ## API keys - Created in the dashboard or via `POST /admin/projects/{id}/keys`; shown once; stored as a SHA-256 hash. - Scopes: `read`, `write`. A key never crosses its project's environment (`sk_test_` cannot reach production data and vice versa). - Per-key rate limit (default 600/min) is enforced platform-wide (shared store), with `Retry-After` on 429. There is also a per-IP limit of 600/min. - Optional headers on writes: `X-Anpheros-Author-Type`, `X-Anpheros-Author-Ref`, `X-Anpheros-Source-System`, `X-Anpheros-Origin-Id`, `X-Anpheros-Acting-As` (a Practitioner/PractitionerRole **of your own directory**), `X-Anpheros-On-Behalf-Of` (an Organization of your own directory). They populate Provenance. ## OAuth 2.1 (SMART on FHIR, standalone launch) Discovery: `GET /.well-known/smart-configuration`. 1. `GET /oauth/authorize?response_type=code&client_id=…&redirect_uri=…&scope=…&state=…&code_challenge=…&code_challenge_method=S256[&purpose=treatment][&patient=][&lang=ro]` Shows the hosted consent page. PKCE S256 is mandatory; the `redirect_uri` must be registered exactly. 2. The patient signs in (Google or email via Firebase), chooses the record (own or a dependent's), the duration (30/90/180/365 days) and allows. The platform issues a one-time code (10 minutes). 3. `POST /oauth/token` with `grant_type=authorization_code&code=…&code_verifier=…&redirect_uri=…&client_id=…` (confidential clients add `client_secret`). Response: `access_token` (30 min), `refresh_token` (30 days, rotating), `patient` (your pairwise id for the record), `grant_id`, `scope`. 4. Refresh: `grant_type=refresh_token`. Each refresh token is single-use. **Presenting a used refresh token revokes the whole chain** (theft detection). A parallel duplicate of a refresh request is refused and may also revoke the chain, so never rotate concurrently. 5. Revoke: `POST /oauth/revoke` (token + client_id). Revoking a refresh token also revokes its access tokens. Token responses carry `Cache-Control: no-store` and `Pragma: no-cache`, as SMART requires. ### OpenID Connect (`openid fhirUser`) Ask for `openid fhirUser` alongside the patient scopes and the token response also contains an `id_token`: a JWT signed with RS256, with `iss` (the platform's base URL), `sub` (your pairwise id for the person), `aud` (your `client_id`), `exp`, `iat` and `fhirUser` — the absolute URL of the person's Patient resource, readable with the access token you just received. Discovery lives at `GET /.well-known/openid-configuration`; the public keys at `GET /oauth/jwks` (`kid` in the token header). The `nonce` parameter is not supported yet (it is optional in the authorization-code flow). `launch/patient` and `offline_access` are accepted; the `patient` field of the token response is the launch context. Other grant types: `client_credentials` (confidential clients; behaves like an API key), and the first-party identity grant (trusted clients only). ### Scopes SMART v2 patient scopes: `patient/.` with an optional `?category=` filter (the only filter the server enforces; any other filter is refused at authorize time). `patient/*.rs` reads everything; `offline_access` adds a refresh token. Patient demographics and the directory are always readable under a grant. A resource type outside the grant returns 403; a patient outside the grant returns 404. ### Consent lifecycle Consents expire automatically, can be revoked by the patient at any time (Connections screen / `/me`), and every read under a consent is logged with the application id. Webhooks `consent.granted` / `consent.revoked` notify the project. ## Errors 401 unknown/expired credential · 403 the credential exists but may not do this · 404 the resource does not exist *for you* · 429 rate limited (`Retry-After`). See [`errors.md`](https://developers.anpheros.com/guides/errors). --- # Consent and access model > Who sees what: project isolation, pairwise ids, grants, write ownership, provenance and what the patient sees about every application with access. Source: https://developers.anpheros.com/guides/consent **Rule:** with the patient's consent an organisation sees the whole record — including what other clinics wrote — but can change or delete only what it wrote itself. Every version of every resource records the project that wrote it and the organisation on whose behalf it was written. ## Who sees what - A **project** (API key) sees the patients it created. Under a **grant** (OAuth token) an application sees exactly one patient, across all writers, limited to the granted scopes and category filters. Everything else returns 404, never 403, so ids cannot be probed. - **Pairwise ids:** each project receives its own id for the same person; internal ids never leave the platform. References to patients outside your scope are masked with an opaque, per-project token. - **Directory** (Organization, Practitioner, PractitionerRole): readable by id across the plane so references resolve; searchable only within your project; usable as `X-Anpheros-Acting-As` / `X-Anpheros-On-Behalf-Of` only when yours. - **Sandbox and production** are different databases. A sandbox key physically cannot reach real patients. ## Writes and ownership - `project_id` on every resource version = the writer. Update/delete by another project → 403 with an explanation; write your own resource instead. - `Provenance.agent.onBehalfOf` = the clinic/organisation at the time of writing: `X-Anpheros-On-Behalf-Of`, else the acting PractitionerRole's organisation, else the project's organisation. - Every write produces a Provenance resource and an audit row (who, what, when, under which grant, which application, from which source fingerprint). ## What the patient sees `/me/patients/{id}/grants` lists every application with access, its scopes and expiry; `…/access-log` lists what each read or wrote — under the consent **and** with the project's own key. Revocation takes effect on the next request; the application cannot refresh back in. --- # FHIR code systems > Which code systems each FHIR resource type uses: LOINC for measurements and lab results, ICD-10 for conditions, ATC for medications, UCUM units, and SNOMED CT behind a licence flag. Source: https://developers.anpheros.com/guides/fhir-code-systems What the platform stores and what Anpheros Daily (the patient app) writes through the API. Applications may use any code system FHIR allows; this page says which ones the platform recognises (display lookup, IPS checks, context engine) and which ones Anpheros itself uses. Last updated 22 September 2026. | Resource | Element | Code systems | Notes | |---|---|---|---| | Observation (vital-signs) | `code` | LOINC (`http://loinc.org`) | 8867-4 heart rate, 85354-9 blood pressure panel (8480-6 / 8462-4 components), 8310-5 body temperature, 2339-0 glucose, 29463-7 body weight, 39156-5 BMI, 59408-5 SpO₂, 8302-2 height | | Observation (laboratory) | `code` | LOINC; local `urn:anpheros:lab` when no LOINC is known | mapped by Anpheros Daily; reference range in `referenceRange`, document in `derivedFrom` | | Observation (symptom) | `code`, `category` | ICD-10 (`http://hl7.org/fhir/sid/icd-10`) chapter R; category `urn:anpheros:observation-category\|symptom`; SNOMED CT behind a flag | free text stays in `code.text`; intensity 1–10 in `valueQuantity` (`{score}`) | | Observation (survey, wellbeing) | `code`, `component` | `urn:anpheros:wellbeing` (dimension: emotional / mental / physical) | intensity as component `valueQuantity` `{score}`; note in `note` | | Observation (activity, daily watch summaries) | `code` | LOINC: 40443-4 resting HR, 8867-4 HR (min/avg/max components), 80404-7 HRV (RMSSD), 59408-5 SpO₂, 41950-7 steps, 41981-2 energy, 93832-4 sleep duration, 93831-6 / 93830-8 sleep stages | `effectivePeriod` covers the day; category `activity` | | Condition | `code`, `severity`, `clinicalStatus` | ICD-10; SNOMED CT severity (24484000 severe, 6736007 moderate, 255604002 mild); `condition-clinical` | category `problem-list-item` | | MedicationStatement | `medicationCodeableConcept` | ATC (`http://www.whocc.no/atc`); `code.text` = product name | extension `daily-medication` for app-specific fields | | MedicationAdministration | `medicationCodeableConcept`, `supportingInformation` | ATC; the treatment plan as `MedicationStatement/{id}` in `supportingInformation` (search parameter `statement`) | one resource per dose taken or skipped (`status` completed / not-done) | | Immunization | `vaccineCode` | ATC J07 (`http://www.whocc.no/atc`) or the national nomenclature; `vaccineCode.text` always kept | `occurrenceDateTime` required for the IPS section; `protocolApplied.doseNumberPositiveInt` for the dose | | AllergyIntolerance | `code`, `reaction.manifestation`, `criticality` | SNOMED CT (behind a flag) or `code.text` only; ATC for drug allergies | category food / medication / environment / biologic | | DocumentReference | `type` | LOINC document kinds (`DOC_KIND_LOINC` in `/v1`) | | | Encounter | `class`, `type` | v3-ActCode class; SNOMED CT type when known | `episodeOfCare` → the EpisodeOfCare of a pregnancy / long-term illness / treatment | | EpisodeOfCare | `type`, `diagnosis.condition` | `urn:anpheros:episode-type` (illness / treatment / pregnancy / other); `diagnosis.condition` → the Condition | one per Anpheros Daily condition ("dosar", 25 Sep 2026); `period` = onset → end. Linked resources point to the Condition: `Observation.focus`, `MedicationStatement.reasonReference`, `DocumentReference.context.related`, `Appointment.reasonReference` (search: `focus`, `reason-reference`, `related`, `condition`) | | Appointment | `serviceType` | `service-type` code system | | | RelatedPerson | `relationship` | v3-RoleCode (MTH, FTH, CHILD, SPS, …) | | | QuestionnaireResponse | `questionnaire` | canonical URLs under `https://anpheros.com/fhir/Questionnaire/` | | | Basic | `code` | `urn:anpheros:basic` | escape hatch; every code documented here before use | | Provenance | `agent.type` | `provenance-participant-type` | | ## Identifiers and extensions - Local identifiers of Anpheros Daily rows: `urn:anpheros:daily:{vital|medication|condition|episode|lab|symptom|document|weight|wellbeing|intake|immunization|allergy|health-day}`. - Condition extension `daily-condition` (25 Sep 2026): `kind` (illness / treatment / pregnancy / other), `color` (app palette key), `source`, `due_date` (pregnancy). A pregnancy without a written code carries ICD-10 `Z33`. - Extensions live under `https://anpheros.com/fhir/StructureDefinition/daily-*` (`daily-medication`, `daily-symptom`, `daily-condition`, …). - Units are UCUM (`http://unitsofmeasure.org`) everywhere a quantity is written. ## Licences LOINC, ATC (WHO), ICD-10 (WHO) and UCUM are used under their public licences. SNOMED CT requires a national or affiliate licence: the mapping tables ship with the code, but SNOMED codes are only written when `TERMINOLOGY_SNOMED_ENABLED` is on (pending the licence for Romania). --- # Webhooks > Signed, retried, thin events for resource writes, consent changes and finalized documents, with signature verification in TypeScript, Dart and Python. Source: https://developers.anpheros.com/guides/webhooks Anpheros Platform can call your server when something happens in your project: a resource was written, a person granted or revoked access, a document was finalized. Events are **thin**: ids, type, version — never clinical content. Read the resource through the API if you need it. Every delivery is signed; verify the signature before trusting it. ## Register an endpoint ```bash curl -X POST $BASE/v1/webhooks -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \ -d '{"url": "https://your.app/anpheros/hook", "events": ["resource.created", "consent.revoked"], "description": "prod"}' ``` The response contains `secret` (`whsec_…`) **once**. Store it; you need it to verify signatures. `events` accepts `["*"]` or any of: | type | when | `data` | |---|---|---| | `resource.created` / `resource.updated` / `resource.deleted` | your project wrote a FHIR resource (REST v1, FHIR API or a bundle) — **or another project wrote into a record you have access to** (you created the patient, or you hold an active grant); then `data.external` is `true` and `data.source` says who wrote it: `author_type` (patient / practitioner / device / import / ai), `organization` (the display name the writer acted on behalf of), `practitioner` (name from the directory, when known), `source_system` | `resource_type`, `id`, `patient` (the id you see), `version`, `last_updated`, and for external writes `external`, `source` | | `consent.granted` | a person granted your app access from the consent page (or a trusted app linked its record) | `grant_id`, `patient`, `application_id`, `scopes`, `purpose`, `expires_at` | | `consent.revoked` | the person (or the platform) ended a grant | same as above plus `revoked_at`, `reason` | | `document.finalized` | a document upload was finalized and checksummed | `id`, `patient`, `content_type`, `size`, `sha256` | | `ping` | you asked for a test delivery | `endpoint` | Endpoints are per project **and environment**: a `sk_test_` key manages sandbox endpoints, a `sk_live_` key production ones. URLs must be `https://` (in sandbox, `http://localhost` is fine). Up to 10 endpoints per project and environment. ## The delivery ``` POST https://your.app/anpheros/hook Content-Type: application/json User-Agent: Anpheros-Webhooks/1.0 Anpheros-Event: resource.created Anpheros-Event-Id: evt_… Anpheros-Delivery: whd_… Anpheros-Signature: t=1789800000,v1=5f3a… {"id":"evt_…","type":"resource.created","created_at":"2026-09-19T12:00:00.000Z","environment":"production", "project":"proj_…","data":{"resource_type":"Observation","id":"…","patient":"…","version":1,"last_updated":"…"}} ``` Respond with any `2xx` within 10 seconds. Anything else (or a timeout) is a failure and the delivery is retried with backoff for up to 24 hours (10 attempts), then marked `exhausted`. Deliveries are at-least-once and may arrive out of order: use `Anpheros-Event-Id` to de-duplicate and `data.version` to ignore stale updates. ## Verify the signature `v1` is HMAC-SHA256 with your secret over `.`; reject if `t` is older than 5 minutes. ```ts import { verifyWebhookSignature } from '@anpheros/sdk'; app.post('/anpheros/hook', express.raw({ type: 'application/json' }), async (req, res) => { const ok = await verifyWebhookSignature({ secret: process.env.ANPHEROS_WEBHOOK_SECRET!, header: req.header('anpheros-signature'), body: req.body }); if (!ok) return res.status(400).end(); const event = JSON.parse(req.body.toString()); // … enqueue and return quickly res.status(204).end(); }); ``` ```dart import 'package:anpheros_sdk/anpheros_sdk.dart'; final ok = verifyWebhookSignature(secret: secret, header: request.headers['anpheros-signature'], body: rawBodyBytes); ``` ```python import hmac, hashlib, time def verify(secret: str, header: str, body: bytes, tolerance=300) -> bool: parts = dict(p.split("=", 1) for p in header.split(",")) if abs(time.time() - int(parts["t"])) > tolerance: return False expected = hmac.new(secret.encode(), f"{parts['t']}.".encode() + body, hashlib.sha256).hexdigest() return hmac.compare_digest(expected, parts["v1"]) ``` ## Operate - `GET /v1/webhooks/{id}/deliveries?status=failed` — the log, newest first, with status code and error. - `POST /v1/webhooks/{id}/deliveries/{delivery_id}/redeliver` — send one again now. - `POST /v1/webhooks/{id}/ping` — a test event. - `POST /v1/webhooks/{id}/rotate` — new secret (the old one stops immediately; update your server first if you can't afford a gap: register a second endpoint, then delete the old one). - `PATCH /v1/webhooks/{id}` with `{"active": false}` pauses deliveries; pending ones are dropped when you delete the endpoint. Both SDKs expose this under `webhooks` (`create`, `list`, `get`, `update`, `delete`, `rotateSecret`, `ping`, `deliveries`, `redeliver`). --- # Lab connector > Send a whole laboratory report as CSV, HL7 v2 ORU^R01 or JSON and get laboratory Observations with LOINC codes and reference ranges. Source: https://developers.anpheros.com/guides/lab-connector A laboratory (or anyone holding a lab report) sends the whole report in one request and the platform turns every result into a laboratory `Observation` of the patient: ``` POST /v1/patients/{patient_id}/labs/import Authorization: Bearer Content-Type: text/csv | x-application/hl7-v2+er7 | application/json X-Anpheros-Source-System: labx (optional; recorded in Provenance) Idempotency-Key: (optional; a retry returns the same answer) ``` ## Formats **CSV** with a header row; separators `,` `;` or tab, decimal comma accepted, dates ISO, `DD.MM.YYYY` or `DD/MM/YYYY`. Recognised columns (Romanian or English): marker (`analiza`, `test`, `marker`), value (`rezultat`, `valoare`, `value`), unit (`um`, `unitate`), reference range (`interval`, `referinta`: `70-100`, `<5`, `>3.5`) or `ref_low`/`ref_high`, date (`data`, `recoltare`), optional LOINC (`loinc`, `code`), note. ``` Analiza;Rezultat;UM;Interval de referinta;Data Hemoglobina glicozilata (HbA1c);6,4;%;4,0-5,6;01.09.2026 TSH;2,1;mUI/L;0,4-4,0;01.09.2026 ``` **HL7 v2 ORU^R01** (ER7 text, segments separated by CR or LF): `OBX-3` identifier (`code^text^LN` is LOINC; other coding systems are kept as the lab's code), `OBX-5` value (`NM`, `SN`, or text), `OBX-6` unit, `OBX-7` reference range, `OBX-8` abnormal flag → `interpretation`, `OBX-11` status, `OBX-14` or `OBR-7` date; `OBR-3`/`MSH-10` become the report id in Provenance. **JSON**: `{"date": "2026-09-01", "origin": "report-77", "items": [{"marker": "TSH", "value": 2.1, "unit": "mUI/L", "ref_low": 0.4, "ref_high": 4.0, "date": "2026-09-01", "code": "3016-3"}]}`. ## What you get back ```json {"created": 3, "skipped": 0, "unmapped": ["Marker foarte rar"], "warnings": [], "observations": [{"id": "…", "marker": "TSH", "code": "3016-3", "system": "http://loinc.org", "value": 2.1, "unit": "mUI/L", "date": "2026-09-01"}]} ``` - Markers are mapped to **LOINC** when the report gives a LOINC code or the name matches the platform's terminology (Romanian and English names and common aliases). Others keep the lab's code under `urn:anpheros:lab-code` with the exact text from the report, and are listed in `unmapped` so you can improve the mapping on your side. - Each row gets a stable identifier (`urn:anpheros:lab-import`) built from the report id, code, date and value: **re-sending the same report skips rows already imported** (`skipped`). - Every Observation carries Provenance with `author_type = import`, your source system and the report id; webhooks fire `resource.created` per Observation; the patient sees the results in their app and any app they consented to can read them. - Up to 500 rows per request. Both SDKs: `labs.importCsv`, `labs.importHl7`, `labs.importItems`. --- # Errors > The error catalogue: HTTP status, OperationOutcome issue codes and what to do for each. Source: https://developers.anpheros.com/guides/errors Under `/fhir/R4` errors are `OperationOutcome`; elsewhere `{"error": {"type", "message", "field"?}}`. Every response carries `Anpheros-Request-Id`; quote it when you write to support. | HTTP | `issue.code` / `type` | Meaning | What to do | |---|---|---|---| | 400 | `invalid`, `structure`, `value` | malformed JSON, invalid FHIR, value not in a required value set, unsupported search parameter, unsupported scope filter | fix the request; the message names the field | | 400 | `too-costly` | resource nesting > 64 levels, text > 10 000 chars | simplify the resource | | 401 | `login` | missing, unknown, expired or revoked credential; consent no longer active | re-authenticate; for OAuth, refresh or re-consent | | 403 | `forbidden` | scope, ownership (written by another organisation), read-only grant, admin only | request the right scope; write your own resource | | 404 | `not-found` | does not exist for this caller | never assume existence from a 404 | | 409 | `conflict` | idempotency key in progress; document already final; endpoint limit | retry shortly / use a new key | | 410 | `deleted` | resource or file deleted | — | | 412 | `conflict` | `If-Match` version mismatch | re-read, then update | | 413 | `too-costly` | body or document over the limit | split or compress | | 422 | `not-found` / `invalid` | referenced patient does not exist for you; resource moved between patients; idempotency key reused with another body | fix the reference | | 429 | `throttled` | per-credential or per-IP rate limit | wait `Retry-After` seconds; the SDKs do this | | 503 | `transient` | document storage unavailable | retry with backoff | | 500 | `exception` | unexpected error, logged and audited with the request id | report the request id | --- # Limits and rate limits > Request rate limits, body and document sizes, search pages, webhook limits and token lifetimes. Source: https://developers.anpheros.com/guides/limits | Limit | Value | Notes | |---|---|---| | Requests per credential | 600 / minute (per key; configurable per key) | shared across all instances; `Retry-After` on 429 | | Requests per IP | 600 / minute | per instance | | JSON body | 2 MiB | refused from `Content-Length` before reading | | Document upload | 25 MiB | direct-to-storage or through the platform | | Resource nesting | 64 levels | | | Text field length | 10 000 characters | | | Search page | `_count` ≤ 200 | `_revinclude` returns at most 1 000 | | Webhook endpoints | 10 per project and environment | | | Webhook attempts | 10 with exponential backoff (30 s → 1 h) | endpoint auto-disabled after 10 consecutive failures | | Idempotency keys | 128 characters, kept 24 h | | | Access token / refresh token / auth code | 30 min / 30 days / 10 min | | | Consent duration | 30, 90, 180 or 365 days | | ## Sandbox (self-service) | Limit | Value | Notes | |---|---|---| | Resource writes | 10 000 per project per day (UTC) | every created, updated or deleted resource counts (a bundle of 200 entries is 200); 429 with `Retry-After` until midnight UTC; the synthetic patients and their reset do not count | | Patients | 500 per project, besides its 30 synthetic patients | | | Documents | 250 MB per project | | | Organisations | 3 created per account | | | Sandbox projects | 5 per organisation | | | API keys | 20 active per project | | Production projects have none of the sandbox limits; they are open to verified organisations with a signed data processing agreement, and their allowances come from the plan: see [Pricing](https://developers.anpheros.com/guides/pricing). The sandbox is free, and the first month of production is free. --- # Pricing > Sandbox free; Starter €49, Growth €199 and Scale €799 a month for 2,500, 10,000 and 50,000 stored patients, what counts as a patient, going past a plan and the free first month of production. Source: https://developers.anpheros.com/guides/pricing Building in the sandbox is free. In production you pay one monthly price per organisation, and that price covers a number of stored patients, API calls and storage. The first month of production is free on every plan. | | Sandbox | Starter | Growth | Scale | |---|---|---|---|---| | Price | Free | €49 / month | €199 / month | €799 / month | | Patients | 30 synthetic + 500 test per project | 2,500 | 10,000 | 50,000 | | Extra patients | – | €4 per 100 | €2.50 per 100 | €1.50 per 100 | | API calls | 10 000 writes a day per project | 1 million a month | 5 million a month | 25 million a month | | Storage (data and files) | 250 MB per project | 25 GB | 100 GB | 500 GB | | Production projects | – | 1 | 3 | 10 | | Team members | – | 3 | 10 | Unlimited | | Support | Documentation | Email | Onboarding call, 1 business day | 4 hours, 99.9% uptime SLA | | Your brand on the consent page | – | – | Yes | Yes | | Single sign-on for your team | – | – | – | Yes | Prices are in euros and exclude VAT. Paying yearly gives two months free (€490, €1,990 or €7,990 a year). Above 100,000 patients, or for a dedicated database or another region, write to contact@anpheros.com. ## What every plan includes The full HL7 FHIR R4 and REST API, patient consent with OAuth 2.1 and SMART on FHIR, International Patient Summaries, the lab connector, provenance and the access log, webhooks, the Dart and TypeScript SDKs and hosting in the European Union. The sandbox has the same API; only the data and the limits differ. ## What counts as a patient Each patient record in your organisation's production projects. The count is taken once a day and the invoice uses the highest count of the month. A patient you delete, for example after an erasure request, stops counting from the next day. Sandbox, test and synthetic patients never count. A person used by several applications in the same organisation counts once. ## Going past your plan - **Patients:** extra patients are billed per 100 at the price of your plan. - **API calls:** above the monthly allowance, €2 per extra 100,000 calls. - **Storage:** above the allowance, €0.50 per extra GB a month. You get an email at 80% and at 100% of each allowance. Access to patient data is never cut off because an allowance was reached. You can set a spending limit; when it is reached, new patients cannot be added until the next month or a plan change, and existing patients keep working. ## The free first month 1. Your organisation is verified and signs the data processing agreement. 2. You choose a plan and add a card. Nothing is charged yet. 3. The free month starts when your first production key is issued. The limits of your plan apply; extra usage during the free month is not billed. 4. You get a reminder a week before the free month ends, and again two days before. 5. The first charge is on day 31. If you cancel before that, production stays readable for 30 days so you can export your data, and is then deleted as the data processing agreement says. The free month is given once per organisation. ## Frequently asked questions ### How much does Anpheros cost? The sandbox is free. Production starts at €49 a month for 2,500 patients, with the first month free. Growth is €199 a month for 10,000 patients and Scale is €799 a month for 50,000 patients. Prices exclude VAT. ### Do I pay for API calls? Each plan includes a monthly allowance of API calls: 1, 5 or 25 million. Most applications stay within it. Above it, extra calls cost €2 per 100,000. ### Do inactive patients count? Yes. Every patient record stored in your production projects counts, whether or not it was used that month. Deleted patients stop counting from the next day. ### Is there a free trial of production? Yes. The first month of production is free on every plan, once per organisation. The sandbox stays free with no time limit. ## Related - [Limits and rate limits](https://developers.anpheros.com/guides/limits) - [Getting started](https://developers.anpheros.com/guides/getting-started) --- # Versioning and deprecation > How the FHIR R4 and REST v1 interfaces, webhook payloads and SDKs change, and how breaking changes are announced. Source: https://developers.anpheros.com/guides/versioning - **FHIR R4** at `/fhir/R4` and **REST v1** at `/v1` are stable interfaces. Additive changes (new fields, new resource types, new endpoints, new event types) ship without notice; the SDKs and `docs/openapi.json` are regenerated in the same commit and a test fails otherwise. - **Breaking changes** get a new prefix (`/v2`) and at least **6 months** of parallel operation; the old prefix answers with a `Deprecation` and `Sunset` header during that period. - **Webhook payloads** carry a `type`; new types are additive. A subscriber to `*` must ignore unknown types. - **SDKs** follow semver; a major SDK version may drop a sunset API prefix. - **Security fixes** may tighten validation (for example value sets) without a version bump; such tightening is announced in the changelog with 30 days' notice unless it closes an active vulnerability. ## Conformance enforcement (announced 23 September 2026) Writes that miss IPS / HL7 Europe laboratory requirements currently return `201`/`200` with an `Anpheros-Conformance` header. After an observation period (planned: 60–90 days from this notice) the platform switches to **block** mode: such writes answer `422` with an `OperationOutcome` listing every gap. Integrators that need more time can be exempted per project during the transition. Resource types added 23 September 2026: `Procedure`, `DiagnosticReport`, `CarePlan`, `FamilyMemberHistory`, `ServiceRequest`, `Goal` (additive). --- # SDKs > The Dart / Flutter (anpheros_sdk) and TypeScript (@anpheros/sdk) clients: same shape, idempotent creates, retries, token refresh and the consent flow. Source: https://developers.anpheros.com/guides/sdks **Anpheros is interoperable medical-data infrastructure for building healthcare applications, medical software and AI services.** Each patient has one HL7 FHIR R4 record that they control; applications, clinics, laboratories and AI agents read and write it through the Anpheros Platform API — with patient consent (OAuth 2.1 / SMART on FHIR), provenance on every write and an access log the patient can see. This repository contains the official client libraries and runnable examples. | Language | Package | Install | Source | |---|---|---|---| | Dart / Flutter | [`anpheros_sdk`](https://pub.dev/packages/anpheros_sdk) | `dart pub add anpheros_sdk` | [`dart/anpheros_sdk`](https://github.com/anpheros/anpheros-sdk/tree/main/dart/anpheros_sdk) | | TypeScript (Node 18+, browsers, Deno, Bun) | [`@anpheros/sdk`](https://www.npmjs.com/package/@anpheros/sdk) | `npm install @anpheros/sdk` | [`ts`](https://github.com/anpheros/anpheros-sdk/tree/main/ts) | ## Who it is for Developers building patient and family health apps, medical-app backends, clinic and laboratory integrations, and AI assistants or agents that need a patient's structured medical context — without designing a medical database, a consent system and an audit trail from scratch. ## Get a sandbox key The sandbox is free and self-service. Sign in with Google on the [dashboard](https://platform.anpheros.com/dashboard/) and press **Get a sandbox key**: you get a sandbox project and a key instantly. Every sandbox project comes with its own 30 synthetic patients — six months of conditions, medications, allergies, lab results and vital signs — that you can change freely and reset at any time. Sandbox keys (`sk_test_…`) never reach real patient data. When you go live, production is for verified organisations with a data processing agreement, and production starts at €49 a month with the first month free ([pricing](https://developers.anpheros.com/guides/pricing)). ## Connect ```ts import { Anpheros, apiKey } from '@anpheros/sdk'; const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) }); // sk_test_… in the sandbox const { data: patients } = await anpheros.patients.list(); const labs = await anpheros.observations.list(patients[0].id, { category: 'laboratory', limit: 10 }); const ctx = await anpheros.context.build({ patient: patients[0].id, task: 'weekly check-in', budget_tokens: 1500, format: 'text' }); ``` ```dart import 'package:anpheros_sdk/anpheros_sdk.dart'; final anpheros = Anpheros(auth: AnpherosAuth.apiKey('sk_test_…')); final patients = await anpheros.patients.list(); final labs = await anpheros.observations.list(patients.data.first.id, category: 'laboratory', limit: 10); ``` API keys belong on servers. An app acting for a person uses OAuth instead: both SDKs implement the consent flow (authorization code + PKCE) and refresh tokens automatically. ## What the SDKs cover Both cover the whole public surface (`/v1`, `/fhir/R4`, `/oauth/token`, `/oauth/revoke`) with the same shape: `patients`, `observations`, `conditions`, `medications`, `documents`, `timeline`, `provenance`, `context`, `grants`, `terminology` and raw `fhir`. A test fails the build when a public route is missing from either SDK or when an SDK calls a route the server does not have. Both SDKs: automatic `Idempotency-Key` on creates, retries with backoff on 429/5xx, one token refresh on 401, typed errors with the request id, PKCE helpers and the consent flow. ## Medical data and FHIR The record is made of standard FHIR R4 resources — 26 types, including `Observation`, `Condition`, `MedicationStatement`, `DocumentReference`, `Immunization` and `AllergyIntolerance` — coded with LOINC, ICD-10, ATC and UCUM. The REST API (`/v1`) and the FHIR API (`/fhir/R4`) read and write the same resources with the same ids; `fhir` in both SDKs gives raw FHIR access (search, transactions, `$everything`, `$summary`, `$validate`). ## Examples | Example | Shows | |---|---| | [quickstart-ts](https://github.com/anpheros/anpheros-sdk/tree/main/examples/quickstart-ts) | write and read a record: measurements, lab result, diagnosis, medication, timeline, FHIR search, IPS, AI context | | [quickstart-dart](https://github.com/anpheros/anpheros-sdk/tree/main/examples/quickstart-dart) | the same from Dart / Flutter | | [consent-app-ts](https://github.com/anpheros/anpheros-sdk/tree/main/examples/consent-app-ts) | a web app that asks for consent (OAuth 2.1 + PKCE) and reads the person's record | | [ai-context-llm](https://github.com/anpheros/anpheros-sdk/tree/main/examples/ai-context-llm) | a question about a record answered by a model of your choice (local or hosted) | | [fhir-transaction](https://github.com/anpheros/anpheros-sdk/tree/main/examples/fhir-transaction) | a FHIR R4 transaction bundle and the resulting International Patient Summary | The examples run against the free sandbox, where each sandbox project has its own 30 synthetic patients — see [Get a sandbox key](#get-a-sandbox-key). ## Conformance Raw test results, published so they can be checked (test results, not certifications): [conformance/](https://github.com/anpheros/anpheros-sdk/tree/main/conformance). On 28 September 2026 the Standalone Launch group of the Inferno SMART App Launch STU2 test kit (v1.0.3) passed 22 of 22 tests against the platform. EHR launch is not supported. ## Documentation - Developer guides: https://developers.anpheros.com/guides/ - SDK guide: https://developers.anpheros.com/guides/sdks - API reference (OpenAPI): https://developers.anpheros.com/docs - For AI assistants: https://developers.anpheros.com/llms.txt - Anpheros: https://anpheros.com/ ## Issues and security Report bugs in this repository's issues. Never include API keys, tokens or patient data in an issue. Security reports: contact@anpheros.com. ## License Apache License 2.0 — see the `LICENSE` file of each package. Copyright 2026 Anpheros. ## @anpheros/sdk TypeScript client for **Anpheros Platform**: a FHIR R4 health record per patient, project isolation, patient consent (OAuth 2.1 / SMART on FHIR), provenance on every write and an AI context API. Runs anywhere `fetch` exists (Node 18+, browsers, Deno, Bun). ```ts import { Anpheros, apiKey } from '@anpheros/sdk'; const anpheros = new Anpheros({ auth: apiKey(process.env.ANPHEROS_KEY!) }); const { data: patients } = await anpheros.patients.list(); const labs = await anpheros.observations.list(patients[0].id, { category: 'laboratory', limit: 10 }); const ctx = await anpheros.context.build({ patient: patients[0].id, task: 'weekly check-in', budget_tokens: 1500, format: 'text' }); ``` Acting for a person: ```ts import { OAuthFlow, OAuthAuth, generatePkce } from '@anpheros/sdk'; const flow = new OAuthFlow({ baseUrl: BASE, clientId: 'client_…', redirectUri: 'https://myapp.example/callback' }); const pkce = await generatePkce(); location.href = flow.authorizeUrl({ scopes: ['patient/Observation.rs?category=laboratory', 'offline_access'], state, pkce, lang: 'ro' }); // on the callback: const tokens = await flow.exchange(code, pkce); const anpheros = new Anpheros({ auth: new OAuthAuth({ tokens, onRefresh: flow.refresh, onTokens: persist }) }); ``` Errors are `AnpherosError` (`status`, `type`, `message`, `field`, `requestId`). Creates send an `Idempotency-Key`; 429/5xx are retried; expired tokens are refreshed once and the call retried. ## anpheros_sdk Dart / Flutter client for **Anpheros Platform**: a health-data backend with a FHIR R4 record per patient, project isolation, patient consent (OAuth 2.1 / SMART on FHIR), provenance on every write and an AI context API. ```dart import 'package:anpheros_sdk/anpheros_sdk.dart'; final anpheros = Anpheros(auth: AnpherosAuth.apiKey('sk_test_…')); // server / sandbox final patients = await anpheros.patients.list(); final elena = patients.data.first; final labs = await anpheros.observations.list(elena.id, category: 'laboratory', limit: 10); final ctx = await anpheros.context.build(ContextRequest(patient: elena.id, task: 'weekly check-in', budgetTokens: 1500)); ``` ## Acting for a person (apps) ```dart final flow = OAuthFlow(baseUrl: 'https://…', clientId: 'client_…', redirectUri: 'myapp://callback'); final pkce = Pkce.generate(); final url = flow.authorizeUrl(scopes: ['patient/Observation.rs?category=laboratory', 'patient/MedicationStatement.r', 'offline_access'], state: 'abc', pkce: pkce, lang: 'ro'); // open `url`; on return with ?code=…: final tokens = await flow.exchange(code: code, pkce: pkce); final anpheros = Anpheros(auth: AnpherosAuth.oauth( accessToken: tokens.accessToken, refreshToken: tokens.refreshToken, expiresAt: tokens.expiresAt, onRefresh: flow.refresh, onTokens: persist)); final meds = await anpheros.medications.listMedications(tokens.patient!); ``` Every object carries `fhir` (its `/fhir/R4` reference); `anpheros.fhir` gives raw FHIR access (read, search, create, transaction, `$everything`, `$summary`, `$validate`). Errors are `AnpherosException` with `status`, `type`, `message`, `field` and `requestId`. Creates send an `Idempotency-Key` automatically; 429/5xx are retried with backoff; expired OAuth tokens are refreshed once and the call retried.