webhooks:write
The webhooks:write scope allows you to manage webhook subscriptions — create new subscriptions, update existing ones, delete them, and send test pings. Webhooks deliver real-time event notifications to your server via HTTPS POST requests with HMAC-SHA256 signatures.
Endpoints
| Method | Path | Description |
|---|---|---|
POST | /public/webhooks | Create a webhook subscription |
PATCH | /public/webhooks/{id} | Update a webhook subscription |
DELETE | /public/webhooks/{id} | Delete a webhook subscription |
POST | /public/webhooks/{id}/test | Send a test ping |
Create webhook subscription
POST /public/webhooks
secret used for HMAC-SHA256 signature verification. Store this secret securely — it is only returned once at creation time.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | HTTPS URL to receive webhook payloads |
events | array of strings | Yes | Event types to subscribe to (min 1) |
Available event types
| Event | Description |
|---|---|
ideacloud.completed | IdeaCloud research finished |
ideacloud.failed | IdeaCloud research failed |
content.progress | Content generation stage transition (researching, outlining, writing, finalizing) |
content.completed | Content generation finished |
content.failed | Content generation failed |
content.approval.submitted | Content submitted for approval |
content.approval.approved | Content approved by reviewer |
content.approval.rejected | Content changes requested by reviewer |
content.approval.escalated | Content approval escalated to next reviewer in round-robin queue |
content.approval.overridden | Content approval overridden by authorized user with reason |
compliance.completed | Compliance check finished |
content_tools.completed | Content tools generation finished |
inventory.description.completed | Vehicle description generated |
inventory.description.batch_completed | Batch description generation finished |
inventory.feed.updated | Inventory feed refreshed |
social.post.published | Social post published to one or more platforms |
social.post.scheduled | Social post scheduled for future publication |
social.post.failed | Social post failed to publish on one or more platforms |
social.review.created | A new social review was ingested |
social.review.updated | A social review was updated (e.g. edited or replied) |
Example
curl -X POST https://api.app.hrizn.io/v1/public/webhooks \
-H "X-API-Key: hzk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://partner.example.com/webhooks/hrizn",
"events": [
"ideacloud.completed",
"content.completed",
"compliance.completed"
]
}'
const response = await fetch("https://api.app.hrizn.io/v1/public/webhooks", {
method: "POST",
headers: {
"X-API-Key": "hzk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://partner.example.com/webhooks/hrizn",
events: [
"ideacloud.completed",
"content.completed",
"compliance.completed",
],
}),
});
const data = await response.json();
console.log(data);
import requests
response = requests.post(
"https://api.app.hrizn.io/v1/public/webhooks",
headers={
"X-API-Key": "hzk_your_key_here",
"Content-Type": "application/json",
},
json={
"url": "https://partner.example.com/webhooks/hrizn",
"events": [
"ideacloud.completed",
"content.completed",
"compliance.completed",
],
},
)
print(response.json())
$ch = curl_init("https://api.app.hrizn.io/v1/public/webhooks");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"X-API-Key: hzk_your_key_here",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"url" => "https://partner.example.com/webhooks/hrizn",
"events" => [
"ideacloud.completed",
"content.completed",
"compliance.completed",
],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Response — 201 Created
{
"data": {
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"url": "https://partner.example.com/webhooks/hrizn",
"events": [
"ideacloud.completed",
"content.completed",
"compliance.completed"
],
"secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"is_active": true,
"created_at": "2026-02-01T10:00:00Z"
}
}
The
secret is only returned when the webhook is created. Store it securely. You will need it to verify webhook signatures. See Webhook Verification for details.Status codes
| Code | Description |
|---|---|
201 | Webhook subscription created |
400 | Validation error (invalid URL, missing events, URL not HTTPS) |
401 | Missing or invalid API key |
403 | API key does not have webhooks:write scope |
429 | Rate limit exceeded |
500 | Internal server error |
Update webhook subscription
PATCH /public/webhooks/{id}
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Webhook subscription ID |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | No | New HTTPS URL for webhook delivery |
events | array of strings | No | New list of event types to subscribe to |
is_active | boolean | No | Enable or disable the webhook |
Example — Update URL and events
curl -X PATCH https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "X-API-Key: hzk_your_key_here" \
-H "Content-Type: application/json" \
-d '{
"url": "https://partner.example.com/webhooks/hrizn-v2",
"events": [
"ideacloud.completed",
"content.completed",
"compliance.completed",
"content_tools.completed"
]
}'
const response = await fetch(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
{
method: "PATCH",
headers: {
"X-API-Key": "hzk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({
url: "https://partner.example.com/webhooks/hrizn-v2",
events: [
"ideacloud.completed",
"content.completed",
"compliance.completed",
"content_tools.completed",
],
}),
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.patch(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
headers={
"X-API-Key": "hzk_your_key_here",
"Content-Type": "application/json",
},
json={
"url": "https://partner.example.com/webhooks/hrizn-v2",
"events": [
"ideacloud.completed",
"content.completed",
"compliance.completed",
"content_tools.completed",
],
},
)
print(response.json())
$ch = curl_init("https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_HTTPHEADER => [
"X-API-Key: hzk_your_key_here",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"url" => "https://partner.example.com/webhooks/hrizn-v2",
"events" => [
"ideacloud.completed",
"content.completed",
"compliance.completed",
"content_tools.completed",
],
]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Response — 200 OK
{
"data": {
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"url": "https://partner.example.com/webhooks/hrizn-v2",
"events": [
"ideacloud.completed",
"content.completed",
"compliance.completed",
"content_tools.completed"
],
"is_active": true,
"updated_at": "2026-02-01T12:00:00Z"
}
}
Example — Disable a webhook
curl -X PATCH https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "X-API-Key: hzk_your_key_here" \
-H "Content-Type: application/json" \
-d '{ "is_active": false }'
const response = await fetch(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
{
method: "PATCH",
headers: {
"X-API-Key": "hzk_your_key_here",
"Content-Type": "application/json",
},
body: JSON.stringify({ is_active: false }),
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.patch(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
headers={
"X-API-Key": "hzk_your_key_here",
"Content-Type": "application/json",
},
json={"is_active": False},
)
print(response.json())
$ch = curl_init("https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "PATCH",
CURLOPT_HTTPHEADER => [
"X-API-Key: hzk_your_key_here",
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode(["is_active" => false]),
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Response — 200 OK
{
"data": {
"id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"url": "https://partner.example.com/webhooks/hrizn-v2",
"events": [
"ideacloud.completed",
"content.completed",
"compliance.completed",
"content_tools.completed"
],
"is_active": false,
"updated_at": "2026-02-01T12:05:00Z"
}
}
Status codes
| Code | Description |
|---|---|
200 | Webhook updated |
400 | Validation error or webhook ID missing |
401 | Missing or invalid API key |
403 | API key does not have webhooks:write scope |
404 | Webhook not found or belongs to a different site |
500 | Internal server error |
Delete webhook subscription
DELETE /public/webhooks/{id}
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Webhook subscription ID |
Example
curl -X DELETE https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "X-API-Key: hzk_your_key_here"
const response = await fetch(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
{
method: "DELETE",
headers: {
"X-API-Key": "hzk_your_key_here",
},
}
);
if (response.status === 204) {
console.log("Webhook deleted");
}
import requests
response = requests.delete(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
headers={
"X-API-Key": "hzk_your_key_here",
},
)
print(response.status_code) # 204
$ch = curl_init("https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => "DELETE",
CURLOPT_HTTPHEADER => [
"X-API-Key: hzk_your_key_here",
],
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
echo $httpCode; // 204
Response — 204 No Content
No response body.
Status codes
| Code | Description |
|---|---|
204 | Webhook deleted |
400 | Webhook ID is required |
401 | Missing or invalid API key |
403 | API key does not have webhooks:write scope |
404 | Webhook not found or belongs to a different site |
500 | Internal server error |
Send test ping
POST /public/webhooks/{id}/test
test.ping event to the webhook URL. The test delivery is performed synchronously and the response includes the HTTP status and body from your endpoint.
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Webhook subscription ID |
Request body
No request body is required.Example
curl -X POST https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890/test \
-H "X-API-Key: hzk_your_key_here"
const response = await fetch(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890/test",
{
method: "POST",
headers: {
"X-API-Key": "hzk_your_key_here",
},
}
);
const data = await response.json();
console.log(data);
import requests
response = requests.post(
"https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890/test",
headers={
"X-API-Key": "hzk_your_key_here",
},
)
print(response.json())
$ch = curl_init("https://api.app.hrizn.io/v1/public/webhooks/wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890/test");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"X-API-Key: hzk_your_key_here",
],
]);
$response = curl_exec($ch);
curl_close($ch);
echo $response;
Response — 200 OK (delivery successful)
{
"data": {
"webhook_id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"delivered": true,
"response_status": 200,
"response_body": "{\"received\":true}"
}
}
Response — 200 OK (delivery failed)
{
"data": {
"webhook_id": "wh-a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"delivered": false,
"response_status": 503,
"error": "Service Unavailable"
}
}
The webhook must be active and subscribed to the
test.ping event for the test to succeed. If the webhook is inactive, a 400 Bad Request error is returned.Status codes
| Code | Description |
|---|---|
200 | Test completed (check delivered field for result) |
400 | Webhook ID missing, webhook is inactive, or not subscribed to test.ping |
401 | Missing or invalid API key |
403 | API key does not have webhooks:write scope |
404 | Webhook not found or belongs to a different site |
500 | Internal server error |
Error response — Missing scope
If your API key does not includewebhooks:write, any request to these endpoints returns:
{
"error": {
"code": "forbidden",
"message": "This API key requires one of the following scopes: webhooks:write",
"details": {
"required_scopes": ["webhooks:write"]
}
}
}
