Create Webhook Endpoint
curl --request POST \
--url https://api.example.com/v1/webhooks \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"name": "<string>",
"url": "<string>",
"event_types": [
{}
],
"is_active": true,
"metadata": {}
}
'import requests
url = "https://api.example.com/v1/webhooks"
payload = {
"name": "<string>",
"url": "<string>",
"event_types": [{}],
"is_active": True,
"metadata": {}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
name: '<string>',
url: '<string>',
event_types: [{}],
is_active: true,
metadata: {}
})
};
fetch('https://api.example.com/v1/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.example.com/v1/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([
'name' => '<string>',
'url' => '<string>',
'event_types' => [
[
]
],
'is_active' => true,
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.example.com/v1/webhooks"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"event_types\": [\n {}\n ],\n \"is_active\": true,\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.example.com/v1/webhooks")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"event_types\": [\n {}\n ],\n \"is_active\": true,\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/webhooks")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"event_types\": [\n {}\n ],\n \"is_active\": true,\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant": "partner-name",
"name": "KYC Status Updates",
"url": "https://api.partner.com/webhooks/kyc",
"apiKey": "whk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2",
"eventTypes": ["kyc.status.changed"],
"isActive": true,
"metadata": {},
"createdAt": "2025-12-29T10:00:00.000Z",
"updatedAt": "2025-12-29T10:00:00.000Z"
}
}
Webhooks
Create Webhook Endpoint
Create a new webhook configuration for receiving event notifications
POST
/
v1
/
webhooks
Create Webhook Endpoint
curl --request POST \
--url https://api.example.com/v1/webhooks \
--header 'Authorization: <authorization>' \
--header 'Content-Type: <content-type>' \
--data '
{
"name": "<string>",
"url": "<string>",
"event_types": [
{}
],
"is_active": true,
"metadata": {}
}
'import requests
url = "https://api.example.com/v1/webhooks"
payload = {
"name": "<string>",
"url": "<string>",
"event_types": [{}],
"is_active": True,
"metadata": {}
}
headers = {
"Authorization": "<authorization>",
"Content-Type": "<content-type>"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: '<authorization>', 'Content-Type': '<content-type>'},
body: JSON.stringify({
name: '<string>',
url: '<string>',
event_types: [{}],
is_active: true,
metadata: {}
})
};
fetch('https://api.example.com/v1/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.example.com/v1/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([
'name' => '<string>',
'url' => '<string>',
'event_types' => [
[
]
],
'is_active' => true,
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>",
"Content-Type: <content-type>"
],
]);
$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.example.com/v1/webhooks"
payload := strings.NewReader("{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"event_types\": [\n {}\n ],\n \"is_active\": true,\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "<authorization>")
req.Header.Add("Content-Type", "<content-type>")
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.example.com/v1/webhooks")
.header("Authorization", "<authorization>")
.header("Content-Type", "<content-type>")
.body("{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"event_types\": [\n {}\n ],\n \"is_active\": true,\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/webhooks")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
request["Content-Type"] = '<content-type>'
request.body = "{\n \"name\": \"<string>\",\n \"url\": \"<string>\",\n \"event_types\": [\n {}\n ],\n \"is_active\": true,\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant": "partner-name",
"name": "KYC Status Updates",
"url": "https://api.partner.com/webhooks/kyc",
"apiKey": "whk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2",
"eventTypes": ["kyc.status.changed"],
"isActive": true,
"metadata": {},
"createdAt": "2025-12-29T10:00:00.000Z",
"updatedAt": "2025-12-29T10:00:00.000Z"
}
}
Create Webhook Endpoint
POST https://api.baanx.com/v1/webhooks Creates a new webhook configuration for receiving event notifications.Overview
Registers a new HTTPS endpoint to receive webhook deliveries. Each webhook can subscribe to one or more event types and is assigned a unique signing key for signature verification.Save the API key immediately. The full API key is returned only at creation time and cannot be retrieved again. If lost, use the Rotate Key endpoint to generate a new one.
Limits and defaults:
- Maximum of 5 webhook endpoints per partner
- New webhooks are created with
is_active: falseby default unless explicitly set - Only HTTPS URLs are accepted
Signature Verification
All webhook deliveries include HMAC-SHA256 signature headers:| Header | Description |
|---|---|
X-Timestamp | Unix timestamp of the request |
X-Signature | HMAC-SHA256 signature of {timestamp}.{body} |
HMAC-SHA256(apiKey, "{timestamp}.{body}")
Authentication
This endpoint requires authentication via Bearer token:Authorization: Bearer YOUR_ACCESS_TOKEN
Request
Headers
string
required
Bearer token for authentication
string
required
Must be
application/jsonBody
string
required
Human-readable name for the webhook (max 255 characters)
string
required
HTTPS endpoint URL for webhook delivery. Must use HTTPS.
array
required
Array of event type strings to subscribe to. Must contain at least one item.Available event types:
kyc.status.changed- User KYC verification status changedcard.activated- Card has been activatedtransaction.cleared- Transaction has been cleared
boolean
default:false
Whether to activate the webhook immediately. Defaults to
false.object
Optional custom metadata to attach to the webhook (e.g., environment tags)
Request Examples
curl -X POST https://api.baanx.com/v1/webhooks \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "KYC Status Updates",
"url": "https://api.partner.com/webhooks/kyc",
"event_types": ["kyc.status.changed"],
"is_active": true
}'
const response = await fetch('https://api.baanx.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify({
name: 'KYC Status Updates',
url: 'https://api.partner.com/webhooks/kyc',
event_types: ['kyc.status.changed'],
is_active: true
})
});
const data = await response.json();
// ⚠️ Store data.data.apiKey securely - it won't be shown again
console.log(data);
import requests
url = "https://api.baanx.com/v1/webhooks"
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN",
"Content-Type": "application/json"
}
payload = {
"name": "KYC Status Updates",
"url": "https://api.partner.com/webhooks/kyc",
"event_types": ["kyc.status.changed"],
"is_active": True
}
response = requests.post(url, headers=headers, json=payload)
data = response.json()
# ⚠️ Store data["data"]["apiKey"] securely - it won't be shown again
print(data)
interface CreateWebhookRequest {
name: string;
url: string;
event_types: string[];
is_active?: boolean;
metadata?: Record<string, unknown>;
}
const createWebhook = async (payload: CreateWebhookRequest) => {
const response = await fetch('https://api.baanx.com/v1/webhooks', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
'Content-Type': 'application/json'
},
body: JSON.stringify(payload)
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const result = await response.json();
// ⚠️ Store result.data.apiKey securely - it won't be shown again
return result;
};
Response
201 Created
Store the
apiKey from the response immediately and securely. It will not be shown again.boolean
Indicates the webhook was created successfully
string (UUID)
Unique identifier for the new webhook
string
Full API key — store securely. Used to verify webhook signatures. Not retrievable after this response.
array
Event types the webhook is subscribed to
boolean
Whether the webhook is active
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant": "partner-name",
"name": "KYC Status Updates",
"url": "https://api.partner.com/webhooks/kyc",
"apiKey": "whk_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2",
"eventTypes": ["kyc.status.changed"],
"isActive": true,
"metadata": {},
"createdAt": "2025-12-29T10:00:00.000Z",
"updatedAt": "2025-12-29T10:00:00.000Z"
}
}
Error Responses
{
"message": "Maximum webhook limit (5) reached for this tenant"
}
{
"message": "url must be an HTTPS URL"
}
{
"message": "Not authenticated"
}
{
"message": "Not authorized"
}
{
"message": "Notification service is not configured for this environment"
}
Common Error Scenarios
Webhook Limit Reached
Webhook Limit Reached
Error:
400 Bad RequestMessage: "Maximum webhook limit (5) reached for this tenant"Cause: You already have 5 webhook endpoints configured.Solution: Delete an existing webhook with DELETE /v1/webhooks/{id} before creating a new one.Non-HTTPS URL
Non-HTTPS URL
Error:
400 Bad RequestCause: The url field does not use the HTTPS scheme.Solution: Ensure your endpoint URL begins with https://.Related Endpoints
GET /v1/webhooks- List all webhook endpointsPUT /v1/webhooks/{id}- Update a webhook configurationPOST /v1/webhooks/{id}/rotate-key- Rotate the signing keyDELETE /v1/webhooks/{id}- Delete a webhook endpoint
Was this page helpful?