Create a webhook
Overview
Register a URL to receive events, choose immediate or batch delivery, and optionally filter which events you want.
Use this once per delivery type: a partner can have one immediate and one batch subscription. You'll get the signing secret in this response and nowhere else automatically; store it now.
You'll need a label, your HTTPS URL, and the delivery type (plus an interval for batch).
Returns the subscription and its secret. Deliveries start with the next matching event. Check your endpoint with Send a test event.
Prerequisites
- A Partner bearer token. See Authentication.
- Your endpoint's HTTPS URL.
- Optional: the events you want, from List the events you can subscribe to.
Base URL
| Environment | URL |
|---|---|
| Production | https://production-api.shoutaboutus.com |
| Development | https://development-api.shoutaboutus.com |
Endpoint
POST /api/v1/partner/webhooks
Authentication
Partner token
- Only partner users can call it; other tokens get
403. - The subscription is created for the partner behind the token.
Rate limit
This endpoint has no rate limit.
Request parameters
None.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
label | string | Yes | Your name for the subscription. Up to 255 characters. |
webhook_url | string | Yes | Your endpoint's HTTPS URL. Up to 2048 characters. |
delivery_kind | string | Yes | immediate (each event as it happens) or batch (one cache_invalidation ping per location per interval). You can have one of each; a second of the same kind gets 422. |
batch_interval_hours | integer | No | Hours between batches: 1, 2, 4, 6 or 12. Required when delivery_kind is batch. |
events | array of strings | No | Immediate only: the events to receive, by value from the events catalogue. Only immediate events can be picked. Left out, [] or null: all immediate events. Ignored on a batch subscription (stored as null). |
payload_mode | string | No | Immediate only: full (default; the review, who did it, and the history entry) or minimal (event name and ids only). A batch subscription is always full. |
is_active | boolean | No | Whether deliveries start now. Default true. |
Request payload
Immediate, with an event filter:
{
"label": "Production webhook",
"webhook_url": "https://partner.example.com/hooks/sau",
"delivery_kind": "immediate",
"is_active": true,
"events": [
"review_pull_connected",
"review_pull_disconnected",
"usage.limit_reached"
],
"payload_mode": "full"
}Batch, every 4 hours:
{
"label": "Nightly refresh",
"webhook_url": "https://partner.example.com/hooks/sau-batch",
"delivery_kind": "batch",
"batch_interval_hours": 4
}Response body
The payload is inside data.
| Field | Type | Description |
|---|---|---|
data | object | The new subscription. |
data.id | integer | The subscription's id (webhookSubscriptionId). |
data.partner_company_id | integer | Your partner id. |
data.label | string | Your name for the subscription. |
data.webhook_url | string | Where deliveries are sent. |
data.events | array of strings or null | The event filter. null: all immediate events. Always null on a batch subscription. |
data.payload_mode | string | full (the review, who did it, and the history entry) or minimal (event name and ids only). Always full on a batch subscription. |
data.delivery_kind | string | immediate (each event as it happens) or batch (one cache_invalidation ping per location per interval). |
data.batch_interval_hours | integer or null | Hours between batches: 1, 2, 4, 6 or 12. null on an immediate subscription. |
data.delivery_label | string | The delivery type in words: immediate, hourly batch or every N hours. |
data.last_batch_dispatched_at | string or null | When the last batch was sent (ISO 8601). Set to the creation time for a new batch subscription; null on an immediate one. |
data.is_active | boolean | Whether deliveries are being sent. |
data.hmac_secret_fingerprint | string | The first 16 characters of the SHA-256 hash of the signing secret, so you can tell which secret is current. The secret itself is never returned here. |
data.last_succeeded_at | string or null | When a delivery last succeeded (ISO 8601), or null. |
data.last_failed_at | string or null | When a delivery last failed (ISO 8601), or null. |
data.last_failure_reason | string or null | Why the last delivery failed, or null. |
data.consecutive_failure_count | integer | Failed deliveries in a row since the last success. |
data.created_at | string | When the subscription was created (ISO 8601). |
data.updated_at | string | When it last changed (ISO 8601). |
data.hmac_secret | string | The signing secret. Use it to check the X-SAU-Signature header (sha256= and the HMAC-SHA256 of the request body) on every delivery. Shown here once; store it now. |
data.hmac_secret_warning | string | A reminder to store the secret. |
Response payload
{
"data": {
"data": {
"id": 2,
"partner_company_id": 5,
"label": "Production webhook",
"webhook_url": "https://partner.example.com/hooks/sau",
"events": [
"review_pull_connected",
"review_pull_disconnected",
"usage.limit_reached"
],
"payload_mode": "full",
"delivery_kind": "immediate",
"batch_interval_hours": null,
"delivery_label": "immediate",
"last_batch_dispatched_at": null,
"is_active": true,
"hmac_secret_fingerprint": "587647e874083b23",
"last_succeeded_at": null,
"last_failed_at": null,
"last_failure_reason": null,
"consecutive_failure_count": 0,
"created_at": "2026-06-16T10:23:23+00:00",
"updated_at": "2026-06-16T10:23:23+00:00",
"hmac_secret": "<hmac-secret>",
"hmac_secret_warning": "Store this value securely — it will not be shown again. Use it to verify the X-SAU-Signature header on every incoming delivery."
}
}
}Examples
Success payload
Immediate: see Response payload.
Batch:
{
"data": {
"data": {
"id": 4,
"partner_company_id": 5,
"label": "Nightly refresh",
"webhook_url": "https://partner.example.com/hooks/sau-batch",
"events": null,
"payload_mode": "full",
"delivery_kind": "batch",
"batch_interval_hours": 4,
"delivery_label": "every 4 hours",
"last_batch_dispatched_at": "2026-06-16T10:30:00+00:00",
"is_active": true,
"hmac_secret_fingerprint": "335b947fe611b6b2",
"last_succeeded_at": null,
"last_failed_at": null,
"last_failure_reason": null,
"consecutive_failure_count": 0,
"created_at": "2026-06-16T10:30:00+00:00",
"updated_at": "2026-06-16T10:30:00+00:00",
"hmac_secret": "<hmac-secret>",
"hmac_secret_warning": "Store this value securely — it will not be shown again. Use it to verify the X-SAU-Signature header on every incoming delivery."
}
}
}Error payload
403 Not a Partner token
{
"message": "Only partner-admin users can manage webhook subscriptions.",
"status": "error",
"errors": []
}422 Missing fields
{
"message": "The label field is required. (and 2 more errors)",
"errors": {
"label": [
"The label field is required."
],
"webhook_url": [
"The webhook url field is required."
],
"delivery_kind": [
"The delivery kind field is required."
]
}
}422 Invalid values
{
"message": "The webhook url field must be a valid URL. (and 4 more errors)",
"errors": {
"webhook_url": [
"The webhook url field must be a valid URL."
],
"delivery_kind": [
"The selected delivery kind is invalid."
],
"batch_interval_hours": [
"The selected batch interval hours is invalid."
],
"payload_mode": [
"The selected payload mode is invalid."
],
"events.0": [
"The selected events.0 is invalid."
]
}
}422 Batch event on an immediate subscription
{
"message": "'review_ingested' is not individually subscribable — it is delivered folded into the batch slot's coalesced 'cache_invalidation' ping. Create a batch subscription (no event filter) to receive it.",
"errors": {
"events.0": [
"'review_ingested' is not individually subscribable — it is delivered folded into the batch slot's coalesced 'cache_invalidation' ping. Create a batch subscription (no event filter) to receive it."
]
}
}422 You already have one of this kind
{
"message": "A immediate webhook already exists for this partner. Edit the existing one or delete it first.",
"errors": {
"delivery_kind": [
"A immediate webhook already exists for this partner. Edit the existing one or delete it first."
]
}
}| Status | Meaning |
|---|---|
201 | The subscription was created; store hmac_secret now. |
401 | The token is missing, expired or invalid. |
403 | The token isn't a Partner token. |
422 | A field is missing or invalid, an event isn't in the catalogue or can't be picked, or you already have a subscription of this kind. |
500 | Unexpected server error. |
Example request
curl --request POST \
--url "https://production-api.shoutaboutus.com/api/v1/partner/webhooks" \
--header 'Authorization: Bearer <bearer-token>' \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--data '{"label": "Production webhook", "webhook_url": "https://partner.example.com/hooks/sau", "delivery_kind": "immediate", "is_active": true, "events": ["review_pull_connected", "review_pull_disconnected", "usage.limit_reached"], "payload_mode": "full"}'Updated 17 days ago
Did this page help you?
