> ## Documentation Index
> Fetch the complete documentation index at: https://docs.knoxcall.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Inbound Webhooks overview

> Verify HMAC-signed webhooks from Stripe, GitHub, Slack and others without writing verification code in every service. KnoxCall checks the signature, audits the request, and forwards it to your app.

# Inbound Webhooks overview

KnoxCall's **Inbound Webhooks** feature is a **signature-verifying ingress** for HMAC-signed webhooks. Point Stripe (or GitHub, Slack, AWS SNS, anything that signs requests) at a KnoxCall URL. KnoxCall verifies the signature, audits the call, and optionally forwards the request to your app with an `X-Knox-Verified: true` header.

The job your app *would* do — verify the HMAC, enforce the replay window, log the result — lives once in KnoxCall instead of being copy-pasted across every service that consumes webhooks.

## Why use it

| Problem                                                              | Without KnoxCall                                           | With KnoxCall                                                                       |
| -------------------------------------------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| Each service that consumes Stripe webhooks reimplements verification | One mistake = signature bypass for that whole service      | Verification happens once at the edge, your app trusts the `X-Knox-Verified` header |
| Replay-attack windows (Stripe, Slack) drift across codebases         | Easy to forget; SDK upgrades change defaults               | KnoxCall enforces the configured window per subscription, not per app               |
| Audit trail of "did this webhook signature match?"                   | Per-app, by log line, often missing                        | Every ingest writes a row to KnoxCall's API logs with verified=true/false           |
| Rotating a webhook secret                                            | Find every service, redeploy each                          | Rotate in the admin UI; old secret stops working immediately                        |
| Webhook-source IP filtering                                          | Maintain Stripe/GitHub IP allowlists in every NAT/firewall | Customer-facing URL is on a single hostname, easy to allow                          |

## How it works

1. **Create an inbound webhook subscription** in the admin UI — pick a format (Stripe, GitHub, Slack, AWS SNS, KnoxCall legacy, or custom-header), paste the shared secret, choose where to forward verified requests.
2. KnoxCall hands you a **receiver URL**: `https://hooks.knoxcall.com/<your_tenant_slug>/<webhook_name>`.
3. Paste that URL into the upstream provider's webhook config. Stripe (or whoever) signs every event with HMAC-SHA256 of the body and sends it to KnoxCall.
4. KnoxCall **verifies the signature** using the format's wire spec and the secret you configured.
5. If valid → forward to your app with `X-Knox-Verified: true` (or audit-only if no forward URL).
6. If invalid → return `401` (default), or forward with `X-Knox-Verified: false` if you want your app to log unverified events without losing them.

Either way, the call lands in **API Logs** so you can see verification rate, replay-rejected requests, and forward latency.

## Quick start (UI)

1. Go to **Automation → Webhooks** in the admin UI, switch to the **Inbound** tab, and click **New Inbound Webhook**.
2. Pick the **format** that matches the upstream provider (Stripe, GitHub, Slack, etc.).
3. Paste the **shared secret** the provider gave you (e.g. Stripe's `whsec_...`).
4. Optional: enter a **forward URL** (your app's webhook handler). Leave blank for verify-only auditing.
5. Save. Copy the **receiver URL** that appears.
6. Paste the receiver URL into the upstream provider's webhook configuration.

That's it. The next event from the upstream provider will hit KnoxCall, get verified, and either show up in your app's webhook handler with `X-Knox-Verified: true` or appear in **API Logs** for inspection.

## Supported formats

| Format              | Header                                                      | Replay protection    | Use case                                              |
| ------------------- | ----------------------------------------------------------- | -------------------- | ----------------------------------------------------- |
| **Stripe**          | `Stripe-Signature: t=<unix>,v1=<hex>`                       | yes (timestamp `t=`) | Stripe webhooks, any provider that adopted the format |
| **GitHub**          | `X-Hub-Signature-256: sha256=<hex>`                         | no (no timestamp)    | GitHub webhooks, Postmark, SendGrid, many SaaS        |
| **Slack**           | `X-Slack-Signature: v0=<hex>` + `X-Slack-Request-Timestamp` | yes                  | Slack events, slash commands                          |
| **AWS SNS (HMAC)**  | `x-amz-sns-signature` (base64)                              | no                   | KnoxCall-shaped SNS receivers (not real AWS RSA-SNS)  |
| **KnoxCall legacy** | `X-Webhook-Signature: sha256=<hex>`                         | no                   | KnoxCall-to-KnoxCall flows                            |
| **Custom**          | caller-named header `sha256=<hex>`                          | no                   | Internal tools that don't match a named provider      |

See the [format guide](/essentials/inbound-webhooks/format-guide) for the exact wire format each verifier expects.

## Replay protection

For formats with a timestamp header (Stripe, Slack), KnoxCall enforces a **5-minute window** by default. A request with a timestamp older than that gets rejected with `replay_window_exceeded` even if the signature is valid. This closes the attack where someone captures a real webhook and replays it later.

Configure the window per subscription (range: 0–86400 seconds, where 0 disables the check). The default of 300 matches Stripe's and Slack's recommended values.

## What gets audited

Every ingest call writes a row to **API Logs** (`/logs`) with:

* `path` — `/<tenant_slug>/<webhook_name>`
* `signature_valid` — `true` / `false`
* `signature_error` — the rejection reason if invalid (`replay_window_exceeded`, `no v1 signature matched`, `missing X-Hub-Signature-256 header`, etc.)
* `meta_json.subscription_id` — which subscription handled the request
* `meta_json.forwarded` — whether the verified request was sent on to your app
* `meta_json.forward_status` — HTTP status from your app

Filter the logs by webhook name to see verification health for one provider.

## Security model

KnoxCall stores the shared secret encrypted under the **per-tenant master key** (KCT1 envelope). The receiver URL is **unauthenticated by design** — authentication *is* the HMAC signature. A request that doesn't verify either gets dropped (default) or marked `X-Knox-Verified: false` for your app to handle.

Forwarding is **SSRF-safe**: the forward URL is validated to use HTTPS, point at a DNS hostname (not a literal IP), and not resolve to a private / metadata-IP range.

## Next steps

* [Format guide →](/essentials/inbound-webhooks/format-guide)
* [Outbound Webhook Signing →](/essentials/webhook-signing/overview) — the inverse direction (KnoxCall fires events out and signs them)
* [Crypto Keys →](/essentials/crypto-keys/crypto-keys-overview) — use a managed key for signature verification instead of a per-subscription shared secret
