Skip to content

Create a webhook

POST
/organization_webhooks
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.

Auth
Access key
Roles
Owner / Custom
Media typeapplication/json
object
name
required

Shown in the webhook list. Must contain at least one letter, digit, punctuation mark or symbol.

string
>= 1 characters <= 255 characters

Example

CRM sync
url
required

Your endpoint. It must use https, be at most 2048 characters and carry no credentials (no user name or password).

string
<= 2048 characters /^https:\/\//

Example

https://hooks.customer.example/retorio
subscribedEvents
required
Array<string>
>= 1 items
Allowed values: coaching.result.available
customHeaders

At 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.

Array<object>
<= 10 items
object
name
required

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.

string
>= 1 characters <= 255 characters /^[!#$%&'*+.^_`|~0-9A-Za-z-]+$/

Example

Authorization
value

The 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.

string
>= 1 characters <= 4096 characters

Example

Bearer <your endpoint token>
isEnabled
boolean
default: true
POST
{$request.body#/url}

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.

X-Retorio-Signature
required
string

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.

X-Retorio-Timestamp
required
string

Unix time in seconds at which this attempt was signed.

X-Retorio-Delivery-Id
required
string

Stable across retries of the same event. Deduplicate on it.

X-Retorio-Event-Type
required
string

The event type, the same as eventType in the body.

User-Agent
required
string

Retorio-Webhooks/<version>, the Retorio version that sent it.

X-Retorio-Api-Env
required
string

The Retorio environment that sent the request, for example prod or staging.

X-Retorio-Api-Version
required
string

The Retorio version that sent the request.

X-Retorio-Api-Deployment
required
string

The Retorio deployment that sent the request. Together with the environment, it tells deliveries from different Retorio systems apart on one endpoint.

traceparent
string

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.

Media typeapplication/json
One of:
object
version
required
number
Allowed values: 1
eventId
required
string
>= 1 characters <= 255 characters
occurredAt
required
string format: date-time
organization
required
object
extId
required
string
>= 1 characters <= 255 characters
name
required
string
eventType
required
string
Allowed values: coaching.result.available
data
required
object
user
required
object
extId
required
string
>= 1 characters <= 255 characters
identifierType
required
string
Allowed values: email token
identifier
required
string
cohort
required
object
extId
required
string
>= 1 characters <= 255 characters
name
required
string
program
required
object
extId
required
string
>= 1 characters <= 255 characters
name
required
string
scenario
required
object
extId
required
string
>= 1 characters <= 255 characters
name
required
string
session
required
object
extId
required
string
>= 1 characters <= 255 characters
createdAt
required
string format: date-time
trainingTimeSeconds
required
integer
nullable
practiceTimeSeconds
required
integer
nullable
pausedTimeSeconds
required
integer
nullable
overallScore
required
number
<= 1

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.

Created

Media typeapplication/json
object
extId
required
string
<= 64 characters
isEnabled
required
boolean
name
required
string
url
required
string
customHeaderNames
required
Array<string>
customHeadersUnreadable
required

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.

boolean
subscribedEvents
required
Array<string>
Allowed values: coaching.result.available
lastChangedAt
required
string format: date-time
lastChangedBy
required
string
hasBeenEdited
required
boolean
signingSecret

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.

string

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.

Media typeapplication/json
Any of:
object
message
required
string
status
required

Canonical error name, e.g. INVALID_ARGUMENT.

string
details
nullable

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.

Media typeapplication/json
object
message
required
string
status
required

Canonical error name, e.g. INVALID_ARGUMENT.

string
details
nullable

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.

Media typeapplication/json
Any of:
object
message
required
string
status
required

Canonical error name, e.g. INVALID_ARGUMENT.

string
details
nullable

Example generated

{
"message": "example",
"status": "example",
"details": "example"
}

The request body is larger than 10 MB.

Media typeapplication/json
object
statusCode
required
integer
message
required
string
error
required

The HTTP reason phrase, e.g. Bad Request.

string

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.

Media typeapplication/json
object
statusCode
required
integer
message
required
string
error
required

The HTTP reason phrase, e.g. Bad Request.

string

Example generated

{
"statusCode": 1,
"message": "example",
"error": "example"
}

Internal Server Error

Media typeapplication/json
object
key
additional properties
nullable

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.