curl --request POST \
--url https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret', 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.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret",
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: Bearer <token>"
],
]);
$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.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
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.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"agent_ids": [
"3f1c1b2e-6d1a-4c0e-9b2f-1a2b3c4d5e6f"
],
"created_at": "2026-09-10T14:00:00Z",
"description": "Production",
"enabled": true,
"events": [
"call.started",
"call.ended",
"call.analyzed"
],
"id": "b7e1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"secret": "whsec_x9K2mQ7vR4tL8nP1sW5yB3dF6hJ0k9Qz",
"secret_hint": "k9Qz",
"updated_at": "2026-09-10T14:00:00Z",
"url": "https://example.com/webhooks/contour"
}{
"detail": "Invalid or expired API key"
}{
"detail": "Webhook endpoint not found."
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"ctx": {},
"input": "<unknown>"
}
]
}Rotate the signing secret
Replace the signing secret.
The new secret is shown in this response only. The old one stops working immediately, so update your handler’s configuration before calling this.
curl --request POST \
--url https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret \
--header 'Authorization: Bearer <token>'import requests
url = "https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret"
headers = {"Authorization": "Bearer <token>"}
response = requests.post(url, headers=headers)
print(response.text)const options = {method: 'POST', headers: {Authorization: 'Bearer <token>'}};
fetch('https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret', 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.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret",
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: Bearer <token>"
],
]);
$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.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret"
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("Authorization", "Bearer <token>")
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.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret")
.header("Authorization", "Bearer <token>")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.contourvoice.com/v1/webhook-endpoints/{endpoint_id}/rotate-secret")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
response = http.request(request)
puts response.read_body{
"agent_ids": [
"3f1c1b2e-6d1a-4c0e-9b2f-1a2b3c4d5e6f"
],
"created_at": "2026-09-10T14:00:00Z",
"description": "Production",
"enabled": true,
"events": [
"call.started",
"call.ended",
"call.analyzed"
],
"id": "b7e1c2d3-4f5a-4b6c-8d7e-9f0a1b2c3d4e",
"secret": "whsec_x9K2mQ7vR4tL8nP1sW5yB3dF6hJ0k9Qz",
"secret_hint": "k9Qz",
"updated_at": "2026-09-10T14:00:00Z",
"url": "https://example.com/webhooks/contour"
}{
"detail": "Invalid or expired API key"
}{
"detail": "Webhook endpoint not found."
}{
"detail": [
{
"loc": [
"<string>"
],
"msg": "<string>",
"type": "<string>",
"ctx": {},
"input": "<unknown>"
}
]
}Authorizations
Your organization's API key (sk_cont_...), sent as Authorization: Bearer sk_cont_.... Keep it server-side.
Path Parameters
Response
Successful Response
Returned by create and rotate-secret only. secret is shown once.
False while deliveries are paused.
Subscribed events.
Endpoint id; use it in every other endpoint call.
The signing secret (whsec_...). Shown in this response only; store it in your webhook handler's configuration.
The last four characters of the signing secret, so you can tell which secret an endpoint is using without exposing it.
Where events are delivered.
Agent filter, or null for all calls in the organization.
Your label.