What is a webhook payload? Structure and examples

A webhook payload is the data in the body of a webhook HTTP request: a description of the event that just happened, usually as JSON. It typically includes an event ID, an event type, a timestamp and the resource the event is about. The provider sends it to your webhook endpoint, along with headers that identify and sign it.

POST /webhooks/billing HTTP/1.1
Content-Type: application/json
webhook-id: msg_2xKq8f3Ld9
webhook-timestamp: 1793180400
webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=

{
  "id": "evt_01JBX8Q3",
  "type": "invoice.paid",
  "created_at": "2026-10-28T09:00:00Z",
  "data": {
    "invoice_id": "inv_8842",
    "customer_id": "cus_193",
    "amount": 4900,
    "currency": "usd"
  }
}

What's in a typical payload

FieldPurpose
Event ID (id)Unique per event. Use it to deduplicate retries. See idempotency.
Event type (type, event, action)Lets one endpoint route invoice.paid and invoice.failed to different handlers.
TimestampWhen the event happened. Useful for ordering, since deliveries can arrive out of order.
Resource (data, object)The thing that changed, either in full or as a reference.
API versionSome providers (Stripe, for example) pin the payload shape to an API version.

Some providers put the event type or delivery ID in headers instead. GitHub sends X-GitHub-Event and X-GitHub-Delivery, and the Standard Webhooks spec uses webhook-id.

Payload formats

  • JSON (application/json): Stripe, GitHub, Shopify and most modern APIs.
  • Form-encoded (application/x-www-form-urlencoded): Twilio, Slack slash commands, and some older systems. Slack's interactive payloads are a JSON string inside a form field called payload.
  • XML: some payment, telecom and enterprise systems.
  • Multipart: inbound email services that send attachments.

Read the Content-Type header and parse accordingly.

Fat vs thin payloads

A fat payload carries the full resource, so you can act on it directly. A thin payload carries only the type and an ID, and you call the provider's API for the current state. Thin payloads are smaller, never stale, and limit the damage if a payload leaks, at the cost of an extra API request per event. Even with fat payloads, fetching the latest state before acting is a safe pattern when events can arrive out of order.

Handling payloads safely

  1. Keep the raw bytes. Signatures are computed over the exact body. If a framework parses and re-serializes JSON first, whitespace or key order changes and verification fails. In Express, use express.raw() on the webhook route.
  2. Verify, then parse. Check the signature with your webhook secret before trusting any field.
  3. Validate the shape. Return 400 for a body you can't parse and 422 for a valid body you can't accept. See 400 vs 422. Most providers retry both, so log them.
  4. Ignore unknown fields and event types. Providers add fields without warning. Acknowledge events you don't handle with 200 so they aren't retried.
  5. Store before processing. Write the raw payload to a queue or table, return 200, and process asynchronously.

Size limits

Providers cap what they send (GitHub caps payloads at 25 MB), and receivers cap what they accept: nginx defaults client_max_body_size to 1 MB, and many serverless platforms limit request bodies to a few megabytes. Anything over the limit fails with 413 Payload Too Large. Webhook Relay accepts 4 MB per webhook by default and up to 40 MB with large webhooks enabled.

When the payload is the wrong shape

If a destination expects a different structure, for example forwarding a Stripe event into a Slack message, you can reshape it in code, or transform the webhook in flight with a Webhook Relay function before it's delivered.

Frequently asked questions

What is a webhook payload?

A webhook payload is the data in the body of a webhook HTTP request. It describes the event that happened, usually as a JSON object with an event ID, an event type, a timestamp and the affected resource, such as the payment or the pull request.

What format are webhook payloads in?

Most modern providers send JSON with a Content-Type of application/json. Some send form-encoded bodies, for example Twilio and Slack slash commands, and a few older or enterprise systems send XML. Always check the Content-Type header rather than assuming JSON.

What is the difference between a thin and a fat webhook payload?

A fat payload contains the full resource, so the receiver can act without calling back. A thin payload contains only the event type and an ID, and the receiver fetches the current state from the provider's API. Thin payloads are always fresh and smaller, but cost an extra API call.

How large can a webhook payload be?

It depends on the provider and the receiver. GitHub caps payloads at 25 MB, and many receivers and proxies reject bodies of a few megabytes with 413 Payload Too Large. Webhook Relay accepts webhooks up to 4 MB by default and up to 40 MB when large webhooks are enabled.