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, or DISPUTE.

  • 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.

  • 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.

  • 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!

Was this page helpful?