How it works
When you create a transaction withcallbackUrl, Safefy sends an HTTP POST request to that URL whenever the status changes.
Available events
Transaction events
| Event | Description | When it happens |
|---|---|---|
transaction.completed | Payment confirmed | When PIX is paid and confirmed by the bank |
transaction.expired | Transaction expired | When the payment window ends (default: 30 min) |
transaction.failed | Processing failed | When there is an acquirer or validation error |
transaction.refunded | Payment refunded | When a confirmed payment is refunded |
Cashout events
| Event | Description | When it happens |
|---|---|---|
cashout.completed | Cashout completed | When PIX is sent to the destination account |
cashout.failed | Cashout failed | When a cashout is rejected or fails |
Transaction statuses
Understand the transaction lifecycle and when each webhook is fired:Details for each status
Pending - Awaiting payment
Pending - Awaiting payment
The transaction has been created and is waiting for the customer to pay.What to do: Show the QR Code/PIX copy-and-paste string and wait for confirmation.Webhook: No webhook is sent for this status.
Completed - Payment confirmed
Completed - Payment confirmed
The payment was received and confirmed by the bank. The amount is now available in your balance.What to do: Release the product/service to the customer.Webhook:
transaction.completedImportant fields in the webhook:data.completedAt- Confirmation date/timedata.pix.endToEndId- Unique transaction ID at the Central Bankdata.pix.payerName- Payer namedata.pix.payerDocument- Payer document (masked)data.pix.payerBank- Payer bank
Expired - Transaction expired
Expired - Transaction expired
The payment window expired and the transaction was automatically cancelled.What to do: Inform the customer and offer a new attempt.Webhook:
transaction.expiredFailed - Processing failed
Failed - Processing failed
An error occurred while processing the transaction.What to do: Check the
failureReason field and take the appropriate action.Webhook: transaction.failedImportant field: data.failureReason - Failure reasonRefunded - Payment refunded
Refunded - Payment refunded
The confirmed payment was refunded. The amount was returned to the payer.What to do: Revoke access to the product/service.Webhook:
transaction.refundedImportant field: data.refundedAt - Refund date/timeCancelled - Transaction cancelled
Cancelled - Transaction cancelled
The transaction was manually cancelled before payment.What to do: No action required.Webhook: No webhook is sent for manual cancellations.
Example payloads
transaction.completed
Sent when a PIX payment is confirmed:transaction.expired
Sent when the payment window expires:transaction.refunded
Sent when a payment is refunded:cashout.completed
Sent when a cashout is processed successfully:Sent headers
| Header | Description |
|---|---|
X-Safefy-Signature | HMAC-SHA256 signature for validation |
X-Safefy-Event | Event type (transaction.completed, etc) |
X-Safefy-Delivery | Unique delivery ID |
X-Safefy-Attempt | Attempt number (1, 2, 3…) |
Validating the signature
To ensure the webhook is from Safefy, validate the signature:Retries
If your application does not respond with2xx, Safefy will retry:
| Attempt | Interval |
|---|---|
| 1 | Immediately |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
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.