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
charge_amountThe recurring price, in token’s smallest unit (e.g. "9990000" = 9.99 USDC).
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.
cap_amountThe customer’s authorized maximum per call. Each on-chain charge is enforced amount <= cap_amount. Must be >= charge_amount.

The customer’s signature at the hosted page authorizes the contract to pull up to cap_amount per call. This gives merchants room to raise prices later (via POST /subscriptions/:id/update-charge-amount) without forcing the customer to re-sign — as long as the new amount stays under the cap.

🔐

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.com:

  • https://checkout.exodus.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.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