Setup
curl --request POST \
--url https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"events": [
"<string>"
],
"url": "<string>",
"secret": "<string>",
"account_id": 123
}
'import requests
url = "https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks"
payload = {
"events": ["<string>"],
"url": "<string>",
"secret": "<string>",
"account_id": 123
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({events: ['<string>'], url: '<string>', secret: '<string>', account_id: 123})
};
fetch('https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'events' => [
'<string>'
],
'url' => '<string>',
'secret' => '<string>',
'account_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks"
payload := strings.NewReader("{\n \"events\": [\n \"<string>\"\n ],\n \"url\": \"<string>\",\n \"secret\": \"<string>\",\n \"account_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"events\": [\n \"<string>\"\n ],\n \"url\": \"<string>\",\n \"secret\": \"<string>\",\n \"account_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"events\": [\n \"<string>\"\n ],\n \"url\": \"<string>\",\n \"secret\": \"<string>\",\n \"account_id\": 123\n}"
response = http.request(request)
puts response.read_body{
"account_id": 4521,
"events": ["payin", "payout"],
"url": "https://my-url.requestcatcher.com/test",
"secret": "whsec_9f8e7d6c5b4a3210"
}
{
"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."
}
]
}
{
"error_code": "validation",
"error_description": "Validation error",
"fields": {
"events.1": ["A webhook for this event already exists for this account."]
},
"field_errors": [
{
"field": "events.1",
"code": "webhook_already_exists",
"params": [],
"message": "A webhook for this event already exists for this account."
}
]
}
{
"error_code": "validation",
"error_description": "Validation error",
"fields": {
"url": ["A webhook with this URL already exists for this account."]
},
"field_errors": [
{
"field": "url",
"code": "webhook_url_already_exists",
"params": [],
"message": "A webhook with this URL already exists for this account."
}
]
}
{
"success": false,
"error": {
"code": "unauthorized",
"message": "Invalid API key provided"
}
}
Webhook
Setup
Register a webhook URL and the events it receives
POST
/
v2
/
register
/
companies
/
webhooks
Setup
curl --request POST \
--url https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"events": [
"<string>"
],
"url": "<string>",
"secret": "<string>",
"account_id": 123
}
'import requests
url = "https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks"
payload = {
"events": ["<string>"],
"url": "<string>",
"secret": "<string>",
"account_id": 123
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({events: ['<string>'], url: '<string>', secret: '<string>', account_id: 123})
};
fetch('https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'events' => [
'<string>'
],
'url' => '<string>',
'secret' => '<string>',
'account_id' => 123
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks"
payload := strings.NewReader("{\n \"events\": [\n \"<string>\"\n ],\n \"url\": \"<string>\",\n \"secret\": \"<string>\",\n \"account_id\": 123\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"events\": [\n \"<string>\"\n ],\n \"url\": \"<string>\",\n \"secret\": \"<string>\",\n \"account_id\": 123\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.sandbox.wepayout.com.br/v2/register/companies/webhooks")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"events\": [\n \"<string>\"\n ],\n \"url\": \"<string>\",\n \"secret\": \"<string>\",\n \"account_id\": 123\n}"
response = http.request(request)
puts response.read_body{
"account_id": 4521,
"events": ["payin", "payout"],
"url": "https://my-url.requestcatcher.com/test",
"secret": "whsec_9f8e7d6c5b4a3210"
}
{
"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."
}
]
}
{
"error_code": "validation",
"error_description": "Validation error",
"fields": {
"events.1": ["A webhook for this event already exists for this account."]
},
"field_errors": [
{
"field": "events.1",
"code": "webhook_already_exists",
"params": [],
"message": "A webhook for this event already exists for this account."
}
]
}
{
"error_code": "validation",
"error_description": "Validation error",
"fields": {
"url": ["A webhook with this URL already exists for this account."]
},
"field_errors": [
{
"field": "url",
"code": "webhook_url_already_exists",
"params": [],
"message": "A webhook with this URL already exists for this account."
}
]
}
{
"success": false,
"error": {
"code": "unauthorized",
"message": "Invalid API key provided"
}
}
Setup
The system allows the registration of webhook URLs to receive automatic notifications about relevant events. A webhook is one URL that receives one or more events: send every event the URL should receive in theevents list.
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
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.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.
Subaccounts without a webhook
A subaccount without its own webhook uses the webhook of its main account. For the
payin, payout and kyc events, when a subaccount has no webhook registered for the event, its notifications are delivered to the webhook its main account registered for that same event — to the main account’s URL, signed with the main account’s secret.- The fallback is decided per event: a subaccount with its own
payinwebhook and nopayoutwebhook receivespayinon its own URL andpayouton the main account’s. - Only when neither the subaccount nor its main account has a webhook for the event are the notifications sent to the transaction’s
notification_url(payinandpayout) or to the KYC callback URL configured by our Customer Experience team (kyc). - The
onboardingevent has no fallback: it is always delivered to theonboardingwebhook of the account that requested the onboarding.
account_id.Request Body
string[]
required
Events this webhook will receive. Send at least one event, without repeating any.Allowed values:
onboarding, payin, payout, kyconboarding: notifications about the account onboarding status. Sent without thex-webhook-wp-typeheader.payin: notifications about Payin status changes (Pix — including Pix key credits and Automatic Pix —, Boleto, Credit Card and refunds).x-webhook-wp-typevalues:payin-pix: status update of a Pix Payin (including Automatic Pix and Pix key credits)payin-boleto: status update of a Boleto Payinpayin-credit-card: status update of a Credit Card Payinpayin-refund: refund of a received Pix Payin, requested by the merchant
payout: notifications about Payout status changes, refunds and Data Qualifications.x-webhook-wp-typevalues:payout-pix: status update of a Pix Payoutpayout-ted: status update of a TED Payoutpayout-qrcode: status update of a Pix QR Code Payoutpayout-refund: Pix Payout returned to the merchantpayout-customer-refund: status update of a customer refund (Reembolso) paid out to your customerpayout-data-qualification: status update of a Data Qualification
kyc: notifications about KYC status changes. See KYC Webhook.x-webhook-wp-typevalue:kyc: status update of a KYC
422 and the webhook_already_exists code on that item (for example events.1) — move the event with Update instead.Example: ["payin", "payout"]string
required
Endpoint URL that will receive the notifications of every event in
events. The URL identifies the webhook: use it to update or remove the webhook later.Each URL can be registered only once per account (URLs that differ only in letter case count as the same URL). Registering a URL that the target account already has fails with 422 and the webhook_url_already_exists code — add the new events to the existing webhook with Update instead.Maximum length: 120 charactersExample: https://my-url.com/teststring
Secret used to sign the
payin, payout and kyc webhooks with HMAC-SHA256. When provided, every webhook delivered to this URL includes the x-webhook-wp-signature header.Maximum length: 255 characters. Use a long, randomly generated value.Example: whsec_9f8e7d6c5b4a3210integer
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: 4521Response
integer
ID of the account the webhook was registered for.Example:
4521string[]
Events the webhook receives.Allowed values:
onboarding, payin, payout, kycExample: ["payin", "payout"]string
Endpoint URL that was registered to receive webhook notifications.Example:
https://my-url.requestcatcher.com/teststring
Secret used to sign the webhooks delivered to this URL, or
null if none is set.Example: whsec_9f8e7d6c5b4a3210Request Example
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 '{
"events": ["payin", "payout"],
"url": "https://my-url.requestcatcher.com/test",
"secret": "whsec_9f8e7d6c5b4a3210",
"account_id": 4521
}'
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({
events: ['payin', 'payout'],
url: 'https://my-url.requestcatcher.com/test',
secret: 'whsec_9f8e7d6c5b4a3210',
account_id: 4521
})
});
const data = await response.json();
console.log(data);
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 = {
'events': ['payin', 'payout'],
'url': 'https://my-url.requestcatcher.com/test',
'secret': 'whsec_9f8e7d6c5b4a3210',
'account_id': 4521
}
response = requests.post(url, json=data, headers=headers)
print(response.json())
{
"account_id": 4521,
"events": ["payin", "payout"],
"url": "https://my-url.requestcatcher.com/test",
"secret": "whsec_9f8e7d6c5b4a3210"
}
{
"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."
}
]
}
{
"error_code": "validation",
"error_description": "Validation error",
"fields": {
"events.1": ["A webhook for this event already exists for this account."]
},
"field_errors": [
{
"field": "events.1",
"code": "webhook_already_exists",
"params": [],
"message": "A webhook for this event already exists for this account."
}
]
}
{
"error_code": "validation",
"error_description": "Validation error",
"fields": {
"url": ["A webhook with this URL already exists for this account."]
},
"field_errors": [
{
"field": "url",
"code": "webhook_url_already_exists",
"params": [],
"message": "A webhook with this URL already exists for this account."
}
]
}
{
"success": false,
"error": {
"code": "unauthorized",
"message": "Invalid API key provided"
}
}
Webhook Payload
When an onboarding event occurs, a POST request will be sent to your webhook URL:{
"id": "1234-5678-90ab-cdef-1234567890ab",
"status": "active",
"updated_at": "2024-01-15T10:30:00Z",
"account_id": 123
}
The account_id is only returned the first time in the webhook when the status is active.
When the new Onboarding Documents Flow is enabled for a merchant, the payload for the
pending_documents status also includes a documents array with the documents the client must send.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.Was this page helpful?

