Webhook Overview
Webhooks are HTTP callbacks that notify your application when specific events occur in the Paystand system. They provide real-time notifications about payment status changes, transaction updates, and other important events.
How Webhooks Work
When an event occurs (such as a payment being completed), Paystand sends an HTTP POST request to your specified webhook URL with event details in JSON format.
Event Structure
All webhook events follow a consistent structure:
{
"object": "event",
"id": "unique_event_id",
"eventType": "payment.posted",
"resource": {
// The updated resource (payment, refund, etc.)
},
"diff": {
"previous": {
// Previous state of the resource
},
"changes": {
// What changed in this event
}
},
"urls": ["your_webhook_url"],
"sent": false,
"lastAttemptSent": false,
"attempts": 0,
"sourceId": "resource_id",
"sourceType": "ResourceType",
"status": "active",
"created": "2025-07-11T21:34:56.000Z",
"lastUpdated": "2025-07-11T21:34:57.000Z"
}
Routing on eventType
Every delivered webhook carries a top-level eventType — for example payment.posted,
dispute.won, or credit_memo.created. It is the precise discriminator for the event and is the
recommended field to route on. Use it in preference to inferring the event from resource.object
or from sourceType, which identify the resource but not what happened to it.
status is the delivery state, not the resource state
The top-level status describes the delivery of this webhook, not the resource it carries:
Top-level status | Meaning |
|---|---|
active | The event is queued for delivery |
sent | The event was delivered and accepted (sent: true) |
failed | The last delivery attempt failed. This is not terminal — the event is retried on the schedule below until the attempt limit is reached |
complete | Nothing to deliver: no webhook URL is configured, or the resource had no changes |
The resource's own status always lives at resource.status. These two are independent: an
event carrying a won dispute is delivered as "status": "active" at the top level while
resource.status reads won. Always read the resource's state from resource.status.
Auto-Retry Mechanism
Paystand implements a robust retry mechanism to ensure webhook delivery:
Max Retries
Total number of attempts before marking the event as failed
- 8 attempts total
Retry Intervals
Fixed predefined intervals:
- 1st retry: 300 seconds (5 minutes)
- 2nd retry: 900 seconds (15 minutes)
- 3rd retry: 3600 seconds (1 hour)
- 4th retry: 43200 seconds (12 hours)
- 5th-8th retry: 86400 seconds (24 hours each)
Failure Conditions
Status codes triggering retry: Any response outside 200-299 status code range is considered as a failure and the auto-retry mechanism will be activated.
Status codes stopping retry immediately:
- 404 (Not Found)
- Invalid URL errors
Request timeout: 15 seconds per request
Event Types
Paystand supports the following webhook event types:
- Payment Events: Payment lifecycle notifications
- Receivable Transaction Events: Payment application to invoices
- Refund Events: Refund processing notifications
- Dispute Events: Chargeback and dispute updates
- Transfer Events: Payout and settlement notifications
- Fee Events: Merchant fee confirmations
- Credit Memo Events: Credit memo lifecycle and payment-application notifications
Best Practices
- Idempotency: Handle duplicate events gracefully
- Response Time: Respond within 15 seconds
- Status Codes: Return 2xx to let our system know of successful processing
- Error Handling: Log failures in your system for debugging
- Event Ordering: Don't rely on event order; use timestamps