Skip to Content
CheckoutAPI ReferenceSubscription CheckoutsOverview

Subscription Checkouts

A subscription checkout is a single-use intent that lets a customer authorize a recurring stablecoin subscription. It mirrors the one-shot Checkout flow: the merchant creates an intent on the server, redirects the customer to a hosted subscribe page, and receives webhooks when the customer signs and the first charge confirms on-chain.

Why intents

The subscription plan (price, feature gating, billing day) lives on the merchant side. Exodus only records the per-subscriber intent and captures the resulting on-chain state. One intent maps to one subscriber and one resulting subscription — same lifecycle as one-shot Checkout.

This means there are no reusable /subscribe/:planId URLs in v1: every subscribe flow starts with a fresh merchant-server call to POST /subscription-checkouts.

Atomic first charge

When the customer signs at the hosted page, the on-chain subscribeAndCharge transaction registers the subscription and performs the first charge in a single transaction. The intent never transitions to completed without a confirmed first charge — there is no “subscribed but not charged” state.

Lifecycle

StatusMeaning
pendingIntent created; no on-chain subscribe yet.
completedCustomer signed subscribeAndCharge; first charge confirmed; Subscription materialized.
cancelledMerchant called PATCH /subscription-checkouts/:id/cancel, or customer dismissed the hosted page.
expiredexpires_at elapsed without a successful subscribe. Default expiry is 5 minutes; maximum is 24 hours.

Race resolution — on-chain truth wins

If a subscribeAndCharge transaction is already in the mempool when the merchant cancels (or when the cron sweeper marks the intent expired), and that transaction later confirms on-chain, the indexer flips the intent back to completed and dispatches a subscription_checkout.completed webhook.

Merchants must handle late subscription_checkout.completed webhooks that arrive after a .cancelled or .expired event. The latest webhook is authoritative.

Chain identifiers (CAIP-2)

The subscription surface uses CAIP-2 chain identifier strings throughout — eip155:1 for Ethereum mainnet, eip155:137 for Polygon, etc. The merchant publishes supported_chains: string[] at intent creation; the customer picks one at sign time based on their wallet balances.

V1 supports the eip155: namespace only (EVM chains).

CAIP-2Network
eip155:1Ethereum mainnet
eip155:137Polygon
eip155:42161Arbitrum One
eip155:8453Base
eip155:10Optimism

Amounts and cap

FieldMeaning
priceThe recurring price. Token-denominated plans (no price_currency): settlement-token smallest unit (e.g. "9990000" = 9.99 USDC). FIAT plans: minor units of price_currency.
price_currencyOptional pricing denomination. Omitted = token-denominated; an ISO 4217 code (e.g. ARS) = FIAT, re-rated to the settlement token each cycle.
period_durationSeconds between scheduled charges. Minimum 1 hour. Day-of-month and other calendar billing is the merchant’s responsibility — schedule the API call when desired.
recommended_capOptional. The merchant’s suggested cap, in the settlement token’s smallest unit, shown to the customer at sign time. If provided, must be >= the settlement-token value of price. The customer sets the actual on-chain cap_amount when subscribing — the cap is subscriber-sovereign.

The customer chooses the on-chain cap_amount when they sign at the hosted page — optionally seeded by the merchant’s recommended_cap — authorizing the contract to pull up to that cap per call. FIAT plans re-rate each cycle, so a generous cap absorbs FX swings and price growth; a cycle that would exceed the cap reverts until the customer raises it, never a silent over-pull.

🔐

The customer’s wallet approves the on-chain contract for uint256.max allowance at subscribe time (industry standard pattern matching Uniswap, Aave, etc.). Cap enforcement happens in the contract, not the ERC-20 allowance.

Hosted pages

Two hosted pages live on checkout.exodus-int.com:

  • https://checkout.exodus-int.com/subscribe/:subscription_checkout_id — the subscribe page returned in checkout_url. The customer connects a wallet, picks a chain, optionally signs an EIP-2612 permit, and signs subscribeAndCharge.
  • https://checkout.exodus-int.com/cancel/:subscription_id — a customer-facing cancel page keyed on the on-chain subscription_id. The customer connects the subscribing wallet and signs cancel(subscriptionId) directly. Surface this URL in your customer account UI for self-service cancellation.

Available Endpoints

After the customer signs, the resulting on-chain subscription is managed via the Subscriptions endpoints.

Start building

XO

Request Demo

Schedule a call with our team

Select a product
Arrow right

Start building
Grateful

Contact Us

We're here to help