Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
Вебхуки
Подписанные, повторяемые, краткие события для записи ресурсов, изменений согласия и завершенных документов с проверкой подписи на TypeScript, Dart и Python.
Платформа Anpheros может вызывать ваш сервер, когда что-то происходит в вашем проекте: ресурс был записан, человек предоставил или отозвал доступ, документ был финализирован. События компактные: идентификаторы, тип, версия — никогда клиническое содержимое. Читайте ресурс через API, если он вам нужен. Каждая доставка подписана; проверьте подпись, прежде чем доверять ей.
Регистрация конечной точки
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"}'
Ответ содержит secret (whsec_…) один раз. Сохраните его; он вам понадобится для проверки подписей.
events принимает ["*"] или любой из следующих вариантов:
| тип | когда | data |
|---|---|---|
resource.created / resource.updated / resource.deleted |
ваш проект записал ресурс FHIR (REST v1, FHIR API или пакет) — или другой проект записал в запись, к которой у вас есть доступ (вы создали пациента или у вас есть активное разрешение); тогда data.external равно true, а data.source указывает, кто записал: author_type (пациент / практикующий врач / устройство / импорт / ИИ), organization (отображаемое имя, от имени которого действовал автор), practitioner (имя из каталога, если известно), source_system |
resource_type, id, patient (идентификатор, который вы видите), version, last_updated, а для внешних записей external, source |
consent.granted |
человек предоставил вашему приложению доступ со страницы согласия (или связанная доверенная запись приложения) | grant_id, patient, application_id, scopes, purpose, expires_at |
consent.revoked |
человек (или платформа) отозвал разрешение | то же, что и выше, плюс revoked_at, reason |
document.finalized |
загрузка документа была завершена и проверена по контрольной сумме | id, patient, content_type, size, sha256 |
proposal.created |
агент ИИ предложил запись в запись, которую вы можете видеть; ожидается одобрение человека | id, patient, action, resource_type |
ping |
вы запросили тестовую доставку | endpoint |
Конечные точки зависят от проекта и среды: ключ sk_test_ управляет конечными точками песочницы,
ключ sk_live_ — производственными. URL-адреса должны быть общедоступными конечными точками https://. Регистрация (и любое последующее изменение url) отклоняет локальные, частные, link-local, метаданные и другие зарезервированные адреса — localhost, 127.0.0.1, ::1, 10.0.0.0/8, 192.168.0.0/16, fd00::/8 и тому подобное — а также имена, которые разрешаются в них, с 400 invalid в поле url; это применимо и в песочнице. Каждая доставка повторно проверяет адрес и подключается только к только что проверенным IP-адресам, поэтому имя, которое позже указывает на частную сеть (DNS rebinding), ничего не получит. Чтобы получать события на своей машине во время разработки, выведите ее через общедоступный HTTPS-туннель и зарегистрируйте адрес туннеля.
До 10 конечных точек на проект и среду.
Доставка
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":"…"}}
Отвечайте любым 2xx в течение 10 секунд. Все остальное (или тайм-аут) считается сбоем, и доставка
повторяется с экспоненциальной задержкой до 24 часов (10 попыток), после чего помечается как exhausted.
Доставки осуществляются как минимум один раз и могут поступать не по порядку: используйте Anpheros-Event-Id для
дедупликации и data.version для игнорирования устаревших обновлений.
Проверка подписи
v1 — это HMAC-SHA256 с вашим секретным ключом поверх <t>.<raw body>; отклоните запрос, если t старше 5 минут.
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"])
Эксплуатация
GET /v1/webhooks/{id}/deliveries?status=failed— журнал, от новых к старым, с кодом состояния и ошибкой.POST /v1/webhooks/{id}/deliveries/{delivery_id}/redeliver— отправить еще раз сейчас.POST /v1/webhooks/{id}/ping— тестовое событие.POST /v1/webhooks/{id}/rotate— новый секрет (старый немедленно перестанет действовать; обновите ваш сервер заранее, если не можете позволить себе перерыв: зарегистрируйте второй конечный пункт, затем удалите старый).PATCH /v1/webhooks/{id}с{"active": false}приостанавливает доставку; ожидающие будут отброшены при удалении конечного пункта.
Оба SDK предоставляют это под 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