Webhooks Overview

By using webhooks, you can tightly integrate your server application with Stream Chat. The platform supports three kinds of webhooks: Push, Before-Message-Send, and Custom Commands. All of them follow the common set of rules:

  • Webhook should be reachable from the public internet. Tunneling services like Ngrok are supported

  • Webhook should accept HTTP POST requests with JSON payload

  • Webhook should respond with response codes from 200 to 299

  • Webhook should respond as fast as possible. The exact time given for the response varies between webhook types

  • Webhook should be ready to accept the same call multiple times: in case of network or remote server failure Stream Chat could retry the request (behavior varies between webhook types)

All webhook requests contain these headers:

NameDescriptionExample
X-Webhook-IdUnique ID of the webhook call. This value is consistent between retries and could be used to deduplicate retry calls123e4567-e89b-12d3-a456-426614174000
X-Webhook-AttemptNumber of webhook request attempt starting from 11
X-Api-KeyYour application’s API key. Should be used to validate request signaturea1b23cdefgh4
X-SignatureHMAC signature of the request body. See Signature sectionca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb

Security and Performance

We highly recommend following common security guidelines to make your webhook integration safe and fast:

  • Use HTTPS with a certificate from a trusted authority (eg.Let’s Encrypt)

  • Verify the ” X-Signature ” header

  • Support HTTP Keep-Alive

  • Be highly available

  • Offload the processing of the message if possible (read, store, and forget)

Webhook types

Stream Chat supports several webhook types:

TypeDescription
PushPush webhook is useful when you want your server application to receive all important events happening in the Stream Chat
Before Message SendThis webhook allows you to modify or moderate message content before sending it to the chat for everyone to see
Custom CommandsThis webhook reacts to custom /slash commands

Please consult with corresponding pages to choose the webhook type that best fits your needs

Signature

All HTTP requests can be verified as coming from Stream (and not tampered by a 3rd party) by analyzing the signature attached to the request. Every request includes an HTTP header called “X-Signature” containing a cryptographic signature of the message. Your webhook endpoint can validate that payload and signature match:

// signature comes from the HTTP header x-signature
var valid = App.verifyWebhook(body, signature);

If your application uses more than one API Key, you can use the HTTP Header X-Api-Key to match the signature to the correct secret. Stream will always use the oldest key.

Configuration

You can configure your webhook endpoints in the Stream Chat Dashboard or by using server-side SDK client:

App
 .update()
 .webhookURL("https://example.com/webhooks/stream/push") // sets Push webhook address
 .beforeMessageSendHookUrl("https://example.com/webhooks/stream/before-message-send") // sets Before Message Send webhook address
 .customActionHandlerUrl("https://example.com/webhooks/stream/custom-commands?type={type}") // sets Custom Commands webhook address
 .request();

Also, webhooks could be configured using our CLI client:

stream chat:webhook:push --url 'https://example.com/webhooks/stream/push'
stream chat:webhook:before-message-send --url 'https://example.com/webhooks/stream/before-message-send'
stream chat:webhook:custom-commands --url 'https://example.com/webhooks/stream/custom-commands?type={type}'

See theCLI introduction for more information on the Stream CLI.

Request info

Some webhooks contain a field request_info, which holds information about the client that issued the request. This info is intended as an additional signal that you can use for moderation, fraud detection, or other similar purposes.

When configuring the SDK, you may also set an additional x-stream-ext header to be sent with each request. The value of this header is passed along as an ext field in the request_info. You can use this to pass along information that may be useful, such as device information. Refer to the SDK-specific docs on how to set this header.

"request_info": {
 "type": "client",
 "ip": "86.84.2.2",
 "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:109.0) Gecko/20100101 Firefox/117.0",
 "sdk": "stream-chat-react-10.11.0-stream-chat-javascript-client-browser-8.12.1",
 "ext": "device-id=123"
}

For example, in Javascript, you can set the value like this:

client = new StreamChat(apiKey, {
 axiosRequestConfig: {
  headers: {
   "x-stream-ext": "device-id=123"
  }
 }
});

The format of the ext header is up to you and you may leave it blank if you don’t need it. The value is passed as-is, so you can use a simple value, comma-separated key-values, or more structured data, such as JSON. Binary data must be encoded as a string, for example using base64 or hex encoding.

Restricting access to webhook

If necessary, you can only expose your webhook service to Stream. This is possible by configuring your network (eg. iptables rules) to drop all incoming traffic that is not coming from our API infrastructure.

Below you can find the complete list of egress IP addresses that our webhook infrastructure uses. Such list is static and is not changing over time.

US-EastZONE IDeip
Primaryuse1-az234.225.10.29/32
Secondaryuse1-az434.198.125.61/32
Tertiaryuse1-az352.22.78.160/32
Quaternaryuse1-az63.215.161.238/32
EU-westZONE IDeip
Primaryeuw1-az352.212.14.212/32
Secondaryeuw1-az152.17.43.232/32
Tertiaryeuw1-az234.241.110.177/32
SydneyZONE IDeip
Primaryapse2-az354.252.193.245/32
Secondaryapse2-az213.55.254.141/32
Tertiaryapse2-az13.24.48.104/32
mumbaiZONE IDeip
Primaryaps1-az165.1.48.87/32
Secondaryaps1-az315.206.221.25/32
Tertiaryaps1-az213.233.48.78/32
SingaporeZONE IDeip
Primaryapse1-az213.229.11.158/32
Secondaryapse1-az152.74.225.150/32
Tertiaryapse1-az352.76.180.70/32
OHIOZONE IDEIP
Primaryuse2-az13.14.163.216/32
Secondaryuse2-az23.15.245.3/32
Tertiaryuse2-az33.141.116.179/32
CANADAZONE IDEIP
Primarycac1-az135.183.141.98/32
Secondarycac1-az252.60.71.231/32
Tertiarycac1-az43.97.253.35/32
OREGONZONE IDEIP
Primaryusw2-az152.25.165.25/32
Secondaryusw2-az244.237.58.11/32
Tertiaryusw2-az352.10.213.81/32
© Getstream.io, Inc. All Rights Reserved.