Webhooks
Subscribe to versioned event types and receive them at your callback URL. Every delivery is signed with an HMAC over the raw body, carried in the X-MedFlo-Signature header, so you can verify authenticity and integrity.
Webhook management requires the webhooks.manage scope, and subscriptions are org-scoped under /api/v1/ofctx/{org_id}/webhooks.
Manage subscriptions in the portal
Event types
| Event type | Fires when |
|---|---|
resident.admitted | A resident is admitted to a facility. |
resident.discharged | A resident is discharged. |
resident.transferred | A resident is transferred between facilities. |
coverage.updated | A resident's payer coverage changes. |
clinical.condition.created | A new diagnosis is recorded. |
clinical.order.created | A new order (e.g. medication) is created. |
Discover the current list at any time: GET /api/v1/ofctx/{org_id}/webhooks/event-types.
Endpoints
| Method | Path | Description |
|---|---|---|
| POST | /…/webhooks | Register a subscription. The signing secret is returned once. |
| GET | /…/webhooks | List your org's subscriptions (secret never re-shown). |
| DELETE | /…/webhooks/{id} | Revoke a subscription. |
| POST | /…/webhooks/{id}/test | Emit a signed test event and get back the exact bytes + signature to validate your verifier. |
Subscribe
Register a callback_url and one or more event_types. The response includes a signing_secret — this is the only time it's returned, so store it immediately.
# Register a signed webhook subscription. The signing_secret is returned ONCE.
TOKEN="eyJ..." # a token issued with the webhooks.manage scope
curl -s -X POST \
'https://medflo-pcc-vendor-api-eez5kqwsxa-uw.a.run.app/api/v1/ofctx/sandbox-org-0001/webhooks' \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"callback_url": "https://example.com/hooks/medflo",
"event_types": ["resident.admitted", "coverage.updated"],
"description": "prod ingest"
}'
# → { "data": { "id": "...", "signing_secret": "whsec_...", <-- store this now
# "signature_header": "X-MedFlo-Signature", "status": "active", ... } }Verify the signature
On each delivery, compute an HMAC-SHA256 of the exact raw request body using your subscription's signing_secret, then compare it (constant-time) against the X-MedFlo-Signature header. Reject the delivery if they don't match.
Use the raw bytes
// Verify an inbound webhook (Node).
import crypto from "node:crypto";
function verifyMedFloSignature(rawBody, signatureHeader, signingSecret) {
// rawBody must be the EXACT bytes MedFlo POSTed (do not re-serialize).
const expected = crypto
.createHmac("sha256", signingSecret)
.update(rawBody)
.digest("hex");
// Constant-time compare to avoid timing leaks.
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
// In your handler, read the RAW body (not the parsed JSON):
// const ok = verifyMedFloSignature(rawBody, req.headers["x-medflo-signature"], SIGNING_SECRET);
// if (!ok) return res.status(401).end();Test your verifier
Call the /test endpoint to have MedFlo build a signed delivery and return the exact body, the signature, and the signature_header name. Run your verifier against those bytes to confirm it accepts a valid signature and rejects a tampered one — before wiring up production traffic.
Payload shape
Deliveries carry a versioned envelope with api_version, the event_type, and a minimal data body. Payloads carry the minimum necessary and never include unnecessary PHI. See Versioning for how event payloads evolve.