Webhook Payload Format — Complete Guide
In this tutorial, you will learn about Webhook Payload Format. We cover key concepts, practical examples, and best practices to help you master this topic.
Learn webhook payload format standards: CloudEvents, JSON structure, versioning, signature fields, metadata conventions, and designing extensible payloads for consumer compatibility.
What You Learn
You will learn how to design webhook payloads that are self-describing, versioned, extensible, and compatible with the CloudEvents specification. You will understand metadata fields, data envelopes, and how to evolve payloads without breaking consumers.
Why It Matters
A well-designed payload format prevents integration breakage when adding fields, supports multiple consumer versions simultaneously, and follows industry standards that consumers already understand. Bad payload design causes Parsing errors, silent data loss, and brittle integrations.
Real-World Use
DodaTech's webhook system follows the CloudEvents specification across all 15 event types. The standardized format allows 200+ integration partners to build consumers without per-event-type documentation. A single parser handles all Webhooks.
CloudEvents Standard
// CloudEvents compliant webhook payload
const cloudEventPayload = {
specversion: '1.0',
id: 'wh_abc123def456',
source: '/com/dodatech/antivirus/threats',
specversion: '1.0',
type: 'com.dodatech.threat.detected',
datacontenttype: 'application/json',
dataschema: 'https://api.dodatech.com/schemas/threat.json',
subject: 'endpoint-445',
time: '2026-06-28T12:00:00Z',
data: {
threatId: 'thr_789',
type: 'ransomware',
severity: 'critical',
endpoint: 'endpoint-445',
detectedAt: '2026-06-28T12:00:00Z',
},
};
Expected output: specversion tells consumers which CloudEvents version to use. id is unique. source identifies the origin. type uses reverse-DNS notation for namespacing. data contains the event-specific payload.
Custom Payload Design
// Well-designed custom payload
const webhookPayload = {
// Metadata
webhookId: 'wh_abc123',
event: 'order.created',
version: '2.1',
createdAt: '2026-06-28T12:00:00Z',
environment: 'production',
// Signature (in header typically, but can be in body)
signature: 'sha256=abc123def456...',
// Source information
source: {
system: 'order-service',
instance: 'ord-123',
region: 'us-east-1',
},
// Event data
data: {
orderId: 'ord_456',
customerId: 'cus_789',
items: [
{ productId: 'prod_1', quantity: 2, price: 2500 },
{ productId: 'prod_2', quantity: 1, price: 5000 },
],
total: 10000,
currency: 'USD',
status: 'confirmed',
},
// Extension fields for future compatibility
extensions: {
featureFlags: ['express-checkout', 'loyalty-points'],
},
};
Expected output: Metadata separates identity (webhookId), routing (event, source), and versioning. Data is the core payload. Extensions allow adding optional fields without breaking existing parsers.
Payload Versioning
// Version 1.0 payload
const v1Payload = {
webhookId: 'wh_001',
event: 'user.created',
version: '1.0',
data: {
userId: 1,
name: 'Alice',
email: 'alice@example.com',
},
};
// Version 2.0 payload (added phone, changed userId to string)
const v2Payload = {
webhookId: 'wh_002',
event: 'user.created',
version: '2.0',
data: {
userId: 'user_002',
name: 'Bob',
email: 'bob@example.com',
phone: '+1234567890',
},
};
// Consumer handles both versions
function handleUserCreated(payload) {
const { version, data } = payload;
if (version === '1.0') {
// Legacy: userId is number
return processLegacyUser({
id: `user_${data.userId}`,
name: data.name,
email: data.email,
});
}
if (version.startsWith('2.')) {
// Current: userId is string, phone available
return processUser({
id: data.userId,
name: data.name,
email: data.email,
phone: data.phone || null,
});
}
}
Expected output: Version field allows the consumer to parse differently based on format version. Old consumers Process v1 unchanged. New consumers use v2 features. Backward-compatible changes use minor versions.
Array vs Single Event
// Single event (per webhook)
const singleEvent = {
webhookId: 'wh_001',
event: 'order.created',
data: { orderId: 'ord_001' },
};
// Batch events (multiple in one webhook)
const batchEvent = {
webhookId: 'wh_002',
event: 'orders.created',
data: [
{ orderId: 'ord_002' },
{ orderId: 'ord_003' },
{ orderId: 'ord_004' },
],
};
// Consumer handles both
function processWebhook(payload) {
const events = Array.isArray(payload.data)
? payload.data
: [payload.data];
for (const event of events) {
processSingleEvent(payload.event, event);
}
}
Expected output: Single events are simpler for real-time processing. Batch events are more efficient for high-volume scenarios. The consumer normalizes both formats by wrapping single events in an array.
Payload Size Limits
// Payload size check
function validatePayload(payload) {
const payloadStr = JSON.stringify(payload);
const sizeBytes = Buffer.byteLength(payloadStr, 'utf8');
console.log(`Payload size: ${(sizeBytes / 1024).toFixed(1)} KB`);
if (sizeBytes > 256 * 1024) {
console.error('Payload exceeds 256KB limit');
return false;
}
// Truncate large fields if necessary
if (payload.data && typeof payload.data.description === 'string') {
if (payload.data.description.length > 1000) {
payload.data.description =
payload.data.description.slice(0, 1000) + '...';
}
}
return true;
}
// Test
const largePayload = {
webhookId: 'wh_003',
event: 'report.generated',
data: {
description: 'A'.repeat(5000), // 5KB text
largeArray: new Array(10000).fill('item'), // ~60KB
},
};
validatePayload(largePayload);
Expected output: Most providers enforce 256KB-1MB payload limits. Large payloads are truncated or rejected. Keep webhook payloads under 100KB for reliable delivery.
Common Mistakes
1. No Version Field
Without a version field, any format change breaks all consumers. Add version from day one. Use semver (major.minor). Breaking changes increment major version.
2. Inconsistent Date Formats
One payload uses ISO 8601, another uses Unix timestamp, another uses US date format. Standardize all dates to ISO 8601 (2026-06-28T12:00:00Z). Document the format.
3. Nested Data Without Schema
Deeply nested data without documented schemas causes parsing errors. Define JSON Schema for each event type. Validate payloads against schemas before sending.
4. No Nullable Field Handling
Consumers crash on null where they expect an object, or missing fields where they expect strings. Use default values. Document which fields are nullable. Include empty arrays instead of null.
5. Mixing Types in Fields
A field is a string in v1, number in v2, and array in v3. Consumers cannot handle three different types for one field. Use separate fields (userId, userIds) instead of changing types.
Practice Questions
1. What is the purpose of the specversion field in CloudEvents?
It identifies the CloudEvents specification version. Consumers use it to determine parsing rules. Different spec versions may have different required fields or semantics.
2. How do you evolve a webhook payload without breaking consumers?
Add optional fields. Never remove fields. Use version field for breaking changes. Consumers check version and parse accordingly. Old consumers ignore unknown fields.
3. What is the recommended maximum webhook payload size?
256KB to 1MB depending on the provider. Keep payloads under 100KB for reliable delivery. Use references (URLs) for large data instead of embedding it.
4. Why use reverse-DNS for event type names?
Reverse DNS prevents naming conflicts. com.stripe.payment.succeeded is globally unique. payment.succeeded could conflict with another provider's event. Reverse DNS is the CloudEvents standard.
Challenge
Design a webhook payload format for a file processing service. Include events for file.uploaded, file.optimized, file.error. Follow CloudEvents spec. Include versioning. Design for sizes up to 10MB (use URLs for large data). Create JSON Schema for each event type.
FAQ
Mini Project: Payload Validator
Build a webhook payload validator tool that: accepts a payload format definition (JSON Schema), tests payloads against the schema, validates dates and field types, checks size limits, suggests improvements, and generates documentation markdown.
What's Next
Now that you know how to design payloads, learn how to sign and verify webhooks with HMAC to ensure authenticity and integrity.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro