Skip to main content
AgentaOS sends a webhook to your server for every payment event: a checkout completing, an outbound send confirming or failing. Webhooks are how your backend finds out about a payment without polling, and they’re the only source of truth you should build on, not the browser redirect after checkout.
Always verify the signature before you act on a webhook body. Anyone who knows your webhook URL can POST a fake payload to it. Verification is what proves the request actually came from AgentaOS.

Register a webhook URL

1

Open Developer settings

Go to app.agentaos.aiDeveloperWebhooks.
2

Set your endpoint

Enter the HTTPS URL you want events sent to, for example https://myshop.com/webhooks.
3

Reveal the signing secret

Click Reveal signing secret and copy the whsec_... value.
4

Store it as a secret

Add it to your server’s environment as AGENTAOS_WEBHOOK_SECRET. Never commit it, never log it, never send it to the client.
The signing secret is stable, it doesn’t change when you update the URL. If you suspect it’s been exposed, click Rotate to issue a new one. Rotating invalidates the old secret immediately, so deploy the new value before you rotate if you can’t afford downtime.
You can also pass a one-off webhookUrl when creating a checkout or payment link to route that specific payment’s event to a different endpoint, useful for per-integration or per-customer routing without touching your account-wide URL.

Verify the signature

Every webhook request carries an X-AgentaOS-Signature header. Verifying it proves two things: the payload came from AgentaOS, and it hasn’t been replayed from an old request.
webhooks.verify() does four things, in order: parses the t=...,v1=... header, rejects it if the timestamp is older than 5 minutes (replay protection), recomputes the HMAC-SHA256 digest and compares it in constant time, then parses and returns a typed WebhookEvent. Any failure throws WebhookVerificationError rather than returning a falsy value, so you can’t accidentally skip the check.

Manual verification (no SDK)

The algorithm is plain HMAC-SHA256 over {timestamp}.{raw_body}, so it’s straightforward to reimplement in any language that can do an HMAC and a constant-time compare.
Use a constant-time comparison (hmac.compare_digest, hmac.Equal, hash_equals, crypto.timingSafeEqual), never == or ===. A naive string comparison leaks timing information an attacker can use to forge a valid signature byte by byte.

Signature format

The t prefix exists so the same payload signed twice never produces the same signature, and so a captured request can’t be replayed indefinitely, verification rejects anything older than 5 minutes by default.

Delivery and retries

Each delivery attempt gets a 10-second response timeout. If your endpoint doesn’t return a 2xx status in time, AgentaOS retries with exponential backoff, up to 3 attempts total. After the last attempt fails, the event is marked failed and isn’t retried further.
Return 200 as soon as you’ve verified the signature and durably queued the event (a job, a database row). Do the actual work, fulfillment emails, external API calls, asynchronously. A slow handler is the most common reason webhooks fail and retry unnecessarily.

Events

checkout.session.completed

A checkout was paid, by card, bank transfer, or stablecoin.

send.completed

An outbound send confirmed on-chain.

send.failed

An outbound send failed to broadcast.
See the event reference for the full payload shape of each one.
Every webhook payload’s amount field is a string (e.g. "49.99"), not a number. This is different from amount on SDK create calls, which is a plain number. Parse it before doing arithmetic.

Best practices

Don't trust the redirect

The successUrl redirect is best-effort. The customer might close their browser before it fires. Always treat the webhook, not the redirect, as the source of truth that a payment happened.

Handle idempotently

Retries mean the same event can arrive more than once. Key your fulfillment logic off event.data.sessionId or event.data.transactionId and make it safe to process twice.

Respond quickly

Verify, queue, return 200. Do the slow work outside the request.

Verify every time

Never branch on event.data before webhooks.verify() (or the manual equivalent) has returned successfully.

Next steps

Event reference

Every event type, its full payload, and a JSON example.

Payment SDK: Webhooks

The webhooks resource in @agentaos/pay, in full.

Checkouts

Set a per-checkout webhookUrl when you create one.

Payouts

What happens to your balance after a payment lands.