Skip to content

Webhooks

Overview

Incoming provider webhooks are handled by WebhookController and routed through WebhookService to the appropriate WebhookHandlerInterface implementation.

Webhook payloads are always persisted to paymenthub_webhooks before processing to ensure idempotency. A webhook with a duplicate (provider, external_id) pair is silently skipped.

Flow

sequenceDiagram
    participant Provider as Payment Provider
    participant WP as WordPress REST API
    participant WC as WebhookController
    participant WS as WebhookService
    participant WH as WebhookHandler (MobilePay / Frisbii)
    participant DB as paymenthub_webhooks

    Provider->>WP: POST /wp-json/payment-hub/v1/webhook/{provider}
    WP->>WC: handle()
    WC->>WS: process(provider, payload)
    WS->>WH: verify signature
    WH->>DB: INSERT webhook (status=PENDING)
    Note over WH,DB: Duplicate external_id → skip
    WH->>WH: dispatch to Action Scheduler
    WH-->>WC: 200 OK
    Note over WH: Async processing via Action Scheduler
    WH->>DB: UPDATE status=PROCESSED / FAILED

Signature verification

Each webhook handler verifies the provider's HMAC signature against the configured webhook secret before persisting or processing the payload. A failed verification returns HTTP 401.

Async processing

Webhook processing is deferred to Action Scheduler (paymenthub/webhook/process). This decouples the HTTP response time from business logic and provides automatic retry on failure.

Webhook handlers

Provider Handler class
mobilepay MobilePayWebhookHandler
frisbii FrisbiiWebhookHandler

Both implement WebhookHandlerInterface and receive their dependencies via container inflectors in PaymentServiceProvider::boot().