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().