API reference
Webhook events
What NezerCare sends to your endpoints.
Events NezerCare sends to your endpoints. Add an endpoint in Workforce → Integrations; its signing secret is shown once.
Verify x-nezer-signature against the raw request bytes before parsing JSON. Compute the lowercase hexadecimal HMAC-SHA256 of <x-nezer-timestamp>.<raw-body> using the endpoint signing secret and compare it to the value after v1= using a constant-time comparison. Reject stale timestamps and deduplicate by x-nezer-event-id.
Workflow calls to your own systems (Destinations) are signed too, with the environment's widget signing secret: x-nezer-signature is the HMAC-SHA256 of <x-nezer-timestamp>.<METHOD> <path and query>\n<raw body>. order_lookup.requested below is the order lookup contract an "Order status and tracking" workflow holds your order system to.
The event catalog includes the clinical-case lifecycle plus billing.usage_threshold_reached and subscription.updated. billing.usage_threshold_reached is sent once each as use, in every environment, reaches 80%, 95% and 100% of the month's credits, with threshold, creditsUsed, monthlyCredits, remaining and paused. Subscription updates report lifecycle states such as active, grace_period, restricted, and canceled; grace expiry uses reason PAYMENT_GRACE_PERIOD_EXPIRED, and a paid invoice that follows a failed payment carries recovered: true (a first or ordinary monthly charge doesn't). Event bodies may contain protected health information and must not be written to ordinary logs.
Until the organization signs its BAA, clinical-case events are held (not dropped, and no attempt is used) and go out once it's signed. billing.usage_threshold_reached and subscription.updated are about your account and carry no patient data, so they're never held for the BAA.
order_lookup.requested
POSTto your endpoint
Sent by an active "Order status and tracking" workflow when a signed-in patient asks where their order is (English or Spanish), to your connection's address + the step's path (POST /orders/lookup in the template). Never sent for an anonymous visitor, a health question or an emergency, and never contains what the patient typed. One attempt; NezerCare waits up to 5 seconds (less if the connection says so). Answer 200 with an orders array, empty when there are none. Anything else (another status, no answer in time, or an answer that breaks the contract) makes the workflow say it couldn't check and offer the team; nothing is guessed.
Verify x-nezer-signature with the environment's widget signing secret: the lowercase hex HMAC-SHA256 of <x-nezer-timestamp>.<METHOD> <path and query>\n<raw body>, compared after v1= in constant time. Reject timestamps more than 5 minutes old.
Signed by NezerCare. Check x-nezer-signature before you trust the body: Verify webhooks.
Headers
| Field | Type | Description |
|---|---|---|
x-nezer-timestampRequired | header · string | Unix seconds.Matches ^[0-9]+$. |
x-nezer-signatureRequired | header · string | v1=<hex HMAC-SHA256 of timestamp + '.' + METHOD + ' ' + path and query + '\n' + raw body>, keyed with the widget signing secret.Matches ^v1=[a-f0-9]{64}$. |
Payload
| Field | Type | Description |
|---|---|---|
versionRequired | integer | One of 1. |
typeRequired | string | One of order_lookup.requested. |
requestIdRequired | string | The workflow run's id; the same for every call in one run. |
patientRequired | object | |
patient.Required | string | Example: test-patient-1. |
{
"version": 1,
"type": "order_lookup.requested",
"requestId": "0f2c9a4e-3d7b-4c1e-9a55-000000000000",
"patient": {
"externalId": "test-patient-1"
}
}Your response
| Status | Meaning |
|---|---|
200 | The patient's orders (latest first, or with placedAt on each). At most three are shown. |
200 body
| Field | Type | Description |
|---|---|---|
ordersRequired | array of objects | Up to 50 items. |
orders[].Required | string | Your order number, as the patient knows it. A string (not a number).1–64 characters. |
orders[].Required | string | One of processing, shipped, delivered, delayed, cancelled. |
orders[]. | string or null | Shown instead of the widget's own word for the status, as written.Up to 80 characters. |
orders[]. | string or null | Up to 60 characters. |
orders[]. | string or null | Shown as a Track package link only when it's https (and has no user name or password); otherwise dropped.Up to 2000 characters. |
orders[]. | string or null | YYYY-MM-DD, or an ISO 8601 date-time with a time zone. |
orders[]. | string or null | YYYY-MM-DD or ISO 8601. When every order has it, the widget sorts latest first; otherwise it keeps your order. |
orders[]. | array of objects or null | Up to 20 items. |
orders[].Required | string | 1–120 characters. |
orders[].Required | integer | 1 to 999. |
{
"orders": [
{
"id": "TEST-1003",
"status": "shipped",
"statusLabel": "On its way",
"carrier": "UPS",
"trackingUrl": "https://www.ups.com/track?tracknum=1Z0000000000000000",
"estimatedDelivery": "2026-10-02",
"placedAt": "2026-09-25T15:04:00Z",
"items": [
{
"name": "Test Product A",
"quantity": 1
}
]
},
{
"id": "TEST-1001",
"status": "delivered",
"carrier": "USPS",
"placedAt": "2026-08-28T12:00:00Z"
}
]
}{
"orders": []
}clinical_case.opened
POSTto your endpoint
Return 2xx after durable receipt. Verify the raw-body signature and deduplicate by x-nezer-event-id before creating or associating a provider workflow.
Signed by NezerCare. Check x-nezer-signature before you trust the body: Verify webhooks.
Headers
| Field | Type | Description |
|---|---|---|
x-nezer-event-idRequired | header · string (uuid) | |
x-nezer-event-typeRequired | header · string | |
x-nezer-timestampRequired | header · string | |
x-nezer-signatureRequired | header · string | v1=<hex HMAC-SHA256 of timestamp + '.' + raw request body>Matches ^v1=[a-f0-9]{64}$. |
idempotency-keyRequired | header · string (uuid) |
Payload
| Field | Type | Description |
|---|---|---|
idRequired | string (uuid) | |
typeRequired | string | Always clinical_case.opened. |
createdAtRequired | string (date-time) | |
dataRequired | object | |
data.Required | string (uuid) | |
data.Required | string (uuid) | |
data.Required | string | routine when the only red flags asked for a routine follow-up (for example, a medicine that isn't working). A staff_slack case is urgent, or emergency when the teammate's request used NezerCare's emergency words.One of emergency, urgent, routine. |
data. | string | Where the case came from: a check-in the patient answered, a concern the patient raised in the widget, or staff_slack, a clinical request a teammate made of @Nezer in your Slack channel. A staff_slack case is raised by staff, not reported by the patient: patientNotes is empty, symptomScores is {}, and the teammate's words stay in NezerCare as an internal note on the case.One of check_in, patient_concern, staff_slack. |
data. | string or null | What the patient wrote. Empty for a staff_slack case. |
data. | object | The answers, by question key. When stoppedEarly is true, only the questions answered before the check-in stopped are here; the rest were skipped, not answered 0. |
data. | array of strings | Every red flag that matched, not only the worst: score:<tier>:<question key>>=<n> (or <=<n> on a scale where higher is better), phrase:<phrase> and semantic_phrase:<phrase> for the protocol's emergency phrases, and emergency_terms:<kind> for NezerCare's own emergency words in the patient's note (or, for a staff_slack case, in the teammate's request), and staff_request:slack on every case raised from Slack. |
data. | boolean | True when an answer called for 911: the check-in stopped at emergency guidance and sent what had been answered at once. |
data.Required | object | |
data. | string | |
data. | string | |
data. | string |
Your response
| Status | Meaning |
|---|---|
200 | Durably received. |
clinical_case.patient_message_created
POSTto your endpoint
Contains patient-authored clinical content. Verify, deduplicate, and route it without placing the body in ordinary application logs.
Signed by NezerCare. Check x-nezer-signature before you trust the body: Verify webhooks.
Headers
| Field | Type | Description |
|---|---|---|
x-nezer-event-idRequired | header · string (uuid) | |
x-nezer-event-typeRequired | header · string | |
x-nezer-timestampRequired | header · string | |
x-nezer-signatureRequired | header · string | v1=<hex HMAC-SHA256 of timestamp + '.' + raw request body>Matches ^v1=[a-f0-9]{64}$. |
idempotency-keyRequired | header · string (uuid) |
Payload
| Field | Type | Description |
|---|---|---|
idRequired | string (uuid) | |
typeRequired | string | Always clinical_case.patient_message_created. |
createdAtRequired | string (date-time) | |
dataRequired | object | |
data.Required | string (uuid) | |
data.Required | string (uuid) | |
data.Required | string (uuid) | |
data. | string | Always patient. |
data.Required | string | |
data.Required | string (date-time) | |
data. | string |
Your response
| Status | Meaning |
|---|---|
200 | Durably received. |
clinical_case.acknowledged
POSTto your endpoint
Sent when your team acknowledges a case in NezerCare. It isn't the same as your processed case update.
Signed by NezerCare. Check x-nezer-signature before you trust the body: Verify webhooks.
Headers
| Field | Type | Description |
|---|---|---|
x-nezer-event-idRequired | header · string (uuid) | |
x-nezer-event-typeRequired | header · string | |
x-nezer-timestampRequired | header · string | |
x-nezer-signatureRequired | header · string | v1=<hex HMAC-SHA256 of timestamp + '.' + raw request body>Matches ^v1=[a-f0-9]{64}$. |
idempotency-keyRequired | header · string (uuid) |
Payload
| Field | Type | Description |
|---|---|---|
idRequired | string (uuid) | |
typeRequired | string | One of clinical_case.acknowledged, clinical_case.resolved. |
createdAtRequired | string (date-time) | |
dataRequired | object | |
data.Required | string (uuid) | |
data.Required | string (uuid) | |
data.Required | string | |
data. | string or null | |
data. | string or null |
Your response
| Status | Meaning |
|---|---|
200 | Durably received. |
clinical_case.resolved
POSTto your endpoint
Emitted when a case reaches its final resolved state. A late delivery can describe a case your integration has already processed; deduplicate by event ID.
Signed by NezerCare. Check x-nezer-signature before you trust the body: Verify webhooks.
Headers
| Field | Type | Description |
|---|---|---|
x-nezer-event-idRequired | header · string (uuid) | |
x-nezer-event-typeRequired | header · string | |
x-nezer-timestampRequired | header · string | |
x-nezer-signatureRequired | header · string | v1=<hex HMAC-SHA256 of timestamp + '.' + raw request body>Matches ^v1=[a-f0-9]{64}$. |
idempotency-keyRequired | header · string (uuid) |
Payload
| Field | Type | Description |
|---|---|---|
idRequired | string (uuid) | |
typeRequired | string | One of clinical_case.acknowledged, clinical_case.resolved. |
createdAtRequired | string (date-time) | |
dataRequired | object | |
data.Required | string (uuid) | |
data.Required | string (uuid) | |
data.Required | string | |
data. | string or null | |
data. | string or null |
Your response
| Status | Meaning |
|---|---|
200 | Durably received. |