Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions docs/webhooks/webhooks_overview/webhooks_overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,52 @@ All webhook requests contain these headers:
| X-Webhook-Attempt | Number of webhook request attempt starting from 1 | 1 |
| X-Api-Key | Your application’s API key. Should be used to validate request signature | a1b23cdefgh4 |
| X-Signature | HMAC signature of the request body. See Signature section | ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb |
| Content-Encoding | Compression algorithm applied to the request body. Only set when webhook compression is enabled on the app | `gzip` |

### Compressed webhook bodies

GZIP compression can be enabled for hooks payloads from the Dashboard. Enabling compression reduces the payload size significantly (often 70–90% smaller) reducing your bandwidth usage on Stream. The computation overhead introduced by the decompression step is usually negligible and offset by the much smaller payload.

When payload compression is enabled, webhook HTTP requests will include the `Content-Encoding: gzip` header and the request body will be compressed with GZIP. Some HTTP servers and middleware (Rails, Django, Laravel, Spring Boot, ASP.NET) handle this transparently and strip the header before your handler runs — in that case the body you see is already raw JSON.

Before enabling compression, make sure that:

* Your backend integration is using a recent version of our official SDKs with compression support
* If you don't use an official SDK, make sure that your code supports receiving compressed payloads
* The payload signature check is done on the **uncompressed** payload

Use `App.verifyAndDecodeWebhook` to handle decompression and signature verification in one call. It returns the raw JSON bytes ready to parse:

```java
// rawBody — bytes read straight from the HTTP request body
// signature — value of the X-Signature header
// contentEncoding — value of the Content-Encoding header (null when absent)
byte[] json = App.verifyAndDecodeWebhook(rawBody, signature, contentEncoding);
// json now contains the uncompressed JSON; parse it as usual.
```

If you prefer to handle the steps yourself, the primitives are also exposed:

```java
byte[] json = App.decompressWebhookBody(rawBody, contentEncoding);
boolean valid = App.verifyWebhookSignature(apiSecret, json, signature);
```

This SDK supports `gzip` only — gzip uses the JDK and adds no external dependencies. Any other `Content-Encoding` value raises an `IllegalStateException`; if you see one in production, set `webhook_compression_algorithm` back to `gzip` (or `""` to disable compression) on the app via `App.update()` or the dashboard.

#### SQS / SNS payloads

The same helper handles compressed messages delivered through SQS or SNS. There the compressed body is base64-wrapped so it stays valid UTF-8 over the queue. Pass the encoding values that arrived with the message (typically as message attributes such as `Content-Encoding`, `payload_encoding`, and `X-Signature`) as the extra `payloadEncoding` argument:

```java
// body — the SQS Body / SNS Message string, decoded to bytes
// signature — X-Signature attribute value
// contentEncoding — "gzip" when compression is enabled, otherwise null
// payloadEncoding — "base64" for SQS / SNS firehose payloads
byte[] json = App.verifyAndDecodeWebhook(body, signature, contentEncoding, payloadEncoding);
```

The signature is always computed over the innermost (uncompressed, base64-decoded) JSON, regardless of transport.

## Webhook types

Expand Down
Loading
Loading