Skip Navigation Links

Webhooks

Flip provides webhooks for event-driven integrations.

Webhooks are used by integrations to subscribe to a range of event types and receive webhook messages when these events are happening on the Flip platform. For example, a chat bot application would subscribe to chat.message.sent events and receive a webhook message whenever a new chat message was sent to it.

Getting Started

In order to use webhooks, you have to be admin of an instance of Flip and have a server that can receive webhook messages via HTTPS. Setting up a new webhook requires these steps:

  1. create an API client in the web admin console, and ensure it has the WEBHOOK_MANAGEMENT permission
  2. retrieve an access token (see API Authentication)
  3. register a new webhook (see Webhook API)

Webhook Subscriptions

You can subscribe to multiple different event types, but for each webhook you have to subscribe to at least one. The subscribed event types are specified during webhook registration.

Event types use hierarchical identifiers, e.g. chat.message.sent. An event type specification can match exactly one event type, or it can match a prefix of multiple event types. For example, chat would match any event type of the Chat domain, and chat.message would match any event type related to Chat Messages.

A subscription can contain multiple event type specifications. For example, a chat bot that handles onboarding can subscribe to channel.member.added to track new employees, and to chat.message.sent in order to exchange chat messages with them.

Receiving Messages

When you subscribe to events with a webhook, Flip will send you messages to the registered URL. To receive a webhook message, we suggest these steps:

  1. Check if the request comes with all expected message headers: webhook-id, webhook-timestamp, and webhook-signature.
  2. Ignore the message, if you already processed a message with the same webhook-id.
  3. Check webhook-timestamp to make sure the message is no older (or younger) than five minutes.
  4. Check webhook-signature to ensure the message is authentic.
  5. Check the tenant field in the message body, if you write a multi-tenant integration.
  6. Consume the events in the message body.

In return for this, you get two amazing delivery guarantees:

  • Reliability: Flip will retry delivery of messages if a delivery attempt fails or times out. In consequence, please expect the same message to be sent more than once.
  • Ordering: Flip will maintain the order of events during delivery. In consequence, Flip will not send more than one message at the same time for the same subscription. Unless the events of the previous message are delivered, the following events are retained in a buffer.

Message ID and Deduplication

You can use the webhook-id header to check if you already processed a message. In case of a downtime or network issue, a message could be delivered more than once to ensure that you actually received them (reliability guarantee).

Message Timestamps

Flip updates the message timestamp in the webhook-timestamp header every time it attempts to deliver the message. The timestamp should never deviate more than a few minutes from your system time. If a timestamp is more than five minutes in the past or future, drop the message. It could be forged or an attempt at a replay attack. An authentic message will be re-delivered with an updated timestamp.

Message Signatures

The webhook-signature header contains one or more base64-encoded HMAC-SHA256 signatures of the message content. If there is more than one signature, each is separated with a space character. A signature is prefixed with v1 to indicate that we currently use a symmetric encryption scheme. Use the Webhook API to obtain the shared secret used to sign the message. Shared secrets are prefixed whsec_ and base64-encoded. The signed content consists of the dot-separated webhook-id, webhook-timestamp, and the JSON-serialized payload (e.g. 9b3999bf-291b-44a3-a409-de1e247eb301.1730192335.{"items":[{"id":"283…).

Here is how we calculate the signature in Kotlin:

Here is an example of signed content:

84476261-219f-4f3c-9a3d-4184567c98dd.1745936362.{
  "id" : "84476261-219f-4f3c-9a3d-4184567c98dd",
  "items" : [ {
    "type" : "my.event.type",
    "data" : "SampleEvent123",
    "timestamp" : "2025-04-29T14:19:22.403Z"
  } ],
  "recipient" : "633e26c2-fa98-4773-8f35-e70dce70b6c5",
  "tenant" : "your-company"
}

With a key of whsec_VGhpcyBpcyBhIHNlY3JldCBrZXkgdXNlZCB0byBzaWduIHdlYmhvb2sgbWVzc2FnZXMh, the signature for this message is v1,lKU3+t3uPFkG8HCe3Z26GMvbY2/ecF/TG7BaDbil3Xc=.

Tenant and Recipient

The message body contains two additional fields:

  • tenant contains the name of the Flip tenant for which the webhook was registered.
  • recipient contains the Flip user ID of the API client that registered the webhook.

You can use these fields to validate requests or debug issues in multi-tenant integrations.

Consuming Events

In general Webhook endpoints should react fast. Webhook messages can contain several hundred events and deliveries should not time out. We recommend receiving a message and putting the events in a local database or queue for subsequent processing.

Response Codes

Flip looks at the HTTP response code to decide if a message was delivered.

  • Any 2xx response code means the message was successfully received by the subscriber.
  • Any 5xx response means temporary failure and Flip will retry to deliver the same message multiple times.
  • Any 4xx response is treated as an unrecoverable error and will pause the webhook.
  • Any 3xx response is treated as an unrecoverable error and will pause the webhook.

Paused webhooks have to be reactivated via API call before they will resume delivery.

Webhook States

You can inspect the status of a webhook by listing webhooks via the Webhook API.

Webhooks can have any of the following states:

  • ACTIVE: The webhook will deliver messages with new events immediately.
  • FAILING: An attempt to deliver a previous message failed. Flip will retry to deliver the message at next_retry for a limited number of times over 3 days. Events are retained during that time, so no information is lost. The webhook is deactivated once retry attempts are exhausted.
  • PAUSED: The webhook is not delivering messages until it is resumed by an API call. Webhooks can be paused via API (to delay delivery, e.g. during a maintenance window). Flip pauses a webhook when delivering a message leads to an unrecoverable error (e.g. a 4xx response from the registered URL). Events are retained while the webhook is paused, so no information is lost. A paused webhook will be deactivated after 3 days.
  • INACTIVE: The webhook is not delivering messages, and new events are not retained. Inactive webhooks will be deleted after 7 days, unless they are reactivated via API.

Security

Flip sends webhook messages to the URL provided on registration via HTTPS. Messages are cryptographically signed for authentication. Message content is not encrypted. We rely on the encrypted tunnel HTTPS provides. Flip will not accept webhook registrations for HTTP URLs.

Access and Visibility

Only API clients can currently register webhooks. In general, webhooks can only receive events that are also visible to the subscribing API client (limited visibility). For example, an API client that is not a member of a group chat will not receive an event when a user sends a message to that group. We recommend to create API clients that are regular users instead of admins.

Some events do not or not yet have a natural receiver and are instead published to any subscribing webhook from the same tenant (global visibility). This applies, for example, to auditing events. Subscription to globally visible events will potentially give an API client broad access to data and should be considered carefully.

List of Event Types

Channels

Event TypeDescriptionVisibility
channel.member.addedA member was removed from a channel that the API client is a member of.Limited
channel.member.removedA member was added to a channel that the API client is a member of.Limited

Chat

Event TypeDescriptionVisibility
chat.message.sentA chat message was sent to the API client.Limited

HR Absences

Event TypeDescriptionVisibility
hr.absence.requestedA user requested time off.Global

User Attribute Definitions

Event TypeDescriptionVisibility
user.attribute-definition.createdA user attribute definition was created.Global
user.attribute-definition.deletedA user attribute definition was deleted.Global