Skip to Content

Create Subscription Checkout

POST/subscription-checkouts

Description

Create a single-use intent that authorizes a customer to start a recurring subscription. The response includes a checkout_url — redirect the customer there to complete the subscribe + first-charge flow.

The intent does not require a signed request at creation time. The customer’s on-chain signature at the hosted page authorizes the subscription and the first charge atomically. Subsequent merchant-driven charges, cancels, and amount updates use signed requests.

Headers

HeaderDescriptionRequired
AuthorizationBearer token with your API keyyes
Content-Typeapplication/jsonyes

Body Parameters

NameTypeDescriptionRequired
token_symbolstringSettlement token the subscriber pays in (e.g. "USDC", "USDT"). Must resolve to a token address on every chain in supported_chains, with consistent decimals across them.yes
pricestringRecurring price as an integer string. Token-denominated plans (no price_currency): smallest unit of the settlement token (e.g. "9990000" = 9.99 USDC). FIAT plans: minor units of price_currency (e.g. "500000" = ARS 5000.00).yes
price_currencystringPricing denomination. Omit for a token-denominated plan (price is in the settlement token). Set to an ISO 4217 code (e.g. "ARS") for a FIAT plan, which re-rates to the settlement token each cycle.no
period_durationnumberSeconds between scheduled charges. Minimum 3600 (1 hour).yes
supported_chainsstring[]CAIP-2 chain identifiers the customer can pick from (e.g. ["eip155:1", "eip155:137"]). Defaults to every chain where the merchant has a SubscriptionManager deployment. V1 supports the eip155: namespace only.no
recommended_capstringSuggested cap shown to the customer at sign time, in the settlement token's smallest unit — headroom for FX swings and price growth. 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.no
subscriberstringPre-bind the intent to a specific EVM wallet address. When set, the hosted page rejects any other wallet.no
external_customer_idstringYour customer reference. Indexable for filtered queries (GET /subscription-checkouts?external_customer_id=...).no
success_urlstringURL the hosted subscribe page redirects to after the first charge confirms. The page appends ?subscription_checkout_id=schk_xxx&subscription_id=0x... (the on-chain subscription ID).no
cancel_urlstringURL surfaced when the customer dismisses the hosted page or follows a "lost wallet" recovery link.no
metadataobjectArbitrary JSON object for your own bookkeeping (plan reference, session id, referral code, etc.). Echoed back on the intent and copied to the resulting Subscription.no
expires_atstringISO 8601 expiry timestamp. Must be in the future and within 24 hours. Defaults to 5 minutes from creation.no

Example Request

create-subscription-checkout.js
const response = await fetch('https://checkout-api.exodus-int.com/subscription-checkouts', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer sk_live_xxxxxxxxxxxxxxxx',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    token_symbol: 'USDC',
    price: '9990000',
    period_duration: 2592000,
    recommended_cap: '120000000',
    supported_chains: ['eip155:1', 'eip155:137', 'eip155:42161'],
    external_customer_id: 'cus_42',
    success_url: 'https://merchant.com/subscribed',
    cancel_url: 'https://merchant.com/cancelled',
    metadata: { external_plan_ref: 'pro_monthly' },
  }),
});
 
const intent = await response.json();
 
window.location.href = intent.checkout_url;

For a FIAT-denominated plan, set price in the currency’s minor units and add price_currency — e.g. price: '500000', price_currency: 'ARS' (ARS 5000.00/cycle), settled in token_symbol at each cycle’s live rate.

Response

SUCCESSFUL RESPONSE
{
  "object": "subscription_checkout",
  "id": "schk_1234567890abcdef",
  "status": "pending",
  "onchain_id": "0x9f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0d1e2f3a",
  "business_name": "Acme Inc",
  "subscriber": null,
  "external_customer_id": "cus_42",
  "supported_chains": ["eip155:1", "eip155:137", "eip155:42161"],
  "subscription_manager_addresses": {
    "eip155:1": "0xA1B2C3D4E5F6789012345678901234567890ABCD",
    "eip155:137": "0xB2C3D4E5F67890123456789012345678901234CD",
    "eip155:42161": "0xC3D4E5F6789012345678901234567890123456CD"
  },
  "token_addresses": {
    "eip155:1": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
    "eip155:137": "0x2791Bca1f2de4661ED88A30C99A7a9449Aa84174",
    "eip155:42161": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831"
  },
  "token_symbol": "USDC",
  "price": "9990000",
  "price_currency": null,
  "period_duration": 2592000,
  "recommended_cap": "120000000",
  "checkout_url": "https://checkout.exodus-int.com/subscribe/schk_1234567890abcdef",
  "success_url": "https://merchant.com/subscribed",
  "cancel_url": "https://merchant.com/cancelled",
  "metadata": { "external_plan_ref": "pro_monthly" },
  "expires_at": "2026-05-19T12:05:00Z",
  "created_at": "2026-05-19T12:00:00Z",
  "updated_at": "2026-05-19T12:00:00Z"
}

onchain_id is the on-chain subscriptionId (CSPRNG-minted at creation) the contract will identify this subscription by. subscription_manager_addresses and token_addresses are keyed by CAIP-2 — use the entry matching the chain the customer picked.

Validation

Validation failures return an error envelope { error: { type, message, param? } }. There is no machine code for these; switch on error.type and surface error.message.

typeStatusCause
invalid_request422supported_chains includes a chain where the merchant has no SubscriptionManager deployment.
invalid_request422token_symbol doesn’t resolve to a token on every chain in supported_chains.
validation_error400recommended_cap is below the settlement-token value of price.
validation_error400period_duration < 3600 (1 hour).
validation_error400price_currency is not a recognized ISO 4217 code.
validation_error400expires_at is in the past or more than 24 hours in the future.
validation_error400A field failed schema validation (e.g. subscriber is not a valid EVM address). param names the field.

For v1, the chosen token_symbol must have consistent decimals across every chain in supported_chains so a token-denominated price and the recommended_cap are unambiguous. USDC, USDT, and DAI all satisfy this on EVM (6, 6, and 18 decimals respectively, each consistent across chains).

Webhooks Fired

  • subscription_checkout.created — on successful creation
  • subscription_checkout.expired — if expires_at elapses without a successful subscribe
  • subscription_checkout.completed — when the customer signs subscribeAndCharge and the first charge confirms

See Webhooks for the full event payloads.

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