Platform adapters
The developer API as a class: typed requests, exceptions instead of WP_Error, and one method for every webhook.
PayLexer\Integration\PlatformAdapter wraps the same calls as the paylexer_* functions. Use whichever you prefer: an adapter registers the same platform, gets the same orders and is subject to the same limits.
| Functions | Adapter | |
|---|---|---|
| Platform ID | Passed to every call | Set once, as a property |
| Input | Arrays | CheckoutRequest, SubscriptionRequest, Customer, LineItem |
| Errors | Returns WP_Error | Throws PayLexer\Integration\Exception |
| Webhooks | One action per event | One on_event() method |
1. Write the adapter
use PayLexer\Integration\PlatformAdapter;
use PayLexer\Integration\WebhookEvent;
final class Acme_PayLexer extends PlatformAdapter {
protected string $id = 'acme-bookings';
protected string $name = 'Acme Bookings';
protected string $by = 'PayLexer for Acme Bookings';
protected string $plugin = 'acme-bookings/acme-bookings.php';
protected string $plugin_url = 'https://wordpress.org/plugins/acme-bookings/';
protected array $supports = array( 'payments', 'refunds' );
public static function instance(): self {
static $instance = null;
return $instance ??= new self();
}
// Logos for PayLexer → General: the platform's, and your add-on's own.
private function __construct() {
$this->icon = plugins_url( 'assets/acme-bookings.svg', ACME_PAYLEXER_FILE );
$this->addon_icon = plugins_url( 'assets/icon.png', ACME_PAYLEXER_FILE );
}
public function on_event( WebhookEvent $event ): void {
$booking = acme_find_booking_by_paylexer_reference( $event->order_reference );
if ( ! $booking ) {
return;
}
// Events can arrive late or out of order: never move a refunded booking back to paid,
// or a paid or refunded one to failed.
match ( $event->type ) {
'payment.completed' => $booking->is_refunded() ? null : $booking->mark_paid(),
'payment.failed' => $booking->is_paid() || $booking->is_refunded() ? null : $booking->mark_failed(),
// Refunds made in the gateway's or PayLexer's dashboard, full or partial. Skip the
// ones your own refund() sent: you recorded those already.
'payment.refunded' => $event->is_own_refund( $this->id ) ? null : $booking->set_refunded_total( $event->refund->total_refunded ?? $event->refund->amount ),
default => null,
};
}
}
The properties are the same as the paylexer_register_platform() arguments. $id and $name are required.
is_own_refund() needs API 1.1 or later. See WebhookEvent.
2. Register it
PlatformAdapter only exists while PayLexer is active, so load your class inside paylexer_init.
add_action( 'paylexer_init', function () {
require_once __DIR__ . '/class-acme-paylexer.php';
paylexer_register_adapter( Acme_PayLexer::instance() );
} );
paylexer_register_adapter() returns true or a WP_Error, like paylexer_register_platform().
3. Create a checkout
use PayLexer\Integration\CheckoutRequest;
use PayLexer\Integration\Customer;
use PayLexer\Integration\Exception as PayLexerException;
use PayLexer\Integration\LineItem;
try {
$checkout = Acme_PayLexer::instance()->create_checkout( new CheckoutRequest(
gateway: 'stripe',
amount: 120.00,
currency: 'USD',
customer: new Customer( $email, $first_name, $last_name ),
return_url: $thanks_url,
reference: (string) $booking->id,
items: array( new LineItem( 'Kayak tour', 60.00, 2 ) ),
) );
} catch ( PayLexerException $e ) {
// $e->get_error_code() is the same code the functions return, e.g. paylexer_unknown_gateway.
return;
}
update_post_meta( $booking->id, '_paylexer_order_reference', $checkout['order_reference'] );
wp_redirect( $checkout['checkout_url'] );
create_checkout() returns the same array as paylexer_create_checkout(). Send the shopper to checkout_url, or pass the whole array to PayLexer.openCheckout() for the in-page modal.
Settle orders in on_event(), not when the shopper comes back to return_url. The return proves nothing. If you want to show "paid" straight away, call get_payment_status(), which asks the gateway.
4. Handle webhooks
on_event() receives every verified event for your platform. PayLexer has already checked the signature, the tenant and replays.
Throw to have the event delivered again later, for example when your database is down.
WebhookEvent reads payment and subscription events the same way:
| Property | Description |
|---|---|
type | e.g. payment.completed, subscription.renewed |
order_reference | The order from create_checkout(). For a renewal, the renewal's order. |
subscription_id | From create_subscription(); empty for one-time payments. |
amount, currency, status | |
raw | The whole event, as the hook-based API receives it. |
See Webhooks for the event list and retry rules.