Security and Validation

Webhook Payload Versioning Strategies

Webhook payloads evolve over time. Fields change, structures grow, and providers introduce new event formats. If webhook consumers assume a fixed schema, a provider update can break production instantly. A safe versioning strategy prevents this.

Why webhook payloads break integrations

Many webhook integrations treat payloads as stable contracts. In reality they are not. Providers regularly introduce changes:

  • new JSON fields
  • renamed attributes
  • different nested structures
  • new event types

Without versioning, these changes can break JSON parsing, validation logic, or database mapping.

Strategy 1: Version headers

The cleanest approach is including an explicit webhook version header.

                    Webhook-Version: 2024-10-01
                

Your handler can branch logic depending on the version.

                    
$version = $request->header('Webhook-Version');

switch ($version) {

    case '2024-10-01':
        return $this->handleV1($request);

    case '2025-01-01':
        return $this->handleV2($request);

}
                    
                

This prevents schema ambiguity and keeps upgrades explicit.

Strategy 2: Backward compatible schemas

Many providers avoid strict versions and instead guarantee backward compatibility.

Rules commonly used:

  • never remove existing fields
  • only add optional fields
  • avoid changing field meaning

Webhook consumers must therefore ignore unknown fields.

                
$data = $request->json()->all();

$orderId = $data['order_id'] ?? null;
$status  = $data['status'] ?? null;
                
            

Strategy 3: Event type versioning

Another approach is versioning the event name itself.

                payment.completed.v2
subscription.updated.v3
            

This allows a system to keep older handlers active while new handlers process newer events.

Storing raw webhook payloads

Regardless of the versioning strategy, always store the raw webhook payload.

                
WebhookEvent::create([
    'event_id' => $eventId,
    'provider' => 'stripe',
    'payload' => json_encode($request->all()),
]);
                
            

This makes debugging easier if the schema changes later.

Versioning mistakes to avoid

  • assuming payload fields will never change
  • hard-coding JSON paths everywhere
  • throwing errors when unknown fields appear
  • not logging webhook payload history

Monitoring schema changes in production

Schema changes often appear silently. Monitoring webhook payload differences helps detect changes before they break processing pipelines.

Tools like WebhookWatch capture every delivery so you can inspect unexpected payload changes in real time.

Related guides:

Start monitoring your webhook endpoints →