Set up a subscription
Create a recurring billing agreement with one API call. MintCash handles renewals, retries, dunning emails, and cancellation.
A subscription bills a customer on a fixed cadence using a saved card. You create it; we run the billing cycle, retry failures on a sensible schedule, and email the customer at each state transition.
What you decide
- Amount and currency — fixed per subscription.
- Billing interval —
billingIntervalDays. Common values: 7, 14, 30, 90, 365. - First-charge flow — HPP (customer enters card on first sign-up) or token (you already have a saved card).
Creating a subscription
First sign-up (HPP variant)
If the customer doesn't have a saved card yet, send them through the hosted page on creation:
const r = await fetch("https://sandbox.mintcash.me/subscriptions", {
method: "POST",
headers: { Authorization: ..., "Content-Type": "application/json" },
body: JSON.stringify({
externalId: `sub_${customerId}_${planId}`,
amount: 1999,
currency: "USD",
billingIntervalDays: 30,
returnUrl: `${baseUrl}/billing/welcome`,
customer: {
externalId: customerId,
email: customer.email,
name: customer.name,
},
}),
});
const { subscription, redirectUrl } = await r.json();
return Response.redirect(redirectUrl, 302);The customer pays the first invoice on the hosted page. On success, the subscription becomes active and the card token is saved for future renewals.
Returning customer (token variant)
If you already have a cardToken for this customer, skip the hosted page:
const r = await fetch("https://sandbox.mintcash.me/subscriptions", {
method: "POST",
headers: { Authorization: ..., "Content-Type": "application/json" },
body: JSON.stringify({
externalId: `sub_${customerId}_${planId}`,
amount: 1999,
currency: "USD",
billingIntervalDays: 30,
cardToken: savedCardToken,
customer: { externalId: customerId },
}),
});No redirect. The first charge runs server-to-server. You'll receive subscription.succeeded (or .failed) on the webhook.
Listen for renewals
Every renewal fires a webhook. Track the events to keep your own state in sync:
| Event | Subscription state | What to do |
|---|---|---|
subscription.succeeded | active | Extend the customer's access |
subscription.failed | past_due | Surface a banner; we'll auto-retry |
subscription.cancelled | cancelled (terminal) | Revoke access, archive the agreement |
You can also fetch the current state any time with GET /subscriptions/{id}.
Cancel when needed
await fetch(`https://sandbox.mintcash.me/subscriptions/${subscriptionId}`, {
method: "DELETE",
headers: { Authorization: ... },
});Cancellation is immediate and irreversible. No further renewals or retries. Pending invoices are not charged. To start charging again, create a new subscription.
Retry schedule on failure
When a renewal fails, MintCash automatically retries on this cadence:
| Attempt | When |
|---|---|
| 1 | Due date |
| 2 | +1 day |
| 3 | +3 days |
| 4 | +5 days |
| 5 | +7 days |
| — | All exhausted → cancelled |
After the first failure, the customer gets an email prompting them to update their payment method. If they update it, the next renewal cycle starts fresh.
Keep your records consistent
Always use the webhook as the source of truth for subscription state. A
successful response to POST /subscriptions means the agreement was
created — not that the first charge succeeded. Wait for
subscription.succeeded before granting access.
What to test
- Token-flow creation + happy-path renewal
- HPP creation, complete on hosted page, observe
subscription.succeeded - Force first-charge failure (use a failing test card) — subscription should land in
failed - Force renewal failure mid-cycle — observe retries and eventual
cancelled - Customer updates payment method — verify retry recovers the subscription
DELETEan active subscription — observesubscription.cancelled