Webhooks
Register a webhook URL via the API (POST /v1/webhooks) to receive real-time notifications for banking, crypto and OTC events.
Managing Webhooks
All routes use your regular OAuth Bearer token. The secret signs every delivery (HMAC-SHA256) and is never returned by the API.
| Method | Route | Description |
|---|---|---|
POST | /v1/webhooks | Register a webhook: { "url": "https://...", "events": [...], "secret": "min 32 chars" } → 201 with webhookId |
GET | /v1/webhooks | List your subscriptions (secrets omitted) |
PUT | /v1/webhooks/{webhookId} | Update url, events, secret and/or active |
DELETE | /v1/webhooks/{webhookId} | Unregister — deliveries stop immediately |
The url must be HTTPS. events is a non-empty subset of the event types below; each event is delivered to every active subscription that includes its type.
Event Types
| Event | Description |
|---|---|
pix-payment-in | Incoming PIX payment received |
pix-payment-out | Outgoing PIX payment confirmed |
pix-reversal-in | Incoming PIX reversal received |
pix-reversal-out | Outgoing PIX reversal confirmed |
spb-transfer-in | Incoming TED transfer received |
spb-transfer-out | Outgoing TED transfer confirmed |
onboarding-create | Account onboarding status change |
onboarding-backgroundcheck | Background check finished — including refusal, with the reason |
onboarding-documentscopy | KYC documents processed |
onboarding-file | KYC file ready for review |
onboarding-proposal | Proposal status updated |
onboarding-biometrics | Biometric verification URL available/updated |
crypto-cash-in | Onchain crypto deposit received |
otc.trade.settled | OTC trade settled (final) |
otc.trade.failed | OTC trade failed (final) |
Delivery Format
Each delivery is a POST to your URL. Event metadata travels in the headers; the request body is the event data itself (no envelope):
| Header | Description |
|---|---|
X-Webhook-Event | Event type |
X-Webhook-Event-Id | Unique event id (UUID) — use for idempotency |
X-Webhook-Timestamp | Dispatch time (ISO 8601, UTC) |
X-Webhook-Signature | Hex HMAC-SHA256 of the raw body, signed with your secret (no sha256= prefix) |
Validate the signature on every request (timing-safe compare of the hex digest computed over the exact raw body bytes) and deduplicate by X-Webhook-Event-Id.
Banking Webhook (pix-*, spb-*)
Body shape may vary slightly per banking provider; PIX/TED events typically look like:
{
"entity": "pix-payment-in",
"status": "COMPLETED",
"body": {
"transactionId": "E384040820262603101234567890",
"endToEndId": "E384040820262603101234567890",
"amount": 150.00,
"creditParty": {
"name": "João da Silva",
"taxId": "48059890093"
},
"debitParty": {
"name": "Maria Souza",
"taxId": "12345678901"
}
}
}Route events by the X-Webhook-Event header, not by body fields.
Onboarding Webhook
{
"entity": "onboarding-create",
"status": "CONFIRMED",
"body": {
"proposalId": "550e8400-e29b-41d4-a716-446655440001",
"documentNumber": "48059890093",
"account": { "account": "30054029183", "branch": "0001" }
}
}| Onboarding Status | Description |
|---|---|
PROCESSING | KYC verification in progress |
CONFIRMED | Account created successfully |
ERROR | Account creation failed |
Biometrics Webhook (onboarding-biometrics)
Sent when the biometric verification URL becomes available or changes — the push counterpart of polling GET /v1/bank-accounts/checkOnboarding (which returns the same biometricUrl). Forward the URL to the account holder to complete the selfie/liveness step.
{
"onboardingId": "550e8400-e29b-41d4-a716-446655440001",
"accountId": "30054029183",
"documentNumber": "48059890093",
"status": "PROCESSING",
"biometricUrl": "https://kyc.provider.com/biometrics/abc123"
}The
onboardingIdformat varies by banking provider (UUID on some, other formats on others) — treat it as opaque. To correlate with your records, preferdocumentNumber(CPF/CNPJ), whichGET /checkOnboardingalso accepts.
Background Check Refusal Webhook (onboarding-backgroundcheck)
Sent when the banking provider refuses a proposal during background check. This can happen hours after POST /v1/bank-accounts/create returned successfully — the check runs asynchronously.
Refusal is terminal: the onboarding is not re-checked afterwards, so this event is your notification. The same reasons remain available in messages[] from GET /v1/bank-accounts/checkOnboarding.
{
"onboardingId": "550e8400-e29b-41d4-a716-446655440001",
"accountId": null,
"documentNumber": "29480535000199",
"status": "ERROR",
"messages": [
{
"id": "onboarding-backgroundcheck",
"date": "2026-07-14T01:22:00.000Z",
"message": "Não conseguimos confirmar algumas das informações da sua proposta, para mais informações entre em contato com o SAC!",
"status": "proposal-reproved",
"actionRequired": false
}
]
}| Field | Description |
|---|---|
onboardingId | Onboarding id — treat as opaque; prefer documentNumber to correlate |
accountId | Bank account id, when already assigned |
documentNumber | Holder document (CPF/CNPJ) — the stable key to match the onboarding to the account holder |
status | Always ERROR — matches the status returned by GET /checkOnboarding |
messages | Reasons reported by the provider. messages[].message is the text to show the account holder; actionRequired tells whether they can fix and resubmit; url carries the action link when supplied |
Crypto Webhook (crypto-cash-in)
Sent when a tenant wallet receives an onchain deposit. txId is the onchain transaction hash — use it for idempotency. The amount is a decimal string (full onchain precision).
{
"address": "0x1122334455667788990011223344556677889900",
"amount": "1000.00",
"asset": "USDT",
"txId": "0xdeadbeef...",
"chain": "polygon-mainnet",
"network": "EVM",
"walletId": "a1b2c3d4-0000-0000-0000-000000000000",
"type": "token"
}| Field | Description |
|---|---|
address | Receiving wallet address |
amount | Deposited amount (decimal string, full precision) |
asset | Asset symbol (e.g. USDT, MATIC) |
txId | Onchain transaction hash — use for idempotency |
chain | Provider chain id (e.g. polygon-mainnet) |
network | Chain family (EVM | BTC | TRON | SOLANA | XRPL) |
walletId | Wallet identifier in the registry |
type | native | token |
OTC Webhook (otc.trade.settled, otc.trade.failed)
Sent when an OTC trade (see OTC) reaches a terminal state — the push alternative to polling GET /v1/otc/trades/{id}. The trade object is the request body directly. Use the trade id for idempotency.
{
"id": "a1b2c3d4-...",
"side": "BUY",
"asset": "USDT",
"quoteCurrency": "BRL",
"volume": 17912.5,
"unitPrice": 5.5825,
"totalAmount": 100000,
"walletAddress": "TXxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"walletNetwork": "TRON",
"status": "SETTLED",
"txHash": "0xabc...",
"createdAt": "2026-06-18T12:00:00.000Z",
"executedAt": "2026-06-18T12:03:00.000Z"
}On failure: "status": "FAILED", "txHash": null, "executedAt": null. For a BUY paid via QR (paymentMethod: PIX_QRCODE), failure also covers PIX_IN_EXPIRED (QR not paid in time) and PIX_IN_PAYER_MISMATCH (PIX paid by a document other than your tenant's CNPJ — refunded manually by support).
| Field | Description |
|---|---|
id | OTC trade id — matches POST /v1/otc/trades. Use for idempotency |
side | BUY (onramp) | SELL (offramp) |
asset | Traded asset (e.g. USDT) |
quoteCurrency | Fiat currency (e.g. BRL) |
volume | Crypto amount |
unitPrice | Final applied price per unit |
totalAmount | Total fiat amount |
walletAddress | Destination (BUY) / custodial source (SELL) wallet |
walletNetwork | TRON | EVM | POLYGON | ETHEREUM |
status | SETTLED | FAILED |
txHash | Onchain hash when settled; null on failure |
createdAt | When the trade was created |
executedAt | When it settled; null on failure |
The payload is provider-neutral — it never exposes the liquidity source, cost, or margin.
Retries & Security
- A delivery succeeds on any HTTP
2xxwithin 30 seconds - Failed deliveries are retried up to 3 more times with exponential backoff (1s → 2s → 4s), then marked
FAILED - Every attempt is recorded — inspect the delivery log in the BackOffice (Auditoria → Webhooks)
- Always validate
X-Webhook-Signature; respond fast (2xx) and process asynchronously - Every webhook has a poll-based counterpart (e.g.
checkOnboarding,GET /v1/otc/trades/{id}) to reconcile missed events