Webhook Payload Design: Thin vs Fat Payloads
Thin vs fat webhook payloads and safe migration
Designing webhook payloads well avoids repeated breaking changes and reduces consumer complexity. This guide compares thin vs fat payload models, recommends a hybrid approach, and shows Laravel validation patterns you can ship today.
You will learn when to send identifiers only, when to include actionable snapshots, and how to add schema_version and backward-compatible validation. The primary keyword “webhook payload design thin vs fat” appears in the recommended migration guidance.
Define the “contract” before you ship
Agree a stable contract — event key, payload shape, and version — before you add fields.
Event key as routing primitive (event_key) ([SendPromptly][3])
Use event_key for routing and consumer intent. Consumers should switch on event_key, not on payload internals.
Delivery semantics: at-least-once, retries on failure
Expect retries — make payloads idempotent-friendly and small enough to avoid timeouts.
Micro checklist:
- Publish
event_keyand semantics in your contract.- Add
schema_versionwhen changing shape.- Document retries and idempotency expectations for consumers.
Thin payload model
When to use identifiers only and let consumers fetch details.
Include identifiers only (entity_id, event_id)
Thin payloads are small, stable, and keep network usage low. Consumers fetch authoritative details on demand.
Consumer fetches details
Prefer thin when consumers already have reliable fetch endpoints or when payload size matters.
Common gotcha: Thin payloads without a stable fetch endpoint are unusable — ensure a documented detail endpoint exists.
Fat payload model
When to include the full snapshot consumers need to act without additional requests.
Include full snapshot needed to act
Fat payloads improve speed and reduce two-phase fetch logic for consumers, but increase size and coupling.
Large payload risks + validation
Large payloads can cause timeouts, higher latency, and parsing errors. Validate size on both sender and receiver.
Micro checklist:
- Limit payload size (document a max bytes).
- Validate required keys and types.
- Use
schema_versionfor breaking changes.
Recommended hybrid for SendPromptly integrations
Use an actionable snapshot for the common fast path, plus stable identifiers for deep-fetches.
“Actionable snapshot + stable identifiers”
- Include a small, actionable snapshot (status, key fields) plus
entity_idfor a deeper fetch if needed. - Keep optional, non-critical fields clearly documented as nullable/optional.
Add schema_version
Version the payload so consumers can handle migration changes deterministically.
Micro checklist:
- Add
payload.schema_version(integer).- Keep additive changes backward compatible.
- Deprecate fields across releases, not abruptly.
Use the Sample Project to trigger one event and verify your consumer accepts the schema in Message Log.
Laravel validation and backward compatibility
Validate incoming webhook payloads with explicit rules and fail fast for malformed data.
| |
Common gotcha: Returning
5xxfor a permanent validation error causes pointless retries — prefer422or accept+DLQ.
Testing and rollout
- Send a payload missing required fields → expect
422. - Send a valid payload → expect
200.
For end-to-end testing, trigger a SendPromptly event and confirm the webhook run shows 2xx success (and retries on failure).
Failure modes
- No schema version ⇒ breaking changes slip in unnoticed.
- Fat payload grows unbounded ⇒ timeouts and retries.
- Thin payload without fetch endpoint ⇒ consumers can’t act.
- Consumers assume optional fields are always present ⇒ runtime errors.
- “Validation failed” returned as 5xx ⇒ pointless retries.
- Non-deterministic JSON transforms before signing/verification.
Related
- `event_key` routing + ingestion behavior
- Retries, success rules, and signatures
- How to interpret 409/429 in clients
- Designing for late arrivals
Use the Sample Project to validate schema acceptance in Message Log.
Conclusion
- Prefer a hybrid: actionable snapshot + stable identifiers.
- Add
schema_versionfor safe migrations. - Validate with explicit Laravel rules and avoid
5xxfor permanent validation errors. - Keep payloads small where possible; document size limits and expected optional fields.
- Use Message Log to inspect delivered payloads during rollout.