Webhook endpoints
Register, change, test and delete webhooks through the API, and read the deliveries of a webhook.
These operations manage the webhooks themselves. What a webhook sends, how to verify it and how it retries is in
Webhooks. All of them need the admin role; creating, changing and testing also need the plan
feature feature.webhooks.
| Field | Type | Meaning |
|---|---|---|
id |
string | The id of the webhook |
url |
string | Where deliveries are sent |
events |
array | The event names it receives. Empty means every event |
active |
boolean | A paused webhook receives nothing |
created_at |
string | ISO 8601, UTC |
last_status |
integer or null | The HTTP status your endpoint gave to the latest delivery |
last_error |
string or null | Why the latest delivery failed |
last_delivery_at |
string or null | When the latest delivery ended |
secret |
string | The key of the signature. Only in the answer of POST /api/webhooks |
| Field | Type | Meaning |
|---|---|---|
id |
integer | The delivery id, as sent in X-HTS-Delivery |
event |
string | The event name |
status_code |
integer or null | The HTTP status of the last attempt. null when no answer was received |
error |
string or null | Why it failed: the start of your endpoint's answer, or a general reason |
attempts |
integer | How many attempts were made |
created_at |
string | ISO 8601, UTC |
POST /api/webhooks
Changes data in your account when executed. The answer contains secret, the key of the X-HTS-Signature header. It is shown only here. Leave events empty to receive every event. The URL must be https and resolve to a public address. Needs the admin role.
Request body (application/json)
| Name | Type | Required | Description |
|---|---|---|---|
url |
string | Yes | Up to 2083 characters |
events |
string[] | No | Empty = all events |
Returns 200 with a JSON object, as in the example.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl -X POST "https://htspilot.com/api/webhooks" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-H "Content-Type: application/json" \
-d '{
"url": "https://erp.example.com/hooks/hts-pilot",
"events": []
}'import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/webhooks",
data=json.dumps({"url": "https://erp.example.com/hooks/hts-pilot", "events": []}).encode(),
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/webhooks", {
method: "POST",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
"url": "https://erp.example.com/hooks/hts-pilot",
"events": []
}),
});
console.log(await response.json());200{
"id": "95defe1a0b1c4da08d52f19beabb9377",
"url": "https://erp.example.com/hooks/hts-pilot",
"events": [],
"active": true,
"created_at": "2026-10-03T16:07:51.275351+00:00",
"last_status": null,
"last_error": null,
"last_delivery_at": null,
"secret": "0123456789abcdef0123456789abcdef0123456789abcdef"
}
GET /api/webhooks
Needs the admin role.
Returns 200 with a JSON object, as in the example.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/webhooks" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/webhooks",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/webhooks", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200[
{
"id": "95defe1a0b1c4da08d52f19beabb9377",
"url": "https://erp.example.com/hooks/hts-pilot",
"events": [],
"active": true,
"created_at": "2026-10-03T16:07:51.275351",
"last_status": 200,
"last_error": null,
"last_delivery_at": "2026-10-03T16:07:52.722883"
}
]
PATCH /api/webhooks/{hook_id}
Changes data in your account when executed. Needs the admin role.
Path parameters
| Name | Type | Description |
|---|---|---|
hook_id |
string | - |
Request body (application/json)
| Name | Type | Required | Description |
|---|---|---|---|
url |
string or null | No | Up to 2083 characters |
events |
string[] or null | No | - |
active |
boolean or null | No | - |
Returns 200 with a JSON object, as in the example.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
Send only what changes. A new url is checked like a new webhook. The secret cannot be changed here; to rotate it,
delete the webhook and register it again.
curl -X PATCH "https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME" \
-H "Content-Type: application/json" \
-d '{
"active": false
}'import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377",
data=json.dumps({"active": False}).encode(),
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"], "Content-Type": "application/json"},
method="PATCH",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377", {
method: "PATCH",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({
"active": false
}),
});
console.log(await response.json());200{
"id": "95defe1a0b1c4da08d52f19beabb9377",
"url": "https://erp.example.com/hooks/hts-pilot",
"events": [],
"active": false,
"created_at": "2026-10-03T16:07:51.275351",
"last_status": 200,
"last_error": null,
"last_delivery_at": "2026-10-03T16:07:52.722883"
}
DELETE /api/webhooks/{hook_id}
Deletes for real when executed, and cannot be undone. Needs the admin role.
Path parameters
| Name | Type | Description |
|---|---|---|
hook_id |
string | - |
Returns 200 with a JSON object, as in the example.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl -X DELETE "https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="DELETE",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377", {
method: "DELETE",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200{
"ok": true
}
POST /api/webhooks/{hook_id}/test
Changes data in your account when executed. Sends the event ping now, with the same body shape, headers and signature as a real event, and answers with the result. Needs the admin role.
Path parameters
| Name | Type | Description |
|---|---|---|
hook_id |
string | - |
Returns 200 with a JSON object, as in the example.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
ok is true when your endpoint answered 2xx.
curl -X POST "https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377/test" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377/test",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="POST",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377/test", {
method: "POST",
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200{
"ok": true,
"id": "95defe1a0b1c4da08d52f19beabb9377",
"url": "https://erp.example.com/hooks/hts-pilot",
"events": [],
"active": true,
"created_at": "2026-10-03T16:07:51.275351",
"last_status": 200,
"last_error": null,
"last_delivery_at": "2026-10-03T16:07:52.722883"
}
GET /api/webhooks/{hook_id}/deliveries
Needs the admin role.
Path parameters
| Name | Type | Description |
|---|---|---|
hook_id |
string | - |
Returns 200 with a JSON object, as in the example.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377/deliveries" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377/deliveries",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/webhooks/95defe1a0b1c4da08d52f19beabb9377/deliveries", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200[
{
"id": 7,
"event": "ping",
"status_code": 200,
"error": null,
"attempts": 1,
"created_at": "2026-10-03T16:07:52.719008"
},
{
"id": 6,
"event": "lookup.completed",
"status_code": 200,
"error": null,
"attempts": 1,
"created_at": "2026-10-03T16:07:52.493249"
}
]
GET /api/webhooks/events
Needs the admin role.
Returns 200 with a JSON object, as in the example.
Errors: 401 No valid API key was sent; 403 The role of the key, or the plan of the account, does not allow this call; 422 The request is not valid; 500 An unexpected failure.
curl "https://htspilot.com/api/webhooks/events" \
-H "X-API-Key: hts_EXAMPLE_KEY_REPLACE_ME"import json
import os
import urllib.request
request = urllib.request.Request(
"https://htspilot.com/api/webhooks/events",
headers={"X-API-Key": os.environ["HTS_PILOT_API_KEY"]},
method="GET",
)
with urllib.request.urlopen(request) as response:
print(json.load(response))const response = await fetch("https://htspilot.com/api/webhooks/events", {
headers: { "X-API-Key": process.env.HTS_PILOT_API_KEY },
});
console.log(await response.json());200{
"lookup.completed": "A lookup finished",
"lookup.decided": "A reviewer approved / overrode / rejected a code",
"batch.completed": "A batch file finished processing",
"tariff.changed": "A new tariff version and code changes were detected",
"sku.alert": "A SKU is affected by a tariff change"
}