Formatting webhook JSON and reading provider signature headers

Published: 2026-09-05

Pretty-print or minify webhook JSON for debugging, keep the raw body for HMAC checks, and use a local cheat sheet of Stripe, GitHub, Shopify, Slack, and other signature headers without uploading payloads.

Webhook debugging usually fails in two places at once: you cannot read the JSON event (minified one-liners, nested data.object trees), and you cannot verify it because you re-serialized the body or looked at the wrong signature header. Providers sign exact bytes and label authenticity with provider-specific HTTP headers—not with a field inside the JSON.

This guide covers when to pretty-print vs minify, which headers matter for common platforms, and a local workflow that keeps customer payloads and signing secrets in your browser. Pair formatting with HMAC webhook signatures when you need to check digests.

Pretty-print for humans, minify for signatures

Goal Use Why
Read an event in logs or a ticket Pretty-print (2- or 4-space indent) Nested Stripe/GitHub/Shopify objects become scannable
Replay or HMAC-verify what the provider sent Raw body (or minify only if that matches what was signed) Extra spaces, key order, and trailing newlines change the digest
Store a compact fixture Minify after you understand the shape Smaller diffs; still not a substitute for the original wire body

A human-readable {\n "id": "evt_…"\n} and a wire {"id":"evt_…"} are the same object and different messages. Middleware that parses JSON then JSON.stringifys again often reorders keys or drops insignificant whitespace—enough to break Stripe’s t=.… HMAC or GitHub’s sha256= digest. When verification fails, go back to the raw request body from your framework or reverse proxy, not the pretty-printed copy from a dashboard.

LocalTools’ Webhook payload formatter pretty-prints or minifies JSON in-tab and can load Stripe, GitHub, and Shopify samples so you can practice without pasting production events. Formatting runs locally under the same local-only model as other tools on the site.

Signature headers vs metadata headers

Think in two buckets:

  1. Authenticity — HMAC (or RSA) digests and the timestamps/tokens that go into the signed string.
  2. Routing and ops — event type, delivery id, shop domain, correlation ids. These help you log and idempotent-process events; they are usually not what you HMAC alone.

Header names are case-insensitive on the wire (Stripe-Signature and stripe-signature are the same header). Values are not: hex vs Base64, sha256= prefixes, and comma-separated t= / v1= fields must match the provider’s docs.

Common authenticity headers

Provider Header(s) Typical shape
Stripe Stripe-Signature t=<unix>,v1=<hex> — signed string is usually t + . + raw body
GitHub X-Hub-Signature-256 (prefer) / legacy X-Hub-Signature sha256=<hex> or sha1=<hex> over the raw body
Shopify X-Shopify-Hmac-SHA256 Base64 HMAC-SHA256 of the raw body
Slack X-Slack-Signature + X-Slack-Request-Timestamp v0=<hex>; signed string includes v0:timestamp:body
Svix-compatible svix-id, svix-timestamp, svix-signature Signatures over id.timestamp.body
Mailgun Timestamp, token, and signature headers HMAC over timestamp + token (not always “body alone”)
Twilio X-Twilio-Signature Often URL + sorted form params, not JSON body HMAC
PayPal PAYPAL-TRANSMISSION-* + cert URL / algo Transmission metadata + body; often cert-based verify

Twilio and PayPal are easy to mis-debug if you assume “HMAC of JSON body like GitHub.” Always confirm what string the provider signed before comparing digests in the HMAC & Webhook Verifier.

Metadata headers worth logging

Provider Examples Use
GitHub X-GitHub-Event, X-GitHub-Delivery Route by event name; idempotency / log correlation
Shopify X-Shopify-Topic, X-Shopify-Shop-Domain Topic handlers; multi-tenant shop identity
Generic X-Request-Id, X-Webhook-Id, User-Agent, Content-Type Tracing, sender identity, expect application/json

The formatter’s offline headers table lists these (and more) with short purpose notes and example fragments—filter by provider or search “signature,” “hmac,” or “delivery” when you are staring at access logs.

A practical local workflow

  1. Capture the raw body and the signature-related headers from one failed delivery (or a staging replay).
  2. Pretty-print the body in the Webhook payload formatter to understand type / topic / nested objects. Do not feed that pretty string back into HMAC unless it truly matches the wire bytes.
  3. Look up the provider’s signature header name and example shape in the headers cheat sheet; copy the header name into your framework middleware or ticket.
  4. Verify with the HMAC & Webhook Verifier: paste the raw body (minify only if that restores the signed form), secret, algorithm/encoding, and header value. See HMAC webhook signatures for Stripe-style t= / v1= pitfalls.
  5. Keep PII and secrets in the tab. Prefer local tools over pasting live webhook JSON into random online “formatters.”

For timestamp windows and Unix seconds vs milliseconds in replay checks, see Unix timestamps: seconds vs milliseconds. For general JSON hygiene before you minify fixtures, see Minifying JSON safely and What is JSON?.

Common pitfalls

  • Pretty-print then verify — changes bytes; HMAC fails even with the correct secret.
  • Wrong header — using X-Hub-Signature (SHA-1) while the app sends X-Hub-Signature-256, or checking a delivery id instead of the signature header.
  • Body-only HMAC on Stripe/Slack/Svix — those schemes include timestamp (and sometimes id) in the signed string.
  • Assuming every webhook is JSON HMAC — form-encoded or cert-based providers need a different verify path.
  • Uploading production events — customer emails, order totals, and repo metadata do not belong on third-party paste sites; format and reference headers locally.

Try it

Use the Webhook payload formatter to:

  1. Paste a body from logs or load a Stripe / GitHub / Shopify sample.
  2. Pretty-print or minify, then copy output for tickets or fixtures.
  3. Search the bundled headers table for signature and metadata fields.
  4. Jump to the HMAC & Webhook Verifier when you need a local match/mismatch check.

Related: Why “local only” matters for developer tools, HMAC webhook signatures, and Converting curl to JavaScript fetch when you are replaying deliveries from captured HTTP.

All learn articles