Webhook security

Debug webhook signature verification

Verify and troubleshoot webhook signatures without guessing at HMAC inputs, encodings, or provider-specific header formats.

Problem

Webhook signature failures rarely explain themselves.

Webhook providers usually give you a header, a payload, and a secret. When verification fails, the hard part is figuring out whether the mismatch came from encoding, payload mutation, timestamp handling, or the wrong signature format.

When to use it

  • You are wiring up webhook verification for a new integration.
  • You need to compare expected and received signatures while debugging.
  • You need framework-specific reminders for preserving the exact raw request body.
  • You want known-good demo vectors before touching live webhook payloads or secrets.
  • You want a repeatable check before changing production webhook code.

Non-goals

  • Not a hosted webhook receiver or event bus.
  • Not a substitute for storing and rotating production webhook secrets safely.
  • Not coverage for every proprietary signature scheme outside the supported providers.

First call

Run a small request and inspect the named outputs.

curl -X POST 'https://webhook-signature-debug-api.linkridge.net/v1/webhooks/verify' \
  -H 'Content-Type: application/json' \
  -H 'X-API-Key: <your-api-key>' \
  -d '{
  "provider": "stripe",
  "payload": "{\"id\":\"evt_test\"}",
  "secret": "whsec_example",
  "headers": {
    "Stripe-Signature": "t=1700000000,v1=..."
  },
  "now_epoch_seconds": 1700000000
}'

Prefer marketplace auth? Open in RapidAPI for plans, keys, and interactive testing.

Example response

{
  "valid": true,
  "provider": "stripe",
  "reason": "valid",
  "matched_signature_header": "Stripe-Signature",
  "signature_scheme": "hmac-sha256-hex",
  "replay_protected": true,
  "checks": [
    {
      "name": "signature",
      "status": "passed",
      "detail": "Expected signature matched received signature."
    }
  ],
  "raw_body_hints": [
    {
      "framework": "FastAPI",
      "summary": "Read the body before parsing JSON.",
      "detail": "Use request.body() and pass those exact bytes into verification."
    }
  ],
  "replay_test_vectors": [
    {
      "provider": "github",
      "payload": "Hello, World!",
      "headers": {
        "X-Hub-Signature-256": "sha256=..."
      },
      "secret": "It's a Secret to Everybody"
    }
  ]
}