Before you start
- Node.js 20+, Express, and
@agentaos/payinstalled (npm install @agentaos/pay express). - A URL AgentaOS can reach over HTTPS. For local development, run a tunnel (ngrok or similar) so
http://localhost:3000gets a public HTTPS address to register. - A payment link or checkout to test against, see Accept your first payment if you don’t have one yet.
1
Register a webhook URL and reveal the signing secret
Open app.agentaos.ai → Developer → Webhooks, and enter the HTTPS URL you want events sent to, for example
https://myshop.com/webhooks. Click Reveal signing secret, copy the whsec_... value, and add it to your server’s environment as AGENTAOS_WEBHOOK_SECRET. Never commit it, never log it, never send it to the client.2
Set up the raw-body route
Signature verification signs the raw request body. If a JSON body parser runs first, the reserialized body won’t byte-for-byte match what was signed, and every event will fail verification. Mount
express.raw() on the webhook route only, and keep express.json() for everything else.3
Verify the signature
webhooks.verify() parses the t=...,v1=... header, rejects it if older than 5 minutes, recomputes the HMAC-SHA256 digest in constant time, and returns a typed WebhookEvent, or throws WebhookVerificationError if anything doesn’t check out.4
React to checkout.session.completed, idempotently
Key your fulfillment logic off
event.data.sessionId, and check whether you’ve already processed it before doing anything. Retries mean the same event can arrive more than once, your handler needs to be safe to run twice.event.data.amount is a string ("49.99"), not a number. Every other amount you pass into a create call is a plain number, webhook payloads are the one place it’s serialized as a string. Parse it before doing arithmetic.5
Respond 200 quickly
Verify, queue or record the event, then respond. Do slow work, emails, external API calls, outside the request so AgentaOS doesn’t time out waiting for you.
Full example
webhook-server.ts
Test it end to end
1
Start your server
Run the example above, and make sure your tunnel or production URL points at it.
2
Create a checkout with a webhookUrl
Use the link or checkout from Accept your first payment, or create a new one with
webhookUrl set to your endpoint.3
Pay with the test card
4242 4242 4242 4242, any future expiry, any CVC, typed directly into the hosted checkout page.4
Watch your server log the order as paid
You should see
Order <sessionId> paid: 49.99 EUR in your logs within seconds of the payment clearing.Verify it worked
- Your endpoint returned
200for the delivery (check Developer → Webhooks in the dashboard for delivery status). - Your logs show exactly one fulfillment for that
sessionId, even if AgentaOS retries the delivery. - An invalid or missing
X-AgentaOS-Signatureheader gets rejected with400, not silently processed. Try POSTing a fake payload without a valid signature to confirmwebhooks.verify()throws as expected.
Next steps
Event reference
Every event type, its full payload, and a JSON example.
Webhooks (concept)
Manual verification in Python, Go, and PHP, plus retry and delivery details.
Accept your first payment
Create the checkout that triggers this handler.
Payouts
What happens to your balance after the payment lands.