client.webhooks verifies the HMAC signature on an inbound webhook and returns a typed WebhookEvent. See Webhooks for the conceptual model and signing algorithm.
No network call is made — verification is local crypto against the whsec_... secret you saved in the developer portal. Works on Node 18+, browsers, Deno, Bun, and Cloudflare Workers via WebCrypto.
Verifying a delivery
| Argument | Type | Default | Description |
|---|---|---|---|
payload | Uint8Array | ArrayBuffer | string | required | Raw request body. |
sigHeader | string | required | Value of the Spine-Signature request header. |
secret | string | required | The whsec_... secret from the developer portal. |
options.toleranceSeconds | number | 300 | Replay window in seconds. |
options.now | number | Math.floor(Date.now() / 1000) | Inject for deterministic tests. |
Promise<WebhookEvent>. Throws SpineWebhookSignatureError on any verification failure.
Express example
Express parses JSON by default and discards the raw bytes the signature was computed over. Useexpress.raw() on the webhook route so the SDK receives untouched bytes.
Next.js route handler
WebhookEvent
| Field | Type | Notes |
|---|---|---|
id | string | evt_<uuid>. Use for idempotency. |
type | string | e.g. "run.completed", "run.failed", "webhook.ping". |
created | number | Unix seconds. |
livemode | boolean | true in production. |
api_version | string | undefined | Envelope schema version. |
data | { object: Record<string, unknown> } | Event payload. data.object carries the primary entity. |
Notes
- Clock skew matters. If your server drifts more than 5 minutes from Spine’s clock, deliveries will be rejected as stale. Run NTP.
- Rotation invalidates the previous secret immediately. Update your env var before rotating if you care about strict uptime.
- The SDK accepts multiple
v1=values in one header, so a future dual-signing rotation strategy will be forward-compatible.