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, budget, and cap

The merchant declares the plan limits at intent creation. The subscriber signs these exact values at the hosted page — they are not customer-editable.

FieldMeaning
priceThe recurring per-cycle amount, in the settlement token’s smallest unit (e.g. "9990000" = 9.99 USDC). Subscriptions are token-denominated today; FIAT-denominated pricing is not yet available.
budgetRequired. The per-cycle spend ceiling — the maximum total that can be charged within a single billing window (supports multiple metered charges per cycle). Must be >= price.
capOptional per-charge maximum — the most a single charge can pull. Must satisfy price <= cap <= budget. Defaults to budget when omitted.
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.

budget bounds the total pulled per billing window; cap bounds any single charge. A cycle whose charges would exceed budget, or a single charge above cap, reverts on-chain — never a silent over-pull. Headroom above price accommodates later price increases without re-subscribing.

🔐

The customer’s wallet approves the on-chain contract for uint256.max allowance at subscribe time (industry standard pattern matching Uniswap, Aave, etc.). budget and 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.

Last updated on

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