curl --request POST \
--url https://api.cloudtalk.io/v1/webhooks/endpoints \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"url": "https://hooks.example.com/cloudtalk",
"description": "CRM sync",
"eventTypes": [
"call.ended"
]
}
'import requests
url = "https://api.cloudtalk.io/v1/webhooks/endpoints"
payload = {
"url": "https://hooks.example.com/cloudtalk",
"description": "CRM sync",
"eventTypes": ["call.ended"]
}
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
url: 'https://hooks.example.com/cloudtalk',
description: 'CRM sync',
eventTypes: ['call.ended']
})
};
fetch('https://api.cloudtalk.io/v1/webhooks/endpoints', 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.cloudtalk.io/v1/webhooks/endpoints",
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([
'url' => 'https://hooks.example.com/cloudtalk',
'description' => 'CRM sync',
'eventTypes' => [
'call.ended'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>",
"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.cloudtalk.io/v1/webhooks/endpoints"
payload := strings.NewReader("{\n \"url\": \"https://hooks.example.com/cloudtalk\",\n \"description\": \"CRM sync\",\n \"eventTypes\": [\n \"call.ended\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Basic <encoded-value>")
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.cloudtalk.io/v1/webhooks/endpoints")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"url\": \"https://hooks.example.com/cloudtalk\",\n \"description\": \"CRM sync\",\n \"eventTypes\": [\n \"call.ended\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloudtalk.io/v1/webhooks/endpoints")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"url\": \"https://hooks.example.com/cloudtalk\",\n \"description\": \"CRM sync\",\n \"eventTypes\": [\n \"call.ended\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "ep_2nJ4qKZr8C1tY0dXwV3uFh7bM9s",
"url": "https://hooks.example.com/cloudtalk",
"description": "CRM sync",
"eventTypes": [
"call.ended"
],
"status": "enabled",
"createdAt": "2026-10-13T09:12:44Z",
"updatedAt": "2026-10-13T09:12:44Z",
"secret": "whsec_EXAMPLE_SIGNING_SECRET"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"code": "UNAUTHORIZED",
"message": "You are not authorized to access this resource."
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}<string>{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}Create a webhook endpoint
Creates an endpoint and returns it with its signing secret. This response is the only time the secret is part of the resource; read it again with GET /webhooks/endpoints/{endpointId}/secret.
The URL must be https:// and point at a public host: private, loopback and other non-public addresses, internal names and non-ASCII hosts are rejected. A company can have at most 50 endpoints, Dashboard-created ones included.
Send an Idempotency-Key to make retries safe. A retry with the same key and the same body returns the endpoint the first request created (201), even when the company has since reached the endpoint limit. The same key with a different body is rejected with 422. After the endpoint is deleted, the key creates a new one.
curl --request POST \
--url https://api.cloudtalk.io/v1/webhooks/endpoints \
--header 'Authorization: Basic <encoded-value>' \
--header 'Content-Type: application/json' \
--data '
{
"url": "https://hooks.example.com/cloudtalk",
"description": "CRM sync",
"eventTypes": [
"call.ended"
]
}
'import requests
url = "https://api.cloudtalk.io/v1/webhooks/endpoints"
payload = {
"url": "https://hooks.example.com/cloudtalk",
"description": "CRM sync",
"eventTypes": ["call.ended"]
}
headers = {
"Authorization": "Basic <encoded-value>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Basic <encoded-value>', 'Content-Type': 'application/json'},
body: JSON.stringify({
url: 'https://hooks.example.com/cloudtalk',
description: 'CRM sync',
eventTypes: ['call.ended']
})
};
fetch('https://api.cloudtalk.io/v1/webhooks/endpoints', 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.cloudtalk.io/v1/webhooks/endpoints",
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([
'url' => 'https://hooks.example.com/cloudtalk',
'description' => 'CRM sync',
'eventTypes' => [
'call.ended'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Basic <encoded-value>",
"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.cloudtalk.io/v1/webhooks/endpoints"
payload := strings.NewReader("{\n \"url\": \"https://hooks.example.com/cloudtalk\",\n \"description\": \"CRM sync\",\n \"eventTypes\": [\n \"call.ended\"\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Basic <encoded-value>")
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.cloudtalk.io/v1/webhooks/endpoints")
.header("Authorization", "Basic <encoded-value>")
.header("Content-Type", "application/json")
.body("{\n \"url\": \"https://hooks.example.com/cloudtalk\",\n \"description\": \"CRM sync\",\n \"eventTypes\": [\n \"call.ended\"\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.cloudtalk.io/v1/webhooks/endpoints")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Basic <encoded-value>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"url\": \"https://hooks.example.com/cloudtalk\",\n \"description\": \"CRM sync\",\n \"eventTypes\": [\n \"call.ended\"\n ]\n}"
response = http.request(request)
puts response.read_body{
"id": "ep_2nJ4qKZr8C1tY0dXwV3uFh7bM9s",
"url": "https://hooks.example.com/cloudtalk",
"description": "CRM sync",
"eventTypes": [
"call.ended"
],
"status": "enabled",
"createdAt": "2026-10-13T09:12:44Z",
"updatedAt": "2026-10-13T09:12:44Z",
"secret": "whsec_EXAMPLE_SIGNING_SECRET"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"code": "UNAUTHORIZED",
"message": "You are not authorized to access this resource."
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}<string>{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}{
"error": {
"code": "<string>",
"message": "<string>",
"details": [
{
"code": "<string>",
"message": "<string>",
"target": "<string>"
}
],
"target": "<string>"
},
"requestId": "<string>"
}Authorizations
HTTP Basic Authentication. Use your API Access Key ID as the username and your API Access Key Secret as the password. Generate keys in the CloudTalk Dashboard under Account -> Settings -> API Keys (https://dashboard.cloudtalk.io/menu/account/settings/API-keys).
Headers
Free text up to 255 characters naming this create. See the operation description.
255Body
https:// URL on a public host whose name ends in a public top-level domain.
2048500Event types to receive (see List webhook event types). Omit or send null for every event type. An empty list is rejected.
1Response
The created endpoint, with its signing secret.
"ep_2nJ4qKZr8C1tY0dXwV3uFh7bM9s"
As stored; the host may come back lowercased and a bare host with a trailing slash.
Subscribed event types, sorted. null means every event type, including ones added later.
disabled: turned off by you (Dashboard or API). failing: turned off automatically after repeated delivery failures; it may be re-enabled automatically, or by you.
enabled, disabled, failing Only in the create response: the signing secret (whsec_...). Absent if it could not be read; then use the secret endpoint.