agentaos.webhooks makes no network call, verify() runs entirely in your process. It checks a payload’s HMAC-SHA256 signature against your webhook secret, rejects stale or malformed signatures, and returns the parsed, camelCased event. Configure the destination URL and copy the signing secret from Settings → Developers → Webhooks in the dashboard (or set webhookUrl per checkout/link, see Checkouts).
webhooks.verify(payload, signature, secret, toleranceSec?)
string | Buffer
required
The raw, unparsed request body. If it’s a
Buffer, it’s decoded as UTF-8 before verifying.string
required
The
x-agentaos-signature header value.string
required
Your webhook signing secret (
whsec_...).number
default:"300"
Max age of the signature’s timestamp, in seconds. A signature older than this (or with a timestamp in the future) throws
WebhookVerificationError.WebhookEvent, throws WebhookVerificationError on any failure.
Signature format
The header ist=<unix_timestamp>,v1=<hmac_hex>. verify():
- Parses
tandv1out of the header, throws if either is missing. - Checks
now - tis between0andtoleranceSecseconds, throwsWebhook signature expiredif not (this rejects both stale replays and clock-skewed future timestamps). - Recomputes
HMAC-SHA256(secret, "${t}.${payload}")and compares it tov1withcrypto.timingSafeEqual(constant-time, no early-exit on mismatch). JSON.parses the payload and deep-transforms it from snake_case to camelCase before returning it as aWebhookEvent.
WebhookVerificationError, there’s no partial or “unverified” event returned.
WebhookEvent
A discriminated union on type. switch/narrow on it to get typed data.
string
Unique event ID,
evt_<uuid>. Present on every event, both on the wire and on the object verify() returns.'checkout.session.completed' | 'send.completed' | 'send.failed'
checkout.session.completed
Fires when a checkout session’s payment confirms.
string
The payment link’s secure ID.
string
string
e.g.
"49.99".string
string
On-chain settlement hash.
string
Payer wallet address.
'human' | 'agent'
string
CAIP-2 network ID.
object
Whatever
metadata you passed at checkouts.create().send.completed
Fires when an outbound send (a payout or transfer you initiated) is broadcast successfully.
string
string
string
string
string
string
number
string
string | null
send.failed
Same shape as send.completed, but txHash is always null and no broadcast succeeded.
string
null
string
string
string
string
number
string
string | null
Don't fulfill on the success page redirect
Don't fulfill on the success page redirect
successUrl is best-effort, the customer might close their browser before the redirect lands. Fulfill orders from the webhook (server-to-server, reliable), not the redirect.Webhooks can be delivered more than once
Webhooks can be delivered more than once
Treat delivery as at-least-once. Use
event.data.sessionId (or transactionId) to check whether you’ve already processed it before fulfilling again.Poll as a fallback, not a replacement
Poll as a fallback, not a replacement
If your endpoint is ever down, poll
checkouts.retrieve() for status === 'completed' as a backstop. Don’t build your primary flow on polling, it’s slower and burns rate limit budget.Next steps
Checkouts
Set
webhookUrl to receive checkout.session.completed.Errors
WebhookVerificationError and the rest of the error hierarchy.