Send Test Webhook
curl --request POST \
--url https://app.tuco.ai/api/webhooks/{id}/test \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"event": "<string>",
"variant": "<string>"
}
'import requests
url = "https://app.tuco.ai/api/webhooks/{id}/test"
payload = {
"event": "<string>",
"variant": "<string>"
}
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({event: '<string>', variant: '<string>'})
};
fetch('https://app.tuco.ai/api/webhooks/{id}/test', 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://app.tuco.ai/api/webhooks/{id}/test",
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([
'event' => '<string>',
'variant' => '<string>'
]),
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://app.tuco.ai/api/webhooks/{id}/test"
payload := strings.NewReader("{\n \"event\": \"<string>\",\n \"variant\": \"<string>\"\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://app.tuco.ai/api/webhooks/{id}/test")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"event\": \"<string>\",\n \"variant\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/webhooks/{id}/test")
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 \"event\": \"<string>\",\n \"variant\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"status": 123,
"statusText": "<string>",
"latency": 123,
"body": "<string>",
"results": [
{}
]
}Webhooks
Send Test Webhook
Send a realistic, signed test event to your Tuco webhook: heartbeat, message sent (attachment, voice note, P2P SMS), reply, fallback and more.
POST
/
api
/
webhooks
/
{id}
/
test
Send Test Webhook
curl --request POST \
--url https://app.tuco.ai/api/webhooks/{id}/test \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"event": "<string>",
"variant": "<string>"
}
'import requests
url = "https://app.tuco.ai/api/webhooks/{id}/test"
payload = {
"event": "<string>",
"variant": "<string>"
}
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({event: '<string>', variant: '<string>'})
};
fetch('https://app.tuco.ai/api/webhooks/{id}/test', 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://app.tuco.ai/api/webhooks/{id}/test",
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([
'event' => '<string>',
'variant' => '<string>'
]),
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://app.tuco.ai/api/webhooks/{id}/test"
payload := strings.NewReader("{\n \"event\": \"<string>\",\n \"variant\": \"<string>\"\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://app.tuco.ai/api/webhooks/{id}/test")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"event\": \"<string>\",\n \"variant\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://app.tuco.ai/api/webhooks/{id}/test")
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 \"event\": \"<string>\",\n \"variant\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"ok": true,
"status": 123,
"statusText": "<string>",
"latency": 123,
"body": "<string>",
"results": [
{}
]
}Sends a test event to your webhook endpoint, signed with your webhook secret exactly like a live delivery. Each test payload is built by the same code that builds live webhooks, so a test that passes means your parser handles the real event.
Tests are marked with the
X-Tuco-Test: true header and "testMode": true in the body. They appear in the delivery log and never count as failures on your webhook.
Authentication
Authorization: Bearer tuco_xxxxxxxxxxxxx
Path parameters
string
required
Webhook ID.
Body
Send no body to test every event the webhook subscribes to (one request per event).string
Send only this event. Any event below, including
heartbeat, even if the webhook is not subscribed to it.string
Payload variant for the event. Defaults to the first variant listed for that event.
event | variant (first is the default) |
|---|---|
heartbeat | default |
message.sent | text, attachment, pdf, link, voice_note, p2p_sms |
message.reply | text, attachment, pdf, voice_note |
message.failed | strike_2, expired |
message.fallback | default |
message.opened | default |
message.reaction | default |
message.ai_draft | default |
message.ai_draft_approved | default |
message.ai_draft_rejected | default |
conversation.handover | default |
call.recording.ready | default |
Response
boolean
true when every test got a 2xx.number
Your endpoint’s HTTP status for the first failing test, or the last test.
string
Status text, or
Timeout (10s) / the network error.number
Milliseconds for that request.
string
First 500 characters of your endpoint’s last response.
array
One entry per test:
event, variant, ok, status, statusText, latency.| Status | When |
|---|---|
200 | Tests were sent (check ok for your endpoint’s result) |
400 | Unknown event or variant, invalid JSON, or the webhook is inactive |
401 | Missing or invalid API key |
404 | Webhook not found in your workspace |
Examples
curl -X POST "https://app.tuco.ai/api/webhooks/680a1b2c3d4e5f6789012345/test" \
-H "Authorization: Bearer tuco_xxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"event": "message.sent", "variant": "p2p_sms"}'
{
"event": "heartbeat",
"testMode": true,
"timestamp": "2026-10-15T21:26:17.747Z",
"workspaceId": "org_xxx",
"data": {}
}
{
"event": "message.sent",
"timestamp": "2026-10-15T21:26:17.748Z",
"workspaceId": "org_xxx",
"leadId": "7e57ab1e0000000000000001",
"lead": {
"_id": "7e57ab1e0000000000000001",
"firstName": "Test",
"lastName": "Contact",
"email": "test.contact@example.com",
"phone": "+15551234567",
"companyName": "Test Co",
"listId": "7e57ab1e0000000000000004",
"workspaceId": "org_xxx",
"source": "api",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
},
"messageId": "7e57ab1e0000000000000002",
"message": {
"_id": "7e57ab1e0000000000000002",
"message": "This is a test webhook from Tuco. If you see this, your endpoint is working correctly.",
"messageType": "imessage",
"direction": "sent",
"recipientPhone": "+15551234567",
"recipientName": "Test Contact",
"fromLineId": "7e57ab1e0000000000000003",
"fromLinePhone": "+15557654321",
"fromLineEmail": "line@example.com",
"leadId": "7e57ab1e0000000000000001",
"source": "api",
"workspaceId": "org_xxx",
"createdByUserId": "user_test",
"status": "sent",
"externalMessageId": "TEST-0000-0000-0000-000000000001",
"createdAt": "2026-10-15T21:26:17.748Z",
"updatedAt": "2026-10-15T21:26:17.748Z",
"sentAt": "2026-10-15T21:26:17.748Z",
"smsForwarded": true,
"smsForwardedAt": "2026-10-15T21:26:17.748Z",
"smsForwardedMethod": "apple-script"
},
"contactOwnerEmail": null,
"ghlContactId": null,
"ghlLocationId": null,
"hsPortalId": null,
"hsContactId": null,
"channel": "p2p_sms",
"data": {},
"testMode": true
}
{
"event": "message.reply",
"timestamp": "2026-10-15T21:26:17.749Z",
"workspaceId": "org_xxx",
"leadId": "7e57ab1e0000000000000001",
"lead": {
"_id": "7e57ab1e0000000000000001",
"firstName": "Test",
"lastName": "Contact",
"email": "test.contact@example.com",
"phone": "+15551234567",
"companyName": "Test Co",
"listId": "7e57ab1e0000000000000004",
"workspaceId": "org_xxx",
"source": "api",
"createdAt": "2026-01-01T00:00:00.000Z",
"updatedAt": "2026-01-01T00:00:00.000Z"
},
"messageId": "7e57ab1e0000000000000006",
"message": "",
"firstName": "Test",
"lastName": "Contact",
"phone": "+15551234567",
"listId": "7e57ab1e0000000000000004",
"fromLineId": "7e57ab1e0000000000000003",
"recipientName": "Test Contact",
"contactOwnerEmail": null,
"repliedAtUtc": "2026-10-15T21:26:17.748Z",
"parentMessages": [],
"ghlContactId": null,
"ghlLocationId": null,
"hsPortalId": null,
"hsContactId": null,
"optedOut": false,
"attachmentUrls": [
"https://example.private.blob.vercel-storage.com/tuco-test/photo.jpeg"
],
"attachmentDownloadUrls": [
"https://app.tuco.ai/api/attachments/crm-media/photo.jpeg?u=aHR0cHM6Ly9leGFtcGxlLnByaXZhdGUuYmxvYi52ZXJjZWwtc3RvcmFnZS5jb20vdHVjby10ZXN0L3Bob3RvLmpwZWc&exp=1794691577749&sig=T4YoMYGXdllKOG1bS-yVmbdD9njn-gfW98c4Gi3SA2M"
],
"attachmentNames": [
"photo.jpeg"
],
"data": {
"reply": {
"leadId": "7e57ab1e0000000000000001",
"messageId": "7e57ab1e0000000000000006",
"respondedAtUtc": "2026-10-15T21:26:17.748Z",
"recipientPhone": "+15551234567",
"name": "Test Contact",
"recentReplies": [],
"parentMessages": [],
"attachmentUrls": [
"https://example.private.blob.vercel-storage.com/tuco-test/photo.jpeg"
],
"attachmentDownloadUrls": [
"https://app.tuco.ai/api/attachments/crm-media/photo.jpeg?u=aHR0cHM6Ly9leGFtcGxlLnByaXZhdGUuYmxvYi52ZXJjZWwtc3RvcmFnZS5jb20vdHVjby10ZXN0L3Bob3RvLmpwZWc&exp=1794691577749&sig=T4YoMYGXdllKOG1bS-yVmbdD9njn-gfW98c4Gi3SA2M"
],
"attachmentNames": [
"photo.jpeg"
]
},
"repliedAtUtc": "2026-10-15T21:26:17.748Z",
"parentMessages": []
},
"testMode": true
}