Subscriptions

Recurring billing across Stripe (auto-renew) and Moncash (prepaid term + reminders).

Overview

Sell subscriptions to your customers on two rails, one API. Stripe holds a card and auto-charges each period. Moncash has no mandate, so a subscription is a prepaid term (e.g. 3 months) the customer manually renews after a reminder — if they don't re-pay, access lapses. A plan is single-rail: Moncash plans are HTG, Stripe plans use a card currency (USD/DOP/CLP).

Create a Plan

A plan defines the price and interval. interval + intervalCount make the term — e.g. month × 3 = every 3 months.

const { plan } = await icone.createSubscriptionPlan({
  name: "Pro",
  amount: 300,          // HTG for Moncash; card currency for Stripe
  processor: "moncash",
  interval: "month",
  intervalCount: 3,     // every 3 months
});

Subscribe a Customer

Subscribing returns a checkoutUrl — send the customer there (Moncash prepaid checkout, or Stripe subscription checkout). The subscription activates when that first payment settles. Pass customerEmail to let Icone Pay email renewal reminders directly.

const res = await icone.subscribe({
  planId: "plan_1",
  customerRef: "user_42",              // your id for the subscriber
  customerEmail: "user@example.com",   // optional
  successUrl: "https://you.com/thanks",
  cancelUrl: "https://you.com/billing",
});
if (!res.error) redirect(res.checkoutUrl!);

Check Access

Icone Pay tracks status; your app grants access. Either react to the webhooks below, or check on demand — an active subscription with a future currentPeriodEnd means grant access.

const { subscriptions } = await icone.listSubscriptions({
  customerRef: "user_42",
  status: "active",
});
const hasAccess = (subscriptions ?? []).length > 0;

Renewals

Stripe renews automatically. Moncash can't auto-charge, so Icone Pay sends a subscription.expiring webhook (and an email if you provided one) before the term ends. Get a fresh checkout URL and send it to your customer to renew:

const { checkoutUrl } = await icone.renewSubscription("sub_abc", {
  successUrl: "https://you.com/thanks",
  cancelUrl: "https://you.com/billing",
});

Cancel

await icone.cancelSubscription("sub_abc");        // immediately
await icone.cancelSubscription("sub_abc", true);  // at period end

Webhooks

Subscription events are signed and delivered to your route webhook URL, exactly like payment webhooks (verify them the same way — see Verifying Webhooks): subscription.active, subscription.renewed, subscription.expiring, subscription.past_due, subscription.expired, subscription.canceled.

{
  "event": "subscription.expiring",
  "subscriptionId": "sub_abc",
  "status": "active",
  "planId": "plan_1",
  "processor": "moncash",
  "customerRef": "user_42",
  "currentPeriodEnd": "2026-06-01T00:00:00.000Z",
  "cancelAtPeriodEnd": false,
  "timestamp": "2026-05-25T05:00:00.000Z"
}