Webhooks
Actions and event objects delivered to your plugin.
PayLexer verifies each delivery's signature, checks the tenant, drops replays and logs it before firing your hooks. Guide: Webhooks.
Init action
paylexer_init
Fired on plugins_loaded (priority 20), only while PayLexer is active. Register platforms and adapters here.
Example
add_action( 'paylexer_init', function () {
paylexer_register_platform( 'acme-bookings', array( 'name' => 'Acme Bookings' ) );
} );
Event actions
paylexer_platform_{id}_{event}
paylexer_platform_{id}_webhook
| Action | Arguments | Fired |
|---|---|---|
paylexer_platform_{id}_{event} | array $event | One per verified event. {event} is the event type with . replaced by _. |
paylexer_platform_{id}_webhook | array $event, string $event_type | Every verified event. |
Event types
| Payment | Subscription |
|---|---|
payment_initiated | subscription_created |
payment_authorized | subscription_activated |
payment_captured | subscription_renewed |
payment_completed (fulfil here) | subscription_payment_failed |
payment_failed | subscription_cancelled |
payment_cancelled | subscription_paused, subscription_resumed |
payment_refunded | subscription_trial_started, subscription_trial_ended |
payment_refund_voided | subscription_updated |
Responses
| Handler outcome | Description |
|---|---|
| Returns | The delivery succeeds. Return normally when the order is unknown to you. |
| Throws | The delivery answers 400 and PayLexer retries with backoff. |
| No platform registered | The delivery answers 503 and is retried a limited number of times. |
A late payment_failed can arrive after payment_completed, so never move a paid order back to unpaid. A retry can deliver the same event twice, so make handlers idempotent. See Writing safe handlers.
Example
add_action( 'paylexer_platform_acme-bookings_payment_completed', function ( array $event ) {
$reference = $event['data']['orderReference'];
// Mark your order paid.
} );
Payload
{
"event": "payment.completed",
"timestamp": "2026-10-01T10:00:00.000Z",
"platform": "acme-bookings",
"data": {
"orderReference": "ORD-ADF79AA433405B80",
"amount": 120,
"currency": "USD",
"status": "completed",
"paymentGateway": "stripe",
"customer": { "email": "jo@example.com", "name": "Jo Doe" }
}
}
WebhookEvent
Passed to PlatformAdapter::on_event(). Namespace PayLexer\Integration.
| Field | Description |
|---|---|
type | The event type, e.g. payment.completed. |
order_reference | A renewal's new order for subscription.renewed. |
subscription_id | The subscription_id create_subscription() returned (data.subscriptionReference). |
amount, currency, status | |
raw | The full payload. |
refund | A WebhookRefund on payment.refunded and payment.refund_voided, otherwise null. |
is_own_refund( string $platform ) | true when the refund was sent with your own refund(), so you already recorded it. API 1.1 and later. |
WebhookRefund
| Field | Description |
|---|---|
id | |
amount | This refund only, major units. |
total_refunded | Every succeeded refund on the order, this one included. null from older senders. |
remaining_refundable | |
order_status | refunded, partially_refunded, or completed after a voided refund. |
source | Your platform ID, a gateway code, dashboard or api. |
reason |
Set your refunded total from total_refunded, not by adding amount, so a replayed event changes nothing.