Rotate Webhook Signing Key
curl --request POST \
--url https://api.example.com/v1/webhooks/{id}/rotate-key \
--header 'Authorization: <authorization>'import requests
url = "https://api.example.com/v1/webhooks/{id}/rotate-key"
headers = {"Authorization": "<authorization>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: '<authorization>'}};
fetch('https://api.example.com/v1/webhooks/{id}/rotate-key', 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/{id}/rotate-key",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/webhooks/{id}/rotate-key"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "<authorization>")
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/{id}/rotate-key")
.header("Authorization", "<authorization>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/webhooks/{id}/rotate-key")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant": "partner-name",
"name": "KYC Status Webhook",
"url": "https://api.partner.com/webhooks/kyc",
"apiKey": "whk_z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8d7c6b5a4z3y2x1w0v9u8",
"eventTypes": ["kyc.status.changed"],
"isActive": true,
"metadata": {},
"createdAt": "2025-12-29T10:00:00.000Z",
"updatedAt": "2025-12-29T14:00:00.000Z"
}
}
Webhooks
Rotate Webhook Signing Key
Generate a new API key for webhook signature verification
POST
/
v1
/
webhooks
/
{id}
/
rotate-key
Rotate Webhook Signing Key
curl --request POST \
--url https://api.example.com/v1/webhooks/{id}/rotate-key \
--header 'Authorization: <authorization>'import requests
url = "https://api.example.com/v1/webhooks/{id}/rotate-key"
headers = {"Authorization": "<authorization>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: '<authorization>'}};
fetch('https://api.example.com/v1/webhooks/{id}/rotate-key', 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/{id}/rotate-key",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: <authorization>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/webhooks/{id}/rotate-key"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "<authorization>")
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/{id}/rotate-key")
.header("Authorization", "<authorization>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/webhooks/{id}/rotate-key")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = '<authorization>'
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant": "partner-name",
"name": "KYC Status Webhook",
"url": "https://api.partner.com/webhooks/kyc",
"apiKey": "whk_z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8d7c6b5a4z3y2x1w0v9u8",
"eventTypes": ["kyc.status.changed"],
"isActive": true,
"metadata": {},
"createdAt": "2025-12-29T10:00:00.000Z",
"updatedAt": "2025-12-29T14:00:00.000Z"
}
}
Rotate Webhook Signing Key
POST https://api.baanx.com/v1/webhooks/{id}/rotate-key Generates a new API key for webhook signature verification and immediately invalidates the old one.Overview
Use this endpoint when you need to rotate your webhook signing key — for example, if the key has been compromised or as part of a routine key rotation policy.Immediate invalidation. The old API key is invalidated the moment this endpoint is called. Any in-flight webhooks that were signed with the old key will fail signature verification on your end.Save the new key immediately. The full API key is returned only once and cannot be retrieved again.
Authentication
This endpoint requires authentication via Bearer token:Authorization: Bearer YOUR_ACCESS_TOKEN
Request
Headers
string
required
Bearer token for authentication
Path Parameters
string (UUID)
required
Unique identifier of the webhook configuration
Request Example
curl -X POST https://api.baanx.com/v1/webhooks/550e8400-e29b-41d4-a716-446655440000/rotate-key \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const webhookId = '550e8400-e29b-41d4-a716-446655440000';
const response = await fetch(
`https://api.baanx.com/v1/webhooks/${webhookId}/rotate-key`,
{
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
}
);
const data = await response.json();
// ⚠️ Store data.data.apiKey securely - it won't be shown again
console.log(data);
import requests
webhook_id = "550e8400-e29b-41d4-a716-446655440000"
url = f"https://api.baanx.com/v1/webhooks/{webhook_id}/rotate-key"
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
response = requests.post(url, headers=headers)
data = response.json()
# ⚠️ Store data["data"]["apiKey"] securely - it won't be shown again
print(data)
const rotateWebhookKey = async (webhookId: string) => {
const response = await fetch(
`https://api.baanx.com/v1/webhooks/${webhookId}/rotate-key`,
{
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
}
}
);
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
200 Success
Store the
apiKey from the response immediately and securely. It will not be shown again.boolean
Indicates the key was rotated successfully
string
New full API key — store securely and update your webhook receiver immediately. The old key is now invalid.
object
Full webhook configuration. See Get Webhook for all field descriptions.
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"tenant": "partner-name",
"name": "KYC Status Webhook",
"url": "https://api.partner.com/webhooks/kyc",
"apiKey": "whk_z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e8d7c6b5a4z3y2x1w0v9u8",
"eventTypes": ["kyc.status.changed"],
"isActive": true,
"metadata": {},
"createdAt": "2025-12-29T10:00:00.000Z",
"updatedAt": "2025-12-29T14:00:00.000Z"
}
}
Error Responses
{
"message": "Not authenticated"
}
{
"message": "Not authorized"
}
{
"message": "Webhook config not found"
}
{
"message": "Notification service is not configured for this environment"
}
Key Rotation Checklist
Before Rotating
Before Rotating
- Ensure you have a secure place to store the new key (e.g., a secrets manager)
- Notify your team that a rotation is occurring
- Be prepared to update your webhook receiver immediately after rotation
After Rotating
After Rotating
- Immediately store the new
apiKeyfrom the response in your secrets manager - Deploy the new key to your webhook receiver
- Verify incoming webhooks are being verified correctly with the new key
- Monitor your delivery logs for any signature failures
Related Endpoints
GET /v1/webhooks/{id}- Get current webhook configurationGET /v1/webhooks/{id}/logs- Monitor delivery success after key rotationPOST /v1/webhooks- Create a new webhook (also returns a full key)
Was this page helpful?