AnpherosAnpheros PlatformDevelopers

Webhooks

Signed, retried, thin events for resource writes, consent changes and finalized documents, with signature verification in TypeScript, Dart and Python.

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

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 <t>.<raw body>; reject if t is older than 5 minutes.

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();
});
import 'package:anpheros_sdk/anpheros_sdk.dart';
final ok = verifyWebhookSignature(secret: secret, header: request.headers['anpheros-signature'], body: rawBodyBytes);
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

Both SDKs expose this under webhooks (create, list, get, update, delete, rotateSecret, ping, deliveries, redeliver).