Create a webhook
const url = 'https://api.retorio.com/be/v2/organization_webhooks';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"name":"CRM sync","url":"https://hooks.customer.example/retorio","subscribedEvents":["coaching.result.available"],"customHeaders":[{"name":"Authorization","value":"Bearer <your endpoint token>"}],"isEnabled":true}'};
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.retorio.com/be/v2/organization_webhooks \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "name": "CRM sync", "url": "https://hooks.customer.example/retorio", "subscribedEvents": [ "coaching.result.available" ], "customHeaders": [ { "name": "Authorization", "value": "Bearer <your endpoint token>" } ], "isEnabled": true }'Creates a webhook and its first configuration version. The response includes the signingSecret in plaintext (returned only here and by an update that rotates it), so store it immediately: it is required to verify the X-Retorio-Signature header on every delivery. An organization may have at most 5 webhooks, disabled ones included.
Authentication
Section titled “Authentication”- Auth
- Access key
- Roles
- Owner / Custom
Request Bodyrequired
Section titled “Request Bodyrequired”object
Shown in the webhook list. Must contain at least one letter, digit, punctuation mark or symbol.
Example
CRM syncYour endpoint. It must use https, be at most 2048 characters and carry no credentials (no user name or password).
Example
https://hooks.customer.example/retorioAt most 10 headers, sent with every delivery. Together they may take at most 8192 bytes, counting each as <name>: <value>\r\n, stored values included.
object
A valid HTTP header name, unique within the set regardless of case. Names starting with X-Retorio- and these are reserved: connection, content-encoding, content-length, content-type, expect, host, keep-alive, proxy-authenticate, proxy-authorization, te, trailer, transfer-encoding, upgrade, user-agent.
Example
AuthorizationThe header value, sent exactly as given. At most 4096 characters of printable ASCII or tab, with no line breaks. Leave it out on an update to keep the value stored under this name, so a credential you cannot read back is kept. Leaving it out for a name that is not stored, or on create, is a 400.
Example
Bearer <your endpoint token>Callbacks
Section titled “Callbacks”coaching.result.available
Section titled “coaching.result.available”Retorio sends this request to the URL you configured, signed with your webhook’s signingSecret. A receiver needs four of the request headers below: X-Retorio-Signature and X-Retorio-Timestamp to verify the request, X-Retorio-Delivery-Id to deduplicate it and X-Retorio-Event-Type to route it. The others identify the sender or the trace. Your custom headers are sent too, except one whose name matches an X-Retorio- header, Content-Type or User-Agent. Delivery is at-least-once: deduplicate on X-Retorio-Delivery-Id. A coaching result is first sent at least five and a half minutes after it is ready, at the next delivery run after that delay, so that its session times are final.
Parameters
Section titled “Parameters”Header Parameters
Section titled “Header Parameters”v1,<base64 HMAC-SHA256> of <X-Retorio-Timestamp>.<raw body>, keyed with the webhook’s signing secret. The HMAC key is the full signingSecret string exactly as returned, whsec_ prefix included, taken as UTF-8 bytes. Do not strip the prefix or base64-decode it.
Unix time in seconds at which this attempt was signed.
Stable across retries of the same event. Deduplicate on it.
The event type, the same as eventType in the body.
Retorio-Webhooks/<version>, the Retorio version that sent it.
The Retorio environment that sent the request, for example prod or staging.
The Retorio version that sent the request.
The Retorio deployment that sent the request. Together with the environment, it tells deliveries from different Retorio systems apart on one endpoint.
Usually present. A standard W3C trace ID that lets Retorio find this delivery in its logs, so include it when you report a problem. Your endpoint can ignore it.
Request Bodyrequired
Section titled “Request Bodyrequired”object
object
object
object
object
object
object
object
object
object
object
Responses
Section titled “Responses”Any 2xx response acknowledges the delivery. The response body does not affect the outcome. Requests time out after 10 seconds. A timeout, no response, a 5xx, a 408 or a 429 is retried with backoff for roughly a day. Any other 4xx, and any 3xx (redirects are not followed), is treated as a refusal and is not retried.
Responses
Section titled “Responses”Created
object
True when the stored custom headers cannot be decrypted, in which case customHeaderNames is empty. While it is true, every delivery to this webhook, the test event included, fails and is not retried. Repair it with an update that sends every header with its value, or customHeaders: []. An entry without a value cannot be kept from an unreadable set, and the update answers 400.
The secret that signs every delivery, returned only by create and by an update with rotateSigningSecret: true. The HMAC key is the full signingSecret string exactly as returned, whsec_ prefix included, taken as UTF-8 bytes. Do not strip the prefix or base64-decode it.
Example
{ "subscribedEvents": [ "coaching.result.available" ]}The configuration is not valid (see the request fields), a custom header entry without a value names no stored header or the stored headers cannot be read, the custom headers exceed 8192 bytes once merged, your organization already has 5 webhooks (create only), or this environment cannot store webhook credentials. Also answered when the request body is not valid JSON.
object
Canonical error name, e.g. INVALID_ARGUMENT.
object
The HTTP reason phrase, e.g. Bad Request.
Example generated
{ "message": "example", "status": "example", "details": "example"}Not authenticated: the bearer token is missing, malformed, expired or revoked, its sign-in method does not match your organization’s configuration, the user it belongs to was removed, or your organization is deactivated.
object
Canonical error name, e.g. INVALID_ARGUMENT.
Example generated
{ "message": "example", "status": "example", "details": "example"}Refused: the token does not belong to an admin, or the admin’s roles do not grant webhooks:manage.
object
Canonical error name, e.g. INVALID_ARGUMENT.
object
The HTTP reason phrase, e.g. Bad Request.
Example generated
{ "message": "example", "status": "example", "details": "example"}The request body is larger than 10 MB.
object
The HTTP reason phrase, e.g. Bad Request.
Example generated
{ "statusCode": 1, "message": "example", "error": "example"}The Content-Type charset or the Content-Encoding is one the API cannot decode. Send UTF-8 JSON without a content encoding.
object
The HTTP reason phrase, e.g. Bad Request.
Example generated
{ "statusCode": 1, "message": "example", "error": "example"}Internal Server Error
object
Example generated
{ "additionalProperty": "example"}Retorio is GDPR and DSGVO compliant, EU AI Act aligned, ISO 27001 certified, and hosted on Google Cloud with EU data residency. For anything specific to your rollout, ask your Retorio contact.