Receive webhook updates
Keep checkout status and prize notifications up to date.
In the partner workspace, an owner or developer can save your public HTTPS webhook URL and manage its signing secret. Keep the secret on your server, separately from the partner API key. Use a publicly reachable IPv4 hostname on HTTPS port 443 and the final endpoint URL; redirects are not followed.
Verify before processing
Every delivery has x-verity-event and x-verity-signature headers, with this body shape:
{"event":"payment.updated","data":{"operation_id":"<operation UUID>","status":"completed"}}The signature is the hex HMAC-SHA256 of the exact raw body bytes. Verify before parsing JSON. Do not reconstruct the body with JSON.stringify for verification.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhook(rawBody: Buffer, signature: string, secret: string) {
const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(expected);
const b = Buffer.from(signature);
return a.length === b.length && timingSafeEqual(a, b);
}In Express, use express.raw({ type: 'application/json' }) on this route before any global JSON parser. Return a non-2xx response if the signature is invalid. Return 2xx after safely accepting the valid event for processing.
Test your endpoint
After saving the endpoint and configuring its signing secret on your server, choose Send test event in Integration. The signed event is integration.test with data.test: true and a timestamp. Verify its signature and return a 2xx response without creating a purchase or prize. Test deliveries are sent once; use the button again after fixing a failed endpoint.
Events to handle
| Event | Your action |
|---|---|
payment.updated | Fetch the payment operation's current state |
raffle.live | Refresh the raffle and enable checkout if live |
raffle.closed | Stop new checkouts; continue tracking existing purchases |
raffle.drawn | Refresh and display the drawn prize result |
prize.won | Notify your winner and refresh their prize list |
raffle.cancelled | Show cancellation; refunds may still be pending |
refund.sent | A cancellation refund has completed |
Handle duplicates and delivery order
- Deliveries can repeat. Do not send a second winner notification for the same prize.
- Events can arrive out of order. For payment events, query
GET /payments/{operationId}for the latest state rather than blindly applying the last event received. - A raffle may close, be extended, and reopen. Do not permanently ignore later events just because you have already seen that event name and raffle ID.
- Non-2xx responses and timeouts are retried. Keep your handler quick and idempotent.
Track the correct refund
payment.updated can describe purchases, refunds or payouts. Read the operation and inspect kind. If a purchase includes refund_operation_id, track that refund separately.
refund.sent is a cancellation-refund event, not a universal event for all refunds. For checkout refunds, use the payment operation. For existing payment-first integrations, repeat the same tickets request to read refund_status.
No webhook is permission to initiate another payment.