Webhooks
In this guide, we will look at how to register and consume webhooks to integrate your app with Hub. With webhooks, your app can know when something happens in Hub, such as a transaction status change or a withdrawal being processed.
Registering webhooks
To register a webhook, you can either configure it in the Hub dashboard or use the Webhooks to register it programmatically. Whenever a relevant event occurs, Hub will send a notification to the specified URL.
Webhook headers
Every webhook request includes these headers for identification and verification:
- Name
x-webhook-signature- Type
- string
- Description
Payload signed with your webhook secret using HMAC SHA256.
- Name
x-webhook-event- Type
- string
- Description
Event type:
TRANSACTION,WITHDRAW, orDISPUTE.
- Name
x-user-reference- Type
- string
- Description
Your user reference identifier (e.g.,
U_DASHJK12390A1).
Example headers
x-webhook-signature: payload-signed-with-secret
x-webhook-event: TRANSACTION
x-user-reference: U_DASHJK12390A1
Transaction webhook
A webhook is triggered on transaction creation (initially PENDING) and on every status change.
For detailed status meanings and handling tips, see Transaction statuses.
- Name
PENDING- Type
- enum
- Description
Awaiting completion or payment confirmation.
- Name
CONFIRMED- Type
- enum
- Description
Payment authorized/cleared and funds available.
- Name
FAILED- Type
- enum
- Description
Payment attempt did not complete (invalid data, network, or processor error).
- Name
REFUNDED- Type
- enum
- Description
Full amount returned to the payer.
- Name
EXPIRED- Type
- enum
- Description
Payment window closed without completion.
- Name
DISPUTE_NEEDS_RESPONSE- Type
- enum
- Description
A dispute was opened and action from you is required.
- Name
DISPUTE_IN_REVIEW- Type
- enum
- Description
Dispute under review by the processor/network.
- Name
DISPUTE_WON- Type
- enum
- Description
Dispute resolved in your favor. Funds remain with you.
- Name
DISPUTE_LOST- Type
- enum
- Description
Dispute resolved against you. Funds debited.
Example payload
{
"data": {
"amount": 1.0,
"currency": "BRL",
"decline_reason": null,
"description": "optional",
"end_to_end": null,
"external_ref": "external_ref_order",
"magic_id": "T_123JKL114HJHDKSAH1JK23",
"payment_method": "Pix",
"qr_code": "00020101021126700014br.gov.bcb.pix0136e390c530-90e7-4ba4-9920-019dfd890bcf0208opcional52040000530398654044.005802BR5925Syfra Payments Solucoes e6009Sao Paulo610803342000622905256bce8d0e242c489bb0ac91c3263044F3B",
"requester": {
"document": "12468239008",
"email": "john.doe@example.com",
"name": "John Doe",
"phone": "11 99999-9999"
},
"movement": {
"payer": {
"name": "string",
"document": "string",
"bank": "string",
"agency": "string",
"account": "string"
},
"payee": {
"name": "string",
"document": "string",
"bank": "string",
"agency": "string",
"account": "string"
}
},
"status": "PENDING",
"created_at": "2025-12-14T01:03:06.467Z",
"updated_at": "2025-12-14T01:03:06.467Z"
},
"event": "TRANSACTION"
}
Withdrawal webhook
A webhook is triggered when a withdrawal is created (PENDING) and on every status change.
For detailed status meanings and handling tips, see Withdrawal statuses.
- Name
CREATED- Type
- enum
- Description
Withdrawal request accepted and queued.
- Name
PROCESSING- Type
- enum
- Description
Bank transfer is being executed.
- Name
CONFIRMED- Type
- enum
- Description
Transfer completed successfully.
- Name
FAILED- Type
- enum
- Description
Transfer failed (invalid key, insufficient funds, or bank error).
- Name
CANCELED- Type
- enum
- Description
Request canceled before completion.
- Name
REFUNDED- Type
- enum
- Description
Funds returned after a completed transfer (reversal).
Example payload
{
"data": {
"amount": 1.0,
"currency": "BRL",
"decline_reason": null,
"description": "optional",
"end_to_end": null,
"external_ref": "external_ref_order",
"fee": 0,
"magic_id": "cmj91whot00013k95ao1nz5lm",
"status": "CONFIRMED",
"transfer_method": "Pix",
"movement": {
"payer": {
"name": "string",
"document": "string",
"bank": "string",
"agency": "string",
"account": "string"
},
"payee": {
"name": "string",
"document": "string",
"bank": "string",
"agency": "string",
"account": "string"
}
},
"created_at": "2025-12-16T20:44:25.618+00:00",
"updated_at": "2025-12-16T20:44:25.618+00:00"
},
"event": "WITHDRAW"
}
Security
To know for sure that a webhook was, in fact, sent by Hub instead of a malicious actor, you can verify the request signature. Each webhook request contains a header named x-webhook-signature, and you can verify this signature by using your secret webhook key. The signature is an HMAC hash of the request payload hashed using your secret key. Here is an example of how to verify the signature in your app:
Verifying a request
const signature = req.headers['x-webhook-signature']
const hash = crypto.createHmac('sha256', secret).update(payload).digest('hex')
if (hash === signature) {
// Request is verified
} else {
// Request could not be verified
}
If your generated signature matches the x-webhook-signature header, you can be sure that the request was truly coming from Hub. It's essential to keep your secret webhook key safe — otherwise, you can no longer be sure that a given webhook was sent by Hub. Don't commit your secret webhook key to GitHub!