Dual Webhooks
Why a hybrid integration receives two webhook formats, and how to route and deduplicate them.
In the Hybrid model, a single transaction can emit two webhooks: one in Long format (from Hosted/SDK, for the card) and one in Short format (from API Direct, for non-card methods, withdrawals, and refunds). This is by design.
Why duplicate webhooks arrive
Because each leg of your integration (SDK/Hosted for cards, API Direct for everything else) has its
own webhook channel, you'll receive notifications from both. A single payment can generate a
Pending event and then a Success for each channel involved.
Duplicate webhooks in Hybrid mode are intentional (Pending + Success). Correlate both legs on
metadata.external_id, and deduplicate each delivery on the webhook-id header (Webhooks 2.0) or
on id + event_type.
What you need to configure
- Two webhook endpoints, one per integration style. With Webhooks 2.0, subscribe the card endpoint to the Checkout sessions — Hosted & SDK events and the other one to Payments — API Direct and Withdrawals (see the Events catalog). Without Webhooks 2.0 every registered URL receives both formats, so route by format in your handler.
- Separate handling logic: Hosted/SDK-style webhooks for card transactions, and API Direct-style for other methods, withdrawals, and refunds.
Deduplication checklist
- Dedupe on the
webhook-idheader with Webhooks 2.0 — a retry or a resend carries the same one. Without Webhooks 2.0, dedupe onid+event_type. Correlate withmetadata.external_id, which repeats on every event of a transaction and works across Short + Long formats. - Keep processed
webhook-ids for at least 60 days — an event can be resent while it is kept. - Keep an
idempotency_keyindex in your DB. - Treat duplicate Pending + Success in Hybrid mode as intentional.
- Always verify final status via
GET /api/v1/transactions/{id}/. - Handle all five withdrawal terminal states —
Success,Declined,Cancelled,FailedandReturned;Returnedarrives afterSuccess.
