Webhooks
Configure signed webhook deliveries for contacts, conversations, and messages.
8 generated endpoints in this resource group.
/webhooksGet webhook settings#
Returns the current tenant webhook configuration, selected event types, and event types that can be subscribed to.
Authorization
Scheme
- bearerAuth
Required scopes
- webhook:read
Allowed roles
- owner
- admin
Read webhook settings.
Responses
- Name
200- Type
- application/json
- Description
- Webhook settings
- Name
default- Type
- application/json
- Description
- Error
Related schemas
Request
curl -X GET "https://api.flownally.com/v1/webhooks" \
-H "Authorization: Bearer {token}"Response
{
"id": "string",
"enabled": true,
"verified": true,
"url": "https://example.com",
"eventTypes": [
"contact.created"
],
"availableEventTypes": [
"contact.created"
],
"createdAt": "2026-04-27T00:00:00.000Z",
"updatedAt": "2026-04-27T00:00:00.000Z"
}/webhooksUpdate webhook settings#
Partially updates the single webhook configuration for the current tenant. Select event types from availableEventTypes.
Authorization
Scheme
- bearerAuth
Required scopes
- webhook:update
Allowed roles
- owner
- admin
Update webhook settings.
Request body
Send a application/json body. The body is required for this operation.
Optional attributes
- Name
enabled- Type
- boolean
- Description
- Optional request attribute.
- Name
url- Type
- string
- Description
- Optional request attribute.
- Name
eventTypes- Type
- array<WebhookEventType>
- Description
- Optional request attribute.
Responses
- Name
200- Type
- application/json
- Description
- Updated webhook settings
- Name
default- Type
- application/json
- Description
- Error
Related schemas
Request
curl -X PATCH "https://api.flownally.com/v1/webhooks" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"enabled": true,
"url": "https://example.com",
"eventTypes": [
"contact.created"
]
}'Response
{
"id": "string",
"enabled": true,
"verified": true,
"url": "https://example.com",
"eventTypes": [
"contact.created"
],
"availableEventTypes": [
"contact.created"
],
"createdAt": "2026-04-27T00:00:00.000Z",
"updatedAt": "2026-04-27T00:00:00.000Z"
}/webhooksDelete webhook settings#
Disables and removes the current tenant webhook configuration. Attempt logs remain visible for the retention window.
Authorization
Scheme
- bearerAuth
Required scopes
- webhook:delete
Allowed roles
- owner
- admin
Delete webhook settings.
Responses
- Name
204- Description
- Webhook settings deleted
- Name
default- Type
- application/json
- Description
- Error
Related schemas
Request
curl -X DELETE "https://api.flownally.com/v1/webhooks" \
-H "Authorization: Bearer {token}"Response
204 Webhook settings deleted/webhooks:verifyVerify webhook delivery#
Sends a signed synthetic webhook test event to the supplied URL or the saved webhook URL.
Authorization
Scheme
- bearerAuth
Required scopes
- webhook:update
Allowed roles
- owner
- admin
Verify webhook delivery.
Request body
Send a application/json body. The body is optional for this operation.
Optional attributes
- Name
url- Type
- string
- Description
- Optional request attribute.
Responses
- Name
200- Type
- application/json
- Description
- Verification result
- Name
default- Type
- application/json
- Description
- Error
Related schemas
Request
curl -X POST "https://api.flownally.com/v1/webhooks:verify" \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com"
}'Response
{
"delivered": true,
"statusCode": 0,
"error": "string"
}/webhooks/attemptsList webhook delivery attempts#
Returns newest-first webhook delivery attempts from the last 7 days. Use this for delivery debugging, not long-term audit.
Authorization
Scheme
- bearerAuth
Required scopes
- webhook:read
Allowed roles
- owner
- admin
List webhook delivery attempts.
Optional parameters
- Name
pageSize- Type
- query integer
- Description
- Values above 100 are reduced to 100; 0 or omitted uses the default (50).
- Name
pageToken- Type
- query string
- Description
- Optional parameter.
- Name
eventType- Type
- query WebhookEventName
- Description
- Optional parameter.
- Name
status- Type
- query WebhookAttemptStatus
- Description
- Optional parameter.
Responses
- Name
200- Type
- application/json
- Description
- Webhook delivery attempts
- Name
default- Type
- application/json
- Description
- Error
Related schemas
Request
curl -G "https://api.flownally.com/v1/webhooks/attempts" \
-H "Authorization: Bearer {token}" \
-d pageSize="{pageSize}" \
-d pageToken="{pageToken}" \
-d eventType="{eventType}" \
-d status="{status}"Response
{
"webhookAttempts": [
{
"id": "string",
"eventId": "string",
"eventType": {},
"status": "succeeded",
"deliveryId": "string",
"attemptNumber": 0,
"attemptedAt": "2026-04-27T00:00:00.000Z",
"responseStatus": 0,
"responseBody": "string",
"latencyMs": 0,
"errorText": "string",
"signedWithVersions": [
0
]
}
],
"nextPageToken": "string"
}/webhooks/signing-keysList webhook signing keys for the current tenant#
Returns the active and any expiring (mid-rotation) webhook signing keys. On the very first call for a tenant, a key is bootstrapped automatically and its plaintext is included in the response — exactly once. Subsequent calls return metadata only (no plaintext).
Authorization
Scheme
- bearerAuth
Required scopes
- webhook:read
Allowed roles
- owner
- admin
List webhook signing keys.
Responses
- Name
200- Type
- application/json
- Description
- List of signing keys (plaintext present only on bootstrap response)
- Name
default- Type
- application/json
- Description
- Error
Related schemas
Request
curl -X GET "https://api.flownally.com/v1/webhooks/signing-keys" \
-H "Authorization: Bearer {token}"Response
{
"keys": [
{
"id": "string",
"version": 0,
"status": "string",
"createdAt": "2026-04-27T00:00:00.000Z",
"expiresAt": "2026-04-27T00:00:00.000Z",
"last4": "string",
"plaintextKey": "string"
}
]
}/webhooks/signing-keys:rotateRotate the webhook signing key#
Generates a new signing key for webhook deliveries and demotes the previous active key to "expiring" with a 24h overlap. During the overlap, both keys are valid signers; receivers can update at their own pace. Returns the plaintext of the newly-generated key exactly once.
Authorization
Scheme
- bearerAuth
Required scopes
- webhook:update
Allowed roles
- owner
- admin
Rotate a webhook signing key.
Responses
- Name
200- Type
- application/json
- Description
- New key generated; plaintext returned exactly once
- Name
default- Type
- application/json
- Description
- Error
Related schemas
Request
curl -X POST "https://api.flownally.com/v1/webhooks/signing-keys:rotate" \
-H "Authorization: Bearer {token}"Response
{
"key": {
"id": "string",
"version": 0,
"status": "string",
"createdAt": "2026-04-27T00:00:00.000Z",
"expiresAt": "2026-04-27T00:00:00.000Z",
"last4": "string",
"plaintextKey": "string"
}
}{configured webhook URL}Webhook payloads#
Endpoint shape implemented by external webhook receivers. Return any 2xx response after accepting an event. - Delivery is at least once. Deduplicate on the `webhook-id` header, which equals the payload `id` and stays the same on every retry of an event. The body is identical on every retry. - Delivery order isn't guaranteed, even within one conversation. For `message.updated`, keep the snapshot with the highest `message.revision`. - Each attempt times out after 15 seconds. Any 2xx response acknowledges the event. Redirects aren't followed. - Timeouts, connection errors, 3xx, 408, 429 and 5xx responses are retried about 30 seconds, 5 minutes and 30 minutes after the first attempt, for 4 attempts in total. Retry times include up to 20% random jitter, and the last retry happens within 30 minutes of the first attempt. - After a 429, a `Retry-After` value in seconds makes the next attempt wait at least that long. If that is later than 30 minutes after the first attempt, the event isn't retried. - 410 and any other 4xx response stop retries for that event. - An event that isn't delivered after its last attempt isn't sent again. Flownally never disables the endpoint automatically. - `webhook-timestamp` and `webhook-signature` are generated again for each attempt. - `GET /webhooks/attempts` lists delivery attempts from the last 7 days. - Events are delivered only while the webhook is enabled and verified. Changing `url` clears `verified`; deliveries resume after `POST /webhooks:verify` succeeds for the saved URL. Events from the time in between aren't delivered later.
Authorization
Scheme
- standardWebhooks
External receiver endpoint shape for webhook events.
Required parameters
- Name
Webhook-Id- Type
- header string
- Description
- Event identifier. Equals the payload `id` and stays the same on every retry of the event. Deduplicate deliveries with this value.
- Name
Webhook-Timestamp- Type
- header integer
- Description
- Unix timestamp in seconds for this delivery attempt; it changes on each retry. Reject stale timestamps to prevent replay.
- Name
Webhook-Signature- Type
- header string
- Description
- Standard Webhooks signature header, generated for each attempt. Verify it against `webhook-id`, `webhook-timestamp`, and the exact raw request body.
Request body
Flownally sends a application/json body. The body is required for this operation.
Payload variants
- Name
contact.created- Type
- ContactCreatedWebhookEvent
- Description
- Name
contact.updated- Type
- ContactUpdatedWebhookEvent
- Description
- Name
contact.archived- Type
- ContactArchivedWebhookEvent
- Description
- Name
conversation.started- Type
- ConversationStartedWebhookEvent
- Description
- A session started in a conversation. Sent once per session, when its first customer message or human agent's message arrives. Outbound automated messages (API, journey, campaign or desk) sent while the conversation has no active session start no session; they are delivered without one. A conversation can have many sessions over its lifetime.
- Name
conversation.updated- Type
- ConversationUpdatedWebhookEvent
- Description
- An open session's status or owner changed; `changedFields` lists what changed, and changes that aren't visible in the payload (such as team access) send nothing. For example, a chatbot handing a session over to agents sends this event with `changedFields` `["status", "owner"]` and `session.status` `pending`. Starting and closing a session send `conversation.started` and `conversation.closed` instead, so `session.status` is never `closed` here.
- Name
conversation.closed- Type
- ConversationClosedWebhookEvent
- Description
- A session closed. Sent once for every session that closes; `session.started` is `false` for a session no customer or human agent wrote in. A closed session is never reopened; the next message starts a new session in the same conversation.
- Name
message.created- Type
- MessageCreatedWebhookEvent
- Description
- Name
message.updated- Type
- MessageUpdatedWebhookEvent
- Description
- Name
webhook.test- Type
- WebhookTestEvent
- Description
- Sent only by `POST /webhooks:verify` to confirm the endpoint. Respond with any 2xx. Carries no business data.
Responses
- Name
2XX- Description
- Event accepted
Payload
{
"id": "string",
"type": "contact.created",
"timestamp": "string",
"data": {
"contact": {
"id": "con_d7pibvs6gljrc2pfdc1g",
"tenantId": "tn_d7phk42ge9t9t6324f20",
"name": "Anna Kowalska",
"createdAt": "2026-04-30T09:20:00Z",
"updatedAt": "2026-04-30T10:10:00Z",
"conversations": [
{
"conversationId": "cnv_d7pigoip4tfcdebp5mlg",
"channel": "whatsapp",
"metadata": {
"phone_number": "+48123456789",
"wa_id": "48123456789"
}
}
],
"tagIds": [
"tag_d7pj8kaicb30377174j0"
],
"customFields": {
"cf_d7pgooc1v8t53cs68k5g": "customer",
"cf_d7pgpgin6fdi7ocdmdgg": "Krakow"
},
"archivedAt": null
}
}
}Response
2XX Event accepted