Webhooks
Webhooks notify your system in real-time when payment events occur. Instead of polling the API, register a URL and we’ll send HTTP POST requests with event data as payments are confirmed, expire, or fail.Event Types
| Event | Description | When It Fires |
|---|---|---|
payment_intent.confirmed | Payment received and confirmed on-chain. | ~3-15 seconds after customer sends USDC. |
payment_intent.expired | Payment intent expired without receiving payment. | At the expires_at timestamp. |
payment_intent.cancelled | Payment intent was cancelled by the integrator. | Immediately after cancellation API call. |
transaction.created | A new USDC transaction was detected at a merchant’s payment address. | When any USDC transfer is confirmed, even if not tied to an active payment intent. |
settlement.completed | Merchant funds were sent to their bank account. | When the ACH transfer is initiated. |
settlement.failed | Bank transfer failed (e.g., invalid account). | When the ACH return is received (1-4 business days). |
Webhook Payload
Every webhook has the same envelope structure:payment_intent.confirmed
payment_intent.expired
Handling Webhooks
1. Return 200 quickly
Your endpoint must return a200 status code within 5 seconds. Do any heavy processing asynchronously after responding.
2. Handle duplicates
Webhooks may be delivered more than once. Use theevt_* ID to deduplicate:
3. Verify signatures
Every webhook includes a signature header for verification. See Webhook Security for details.Retry Policy
If your endpoint returns a non-2xx status code or doesn’t respond within 5 seconds, we retry with exponential backoff:| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 12 hours (final) |
Testing Webhooks
In sandbox mode (sk_test_* keys), you can trigger test webhook events from the dashboard to verify your endpoint is working correctly without sending real USDC.