Subscriptions
Start, cancel, pause and resume recurring payments from your plugin.
Declare subscriptions when you register, and pick a gateway that supports them:
$gateways = paylexer_get_gateways( array( 'currency' => 'USD', 'subscriptions' => true ) );
Start a subscription
$sub = paylexer_create_subscription( 'acme-bookings', array(
'gateway' => 'stripe',
'amount' => 15.00, // per period, major units
'currency' => 'USD',
'interval' => 'month', // day | week | month | year
'customer' => array( 'email' => $email, 'first_name' => $first, 'last_name' => $last ),
'return_url' => $thanks_url,
'product_name' => 'Gold membership',
) );
Also accepted:
| Field | Notes |
|---|---|
interval_count | |
trial_days | |
billing_cycles | 0 = until cancelled. |
sign_up_fee | |
plan_name | |
reference | Your own order id, e.g. WP-acme-bookings-42: shown as the Purchase ID in the dashboard, never as PayLexer's order reference. |
items | Extra one-time lines charged with the first payment. |
metadata, cancel_url, test_mode | |
order_url | Your page for this subscription on this site; the PayLexer dashboard links the Purchase ID to it. |
Returns:
array(
'subscription_id' => 'SUB-…', // save it; webhooks carry it as data.subscriptionReference
'order_reference' => 'ORD-…', // PayLexer's reference for the first charge; refund it like a one-off order
'gateway_subscription_id' => '…', // may be empty until the gateway confirms
'checkout_url' => 'https://…',
'form_post' => null, // or array( 'endpoint' => …, 'fields' => … )
)
Send the shopper to checkout_url with PayLexer.openCheckout(), or pass formPost when form_post is set. Some gateways need a signed form POST instead.
A subscription can't be confirmed from the browser, so a completed modal calls onPending, not onSuccess: activate it from the subscription_activated webhook.
Full reference: Create subscription.
Manage it
paylexer_cancel_subscription( 'acme-bookings', $subscription_id );
paylexer_pause_subscription( 'acme-bookings', $subscription_id );
paylexer_resume_subscription( 'acme-bookings', $subscription_id );
Only subscriptions your platform created can be managed. Any other ID returns paylexer_not_found. List yours with paylexer_get_orders( $platform, array( 'type' => 'subscription' ) ).
Not every gateway can pause. PayLexer refuses the call with a message when it can't.
A subscription the shopper never completed has nothing to cancel at the gateway yet, so the gateway may refuse the call.
Check its status
$status = paylexer_get_subscription_status( 'acme-bookings', $subscription_id );
// array(
// 'status' => 'ACTIVE', // PENDING, INCOMPLETE, TRIAL, ACTIVE, PAST_DUE, PAUSED, UNPAID, CANCELLED, EXPIRED
// 'active' => true, // TRIAL or ACTIVE
// 'current_period_end' => '2026-11-27T00:00:00.000Z',
// 'trial_end' => null,
// 'cancel_at' => null, // set when it ends at the period end
// 'billing_cycle_count'=> 2,
// ...
// )
Webhooks stay the source of truth. Use the status when the subscriber comes back from checkout (to show "active" before subscription_activated arrives) or to reconcile one you think you missed. On an adapter it's get_subscription_status( $subscription_id ).
Lifecycle events
Renewals, failures and cancellations arrive as webhooks:
Hook (paylexer_platform_{id}_…) | When |
|---|---|
subscription_created | PayLexer created the subscription. |
subscription_activated | First payment succeeded. |
subscription_trial_started, subscription_trial_ended | Trial boundaries. |
subscription_renewed | A renewal was charged. data.renewalOrderReference is the new order, which your platform can refund like its own. |
subscription_payment_failed | A renewal charge failed. |
subscription_paused, subscription_resumed | Paused or resumed. |
subscription_cancelled | Cancelled, by you, the shopper or the gateway. |
subscription_updated | Anything else changed. |
data carries:
| Field | Notes |
|---|---|
subscriptionReference | The subscription_id you saved; match on this. |
subscriptionId | PayLexer's internal ID. |
gatewaySubscriptionId, status, amount, currency, interval, intervalCount | |
currentPeriodStart, currentPeriodEnd, billingCycleCount, customerEmail, orderReference |
Match on subscriptionReference (the subscription_id you saved), not subscriptionId, which is PayLexer's internal ID.
Granting access
A typical mapping, which the starter template ships in Adapter::on_event():
| Event | Access |
|---|---|
subscription.activated, .trial_started, .trial_ended, .renewed, .resumed | Grant, until data.currentPeriodEnd. |
subscription.payment_failed | Past due. Keep or suspend access, your choice; the gateway retries. |
subscription.paused | Suspend. |
subscription.cancelled | Keep until the period ends, then remove. Ignore any later event for it. |