> ## Documentation Index
> Fetch the complete documentation index at: https://docs.wepayout.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Setup

> Register a webhook URL to receive automatic notifications about relevant events

# Setup

The system allows the registration of webhook URLs to receive automatic notifications about relevant events.

**Webhook URL:** HTTPS address where the events will be delivered.\
**Supported events:** onboarding, payin, payout, kyc\
**Notification format:** JSON payload sent via HTTP request\
**Request method:** All notifications will be sent exclusively using the POST method

<Danger>
  **The registered URL overrides the URL sent in each request.** Once a webhook is registered for the `payin` or `payout` event, **every** webhook of that event is delivered to the registered URL, and the `notification_url` / `callback_url` sent when creating a transaction is **ignored**. The same applies to all Payin and Payout webhooks — status updates, refunds and Data Qualifications. The URL sent in the request is only used when no webhook is registered for the event.

  For the `kyc` event, the registered URL replaces the KYC callback URL previously configured by our Customer Experience team.

  Registered deliveries are sent with the `x-webhook-wp-type` and `x-webhook-wp-timestamp` headers (plus `x-webhook-wp-signature` when a `secret` is set). See [Webhook Signature](/concepts/webhooks).
</Danger>

<Warning>
  Registering, updating or removing a webhook may take up to **5 minutes** to take effect. Until then, webhooks keep being delivered to the previous destination.
</Warning>

## Request Body

<ParamField body="event" type="string" required>
  Type of event that will trigger the webhook.

  Allowed values: `onboarding`, `payin`, `payout`, `kyc`

  * `onboarding`: notifications about the account onboarding status. Sent without the `x-webhook-wp-type` header.
  * `payin`: notifications about Payin status changes (Pix — including Pix key credits and Automatic Pix —, Boleto, Credit Card and refunds). `x-webhook-wp-type` values:
    * `payin-pix`: status update of a Pix Payin (including Automatic Pix and Pix key credits)
    * `payin-boleto`: status update of a Boleto Payin
    * `payin-credit-card`: status update of a Credit Card Payin
    * `payin-refund`: refund of a received Pix Payin, requested by the merchant
  * `payout`: notifications about Payout status changes, refunds and Data Qualifications. `x-webhook-wp-type` values:
    * `payout-pix`: status update of a Pix Payout
    * `payout-ted`: status update of a TED Payout
    * `payout-qrcode`: status update of a Pix QR Code Payout
    * `payout-refund`: Pix Payout returned to the merchant
    * `payout-customer-refund`: status update of a customer refund (Reembolso) paid out to your customer
    * `payout-data-qualification`: status update of a Data Qualification
  * `kyc`: notifications about KYC status changes. See [KYC Webhook](/api-reference/kyc/webhook). `x-webhook-wp-type` value:
    * `kyc`: status update of a KYC

  See [Webhook types](/concepts/webhooks#webhook-types) for details.

  Only one webhook can be registered per event **per account**: the same event can be registered on your merchant and on each of its subaccounts. Registering an event that the target account already has fails with `422` and the `webhook_already_exists` code — use [Update](/api-reference/account/webhook/webhook-update) instead.

  Example: `payin`
</ParamField>

<ParamField body="url" type="string" required>
  Endpoint URL that will receive the webhook notifications for the selected event.

  URL characters: `a-z`, `A-Z` characters

  Maximum length: 120 characters

  Example: `https://my-url.com/test`
</ParamField>

<ParamField body="secret" type="string">
  Secret used to sign the `payin`, `payout` and `kyc` webhooks with [HMAC-SHA256](/concepts/webhooks#hmac-sha256-signature). When provided, every webhook for this event includes the `x-webhook-wp-signature` header.

  Maximum length: 255 characters. Use a long, randomly generated value.

  Example: `whsec_9f8e7d6c5b4a3210`
</ParamField>

<ParamField body="account_id" type="integer">
  ID of the account the webhook will be registered for: your own merchant or one of its subaccounts. Use it to register the webhooks of a subaccount with your own credentials.

  When omitted, the webhook is registered for **your merchant** (the authenticated account).

  If the account does not exist or is not linked to your merchant, the request fails with `422` and the `invalid_account` code.

  Example: `4521`
</ParamField>

## Response

<ResponseField name="account_id" type="integer">
  ID of the account the webhook was registered for.

  Example: `4521`
</ResponseField>

<ResponseField name="event" type="string">
  Type of event that will trigger the webhook.

  Allowed values: `onboarding`, `payin`, `payout`, `kyc`

  Example: `payin`
</ResponseField>

<ResponseField name="url" type="string">
  Endpoint URL that was registered to receive webhook notifications.

  Example: `https://my-url.requestcatcher.com/test`
</ResponseField>

<ResponseField name="secret" type="string">
  Secret used to sign the webhooks for this event, or `null` if none is set.

  Example: `whsec_9f8e7d6c5b4a3210`
</ResponseField>

## Request Example

<CodeGroup>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks \
    --header 'Accept: application/json' \
    --header 'Authorization: Bearer {token}' \
    --header 'Content-Type: application/json' \
    --data '{
      "event": "payin",
      "url": "https://my-url.requestcatcher.com/test",
      "secret": "whsec_9f8e7d6c5b4a3210",
      "account_id": 4521
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks', {
    method: 'POST',
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Bearer YOUR_TOKEN',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      event: 'payin',
      url: 'https://my-url.requestcatcher.com/test',
      secret: 'whsec_9f8e7d6c5b4a3210',
      account_id: 4521
    })
  });

  const data = await response.json();
  console.log(data);
  ```

  ```python Python theme={null}
  import requests

  url = 'https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks'
  headers = {
      'Accept': 'application/json',
      'Authorization': 'Bearer YOUR_TOKEN',
      'Content-Type': 'application/json'
  }
  data = {
      'event': 'payin',
      'url': 'https://my-url.requestcatcher.com/test',
      'secret': 'whsec_9f8e7d6c5b4a3210',
      'account_id': 4521
  }

  response = requests.post(url, json=data, headers=headers)
  print(response.json())
  ```
</CodeGroup>

<ResponseExample>
  ```json 201 Created theme={null}
  {
    "account_id": 4521,
    "event": "payin",
    "url": "https://my-url.requestcatcher.com/test",
    "secret": "whsec_9f8e7d6c5b4a3210"
  }
  ```

  ```json 422 Invalid account theme={null}
  {
    "error_code": "validation",
    "error_description": "Validation error",
    "fields": {
      "account_id": ["The account does not exist or is not linked to your merchant."]
    },
    "field_errors": [
      {
        "field": "account_id",
        "code": "invalid_account",
        "params": [],
        "message": "The account does not exist or is not linked to your merchant."
      }
    ]
  }
  ```

  ```json 422 Webhook already exists theme={null}
  {
    "error_code": "validation",
    "error_description": "Validation error",
    "fields": {
      "event": ["A webhook for this event already exists for this account."]
    },
    "field_errors": [
      {
        "field": "event",
        "code": "webhook_already_exists",
        "params": [],
        "message": "A webhook for this event already exists for this account."
      }
    ]
  }
  ```

  ```json 401 Unauthorized theme={null}
  {
    "success": false,
    "error": {
      "code": "unauthorized",
      "message": "Invalid API key provided"
    }
  }
  ```
</ResponseExample>

## Webhook Payload

When an onboarding event occurs, a POST request will be sent to your webhook URL:

```json theme={null}
{
  "id": "1234-5678-90ab-cdef-1234567890ab",
  "status": "active",
  "updated_at": "2024-01-15T10:30:00Z",
  "account_id": 123
}
```

<Info>
  The account\_id is only returned the first time in the webhook when the status is active.
</Info>

<Info>
  When the new [Onboarding Documents Flow](/api-reference/account/webhook/onboarding-documents) is enabled for a merchant, the payload for the `pending_documents` status also includes a `documents` array with the documents the client must send.
</Info>

<Note>
  Your webhook endpoint must return a `200 OK` status code to acknowledge receipt. If the endpoint fails or returns an error, delivery is retried **up to 3 times, every 15 minutes**.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.