Try it free in the sandbox · first FHIR call in 5 minutesFree · 30 synthetic patients · no card
Webhooks
Eventos assinados, com novas tentativas, finos para escritas de recursos, alterações de consentimento e documentos finalizados, com verificação de assinatura em TypeScript, Dart e Python.
A Plataforma Anpheros pode chamar o seu servidor quando algo acontece no seu projeto: um recurso foi escrito, uma pessoa concedeu ou revogou acesso, um documento foi finalizado. Os eventos são reduzidos: IDs, tipo, versão — nunca conteúdo clínico. Leia o recurso através da API se precisar dele. Cada entrega é assinada; verifique a assinatura antes de confiar nela.
Registar um 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"}'
A resposta contém secret (whsec_…) uma vez. Armazene-o; necessita dele para verificar assinaturas.
events aceita ["*"] ou qualquer um dos seguintes:
| tipo | quando | data |
|---|---|---|
resource.created / resource.updated / resource.deleted |
o seu projeto escreveu um recurso FHIR (REST v1, FHIR API ou um bundle) — ou outro projeto escreveu num registo ao qual tem acesso (criou o paciente, ou detém uma concessão ativa); então data.external é true e data.source indica quem escreveu: author_type (paciente / praticante / dispositivo / importação / ai), organization (o nome de exibição em nome do qual o escritor agiu), practitioner (nome do diretório, quando conhecido), source_system |
resource_type, id, patient (o id que vê), version, last_updated, e para escritas externas external, source |
consent.granted |
uma pessoa concedeu à sua aplicação acesso a partir da página de consentimento (ou uma aplicação confiável ligou o seu registo) | grant_id, patient, application_id, scopes, purpose, expires_at |
consent.revoked |
a pessoa (ou a plataforma) terminou uma concessão | o mesmo que acima mais revoked_at, reason |
document.finalized |
o upload de um documento foi finalizado e o seu checksum verificado | id, patient, content_type, size, sha256 |
proposal.created |
um agente de IA propôs uma escrita num registo que pode ver; aguarda a aprovação da pessoa | id, patient, action, resource_type |
ping |
solicitou uma entrega de teste | endpoint |
Os endpoints são por projeto e ambiente: uma chave sk_test_ gere os endpoints sandbox,
uma chave sk_live_ os de produção. Os URLs devem ser endpoints públicos https://. O registo (e qualquer alteração posterior de url) recusa endereços locais, privados, link-local, de metadados e outros endereços reservados — localhost, 127.0.0.1, ::1, 10.0.0.0/8, 192.168.0.0/16, fd00::/8 e similares — e nomes que se resolvam a eles, com 400 invalid no campo url; isto aplica-se também na sandbox. Cada entrega verifica novamente o endereço e conecta-se apenas aos endereços IP que acabou de verificar, pelo que um nome que mais tarde aponte para uma rede privada (rebind DNS) não recebe nada. Para receber eventos na sua própria máquina durante o desenvolvimento, exponha-a através de um túnel HTTPS público e registe o endereço do túnel.
Até 10 endpoints por projeto e ambiente.
A entrega
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":"…"}}
Responda com qualquer 2xx em 10 segundos. Qualquer outra coisa (ou um timeout) é uma falha e a
entrega é retentada com backoff por até 24 horas (10 tentativas), depois marcada como exhausted.
As entregas são "at-least-once" e podem chegar fora de ordem: use Anpheros-Event-Id para
desduplicar e data.version para ignorar atualizações desatualizadas.
Verificar a assinatura
v1 é HMAC-SHA256 com o seu segredo sobre <t>.<raw body>; rejeitar se t for mais antigo que 5 minutos.
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"])
Operar
GET /v1/webhooks/{id}/deliveries?status=failed— o registo, mais recente primeiro, com código de estado e erro.POST /v1/webhooks/{id}/deliveries/{delivery_id}/redeliver— enviar um novamente agora.POST /v1/webhooks/{id}/ping— um evento de teste.POST /v1/webhooks/{id}/rotate— novo segredo (o antigo para imediatamente; atualize o seu servidor primeiro se não puder suportar uma interrupção: registe um segundo endpoint, depois elimine o antigo).PATCH /v1/webhooks/{id}com{"active": false}pausa as entregas; as pendentes são descartadas quando elimina o endpoint.
Ambos os SDKs expõem isto em 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