Capability matrix
The full per-provider RevenueCapabilities reference for Polar, Lemon Squeezy, Stripe, Paddle, and Dodo Payments.
A complete reference of the RevenueCapabilities values each provider reports. Every provider exposes
this object as capabilities, also surfaced on client.capabilities. The client gates on these values
and throws unsupported rather than silently dropping an option — see
Capabilities.
Matrix
| Capability | Type | Polar | Lemon Squeezy | Stripe | Paddle | Dodo Payments |
|---|---|---|---|---|---|---|
cancellationReason |
boolean |
true |
false |
true |
false |
true |
checkoutCustomAmount |
boolean |
true |
true |
false |
false |
false |
checkoutExpiresAt |
boolean |
false |
true |
true |
false |
false |
checkoutStatus |
boolean |
true |
false |
true |
true |
true |
checkoutSuccessUrl |
boolean |
true |
true |
true |
false |
true |
customerMetadata |
boolean |
true |
false |
true |
true |
true |
endTrial |
boolean |
true |
true |
true |
true |
false |
hostedCheckout |
boolean |
true |
true |
true |
false |
true |
licenseKeys |
boolean |
true |
true |
false |
false |
true |
listOrdersByCustomer |
boolean |
true |
false |
true |
true |
true |
listSubscriptionsByCustomer |
boolean |
true |
false |
true |
true |
true |
pause |
boolean |
true |
true |
true |
true |
false |
pauseBehaviors |
PauseBehavior[] |
period_end |
immediately |
immediately |
immediately, period_end |
[] |
portalReturnUrl |
boolean |
true |
false |
true |
false |
true |
prorationBehaviors |
ProrationBehavior[] |
invoice_now, prorate |
invoice_now, prorate, none |
invoice_now, none, prorate |
invoice_now, none, prorate |
invoice_now, none |
revoke |
boolean |
true |
false |
true |
true |
true |
uncancel |
boolean |
true |
true |
true |
true |
true |
usageReporting |
boolean |
true |
false |
true |
false |
true |
The in-memory provider from revenue-sdk/testing reports every capability true, all three
proration behaviors and both pause behaviors, and accepts a Partial<RevenueCapabilities> override —
see Testing provider.
What each field gates
cancellationReason?boolean
Whether subscriptions.cancel forwards reason/comment. Passing either without support throws unsupported.
booleancheckoutCustomAmount?boolean
Whether checkouts.create accepts customAmount, the buyer-chosen price of a pay-what-you-want product. Passing it without support throws unsupported.
booleancheckoutExpiresAt?boolean
Whether checkouts.create accepts expiresAt. Passing it without support throws unsupported — Polar, Paddle, and Dodo Payments apply a fixed lifetime instead.
booleancheckoutStatus?boolean
Whether Checkout.status is populated. When false, status is always null (Lemon Squeezy checkouts carry no lifecycle status).
booleancheckoutSuccessUrl?boolean
Whether checkouts.create accepts successUrl. Passing it without support throws unsupported (Paddle configures redirects in Paddle.js).
booleancustomerMetadata?boolean
Whether customers.create and customers.update accept metadata. Passing it without support throws unsupported (the Lemon Squeezy customer object has no metadata field).
booleanendTrial?boolean
Whether subscriptions.endTrial is supported. Calling it without support throws unsupported.
booleanhostedCheckout?boolean
Whether checkouts.create returns a ready-to-use provider-hosted URL. When false (Paddle), the URL is your own Paddle.js page and needs a configured default payment link plus an approved domain.
booleanlicenseKeys?boolean
Whether the licenseKeys namespace is supported. Calling any of its methods without support throws unsupported (Stripe has no license API; Paddle Billing v1 dropped license keys). Validating and activating keys needs no client at all — see the provider subpath exports.
booleanlistOrdersByCustomer?boolean
Whether orders.list/listAll accept customerId. Passing it without support throws unsupported (Lemon Squeezy filters orders by store, user email, and order number only). Listing unfiltered works everywhere.
booleanlistSubscriptionsByCustomer?boolean
Whether subscriptions.list/listAll accept customerId. Passing it without support throws unsupported.
booleanpause?boolean
Whether subscriptions.pause and subscriptions.resume are supported. Calling either without support throws unsupported.
booleanpauseBehaviors?('immediately' | 'period_end')[]
Behaviors subscriptions.pause accepts. Any other value throws unsupported before the request; omitting behavior uses the provider default. Empty when pause is false.
('immediately' | 'period_end')[]portalReturnUrl?boolean
Whether customerPortal.createSession accepts returnUrl. Passing it without support throws unsupported.
booleanprorationBehaviors?('prorate' | 'invoice_now' | 'none')[]
Behaviors subscriptions.changePlan accepts. Any other value throws unsupported before the request.
('prorate' | 'invoice_now' | 'none')[]revoke?boolean
Whether subscriptions.revoke (cancel immediately) is supported.
booleanuncancel?boolean
Whether subscriptions.uncancel can revert a scheduled cancellation.
booleanusageReporting?boolean
Whether usage.report is supported. Calling it without support throws unsupported (Lemon Squeezy keys usage on a subscription item and has no idempotency; Paddle has no usage API).
booleanBeyond the capability object
Some limits are too fine-grained for a boolean and are enforced by the adapters, which throw
RevenueError { code: 'unsupported' } at call time:
| Limitation | Providers |
|---|---|
Checkout item quantity must be 1 |
Polar |
| Exactly one checkout item | Lemon Squeezy |
customerId not accepted on a checkout (use customerEmail) |
Lemon Squeezy |
Plan-change quantity must be 1 |
Polar, Lemon Squeezy |
| No customer portal until the customer has a subscription | Lemon Squeezy (not_found) |
These gaps trace back to real differences between the underlying APIs — Stripe vs Polar vs Lemon Squeezy vs Paddle vs Dodo explains where each one comes from.
Reading capabilities at runtime
if (client.capabilities.revoke) {
showRevokeButton();
}
const proration = client.capabilities.prorationBehaviors.includes('none') ? 'none' : 'prorate';
if (!client.capabilities.hostedCheckout) {
// Paddle: render your own Paddle.js page instead of redirecting.
}