How it works
When you create a payment or cashout withcallbackUrl, Safefy sends an HTTP POST request to that URL whenever status reaches a relevant state.
For full domain-specific payloads, see:
Payment events
| Event | Description | When it happens |
|---|---|---|
payment.completed | Payment confirmed | When PIX is paid and confirmed by the bank |
payment.expired | Transaction expired | When the payment window ends |
payment.failed | Processing failed | When there is an acquirer or validation error |
payment.cancelled | Payment cancelled | When the payment is manually cancelled |
payment.refunded | Full refund | When a confirmed payment is refunded |
payment.partially_refunded | Partial refund | When part of the payment is refunded |
payment.refund_requested | Refund requested | When the refund is in processing |
Cashout events
| Event | Cashout status |
|---|---|
cashout.completed | Completed |
cashout.failed | Failed |
cashout.rejected | Rejected |
cashout.cancelled | Cancelled |
Sent headers
| Header | Description |
|---|---|
X-Safefy-Signature | HMAC-SHA256 signature for validation |
X-Safefy-Event | Event type (payment.* or cashout.*) |
X-Safefy-Delivery | Unique delivery ID |
X-Safefy-Attempt | Attempt number (1, 2, 3) |
Signature
- For
payment.*events, the secret ispaymentId. - For
cashout.*events, the secret ispayoutId.
Retries
If your endpoint does not return2xx, Safefy retries:
- Attempt 1 (immediate)
- Attempt 2 after ~2 seconds
- Attempt 3 after ~4 seconds
200 OK) and process asynchronously.
Idempotency
Because retries can happen, your webhook processing must be idempotent.- Recommended key:
id(delivery id) ordata.id + type - Ignore already-processed events
Quick example
Payment status flow
Understand the transaction lifecycle and when each webhook is fired:| Attempt | Interval |
|---|---|
| 1 | Immediate |
| 2 | 2 seconds |
| 3 | 4 seconds |
Best practices
Respond quickly
Return 200 OK immediately and process the webhook asynchronously.
Be idempotent
Use the webhook id to avoid processing the same event twice.
Validate the signature
Always verify X-Safefy-Signature before trusting the payload.
Use HTTPS
Configure your callbackUrl with HTTPS in production.