What you will build
- An HTTPS webhook endpoint for partner notifications
- Signature checks on the raw request body before you parse JSON
- Handling for success and failure notifications
- Reject invalid signatures and acknowledge valid notifications
Install the Suki developer docs as a skill to get context on Suki's developer tools, APIs, and SDKs. Add the MCP server for documentation search.
success or failure. Examples are provided in Python and TypeScript coding languages.
By the end of this tutorial, you’ll have a working POST /webhooks/notification handler that rejects invalid signatures with 4xx and acknowledges accepted notifications with 2xx.
Prerequisites
Before you begin, make sure you have:- Completed Partner onboarding.
- Shared your HTTPS callback URL with Suki so it is stored on your partner record. You cannot register or change this URL through a self-service API. See Configuration.
- Your partner secret key from Suki (server-side only).
- A publicly reachable HTTPS endpoint (TLS 1.2 or higher).
- An integration that creates and ends ambient or Form filling sessions so Suki can send completion or failure events. Refer to Build ambient session Streaming Client or Build Form filling Session Client tutorials for examples.
Architecture
Project setup
- Create a script or server project in the language used by this tutorial (Python or TypeScript).
-
Install the required dependencies:
-
Python:
pip install flask -
TypeScript:
npm install express
-
Python:
-
Configure your credentials:
- Store your partner secret key on your backend only. Never expose it in browser code.
-
Expose
POST /webhooks/notification(or the path you registered with Suki) on a publicly reachable HTTPS URL.
How signature verification works in this tutorial
Important points to remember:
- Verify against the raw body before JSON parse. Pretty-print, trim, or auto-parse middleware changes bytes and breaks HMAC.
- Reject requests that are missing
X-API-Keyor have an empty digest with 4xx. - Return 2xx for accepted notifications, including timeout and cancellation events after you log identifiers.
- Confirm the HTTPS callback URL is registered with Suki on your partner record.
Tutorial steps
Work through each step in order. Read the explanation, review the code example, then continue to the next step. The full code example is available in the accordion below.1
Accept the POST Callback
Expose an HTTPS POST route that matches the callback URL you shared with Suki. Keep the partner secret key on your backend only.
2
Read the Raw Body and Headers
Read the raw request body before JSON parsing, plus the
generated-at and X-API-Key headers. See Verify signatures.3
Verify the HMAC Signature
Recompute HMAC-SHA-256 over
generated-at + : + raw body, encode as hex, and compare to X-API-Key with a constant-time compare.4
Parse JSON and Branch on Status
Only after verification succeeds, parse JSON and branch on top-level
status. Documented example payloads exist for success and failure. Timeout and cancellation events also arrive on this endpoint; acknowledge them with 2xx after you log session_id / encounter_id. See Payload and response and Event types.5
Return 2xx
Return 200 (or another 2xx) so Suki treats the notification as delivered. Invalid signatures should stay 401 (or 400).
Full code example
Troubleshooting
Signatures Never Match
Signatures Never Match
Verify against the raw body before JSON parse. Pretty-print, trim, or auto-parse middleware changes bytes and breaks HMAC.
Missing `X-API-Key` or Empty Digest
Missing `X-API-Key` or Empty Digest
Reject with 4xx. Do not call a constant-time compare on an empty expected signature as a successful verify.
Suki Keeps Retrying
Suki Keeps Retrying
Return 2xx for accepted notifications, including timeout and cancellation events after you log identifiers (see Event types).
No Callbacks Arrive
No Callbacks Arrive
Confirm the HTTPS URL is registered with Suki on your partner record (Configuration).
Summary
In this tutorial, you:- Built a
POST /webhooks/notificationhandler. - Verified each request with HMAC-SHA-256 before parsing JSON.
- Branched on
successorfailureand returned 2xx for accepted events.