Skip to content

Update a webhook

PUT
/organization_webhooks/{extId}
curl --request PUT \
--url https://api.retorio.com/be/v2/organization_webhooks/9d4e2b71_3c8a_4f05_b6e2_1a7c5d9e0f38 \
--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>" } ], "rotateSigningSecret": false, "isEnabled": true, "expectedLastChangedAt": "2026-04-15T12:00:00Z" }'

Updates a webhook by appending a new configuration version. The full configuration is restated on every update, not patched: customHeaders omitted keeps the stored set (credential included), [] removes every custom header, and an array that is sent is the whole set going forward. Inside a sent array, an entry with a name and no value keeps the value stored under that name, so you can keep a credential you cannot read back. An entry with no value whose name is not stored is a 400. Pass expectedLastChangedAt (the lastChangedAt you last read) to get a 409 instead of overwriting an edit made since you read it. A 409 can also answer an update that collides with a concurrent one. rotateSigningSecret: true replaces the signing secret and returns the new one once. Every receiver verifying with the old one then fails until updated.

Auth
Access key
Roles
Owner / Custom
extId
required
string

Example

9d4e2b71_3c8a_4f05_b6e2_1a7c5d9e0f38
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>
rotateSigningSecret
boolean
isEnabled
boolean
expectedLastChangedAt
string format: date-time

OK

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"
}

No webhook with this extId in your organization.

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"
}

The webhook was edited by someone else since expectedLastChangedAt, or by a concurrent update that committed first. Reload it and retry.

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