This is in beta. This is only available to Enterprise customers.
Endpoints
Adding an endpoint
In order to start listening to messages, you will need to configure your endpoints. Adding an endpoint is as simple as providing a URL that you control and selecting the event types that you want to listen to.Playground
If your endpoint isn’t quite ready to start receiving events, you can press the “with Svix Play” button to have a unique URL generated for you. You’ll be able to view and inspect webhooks sent to your Svix Play URL, making it effortless to get started.Testing endpoints
Once you’ve added an endpoint, you’ll want to make sure its working. The “Testing” tab lets you send test events to your endpoint. After sending an example event, you can click into the message to view the message payload, all of the message attempts, and whether it succeeded or failed.Events
If you don’t specify any event types, by default, your endpoint will receive all events, regardless of type. This can be helpful for getting started and for testing, but we recommend changing this to a subset later on to avoid receiving extraneous messages.Comments
Comment Annotations (Threads)
Event Type | Description |
---|---|
comment_annotation.add | When a new comment thread is created with the first comment. |
comment_annotation.assign | When a comment thread is assigned to a specific user. |
comment_annotation.status_change | When a comment thread’s status is updated (e.g., open, in progress, resolved). |
comment_annotation.priority_change | When a comment thread’s priority level is modified (e.g., P0, P1, P2, or custom priorities). |
comment_annotation.custom_list_change | When a custom list item is added to or modified on a comment thread. |
comment_annotation.subscribe | When a user subscribes to receive notifications for a comment thread. |
comment_annotation.unsubscribe | When a user unsubscribes from notifications for a comment thread. |
comment_annotation.accept | When a moderator accepts a comment thread. Only available when Moderator Mode is enabled. |
comment_annotation.reject | When a moderator rejects a comment thread. Only available when Moderator Mode is enabled. |
comment_annotation.approve | When a moderator approves a comment thread. Only available when Moderator Mode is enabled. |
comment_annotation.access_mode_change | When a comment thread’s visibility is changed between private and public access. |
Comments (Messages)
Event Type | Description |
---|---|
comment.add | When a new comment is added to a comment thread. |
comment.update | When an existing comment’s content or metadata is modified. |
comment.delete | When an existing comment is permanently removed from a thread. |
comment.reaction_add | When a user adds an emoji reaction to a specific comment. |
comment.reaction_delete | When a user removes their emoji reaction from a specific comment. |
Sample Payload
You will find the sample schema and payload in the advanced webhooks section of the console.Huddle
Event Type | Description |
---|---|
huddle.create | When a user creates a Huddle. |
huddle.join | When a user joins a Huddle. |
Payload Schema
- Default payload: WebhookV2Payload
- Encoded payload: If you have enabled payload encoding, you will receive the payload in this format: WebhookV2PayloadEncoded
- Encrypted payload: If you have enabled payload encryption, you will receive the payload in this format: WebhookV2PayloadEncrypted
Rate Limits
The rate limit is defined as a limit for the number of messages per second to send to the endpoint. After the limit is reached, requests will get throttled so to keep a consistent rate under the limit. Due to the nature of distributed systems the actual rate of messages can sometimes be slightly above the enforce rate limit. So for example, if you set a rate limit of 1,000 per seconds, an endpoint may potentially get messages at a rate of 1,050 or even higher. You can set the rate limit on each of the endpoints you create.Retries
We attempt to deliver each webhook message based on a retry schedule with exponential backoff. Each message is attempted based on the following schedule, where each period is started following the failure of the preceding attempt:- Immediately
- 5 seconds
- 5 minutes
- 30 minutes
- 2 hours
- 5 hours
- 10 hours
- 10 hours (in addition to the previous)
Indicating successful delivery
The way to indicate that a webhook has been processed is by returning a 2xx (status code 200-299) response to the webhook message within a reasonable time-frame (15s). Any other status code, including 3xx redirects are treated as failures.Failed delivery handling
After the conclusion of the above attempts the message will be marked as Failed for this endpoint, and you will get a webhook of typemessage.attempt.exhausted
notifying you of this error.
Manual retries
Use the console to manually retry each message at any time, or automatically retry (“Recover”) all failed messages starting from a given date.Transformations
Transformations are a powerful feature that allows the modification of the received webhook data in-flight. When you enable Transformations, you can write JavaScript code on the endpoints that can change a webhook’s HTTP method, target URL, and body payload. You can enable Transformations in the Advanced tab of the endpoint configuration.How to write a Transformation
We expect a Transformation to declare a function namedhandler
. We will pass a WebhookObject
to this function as its only argument, and expect the function to always return a WebhookObject
.
WebhookObject
is a JSON object containing 4 properties:
method
, a string representing the HTTP method the webhook will be sent with. It is alwaysPOST
by default, and its only valid values arePOST
orPUT
url
, a string representing the endpoint’s URL. It can be changed to any valid URL.payload
, which contains the webhook’s payload as a JSON object. It can be changed as needed.cancel
, a Boolean which controls whether or not to cancel the dispatch of a webhook. This value defaults tofalse
. Note that canceled messages appear as successful dispatches.
handler
function returns the modified WebhookObject
.
Example
Suppose that sometimes, you want to redirect webhooks to a custom URL instead of the endpoint’s defined URL. You only want to do this redirect if a custom URL is present in the webhook payload. You can write a transformation like this:Security
Verifying webhook signatures
Webhook signatures let you verify that webhook messages are actually sent by us and not a malicious actor. Each webhook call includes three headers with additional information that are used for verification:webhook-id
: the unique message identifier for the webhook message. This identifier is unique across all messages, but will be the same when the same webhook is being resent (e.g. due to a previous failure).webhook-timestamp
: timestamp in seconds since epoch.webhook-signature
: the Base64 encoded list of signatures (space delimited).
Constructing the signed content
The content to sign is composed by concatenating the id, timestamp and payload, separated by the full-stop character (.
). In code, it will look something like:
body
is the raw body of the request. The signature is sensitive to any changes, so even a small change in the body will cause the signature to be completely different. This means that you should not change the body in any way before verifying.
Determining the expected signature
We use an HMAC with SHA-256 to sign its webhooks. So to calculate the expected signature, you should HMAC thesigned_content
from above using the base64 portion of your signing secret (this is the part after the whsec_
prefix) as the key.
For example, given the secret whsec_MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw
you will want to use MfKQ9r8GKYqrTwjUPD8ILPZIo2LaLaSw
.
For example, this is how you can calculate the signature in Node.js:
webhook-signature
header.
The webhook-signature
header is composed of a list of space delimited signatures and their corresponding version identifiers. The signature list is most commonly of length one. Though there could be any number of signatures. For example:
v1,
) before verifying the signature.
Please note that to compare the signatures it’s recommended to use a constant-time string comparison method in order to prevent timing attacks.
Verify timestamp
As mentioned above, we also send the timestamp of the attempt in thewebhook-timestamp
header. You should compare this timestamp against your system timestamp and make sure it’s within your tolerance in order to prevent timestamp attacks.
Example signatures
Here is an example you can use to verify you implemented everything correctly. Please note that this may fail verification due to the timestamp being old.Additional Authentication
We sign all webhooks in order to ensure the security and authenticity of all of the webhooks being sent. This security mechanism is already sufficient (and better) than other methods such as HTTP Basic Authentication, and using an authentication token. However, some systems and IT departments have varying requirements for any HTTP request hitting their services (including webhooks), so we’ve built in support for these additional authentication modes.HTTP Basic Authentication
HTTP Basic Authentication (Basic Auth), is a common way of sending a server a pair of username and password, or more often a username and auth token. While there are different ways of passing these credentials, the simplest and most common way is by including it as part of the URL. You can add it to the URL by prefixing the URL with the username and password (or token) and the @ symbol as such:Header based authentication
Some services require specific headers to be passed in order to be processed by their load balancers or application servers. These services often require a specific authentication token passed in theAuthorization
header, but sometimes there could also be different headers and values.
You can set custom headers using the Advanced tab in the endpoint configuration.
Firewalls (IP blocking)
Many organizations have strict firewall rules for which IPs are allowed to send traffic to their systems. While this is not a very strong security mechanism on its own, it’s often useful when used in conjunction with other methods (such as webhook signatures). We only send webhooks requests from a specific set of IPs as detailed below:Static Source IP Addresses
In case your webhook receiving endpoint is behind a firewall or NAT, you may need to allow traffic from these static IP addresses.Payload Encoding
- Enable Base64 encoding for webhook payloads (disabled by default).
- Addresses issues with payloads containing HTML tags that may fail due to strict endpoint policies.
- If enabled, ensure your server can decode Base64 encoded payloads.
-
Example of decoding a Base64 encoded payload:
Payload Encryption
- Enable payload encryption for enhanced security (disabled by default).
- Configure this option in the Velt Console.
- Encryption details:
- Payload encryption: AES-256-CBC
- Key encryption: RSA with PKCS1 OAEP padding and SHA-256 hash
- Public key format:
- Provide only the base64-encoded key string, without PEM headers/footers
- Recommended key size: 2048 bits
- Example of setting up decryption for Node.js:
- Sample Encrypted Payload
- Sample Decryption Code