Webhooks
We notify your server with an HTTP POST whenever a transaction changes state. The URL is the one you sent when creating the transaction:
| Flow | Field that sets the URL |
|---|---|
PIX-IN (POST /wallet/deposit/payment, method_pay=pix) | postback |
Card (POST /wallet/deposit/payment with method_pay=card, or POST /wallet/card/charge) | postback |
PIX-OUT (POST /pixout) | baasPostbackUrl |
Crypto withdrawals have no callback. Use POST /crypto/withdraw/status.
Request format
POST /your/callback/path HTTP/1.1
Content-Type: application/json
Accept: application/json
Every payload has status, idTransaction and typeTransaction. Branch on typeTransaction first, then on status.
Events
typeTransaction | status | When | Extra fields |
|---|---|---|---|
PIX | paid | PIX charge paid. The only PIX-IN event. | none |
PAYMENT | paid | PIX-OUT completed. | none |
PAYMENT | canceled | PIX-OUT failed or cancelled. Amount returned to your balance. | none |
CARD | paid | Card payment confirmed. USD balance credited. | amount, currency |
CARD | cancelled | Card charge ended without payment (session expired, or a direct API attempt failed asynchronously). | amount, currency, failure_code, message, decline_code (when a decline happened) |
CARD | refunded | Charge fully refunded. | amount, refund_amount, total_refunded, net_amount, currency |
CARD | partially_refunded | Part of the charge refunded. | same as refunded |
CARD | disputed | Chargeback opened. Disputed amount held. | none |
CARD | dispute_won | Chargeback resolved in your favor. Funds restored. | none |
CARD | dispute_lost | Chargeback lost. Funds stay debited. | none |
CARD_REFUND | pending, succeeded, failed, canceled, requires_action | An individual refund changed state. status is the refund state. | refund_id, refund_status, amount, currency, failure_reason, arn |
Note the two spellings: PIX-OUT uses canceled, card uses cancelled.
Payload examples
PIX-IN paid:
{ "status": "paid", "idTransaction": "a1b2c3d4e5f60718293a4b5c6d7e8f90", "typeTransaction": "PIX" }PIX-OUT canceled:
{ "status": "canceled", "idTransaction": "F3A9C2D18B7E4C6A9D0E1F2A3B4C5D6E", "typeTransaction": "PAYMENT" }Card paid:
{
"status": "paid",
"idTransaction": "3f2b8c1e-7a4d-4e3b-9c2a-1d5e6f7a8b9c",
"typeTransaction": "CARD",
"amount": 100.00,
"currency": "USD"
}Card cancelled:
{
"status": "cancelled",
"idTransaction": "3f2b8c1e-7a4d-4e3b-9c2a-1d5e6f7a8b9c",
"typeTransaction": "CARD",
"amount": 100.00,
"currency": "USD",
"failure_code": "insufficient_funds",
"decline_code": "insufficient_funds",
"message": "Your card has insufficient funds."
}Card partially refunded:
{
"status": "partially_refunded",
"idTransaction": "3f2b8c1e-7a4d-4e3b-9c2a-1d5e6f7a8b9c",
"typeTransaction": "CARD",
"amount": 100.00,
"refund_amount": 10.00,
"total_refunded": 20.00,
"net_amount": 80.00,
"currency": "USD"
}refund_amount is the amount of this event. total_refunded is cumulative. net_amount is amount - total_refunded.
Card disputed (dispute events carry no amounts; read them from the status endpoint):
{ "status": "disputed", "idTransaction": "3f2b8c1e-7a4d-4e3b-9c2a-1d5e6f7a8b9c", "typeTransaction": "CARD" }Refund status changed:
{
"status": "failed",
"idTransaction": "3f2b8c1e-7a4d-4e3b-9c2a-1d5e6f7a8b9c",
"typeTransaction": "CARD_REFUND",
"refund_id": "re_3TestExample0000000001",
"refund_status": "failed",
"amount": 12.79,
"currency": "USD",
"failure_reason": "expired_or_canceled_card",
"arn": null
}The OpenAPI file lists each event under webhooks with its schema.
Responding and retries
Answer with any 2xx status as fast as possible. Do the heavy work after responding.
| Your response | What we do |
|---|---|
2xx | Delivered. No more attempts. |
5xx, 408, 425, 429, timeout (15 s) or connection error | Retry. |
Any other 4xx | Permanent failure. No retry. |
Up to 6 attempts in total. Delays between attempts: 30 seconds, 2 minutes, 5 minutes, 15 minutes, 30 minutes (about 52 minutes overall). After that the callback is marked as failed. Use the status endpoints to recover anything you missed.
Do not answer 4xx for an event you do not handle; answer 200 and ignore it, or you lose the delivery.
Duplicates and ordering
- The same event can arrive more than once (for example when your server processed it but timed out before answering). Make your handler idempotent: key on
idTransactionplusstatus(plusrefund_idforCARD_REFUND). - Events can arrive out of order. Do not move an order backwards: a late
cancelledmust not undo apaid.
Verifying a callback
Callbacks are not signed. There is no signature header and no shared secret. Anyone who learns your callback URL could post a fake payload. Before you release goods or money:
- Treat the callback only as a trigger.
- Fetch the transaction from the API with your credentials and act on that response:
- PIX-IN and card:
GET /transactions/payment/{idTransaction} - PIX-OUT:
GET /transactions/pixout/{idTransaction} - Refunds:
GET /wallet/card/refund/{refund_id}
- PIX-IN and card:
- Check that
idTransactionis one you created and that the amount matches your order.
Also recommended:
- Use an HTTPS callback URL with a hard to guess path, for example
https://example.com/callbacks/card/5f0c9e7d2b, and a different path per environment. - Reject payloads whose
idTransactionyou do not know.
Polling as a fallback
If callbacks fail or your endpoint was down, poll the status endpoints. For card charges still pending more than 3 minutes after creation, GET /transactions/payment/{idTransaction} refreshes the state from the card processor before responding, so it recovers a missed paid.
Updated about 2 hours ago
