Create an event subscription
const url = 'https://api.getsitecontrol.com/v1/sites/1/event-subscriptions';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"example","events":["example"],"filter":{"widget_ids":[1]},"url":"example","method":"POST","format":"json","headers":[{"name":"example","value":"example","is_secret":false}],"body":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.getsitecontrol.com/v1/sites/1/event-subscriptions \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "example", "events": [ "example" ], "filter": { "widget_ids": [ 1 ] }, "url": "example", "method": "POST", "format": "json", "headers": [ { "name": "example", "value": "example", "is_secret": false } ], "body": "example" }'Creates an active event subscription and returns it with its signing secret. The secret is shown in this response only: keep it to verify the webhook-signature header (Standard Webhooks, HMAC-SHA256); a lost secret means deleting the event subscription and creating it again. With an Idempotency-Key the stored response, secret included, is kept for 24 hours.
The receiver can be any HTTP API: url, headers and the body template take the request it expects, e.g. a Slack, Telegram or Airtable call.
Event types and their payloads come from list_event_types. The payload follows the request’s GSC-Version, kept as api_version. Only events that happen after creation are sent; earlier data comes from the responses and contacts lists. Before saving, preview_new_event_subscription shows the exact request on a sample. A site holds at most 20 event subscriptions, inactive ones included. Rights follow the data an event subscription sends out: response.created needs the widgets and contacts sections, contact.created the contacts section. Reading needs view of each, changing edit.
Authorizations
Section titled “Authorizations”Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Header Parameters
Section titled “Header Parameters”Makes a retry of a POST safe: a repeat with the same key, body and GSC-Version returns the stored response with Idempotency-Replayed: true instead of running again. The key protects against repeated execution while the key store works. Saving the change and storing the response under the key are not atomic: if the process or the key store fails between them, the change is kept, the key is released after 15 minutes and a retry runs the request again. After a timeout or a 5xx, read the resource to check the result before retrying. 5xx and 429 responses and responses over 256 KB are not stored, so a repeat runs the request again. A key is kept for 24 hours. The same key with another body or version is 422; a repeat while the first request runs is 409.
Makes a retry of a POST safe: a repeat with the same key, body and GSC-Version returns the stored response with Idempotency-Replayed: true instead of running again. The key protects against repeated execution while the key store works. Saving the change and storing the response under the key are not atomic: if the process or the key store fails between them, the change is kept, the key is released after 15 minutes and a retry runs the request again. After a timeout or a 5xx, read the resource to check the result before retrying. 5xx and 429 responses and responses over 256 KB are not stored, so a repeat runs the request again. A key is kept for 24 hours. The same key with another body or version is 422; a repeat while the first request runs is 409.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Your label for the event subscription, at most 100 characters
1 or 2 distinct event types from list_event_types: response.created, a widget response became active; contact.created, a contact was created by a widget submit or through the public API
Which widgets’ responses are sent; every widget by default
object
Only responses of these widgets (ids from list_widgets), at most 100; empty means every widget. Only with response.created
Receiver URL: https only, at most 2000 characters, a public host. Placeholders such as {{ response.fields.email.value }} are allowed in the path and query, never in the scheme, host or port; their values are percent-encoded. Everyone who may read the event subscription sees the URL in full: put secrets in secret headers, not in the URL
HTTP method of the request
Json: an application/json body; form: an application/x-www-form-urlencoded body, the default payload flattened into keys when there is no template
Up to 20 headers sent with every request. Credentials of the receiver go here as secret headers, e.g. {"name": "Authorization", "value": "Bearer ...", "is_secret": true}; a secret value reads ***
object
Header name, e.g. Authorization. Host, Content-Length, Transfer-Encoding, Connection, User-Agent and webhook-* are set by the sender. A Content-Type replaces the one of format
Sent as is, no placeholders; at most 4096 characters, no line breaks. On update, *** in a secret header keeps its stored value
True for credentials: the value is stored encrypted, reads *** everywhere and is masked in the journal
Null sends the default payload of the event (its schema is in list_event_types). Otherwise a JSON object or array sent instead, its strings filled from the event, e.g. {"text": "New lead {{ response.fields.email.value }} from {{ widget.name }}"}. Roots: event, site, contact; for response.created also response (an answer is response.fields.<name>.value), widget and query. A string that is exactly one placeholder keeps the value’s type (number, boolean, list). Filters: default, join, date, lower, upper, url_encode, e.g. {{ contact.first_name | default: '' }}. Keys with dots or dashes: response.fields['first-name'].value. No placeholders in object keys. With format: form the template is a flat object of scalars. At most 16 KB and 10 levels deep; the sent body at most 64 KB. Check it with preview_new_event_subscription or preview_event_subscription
Responses
Section titled “Responses”object
Your label for the event subscription
Event types it sends
object
Only responses of these widgets (ids from list_widgets), at most 100; empty means every widget. Only with response.created
Receiver URL; placeholders are filled for each event
HTTP method of the request
Json: an application/json body; form: an application/x-www-form-urlencoded body, the default payload flattened into keys when there is no template
object
Header name, e.g. Authorization. Host, Content-Length, Transfer-Encoding, Connection, User-Agent and webhook-* are set by the sender. A Content-Type replaces the one of format
Sent as is, no placeholders; at most 4096 characters, no line breaks. On update, *** in a secret header keeps its stored value
True for credentials: the value is stored encrypted, reads *** everywhere and is masked in the journal
Body template; null sends the default payload
Version of the payload sent: the GSC-Version of the request that created the event subscription; changes only with update_event_subscription
True: sends events; false: sends nothing, and deliveries still waiting are cancelled
Last real delivery accepted by the receiver; tests not counted
Last real delivery that failed for good; tests not counted. A failing receiver never disables the event subscription
Null when created with an API key or by Support
object
Null for Support or for a user who was deleted
Null when the user has no name
The user’s sign-in e-mail; null for Support
Signing secret (whsec_...), shown only here: keep it to verify the webhook-signature header
{ "method": "POST", "format": "json", "headers": [ { "is_secret": false } ]}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
True when the response is a stored one, replayed
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
Authentication scheme: Bearer
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
event_subscription_limit_reached: the site already holds 20 event subscriptions; delete one first. idempotency_in_progress: a request with the same Idempotency-Key is still running
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
validation_failed: every problem of the configuration at once, each with its loc in the body and a message, e.g. an unknown event type, a widget not found, a header the sender sets, a URL that is not public https or a template error
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds
Seconds until the bucket refills
temporarily_unavailable: secrets, limits or idempotency keys cannot be handled right now; retry later
The documented shape of every error body on the versioned surface.
object
object
{ "type": "example", "title": "example", "status": 1, "detail": "example", "instance": "example", "reason": "example", "next": "example", "request_id": "example", "errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ], "metadata": {}}Headers
Section titled “Headers”API version the response was produced for
Request id, echoed from the request when valid
Limit of the tightest bucket
Requests left in its window
End of its window, epoch seconds