Webhooks Setup

Last Edit: Jun 06 2020

By using webhooks, you can receive all events within your application. When configured, every event happening on Stream Chat will propagate to your webhook endpoint via an HTTP POST request.

Webhooks can help you migrate from a different chat provider to Stream without disruption, or to support complex notification mechanisms (e.g. sending an SMS to an offline user when a direct message is sent, etc.).

Webhook Requirements

In order to use webhooks, the endpoint responding to the webhook event must:

  • Be reachable from public internet, tunneling services like Ngrok are supported
  • Respond with a 200 HTTP code in less than 3 seconds
  • Handle HTTP requests with POST body
  • Able to parse JSON payloads
  • Support HTTP/1.1

While not required, we recommend following these best-practices for production environments:

  • Use HTTPS with a certificate from a trusted authority (eg. Let's Encrypt)
  • Verify the "x-signature" header
  • Support Keep-Alive
  • Be highly available
  • Offload the processing of the message (read, store, and forget)

Configuration via CLI

stream chat:push:webhook --url 'https://acme.com/my/awesome/webhook/handler/'
See the CLI introduction for more information on the Stream CLI.

Verify Events via X-Signature and X-Api-Key

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.

// first argument is the request body as a string, second the signature header
const valid = client.verifyWebhook(req.rawBody, req.headers['x-signature']);

import stream_chat

client = stream_chat.connect('API_KEY', 'API_SECRET')

# Django request
valid = client.verify_webhook(request.body, request.META['HTTP_X_SIGNATURE'])

# Flask request
valid = client.verify_webhook(request.data, request.headers['X-SIGNATURE'])

require 'stream-chat'

client = StreamChat::Client.new(api_key='STREAM_KEY', api_secret='STREAM_SECRET')

// signature comes from the HTTP header x-signature
valid = client.verify_webhook(request_body, signature)

$client = new GetStream\StreamChat\Client("STREAM_API_KEY", "STREAM_API_SECRET");

// signature comes from the HTTP header x-signature
$valid = $client->verifyWebhook($requestBody, $signature);

// at the moment we don't have a Java client for server side usage

client, _ := stream.NewClient(APIKey, []byte(APISecret))

// signature comes from the HTTP header x-signature
isValid := client.VerifyWebhook(body, signature)

// at the moment we don't have a Swift client for server side usage

using StreamChat;

var client = new Client("API KEY", "API SECRET");

// signature comes from the HTTP header x-signature 
client.VerifyWebhook(requestBody, 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 most recently created API Key to sign payloads.