Skip to main content

Payout webhook

A55 sends a POST to the webhook_url you set on a payout whenever its status changes. The payload is intentionally minimal — use payout_uuid to fetch the full payout from Get payout.

The webhook_url is provided per payout in the Create payout request body. Private and localhost URLs are rejected.

Payload fields

FieldTypeDescription
payout_uuidUUIDUnique payout identifier
statusstringNew payout status (see table below)
transaction_referencestringIdempotency key sent on creation
external_idstringProvider's payout id
type_payoutstringPayout rail (pix, bank_transfer, ted, spei, cash_pickup)
payment_codestring or nullCash pickup code (cash payouts only)
authorization_codestring or nullProvider authorization code, when available

Payload example

{
"payout_uuid": "9b1f0c88-3a3c-4f2f-9d6e-1f0a2d4e88c1",
"status": "realized",
"transaction_reference": "PAY-2048",
"external_id": "MN-20260616-0001",
"type_payout": "pix",
"payment_code": null,
"authorization_code": "AUTH-55812"
}

All possible statuses

StatusDescription
pendingCreated, awaiting processing
issuedSent to the provider
realizedConfirmed and settled
returnedReturned by the receiving bank
canceledCanceled
errorFailed during processing
expiredExpired

Fetching full payout details

The webhook payload is minimal by design. After receiving it, call the API with your Bearer token to get the complete payout object:

curl "https://api.a55.tech/api/v1/bank/wallet/payout/{payout_uuid}/{wallet_uuid}/" \
-H "Authorization: Bearer $ACCESS_TOKEN"
Webhook is the trigger, API is the source of truth

Use the webhook to know when a payout changed, then call GET /api/v1/bank/wallet/payout/{payout_uuid}/{wallet_uuid}/ to get full details such as fee, confirmed_date, and destination.

Handler examples

from flask import Flask, request, jsonify

app = Flask(__name__)
processed = set()

@app.route("/webhooks/a55/payouts", methods=["POST"])
def payout_webhook():
data = request.get_json()
payout_uuid = data.get("payout_uuid")
status = data.get("status")

# Deduplicate
if payout_uuid in processed:
return jsonify(status="duplicate"), 200
processed.add(payout_uuid)

if status == "realized":
mark_payout_settled(payout_uuid)
elif status in ("returned", "error", "expired"):
flag_payout_failure(payout_uuid, status)

return jsonify(status="accepted"), 200

Best practices

PracticeWhy
Return 200 immediatelyAvoids timeouts and duplicate deliveries
Process in backgroundKeeps response time low
Deduplicate by payout_uuidHandles retried webhooks safely
Fetch full details via APIWebhook payload is minimal by design
Use a public, reachable URLPrivate/localhost URLs are rejected