Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
Webhooks
Podpisane, ponawiane, cienkie zdarzenia dla zapisów zasobów, zmian zgody i finalizowanych dokumentów, z weryfikacją podpisu w TypeScript, Dart i Python.
Platforma Anpheros może wywołać Twój serwer, gdy coś wydarzy się w Twoim projekcie: zasób został zapisany, osoba udzieliła lub cofnęła dostęp, dokument został zatwierdzony. Zdarzenia są szczupłe: identyfikatory, typ, wersja — nigdy treść kliniczna. Odczytaj zasób przez API, jeśli go potrzebujesz. Każda dostawa jest podpisana; zweryfikuj podpis przed zaufaniem.
Zarejestruj punkt końcowy
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"}'
Odpowiedź zawiera secret (whsec_…) raz. Zapisz ją; będzie potrzebna do weryfikacji podpisów.
events akceptuje ["*"] lub dowolny z poniższych:
| typ | kiedy | data |
|---|---|---|
resource.created / resource.updated / resource.deleted |
Twój projekt zapisał zasób FHIR (REST v1, FHIR API lub pakiet) — lub inny projekt zapisał dane do rekordu, do którego masz dostęp (stworzyłeś pacjenta lub posiadasz aktywną zgodę); wtedy data.external to true, a data.source mówi, kto to zapisał: author_type (pacjent / praktyk / urządzenie / import / AI), organization (nazwa wyświetlana, w imieniu której działał autor), practitioner (nazwa z katalogu, jeśli znana), source_system |
resource_type, id, patient (identyfikator, który widzisz), version, last_updated, a dla zapisów zewnętrznych external, source |
consent.granted |
osoba udzieliła Twojej aplikacji dostępu ze strony zgody (lub zaufana aplikacja powiązała swój rekord) | grant_id, patient, application_id, scopes, purpose, expires_at |
consent.revoked |
osoba (lub platforma) zakończyła udzielanie zgody | tak samo jak powyżej plus revoked_at, reason |
document.finalized |
przesłanie dokumentu zostało zakończone i zweryfikowane sumą kontrolną | id, patient, content_type, size, sha256 |
proposal.created |
agent AI zaproponował zapis do rekordu, który możesz zobaczyć; oczekuje na zatwierdzenie przez osobę | id, patient, action, resource_type |
ping |
poprosiłeś o testowe dostarczenie | endpoint |
Punkty końcowe są per projekt i środowisko: klucz sk_test_ zarządza punktami końcowymi piaskownicy,
klucz sk_live_ produkcyjnymi. Adresy URL muszą być publicznymi punktami końcowymi https://. Rejestracja (i wszelkie późniejsze zmiany url) odrzuca adresy lokalne, prywatne, link-local, metadane i inne zarezerwowane adresy — localhost, 127.0.0.1, ::1, 10.0.0.0/8, 192.168.0.0/16, fd00::/8 i podobne — oraz nazwy, które się do nich rozwiązują, z 400 invalid w polu url; dotyczy to również piaskownicy. Każde dostarczenie ponownie sprawdza adres i łączy się tylko z adresami IP, które właśnie sprawdziło, więc nazwa, która później wskazuje na sieć prywatną (DNS rebinding), niczego nie otrzyma. Aby odbierać zdarzenia na własnej maszynie podczas tworzenia, udostępnij ją poprzez publiczny tunel HTTPS i zarejestruj adres tunelu.
Do 10 punktów końcowych na projekt i środowisko.
Dostarczenie
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":"…"}}
Odpowiadaj z wszelkimi 2xx w ciągu 10 sekund. Cokolwiek innego (lub przekroczenie limitu czasu) jest błędem, a dostarczenie jest ponawiane z wykładniczym wycofywaniem przez maksymalnie 24 godziny (10 prób), a następnie oznaczane jako exhausted.
Dostarczenia są co najmniej raz (at-least-once) i mogą przybywać w nieuporządkowanej kolejności: użyj Anpheros-Event-Id do
de-duplikacji i data.version do ignorowania nieaktualnych aktualizacji.
Weryfikacja podpisu
v1 to HMAC-SHA256 z Twoim kluczem tajnym na <t>.<raw body>; odrzuć, jeśli t jest starszy niż 5 minut.
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"])
Operacje
GET /v1/webhooks/{id}/deliveries?status=failed— log, najnowsze najpierw, z kodem statusu i błędem.POST /v1/webhooks/{id}/deliveries/{delivery_id}/redeliver— wyślij ponownie teraz.POST /v1/webhooks/{id}/ping— zdarzenie testowe.POST /v1/webhooks/{id}/rotate— nowy sekret (stary przestaje działać natychmiast; zaktualizuj swój serwer, jeśli nie możesz sobie pozwolić na przerwę: zarejestruj drugi punkt końcowy, a następnie usuń stary).PATCH /v1/webhooks/{id}z{"active": false}wstrzymuje dostarczanie; oczekujące elementy są usuwane po usunięciu punktu końcowego.
Oba SDK udostępniają to w ramach webhooks (create, list, get, update, delete, rotateSecret, ping, deliveries, redeliver).
Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card