Webhook signature verify

FREE with proof-of-work · or $0.001 in USDC · POST /api/webhook-verify

Verify a webhook's HMAC signature against the correct per-provider scheme: GitHub (X-Hub-Signature-256, sha256=hex), Stripe (Stripe-Signature t/v1 over "<t>.<body>" with replay tolerance), Shopify (X-Shopify-Hmac-Sha256, base64), Slack (X-Slack-Signature, v0:<ts>:<body> with replay tolerance). Send POST /api/webhook-verify with the required fields provider, payload, secret and signature and pay $0.001 per call over x402 or MPP, or call it free by solving a proof-of-work challenge. It returns a JSON object with valid, provider, scheme and reason.

Constant-time comparison; the secret is never echoed. Pass the RAW request body string - signatures are over the raw bytes. Deterministic.

Category: Validation & parsing · Tags: webhook hmac signature security github stripe shopify slack

TRY IN PLAYGROUND →

Parameters

NameTypeRequiredDescription
providerstringyesgithub | stripe | shopify | slack
payloadstringyesthe RAW request body string, byte-for-byte as received (never a re-serialized object) Also accepted as body, data, claims, message.
secretstringyesthe provider signing secret (never echoed back) Also accepted as key, password, passphrase.
signaturestringyesthe signature header value, with or without its scheme prefix (sha256= / v0= / t=...,v1=...)
timestampstringnoprovider timestamp, required for stripe + slack (stripe may be parsed from a t= element in the signature)
toleranceSecondsnumbernomax timestamp age for stripe/slack replay protection (default 300; 0 skips the age check)

Example request

curl -i -X POST https://agent402.tools/api/webhook-verify \
  -H "Content-Type: application/json" \
  -d '{"provider":"github","payload":"{\"hello\":\"world\"}","secret":"it'\''s a secret","signature":"sha256=8d4063f0a81aa1531d9891a028a68cf2bb537ecdf0e82557674d71e168d570f9"}'

Without payment this returns HTTP 402 Payment Required with the exact price for webhook-verify; any x402 v2 or MPP client pays it and retries.

Example response

{
  "valid": true,
  "provider": "github",
  "scheme": "X-Hub-Signature-256: sha256=hex(HMAC-SHA256(secret, rawBody))",
  "reason": "signature matches the recomputed HMAC for this payload and secret"
}
FieldTypeAlways presentIn the example
validbooleanyestrue
providerstringyesgithub
schemestringyesX-Hub-Signature-256: sha256=hex(HMAC-SHA256(secret, rawBody))
reasonstringyessignature matches the recomputed HMAC for this payload and secret

From an MCP client

catalog.call {
  "slug": "webhook-verify",
  "params": {
    "provider": "github",
    "payload": "{\"hello\":\"world\"}",
    "secret": "it's a secret",
    "signature": "sha256=8d4063f0a81aa1531d9891a028a68cf2bb537ecdf0e82557674d71e168d570f9"
  }
}

On the hosted connector at https://agent402.tools/mcp, catalog.call runs webhook-verify free (rate-limited, no wallet). Local install: npx -y agent402-mcp.

Errors and behavior

Paid call (JavaScript agent)

import { wrapFetchWithPayment } from "@x402/fetch";
import { x402Client } from "@x402/core/client";
import { registerExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";

const client = new x402Client();
client.setSpendControls?.(false); // keep your own spending ceiling in code
registerExactEvmScheme(client, { signer: privateKeyToAccount(KEY) });
const payFetch = wrapFetchWithPayment(fetch, client);

const res = await payFetch("https://agent402.tools/api/webhook-verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    "provider": "github",
    "payload": "{\"hello\":\"world\"}",
    "secret": "it's a secret",
    "signature": "sha256=8d4063f0a81aa1531d9891a028a68cf2bb537ecdf0e82557674d71e168d570f9"
  }),
});

No wallet? Pay with compute

Fetch a challenge, solve the sha256 puzzle (16 leading zero bits, a fraction of a second of CPU), and resend with the X-Pow-Solution header:

import { createHash } from "node:crypto";
const lz = (b) => { let t = 0; for (const x of b) { if (!x) { t += 8; continue; } t += Math.clz32(x) - 24; break; } return t; };
const c = await (await fetch("https://agent402.tools/api/pow/challenge?slug=webhook-verify")).json();
let n = 0;
while (lz(createHash("sha256").update(c.challenge + ":" + n).digest()) < c.difficulty) n++;
await fetch("https://agent402.tools/api/webhook-verify", { method: "POST", headers: { "X-Pow-Solution": c.token + ":" + n, "Content-Type": "application/json" }, body: JSON.stringify({"provider":"github","payload":"{\"hello\":\"world\"}","secret":"it's a secret","signature":"sha256=8d4063f0a81aa1531d9891a028a68cf2bb537ecdf0e82557674d71e168d570f9"}) });

Part of these workflows

Webhook signature verify is one step in this skill pack, each sold as a single call:

Related tools

HMAC

FREE w/ compute · or $0.001 · POST /api/hmac

HMAC signature of a message with a shared key. Algorithms: sha256 (default), sha512, sha1. Returns hex and base64.

Password strength

FREE w/ compute · or $0.001 · POST /api/password-strength

Score a password's strength: character-set size, entropy bits, a 0–4 rating, and an estimated offline crack time. The pa…

Card number validate

FREE w/ compute · or $0.001 · POST /api/card-validate

Validate a payment card number (Luhn checksum) and detect the brand. Numbers are not stored or logged.

Color convert

FREE w/ compute · or $0.001 · POST /api/color

Convert a color between hex, RGB, and HSL. Accepts "#1a2b3c", "rgb(26,43,60)", or "hsl(210,40%,17%)".

CSV lint

FREE w/ compute · or $0.001 · POST /api/csv-lint

Validate CSV structure: consistent column counts across rows, properly closed quotes, delimiter detection. Returns row/c…

Email validate

$0.001 · POST /api/email-validate

Validate an email address: syntax check plus live MX record lookup on the domain (deliverability signal, not a guarantee…