
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 event-layer 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
Frequently asked questions
What is the difference between a payload and a request body?
In practice for webhooks they are the same bytes. The request body is the transport-level term for what was sent; the payload is the meaningful content inside it. The distinction matters when the body carries an envelope — an event type, an id, a timestamp — around the data you actually care about.
Why do webhooks use JSON instead of XML?
Because every language parses it without a dependency, it maps directly onto the data structures a handler already uses, and it is compact enough to read in a log line. XML still appears in older enterprise integrations, and some providers post form-encoded bodies instead, but JSON is the default for anything designed recently.
What is Hooksbase?
Hooksbase is event infrastructure for AI agents. It ingests events over four channels — HTTP, email, HTML form, and scheduled cron — verifies them, routes them by rule, runs versioned Automations in the event path, and delivers them to HTTP and cloud destinations (AWS SQS, AWS EventBridge, GCP Pub/Sub, and S3-compatible storage) with retries, strict ordering, Standard Webhooks-compatible signing, deterministic replay, and a dead-letter path. It is a hosted service, runs on Cloudflare Workers, is operated at hooksbase.com, and is not affiliated with — and shares no code or ownership with — other similarly named webhook, hook, or tunnelling tools.