WordPress GuidesSubscriptions

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:

FieldNotes
interval_count
trial_days
billing_cycles0 = until cancelled.
sign_up_fee
plan_name
referenceYour own order id, e.g. WP-acme-bookings-42: shown as the Purchase ID in the dashboard, never as PayLexer's order reference.
itemsExtra one-time lines charged with the first payment.
metadata, cancel_url, test_mode
order_urlYour 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_createdPayLexer created the subscription.
subscription_activatedFirst payment succeeded.
subscription_trial_started, subscription_trial_endedTrial boundaries.
subscription_renewedA renewal was charged. data.renewalOrderReference is the new order, which your platform can refund like its own.
subscription_payment_failedA renewal charge failed.
subscription_paused, subscription_resumedPaused or resumed.
subscription_cancelledCancelled, by you, the shopper or the gateway.
subscription_updatedAnything else changed.

data carries:

FieldNotes
subscriptionReferenceThe subscription_id you saved; match on this.
subscriptionIdPayLexer'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():

EventAccess
subscription.activated, .trial_started, .trial_ended, .renewed, .resumedGrant, until data.currentPeriodEnd.
subscription.payment_failedPast due. Keep or suspend access, your choice; the gateway retries.
subscription.pausedSuspend.
subscription.cancelledKeep until the period ends, then remove. Ignore any later event for it.

Next steps