Coupons
Use billingData.couponCodes to pass one or more coupon codes for subscription estimation and creation.
Overview
You can provide coupons in two ways:
- In the initial Create Session API request (
billingData.couponCodes) - By re-creating the session with the updated coupon list when the shopper adds or removes a coupon at checkout
couponCodes must be an array of strings.
{
"billingData": {
"couponCodes": ["SPRING25", "WELCOME10"]
}
}
Option 1: Pass coupons in Create Session API
Send couponCodes during POST /api/session/v1/create.
{
"paymentData": {
"currency": "EUR",
"paymentMethod": "card"
},
"redirectUrl": "https://yourdomain.com/success",
"billingData": {
"lineItems": [
{
"type": "plan",
"id": "price_123",
"quantity": "1"
}
],
"billingPlatformId": "3287b8c7-ce43-41fd-9d58-f510e610b8f3",
"couponCodes": ["SPRING25", "WELCOME10"]
}
}
Option 2: Let shoppers apply coupons at checkout
Coupons are part of the session's billingData, which is set server-side. To let shoppers add or remove coupons on your checkout page, re-create the session with the updated coupon list. Sessions are cheap and single-use, so this is the recommended pattern.
This is exactly how the Altruon Merchant Demo does it (see client/src/pages/CheckoutPage.jsx and server/src/routes.js):
// Frontend: coupon state drives session creation. Whenever the shopper
// applies or removes a coupon, the checkout asks the backend for a FRESH
// session that includes the updated coupon list.
const [couponCodes, setCouponCodes] = useState([]);
useEffect(() => {
// (Re)create the session whenever pricing inputs change.
initializeCheckout(); // → POST /api/session { couponCodes, ... }
}, [couponCodes]);
// Backend: forward the coupon list into billingData on session creation.
const data = await createSession({
paymentData: { currency: cfg.currency },
redirectUrl,
billingData: {
billingPlatformId: cfg.billingConnectionId,
lineItems: buildLineItems(cfg),
...(couponCodes?.length ? { couponCodes } : {}),
},
});
To show the discount before the shopper pays, pair this with the estimate endpoint (POST /api/checkout/v1/{billingConnectionId}/estimate-subscription), which prices the subscription (including coupon discount and tax) without creating anything. The demo's live order summary (client/src/components/OrderSummary.jsx) re-runs the estimate every time the coupon list or billing country changes.
Provider expectations
Use couponCodes consistently in Altruon. Altruon maps values per provider as follows:
Chargebee
- Input in Altruon:
couponCodes: string[] - Sent to Chargebee as:
coupon_ids - Important: values should be valid Chargebee coupon IDs
Recurly
- Input in Altruon:
couponCodes: string[] - Sent to Recurly as:
coupon_codes - Important: values should be valid Recurly coupon codes
Stripe Billing
- Input in Altruon:
couponCodes: string[] - Sent to Stripe as:
discounts[].coupon - Important: values are treated as Stripe coupon IDs (not promotion code IDs)
Frisbii
- Input in Altruon:
couponCodes: string[] - Sent to Frisbii as:
coupon_codes - Important: values should be valid Frisbii coupon codes
Behavior notes
- Multiple coupons are supported (
couponCodesarray) - Empty array means no coupon is sent
- Invalid/unknown coupons are rejected by the billing provider
- Always test coupons in sandbox before production