
A payload is the body of an HTTP request — the data the sender wants the receiver to act on. In webhooks, the payload is almost always JSON: a structured, machine-readable representation of the event.
This post explains what a payload is, why JSON beat the alternatives, what a typical webhook payload looks like, and what production systems do with payloads beyond just parsing them.
What is a payload?
In HTTP terms, a request has three parts:
- The method and URL —
POST /webhooks/stripe - The headers —
Content-Type,Authorization, signature headers - The body (the payload) — the actual data
The payload is the body. For webhooks, that body almost always carries:
- The event type (
payment_intent.succeeded) - A unique event ID (
evt_1NxV5y...) - A timestamp (so you can detect replay attacks)
- The data describing what happened (the customer, the amount, the affected object)
Why JSON?
Webhooks could carry XML, protobuf, MessagePack, form-encoded data, or anything else. They mostly use JSON because:
- It's human-readable. You can
curla webhook URL and read the result. - It's universally supported. Every language has a JSON parser in its standard library.
- It's self-describing. Field names are part of the payload, so you can read it without a schema.
- It's flexible enough to evolve. Adding a new field rarely breaks old consumers.
The trade-off is verbosity (JSON is bigger than binary formats) and weak typing (you have to validate). At webhook scale (events per second per tenant, not millions per second), the trade-off is a clear win.
What does a webhook payload look like?
A typical Stripe payment_intent.succeeded payload:
{
"id": "evt_1NxV5y2eZvKYlo2C8wT9pQ4Z",
"type": "payment_intent.succeeded",
"created": 1714000000,
"data": {
"object": {
"id": "pi_3NxV5y2eZvKYlo2C0pZ4uX2A",
"amount": 2999,
"currency": "usd",
"customer": "cus_O8N3K5p4lJ2mNw",
"status": "succeeded"
}
}
}
Most providers follow a similar structure: a top-level id, type, created, and a nested data (or object) with the actual event details.
A GitHub pull_request payload is bigger but follows the same pattern: a pull_request action, the PR object, the repository it lives in, the user who triggered it.
Common payload patterns
Across providers, you'll see four recurring patterns:
Event envelope. Many providers wrap events in a consistent envelope (id, type, created, data), though the exact shape is provider-specific.
Versioned schema. The provider sends a schema or api_version field so consumers know what shape to expect.
Sparse vs full. Some providers send the full state of the affected object on every event ("here's the full subscription"); others send only the changed fields ("here's what changed about the subscription"). Sparse payloads need an API lookup to act on; full payloads are bigger but self-sufficient.
References vs embedded objects. A payment event might embed the customer object inline, or just reference it by ID. The trade-off is payload size vs lookup latency.
What production systems do with payloads
Beyond parsing, production webhook systems often need to:
- Transform the payload into the shape the agent or downstream service expects (rename fields, flatten nested objects, drop sensitive data).
- Persist the original payload so you can replay it later — even after you change the transformation.
- Filter based on payload contents (only deliver
subscription.createdevents fortier=enterprisecustomers, for example). - Verify signatures on the raw bytes — if you parse before verifying, an attacker who can inject malformed JSON can bypass your check.
Hooksbase handles these relay-side concerns: Starter+ payload transforms via JSONPath or Handlebars, persisted dispatch snapshots so retained replays remain correct under config change, programmable routing rules over payload contents, and raw-byte signature verification for supported provider packs after Hooksbase ingest auth.
Where to go next
- What is a webhook? for the underlying mechanics
- Routing, transforms, and replay for AI agents for what to do with the payload once you have it
- Deterministic replay for agents for why persisting payloads matters