Add-ons
An add-on is a subscription of its own — its own plan, products, status and stable id — that bills on another subscription's invoice, inside that subscription's section. The subscription it bills with is its parent. An add-on has no invoices of its own, and cancelling the parent ends it.
Create add-ons together with a subscription, or add one to a subscription that already runs. Read the relation from either side, and remove an add-on by cancelling it. Every endpoint below takes the scopes and license of the rest of the subscription API (see Subscriptions); full schemas are in the API Reference.
| I want to… | Call |
|---|---|
| Create a subscription and its add-ons in one call | POST /v1/subscriptions with addons |
| Add an add-on to an existing subscription | POST /v1/subscriptions/{id}/addons |
| Turn existing subscriptions into add-ons | POST /v1/subscriptions/{id}/addons/attach |
| Check first whether they can be attached | POST /v1/subscriptions/{id}/addons/eligibility |
| List a subscription's add-ons | GET /v1/subscriptions/{id} or GET /v1/subscriptions, field addons |
| Find an add-on's parent | GET /v1/subscriptions/{id} or GET /v1/subscriptions, field addonOfSubscriptionId |
| See which invoice lines are an add-on's | GET /v1/invoices/{id}, line fields subscriptionId and addonOfSubscriptionId |
| Remove an add-on | POST /v1/subscriptions/cancel with the add-on's id |
| End a subscription and its add-ons | POST /v1/subscriptions/cancel with the parent's id |
Read add-ons
GET /v1/subscriptions/{id} on a parent lists its add-ons under addons, oldest
first. On an add-on, addonOfSubscriptionId and addonOfSubscriptionName name
the parent and addons is empty.
Code
Field on addons[] | Meaning |
|---|---|
subscriptionId | The add-on's own stable id. Read it, or cancel it, by this id. |
subscriptionName | The add-on's current name. |
planId | The plan the add-on runs on, or null for an add-on created without a plan. |
status | The add-on's own status. |
addedOn | The day (YYYY-MM-DD) the add-on was added to the parent. |
effectiveNextBillingDate | When the add-on's next charge is created. It lands on the parent's invoice of that date. |
monthlyRevenue | The add-on's own monthly recurring revenue. The parent's monthlyRevenue does not include it: the parent's full recurring amount is its own plus its add-ons'. |
currency | Always the parent's currency. |
GET /v1/subscriptions carries addonOfSubscriptionId and
addonOfSubscriptionName on every row, and addons naming each add-on by
subscriptionId and subscriptionName only. Read a parent's detail for each
add-on's plan, status and next billing date.
billingGroupId is null on an add-on, and on a parent whose only companions
are its add-ons: a subscription with add-ons is not a
billing group. On an add-on,
scheduledChurnDate reports the parent's scheduled cancellation, since that is
the day the add-on ends.
Create a subscription with add-ons
POST /v1/subscriptions takes addons, up to 19 entries, each naming a plan,
optional product overrides and an optional cadence (see
Cadence). The subscription and its add-ons are created in
one transaction and billed by one billing run, on one invoice. A refused add-on
creates nothing, the subscription included.
Code
Each add-on takes everything except its plan and product overrides from the
subscription in the request: the customer, startDate, endDate,
prorationBehavior, billingDirection, the invoice department and contact, and
the subscription's payment terms, revenue deferral and Leverandørservice
collection. The response is the new subscription, with its add-ons listed under
addons. Their first charge rides the subscription's first invoice.
addons cannot be combined with joinBillingGroupId or
formBillingGroupWithSubscriptionId. Either pair answers
400 SHARED_VALIDATION_FAILED with
details.reason: "ADDONS_WITH_BILLING_GROUP_PLACEMENT" and details.fields
naming both fields, and nothing is created.
Add an add-on to an existing subscription
POST /v1/subscriptions/{id}/addons creates one add-on of the subscription
{id} names and answers 201 with the new add-on, not the parent. Read the
parent afterwards to see it listed under addons.
Code
| Field | Required | Effect |
|---|---|---|
planId | yes | The plan the add-on is created from. It must bill in the parent's currency. |
productOverrides | no | Quantity overrides for products in the add-on's plan, the same shape as on Assign a subscription. |
cadence | no | How often the add-on bills, such as month-1 or year-1. Defaults to the plan's own cadence. See Cadence. |
startDate | no | When the customer gets the add-on. Defaults to today. |
prorationBehavior | no | How a partial period from startDate to the add-on's first full cycle is handled. Default none. See Proration. |
The parent supplies the customer, billing direction, revenue deferral, Leverandørservice collection, send offset, invoice department and contact, payment terms, allowed payment providers and payment details.
The add-on bills on the parent's invoices. Its cycles break on the parent's
billing dates, stepped back on the add-on's own cadence to the first one on or
after startDate:
- An add-on on the parent's cadence that starts on one of the parent's billing dates - for example today, when the parent billed today - bills its first full period from that date. The invoice is stamped with the parent and carries only the add-on's lines, because the parent's own period is already billed.
- An add-on that starts between two of the parent's billing dates has a
partial period up to its first cycle date, handled by
prorationBehavior. - An add-on on a shorter cadence than its parent - a monthly add-on on a yearly subscription - bills on its own cycle dates, each on an invoice stamped with the parent.
A parent that is itself an add-on answers
400 SUBSCRIPTION_ADDON_PARENT_IS_AN_ADDON. A parent with a scheduled
cancellation answers 400 SUBSCRIPTION_ADDON_PARENT_HAS_SCHEDULED_END (with
details.endsOn) or, while the cancellation is still a queued change,
400 SUBSCRIPTION_BILLING_GROUP_MEMBER_HAS_PENDING_CHANGES. Either way nothing
is created.
Cadence
An add-on bills at its plan's own cadence unless the request names another with
cadence, written <interval>-<count>: month-1, month-3, year-1. The
value must be the plan's own cadence or one of its alternative cadences; any
other answers 400 SHARED_VALIDATION_FAILED with
details.reason: "ADDON_CADENCE_NOT_ON_PLAN" and details.allowedCadences
listing the ones the plan offers, and nothing is created.
The cadence can differ from the parent's. A monthly add-on of a yearly subscription bills every month on invoices stamped with the parent; each invoice dated when the parent is not due carries only the add-on lines due that day.
Turn existing subscriptions into add-ons
POST /v1/subscriptions/{id}/addons/attach turns subscriptions the customer
already has into add-ons of {id}. Each keeps its own id, plan and products,
and from then on bills on the parent's invoice, inside its section, and ends
when the parent is cancelled.
Code
Attaching cannot be undone. An add-on cannot be detached to bill on its own again; it ends only by being cancelled. Each attached subscription takes the parent's invoice terms and payment settings and moves onto the parent's billing dates; one that bills on other dates is prorated onto them.
An attached subscription loses its own saved card, because its invoice is now
the parent's, which only the parent's card pays. If the parent bills together
with others in a billing group and the
attach leaves that group billing only the parent, the group's card is removed
too, and the buyer is told. The response is the parent's detail, with the
attached subscriptions under addons, plus cardsRemoved:
Code
A card removed from a billing group names the group in billingGroupId and
carries subscriptionId: null.
Check before attaching
POST /v1/subscriptions/{id}/addons/eligibility answers what the attach would,
without changing anything: every refusal at once, where the attach stops at the
first, and the cards it would remove. Omit subscriptionIds to ask only
whether {id} can take add-ons at all.
Code
Code
Each refusal carries the code and details the attach would answer with. It
needs the subscriptions-read scope; the attach needs subscriptions-write.
An unknown subscription is a 404 on both.
Remove an add-on
An add-on is removed by cancelling it:
POST /v1/subscriptions/cancel with the add-on's id and any strategy. It bills
on its parent's invoice, so refundBehavior: "last_invoice" answers
400 SUBSCRIPTION_ADDON_REFUND_LAST_INVOICE_NOT_SUPPORTED; use
prorated or none. The same code answers a parent cancelled with
last_invoice while it has add-ons and bills on its own invoice, since that
invoice carries their lines; a parent that is a member of a billing group
answers SUBSCRIPTION_BILLING_GROUP_REFUND_LAST_INVOICE_NOT_SUPPORTED.
An add-on cannot be detached from its parent to bill on its own. Taking it off a
billing group with DELETE /v1/billing-groups/{id}/members/{subscriptionId}
answers 400 SUBSCRIPTION_ADDON_CANNOT_LEAVE_ALONE.
Cancel a parent
Cancelling a parent cancels its add-ons with it. The cancel response is the
parent's detail plus cascadedAddonSubscriptionIds, the add-ons the
cancellation takes along:
strategy | cascadedAddonSubscriptionIds |
|---|---|
immediately | The add-ons that ended now. |
end_of_cycle / specific_date | The add-ons that will end with the parent, as they stand when the request is made. |
clear_schedule | Always []. |
Code
A scheduled cancellation is stamped on the parent alone, and the add-ons to end
are resolved again on the day it takes effect. Until then each add-on keeps its
current status and reports the parent's date as its scheduledChurnDate. With
end_of_cycle, the parent and its add-ons end together, on the latest period
end among them, so an add-on on another cadence does not bill a stub period.
An immediate cancellation settles the parent and its add-ons on one document, and has three refusals of its own:
400 SUBSCRIPTION_ADDON_CASCADE_MEMBER_NOT_CHURNABLE— an add-on is in a status it cannot be cancelled from.details.addonSubscriptionIdnames it. An add-on you cancelled immediately a moment earlier is still settling its final charge, and is named withdetails.currentStatus: "cancelled"until that settlement has run. Retry shortly. A scheduled cancellation is not affected: it leaves such an add-on out.400 SUBSCRIPTION_ADDON_CASCADE_MIXED_CREDITED_INVOICES— the refund would credit more than one invoice.details.participantslists each subscription with thecreditedInvoiceNumberit would credit. Cancel withrefundBehavior: "none", or cancel the add-ons first.400 SUBSCRIPTION_ADDON_CASCADE_SET_CHANGED— an add-on was added or removed while the request ran. Nothing was cancelled; read the parent again and retry.
Rules
| Rule | What it means |
|---|---|
| One level deep | An add-on cannot have add-ons of its own, and an add-on cannot be a parent. |
| Same terms as the parent | An add-on belongs to the parent's customer, bills in the parent's currency and has the parent's billing direction, revenue deferral and Leverandørservice collection. One that differs is refused with SUBSCRIPTION_ADDON_PARENT_MISMATCH, details.field naming the setting and details.value / details.parentValue the two values. |
| Billed on the parent's invoice | The add-on's lines appear inside the parent's section of the parent's invoice, after the parent's own lines. The invoice's customerSubscriptionId is the parent's; the add-on has no invoices of its own. See Find an add-on's invoices. |
| Its own cadence | An add-on may bill on a different cadence from its parent. A monthly add-on of a yearly parent bills every month, on the parent's invoice, on its own due dates. An invoice dated when the parent is not due carries only the lines of the add-ons due that day. |
| No card of its own | The add-on is paid with the parent's invoice. automaticBilling: true on an add-on answers 400 SUBSCRIPTION_ADDON_DETAILS_FOLLOW_PARENT. A parent whose only companions are its add-ons keeps its own card, which pays for the add-ons' lines too. |
| The parent's billing grid is fixed | The add-ons are anchored to the parent's billing dates. While a parent has add-ons, a direction or cadence change, pause, resume, billing-anchor reset, send-offset change or merge on it is refused with SUBSCRIPTION_ADDON_PARENT_GRID_LOCKED. Cancel the add-ons to lift it. These are operator-driven flows today; see Change flows. |
| The add-on's grid and details are its parent's | The same changes on an add-on are refused with SUBSCRIPTION_ADDON_FOLLOWS_PARENT_GRID, and a change to its invoice terms or payment settings with SUBSCRIPTION_ADDON_DETAILS_FOLLOW_PARENT: change them on the parent, which passes them on to its add-ons. |
| Ends with the parent | Cancelling the parent cancels every add-on, on the parent's date. |
| Not a billing group | A parent with add-ons reports billingGroupId: null. It can join or form a billing group like any other subscription, and its add-ons come with it. |
Add-ons and billing groups
A member of a billing group can have add-ons. They bill inside that member's section of the group's shared invoice.
GET /v1/billing-groups/{id}lists each member's add-ons undermembers[].addons. An add-on is never a member of its own.- Each add-on uses one of the group's slots.
slotsUsedcounts members plus their add-ons againstmaxSlots(20). A write that would exceed it answers400 SUBSCRIPTION_BILLING_GROUP_MEMBER_LIMITwithdetails.slotsUsed,details.slotsRequestedanddetails.maxSlots. - Forming a group with, or adding, a subscription that has add-ons brings the add-ons along. The form and add responses list them under the member they bill with.
POST /v1/subscriptions/{id}/addonson a group member adds the add-on to the member's group, where it takes a slot.- Taking a member off the group takes its add-ons with it. An add-on cannot be taken off alone.
- An add-on reports
billingGroupId: nulleven when its parent is a member of a group; read the parent for the group.
POST /v1/subscriptions cannot create add-ons and place the subscription on a
group in the same call. Create the subscription onto the group, then add the
add-ons with POST /v1/subscriptions/{id}/addons.
A group whose other members all become add-ons of one of them stops billing
together: GET /v1/billing-groups/{id} then answers billsTogether: false, and
its card, if it had one, is removed and named in the attach's cardsRemoved.
Find an add-on's invoices
An add-on has no invoices of its own: its lines ride on its parent's invoice,
which is addressed to the parent. Each line on GET /v1/invoices/{id} names
the subscription it was billed for in subscriptionId (an add-on's lines name
the add-on), and an add-on's lines name the parent in addonOfSubscriptionId.
To find every invoice an add-on was billed on, list
GET /v1/invoices?subscriptionId=<add-on id>: it returns the parent's invoices
that carry the add-on's lines. See
Invoices.
Selling add-ons at checkout
A plan item in the catalogue lists the add-ons a buyer may take with it, and the partner-hosted checkout sells them with the plan, on the plan's invoice. See Partner-Hosted Checkout → Add-ons.
Support matrix
POST /v1/subscriptions with addons | POST /v1/subscriptions/{id}/addons | POST /v1/subscriptions/{id}/addons/attach | Partner checkout addons | |
|---|---|---|---|---|
| Creates | The subscription and its add-ons | One add-on of an existing subscription | Nothing: existing subscriptions become add-ons | The plan's subscription and its add-ons |
| Add-ons per call | Up to 19 | 1 | Up to 19 | Up to 19, each plan once |
| Add-on starts | On the subscription's startDate | On startDate, default today | Already running | On the session's start date |
| First billed | On the subscription's first invoice | On the parent's invoice on the add-on's first cycle date | On the parent's invoice on its next billing date | On the subscription's first invoice |
| Cadence | cadence, default the add-on plan's own | cadence, default the add-on plan's own | Kept | The plan item's period |
| Card | None | None | Its own card is removed | None |
| Undo | Cancel the add-on | Cancel the add-on | Cancel the add-on; it cannot be detached | Cancel the add-on |
| Response | The subscription, with addons | The new add-on | The parent, with addons and cardsRemoved | The confirm names the plan's subscription |
Errors & failure states
| Condition | What you observe | Fix |
|---|---|---|
addons sent with joinBillingGroupId or formBillingGroupWithSubscriptionId | 400 SHARED_VALIDATION_FAILED, details.reason: "ADDONS_WITH_BILLING_GROUP_PLACEMENT" | Create the subscription onto the group first, then add the add-ons. |
More than 19 entries in addons | 400 SHARED_VALIDATION_FAILED | Send at most 19. |
The parent named in /v1/subscriptions/{id}/addons is itself an add-on | 400 SUBSCRIPTION_ADDON_PARENT_IS_AN_ADDON, details.subscriptionId (the add-on you named) | Add the add-on to that add-on's parent instead. |
| The parent has a scheduled cancellation | 400 SUBSCRIPTION_ADDON_PARENT_HAS_SCHEDULED_END, details.endsOn | Clear the cancellation with clear_schedule, or leave the parent to end. |
| The parent has a queued change | 400 SUBSCRIPTION_BILLING_GROUP_MEMBER_HAS_PENDING_CHANGES, details.pendingChangeIds | Wait for the change to take effect, or cancel it from the parent's scheduled changes — each id is a changeId that GET /v1/subscriptions/{id}/scheduled-changes lists. |
| The add-on's plan, or a subscription being attached, differs from the parent in customer, currency, billing direction, revenue deferral or Leverandørservice collection | 400 SUBSCRIPTION_ADDON_PARENT_MISMATCH, details.field, details.value, details.parentValue | Pick a plan, or a subscription, that matches the parent. |
cadence is not one the add-on's plan offers | 400 SHARED_VALIDATION_FAILED, details.reason: "ADDON_CADENCE_NOT_ON_PLAN", details.allowedCadences | Send one of allowedCadences, or omit cadence. |
| The parent is named among the subscriptions to attach | 400 SUBSCRIPTION_ADDON_SELF_ATTACH, details.subscriptionId | Leave the parent out. |
| A subscription to attach is already an add-on of another subscription | 400 SUBSCRIPTION_ADDON_TARGET_ALREADY_AN_ADDON, details.addonOfSubscriptionId | Attach it to that parent, or cancel it. |
| A subscription to attach has add-ons of its own | 400 SUBSCRIPTION_ADDON_JOINER_HAS_ADDONS, details.addonCount | Add-ons are one level deep; attach its add-ons' parent instead of it, or cancel its add-ons. |
| A subscription to attach is billed together with others in a different billing group | 400 SUBSCRIPTION_BILLING_GROUP_ALREADY_IN_A_GROUP | Take it off that group first. |
| The parent's set, or its group, would exceed 20 slots | 400 SUBSCRIPTION_BILLING_GROUP_MEMBER_LIMIT, details.slotsUsed, details.slotsRequested, details.maxSlots | Cancel an add-on or remove a member first. |
| Taking an add-on off a billing group | 400 SUBSCRIPTION_ADDON_CANNOT_LEAVE_ALONE, details.subscriptionId | Cancel the add-on, or take its parent off the group. |
Cancelling an add-on, or a parent with add-ons outside a billing group, with refundBehavior: "last_invoice" | 400 SUBSCRIPTION_ADDON_REFUND_LAST_INVOICE_NOT_SUPPORTED (a group member: SUBSCRIPTION_BILLING_GROUP_REFUND_LAST_INVOICE_NOT_SUPPORTED) | Use prorated or none. |
| Cancelling a parent immediately while an add-on cannot be cancelled | 400 SUBSCRIPTION_ADDON_CASCADE_MEMBER_NOT_CHURNABLE, details.addonSubscriptionId | Resolve the named add-on's state first. |
| Cancelling a parent immediately with a refund that spans invoices | 400 SUBSCRIPTION_ADDON_CASCADE_MIXED_CREDITED_INVOICES, details.participants | Cancel with refundBehavior: "none", or cancel the add-ons first. |
| An add-on was added or removed while a cancellation ran | 400 SUBSCRIPTION_ADDON_CASCADE_SET_CHANGED | Nothing was cancelled. Read the parent again and retry. |
automaticBilling: true, or another invoice or payment setting, on an add-on | 400 SUBSCRIPTION_ADDON_DETAILS_FOLLOW_PARENT, details.field | Change it on the parent, or set up card billing there. |
| Moving the parent's billing grid while it has add-ons | 400 SUBSCRIPTION_ADDON_PARENT_GRID_LOCKED | Cancel the add-ons first. |
A refusal answered outside /v1/billing-groups never carries
details.billingGroupId, whatever the code.