Modify or renew a subscription
Operation ID: modifySubscription
Group: Accounting › Subscriptions
Open in the interactive reference
POST /accounting/subscriptions/{id}/modify
Retry-safe: A write that accepts Idempotency-Key: repeating a request with the same key replays the stored answer instead of executing twice.
Modifies or renews a subscription. When modificationType is 'midTermModification', the changes to lines take effect on modificationDate. You can add products, including tiered, rate-card and ramp pricing, increase quantities, cancel lines, and replace products.
Each 'midTermModification' request creates one subscription modification, whose id is subscriptionModificationId in the response. The request also creates one modification sales order, unless it only cancels lines.
When modificationType is 'renew', the whole subscription renews for another term that starts the day after the current service end date. The request creates one renewal sales order that copies the subscription's active lines.
When modificationType is 'earlyRenew', the new term starts early, on modificationDate, which must fall after the current term's start. The request creates one early-renewal sales order that copies the lines active the day before. On approval the current term ends on that date: its un-invoiced overlap is billed and its invoiced overlap is credited.
To cancel the whole subscription, use POST accounting/subscriptions/:id/cancel.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
Api-Version |
header | string · v1 | yes | The API version this request targets, named by its public identifier. Required on every request; omitting it, or naming a version this company does not have, is answered with 400. This document describes version v1. |
Idempotency-Key |
header | string | no | An opaque caller-chosen string (1-255 characters) that makes this request safe to retry. Repeating the same key with an identical request body replays the original response instead of re-executing - but only once that original request succeeded; a failed attempt re-executes on retry. Repeating the key with a different body is answered with 422. A key still in flight is answered with 409 - as is a key whose original request was interrupted before it finished, for a few minutes afterwards, until that attempt is presumed dead. A completed response stays replayable for 24 hours. The key is scoped to the caller, not to the action: reusing it for a different action is answered with 409 or 422 rather than treated independently. On read actions this header is ignored. On write actions that cannot offer the guarantee it is answered with 400 IDEMPOTENCY_NOT_SUPPORTED rather than silently ignored. |
id |
path | string | yes | Id of the subscription to modify (a UUID); bound from the :id path segment. Must belong to customerId. |
Request body
Required, application/json: modifySubscriptionInput.
| Field | Type | Required | Description |
|---|---|---|---|
customerId |
string | yes | [fk: CustomerApi.customers.id] Id of the customer owning the subscription being modified (a UUID). The subscription must belong to this customer. |
externalOrderId |
string | yes | Idempotency key assigned by the upstream system (e.g. CPQ order id). When the tenant has a SalesOrderExternalIdentifierConfiguration for fieldName externalOrderId, the value is stamped on the generated sales order and a resubmission is rejected with DUPLICATE_EXTERNAL_ORDER_ID; without that configuration duplicates are not detected. |
modificationType |
any | yes | Discriminator for the kind of modification. midTermModification applies the line arrays (addLines/changeLines/cancelLines/replaceGroups) on the modificationDate. renew renews the whole subscription: it carries term/priceChangePercentage and must omit the line arrays and modificationDate. earlyRenew renews the whole subscription early: same shape as renew plus the required modificationDate. One of: "midTermModification", "renew", "earlyRenew". |
bookDate |
date | no | Booking date for the generated sales order (ISO 8601, YYYY-MM-DD). Defaults to today for midTermModification and earlyRenew, and to the renewal service start date for renew. |
effectiveDate |
date | no | Sales effective date stamped on the generated sales order (ISO 8601, YYYY-MM-DD). Defaults to the modificationDate. Not supported for renewal payloads. |
oneTimeDiscountAmount |
decimal | no | Order-level one-time discount amount in the subscription currency. Not supported for renewal payloads. |
oneTimeDiscountAllocation |
any | no | How the one-time discount is allocated across invoices (firstInvoice, alignToInvoiceFrequency). Not supported for renewal payloads. One of: "firstInvoice", "alignToInvoiceFrequency". |
billToAddressId |
string | no | [fk: CustomerApi.customers.addresses.id] Bill-to address for the generated sales order (a UUID). Must belong to the customer. Defaults to the originating order's bill-to address. Not supported for renewal payloads. |
soldToAddressId |
string | no | [fk: CustomerApi.customers.addresses.id] Sold-to address for the generated sales order (a UUID). Must belong to the customer. Defaults to the originating order's sold-to address. Not supported for renewal payloads. |
signDate |
date | no | Date the modification was signed/agreed upstream (ISO 8601, YYYY-MM-DD) |
purchaseOrder |
string | no | Customer purchase order reference |
opportunityId |
string | no | Upstream opportunity identifier (e.g. Salesforce opportunity id) |
opportunityName |
string | no | Upstream opportunity name |
approvalStatus |
any | no | Approval status of the generated sales order. Authoritative upstream systems may pass approved to apply the modification without manual approval. Defaults to pendingApproval. One of: "pendingApproval", "approved". |
externalizedCalculations |
boolean | no | midTermModification only. When true, the caller owns line totals: every addLines entry (top-level and in replaceGroups) and every rampDeal ramp must carry totalPrice (TOTAL_PRICE_REQUIRED), every changeLines entry must carry totalPrice for its added quantity (CHANGE_LINE_TOTAL_PRICE_REQUIRED) and may not target a ramp line (EXTERNALIZED_RAMP_CHANGE_NOT_SUPPORTED), the value is stored as given, and Everest does not recalculate it. Defaults to false, where totals are calculated by Everest and any totalPrice is ignored. |
modificationDate |
date | no | Effective date of the modification (ISO 8601, YYYY-MM-DD). Required for midTermModification: service changes take effect on this date and it must fall within the subscription service period. Required for earlyRenew: the new term starts on this date, which must be after the current term's start date and no later than the service end date. Must be omitted for renew (the renewal starts the day after the current service end date). |
term |
number | no | renew and earlyRenew only: renewal term in months. Defaults to the subscription's configured auto-renewal term; when neither is set a renewal is rejected with RENEWAL_TERM_MISSING. |
priceChangePercentage |
decimal | no | renew and earlyRenew only: fractional price increase applied to the list and unit prices of every renewed line (0.05 = 5% increase; tiered lines keep their prices). Defaults to the subscription's configured auto-renewal price increase. Negative values are rejected. |
note |
string | no | Free-text note. Recorded on the SubscriptionModification for midTermModification and on the renewal sales order for renew/earlyRenew. |
addLines |
array<object> | no | New products to add to the subscription. Same pricing surface as SalesOrderApi.create subscription products (tiers, rate cards, ramp deals). |
addLines[].productLineId |
string | yes | [fk: ProductLineApi.productLines.id] Id of the product line defining pricing and billing rules (a UUID) |
addLines[].quantity |
decimal | no | Quantity of the product. Optional when (a) the line type sources quantity from usage records or external capture, or (b) rampDeal is provided (each ramp period carries its own quantity). |
addLines[].invoiceFrequency |
any | no | Invoice frequency. Defaults to product line setting. One of: "monthly", "biMonthly", "quarterly", "semiAnnually", "annually", "once", "custom", "template", "milestone", "allAtOnce". |
addLines[].invoiceTiming |
any | no | Invoice timing relative to service period (advance, arrears). Defaults to entity policy. One of: "advance", "arrears". |
addLines[].lineInvoiceDay |
string | no | Specific day for generating invoices. Defaults to entity policy. |
addLines[].priceModel |
any | no | Pricing model. Defaults to product line setting. One of: "flat", "perUnit", "tiered", "volume", "stairstep", "rateCard", "thresholdBased". |
addLines[].unitOfMeasure |
any | no | Unit of measure (instance, gigabyte, terabyte, user, seat, minute, hour, day, month, each, license, activeUser, megabyte, message, text, platform, employee, personnel, credit, currency, package, case). Defaults to product line setting. One of: "instance", "gigabyte", "terabyte", "user", "seat", "minute", "hour", "day", "month", "each", "license", "activeUser", "megabyte", "message", "text", "platform", "employee", "personnel", "credit", "currency", "package", "case". |
addLines[].listPrice |
decimal | no | Standard list price before discounts. Defaults to unitPrice when omitted; must be omitted when the product line has enforceListPrice set. |
addLines[].unitPrice |
decimal | no | Actual unit price after applying discounts. Required unless rampDeal is provided. |
addLines[].totalPrice |
decimal | no | Total price of the added line, stored as given. Required when externalizedCalculations is true unless rampDeal is provided (each ramp then carries its own totalPrice); ignored otherwise. |
addLines[].altProductName |
string | no | Alternative product name stored on the created sales order product. Passed through as given. |
addLines[].discount |
decimal | no | Discount value (interpreted based on discountType) |
addLines[].discountType |
any | no | Discount type (amount, percentage) One of: "amount", "percentage". |
addLines[].pricingTerm |
any | no | Pricing term period. Defaults to product line setting. One of: "monthly", "biMonthly", "once", "quarterly", "semiAnnually", "annually". |
addLines[].tiers |
array<object> | no | Pricing tiers for tiered/volume/stairstep price models. Tiers must cover contiguous quantity ranges starting at 0; bounds are inclusive and each tier's fromQuantity must be exactly the previous tier's toQuantity + 1 (e.g. 0-100, 101-500, 501-open). |
addLines[].tiers[].fromQuantity |
decimal | yes | Lower bound of quantity range (inclusive). First tier must start at 0. |
addLines[].tiers[].toQuantity |
decimal | no | Upper bound of quantity range (inclusive). Omit on the last tier for open-ended ranges. |
addLines[].tiers[].unitPrice |
decimal | yes | Per-unit price for quantities in this tier after discount |
addLines[].tiers[].listPrice |
decimal | no | Per-unit list price before discount. Defaults to unitPrice. |
addLines[].tiers[].priceModel |
any | no | Per-tier price model (flat, perUnit). Defaults to perUnit. One of: "flat", "perUnit". |
addLines[].rateCardEntries |
array<object> | no | Rate card entries for this product line. Required when priceModel is rateCard and the product line has no template entries. |
addLines[].rateCardEntries[].identifier |
string | yes | BillableComponent identifier for this meter |
addLines[].rateCardEntries[].description |
string | no | Free-text description of the rate card entry |
addLines[].rateCardEntries[].unitOfMeasure |
string | yes | Unit of measure for this meter |
addLines[].rateCardEntries[].unitPrice |
decimal | yes | Per-unit rate negotiated for this modification |
addLines[].rateCardEntries[].listPrice |
decimal | no | Per-unit list price. Honored only when product line enforceListPrice is false. |
addLines[].rateCardEntries[].conversion |
decimal | no | Conversion factor between billable and reporting units |
addLines[].rampDeal |
object | no | Ramp deal definition for phased additions. Mutually exclusive with top-level quantity/unitPrice. |
addLines[].rampDeal.interval |
any | yes | How ramps are defined. annually = auto-derive yearly ramps; specificDates = caller provides explicit serviceStartDate/serviceEndDate per ramp. One of: "annually", "specificDates". |
addLines[].rampDeal.invoiceTiming |
any | yes | perInterval invoices at each ramp start; allAtOnce invoices the whole deal upfront and requires every ramp invoiceFrequency = allAtOnce. One of: "perInterval", "allAtOnce". |
addLines[].rampDeal.ramps |
array<object> | yes | One entry per ramp, in chronological order. Minimum 2 ramps. |
addLines[].rampDeal.ramps[].serviceStartDate |
date | no | Ramp service start date (ISO 8601, YYYY-MM-DD). Required for specificDates; omit for annually. |
addLines[].rampDeal.ramps[].serviceEndDate |
date | no | Ramp service end date (ISO 8601, YYYY-MM-DD). Required for specificDates; omit for annually. |
addLines[].rampDeal.ramps[].quantity |
decimal | yes | Quantity for this ramp |
addLines[].rampDeal.ramps[].listPrice |
decimal | no | Ramp list price. Defaults to the ramp unitPrice when omitted; must be omitted when the product line has enforceListPrice set. |
addLines[].rampDeal.ramps[].unitPrice |
decimal | yes | Ramp unit price after discount |
addLines[].rampDeal.ramps[].totalPrice |
decimal | no | Total price of this ramp period, stored as given. Required when externalizedCalculations is true; ignored otherwise. |
addLines[].rampDeal.ramps[].invoiceFrequency |
any | no | Ramp invoice frequency. Must be allAtOnce on every ramp when invoiceTiming is allAtOnce. One of: "monthly", "biMonthly", "quarterly", "semiAnnually", "annually", "once", "custom", "template", "milestone", "allAtOnce". |
addLines[].serviceStartDate |
date | no | Service start date of the added product (ISO 8601, YYYY-MM-DD). Defaults to the modificationDate. |
addLines[].serviceEndDate |
date | no | Service end date of the added product (ISO 8601, YYYY-MM-DD). Defaults to coterminous with the subscription. |
addLines[].externalIdentifiers |
array<object> | no | External identifiers to attach, e.g. from NetSuite or Salesforce |
addLines[].externalIdentifiers[].fieldName |
string | yes | Field name defined in the corresponding ExternalIdentifierConfiguration |
addLines[].externalIdentifiers[].value |
string | yes | External identifier value |
addLines[].externalIdentifiers[].externalUrl |
string | no | Optional link to record in originating system |
changeLines |
array<object> | no | Changes to existing subscription lines: quantity, price, discount, and tier changes. Every entry must carry at least one change field (CHANGE_LINE_NO_CHANGES). v1 implements quantity increases only: a decrease is rejected with QUANTITY_DECREASE_NOT_SUPPORTED (model a downgrade as a replaceGroup); tier/volume/stairstep and rate-card priced lines are supported, but flat-priced and usage-type lines are rejected with CHANGE_QUANTITY_UNSUPPORTED_LINE_TYPE. Price, discount, and tier changes (newUnitPrice, newListPrice, newDiscount, newDiscountType, newTiers) are reserved and rejected with CHANGE_KIND_NOT_SUPPORTED. |
changeLines[].subscriptionLineId |
string | yes | Id of the subscription line being changed (a UUID) |
changeLines[].newQuantity |
decimal | no | New total quantity for the line (not the delta). v1 supports increases only. |
changeLines[].unitPrice |
decimal | no | Unit price for the added quantity when newQuantity is provided; defaults to the line's current unit price. This prices the delta only — use newUnitPrice to reprice the whole line. |
changeLines[].totalPrice |
decimal | no | Total price of the added quantity, stored as given on the delta line. Required when externalizedCalculations is true, where the line must not be a ramp line; ignored otherwise. |
changeLines[].newUnitPrice |
decimal | no | New unit price for the whole line from the modification date (reprice without quantity movement). Reserved: rejected with CHANGE_KIND_NOT_SUPPORTED until reprice ships. |
changeLines[].newListPrice |
decimal | no | New list price for the whole line. Only valid together with newUnitPrice; must be omitted when the product line has enforceListPrice set. Reserved: rejected with CHANGE_KIND_NOT_SUPPORTED until reprice ships. |
changeLines[].newDiscount |
decimal | no | New discount value for the line, interpreted based on newDiscountType. Reserved: rejected with CHANGE_KIND_NOT_SUPPORTED until reprice ships. |
changeLines[].newDiscountType |
any | no | How newDiscount is interpreted (amount, percentage). Required when newDiscount is provided. One of: "amount", "percentage". |
changeLines[].newTiers |
array<object> | no | Replacement tier table for a tier/volume/stairstep priced line; same shape and rules as addLines.tiers. May be combined with newQuantity. Reserved: rejected with CHANGE_KIND_NOT_SUPPORTED until reprice ships. |
changeLines[].newTiers[].fromQuantity |
decimal | yes | Lower bound of quantity range (inclusive). First tier must start at 0. |
changeLines[].newTiers[].toQuantity |
decimal | no | Upper bound of quantity range (inclusive). Omit on the last tier for open-ended ranges. |
changeLines[].newTiers[].unitPrice |
decimal | yes | Per-unit price for quantities in this tier after discount |
changeLines[].newTiers[].listPrice |
decimal | no | Per-unit list price before discount. Defaults to unitPrice. |
changeLines[].newTiers[].priceModel |
any | no | Per-tier price model (flat, perUnit). Defaults to perUnit. One of: "flat", "perUnit". |
cancelLines |
array<object> | no | Partial cancellations of existing subscription lines |
cancelLines[].subscriptionLineId |
string | yes | Id of the subscription line to cancel (a UUID) |
cancelLines[].serviceEndDate |
date | no | Service end date (ISO 8601, YYYY-MM-DD). Defaults to the modificationDate; in v1 a differing value is rejected (service always ends on the modificationDate). |
replaceGroups |
array<object> | no | Product replacements (swaps/downgrades). Each group is atomic: its added lines activate together on the group's service start date and each replaced line's service ends on that same date. A group must contain at least one cancelLine and one addLine (REPLACE_GROUP_INCOMPLETE), all its addLines must resolve to the same service start date (REPLACE_GROUP_START_DATE_MISMATCH), and in v1 that date must be the modificationDate. A line may be canceled only once across cancelLines and all groups (DUPLICATE_CANCEL_TARGET). |
replaceGroups[].cancelLines |
array<object> | yes | Existing subscription lines this group replaces. Their service ends on the group's service start date; no per-line serviceEndDate can be provided. |
replaceGroups[].cancelLines[].subscriptionLineId |
string | yes | Id of the subscription line being replaced (a UUID) |
replaceGroups[].addLines |
array<object> | yes | Replacement products to add. Same shape and pricing surface as top-level addLines. serviceStartDate defaults to the modificationDate and must resolve to the same date on every add in the group. |
replaceGroups[].addLines[].productLineId |
string | yes | [fk: ProductLineApi.productLines.id] Id of the product line defining pricing and billing rules (a UUID) |
replaceGroups[].addLines[].quantity |
decimal | no | Quantity of the product. Optional when (a) the line type sources quantity from usage records or external capture, or (b) rampDeal is provided (each ramp period carries its own quantity). |
replaceGroups[].addLines[].invoiceFrequency |
any | no | Invoice frequency. Defaults to product line setting. One of: "monthly", "biMonthly", "quarterly", "semiAnnually", "annually", "once", "custom", "template", "milestone", "allAtOnce". |
replaceGroups[].addLines[].invoiceTiming |
any | no | Invoice timing relative to service period (advance, arrears). Defaults to entity policy. One of: "advance", "arrears". |
replaceGroups[].addLines[].lineInvoiceDay |
string | no | Specific day for generating invoices. Defaults to entity policy. |
replaceGroups[].addLines[].priceModel |
any | no | Pricing model. Defaults to product line setting. One of: "flat", "perUnit", "tiered", "volume", "stairstep", "rateCard", "thresholdBased". |
replaceGroups[].addLines[].unitOfMeasure |
any | no | Unit of measure (instance, gigabyte, terabyte, user, seat, minute, hour, day, month, each, license, activeUser, megabyte, message, text, platform, employee, personnel, credit, currency, package, case). Defaults to product line setting. One of: "instance", "gigabyte", "terabyte", "user", "seat", "minute", "hour", "day", "month", "each", "license", "activeUser", "megabyte", "message", "text", "platform", "employee", "personnel", "credit", "currency", "package", "case". |
replaceGroups[].addLines[].listPrice |
decimal | no | Standard list price before discounts. Defaults to unitPrice when omitted; must be omitted when the product line has enforceListPrice set. |
replaceGroups[].addLines[].unitPrice |
decimal | no | Actual unit price after applying discounts. Required unless rampDeal is provided. |
replaceGroups[].addLines[].totalPrice |
decimal | no | Total price of the added line, stored as given. Required when externalizedCalculations is true; ignored otherwise. |
replaceGroups[].addLines[].altProductName |
string | no | Alternative product name stored on the created sales order product. Passed through as given. |
replaceGroups[].addLines[].discount |
decimal | no | Discount value (interpreted based on discountType) |
replaceGroups[].addLines[].discountType |
any | no | Discount type (amount, percentage) One of: "amount", "percentage". |
replaceGroups[].addLines[].pricingTerm |
any | no | Pricing term period. Defaults to product line setting. One of: "monthly", "biMonthly", "once", "quarterly", "semiAnnually", "annually". |
replaceGroups[].addLines[].tiers |
array<object> | no | Pricing tiers for tiered/volume/stairstep price models. Tiers must cover contiguous quantity ranges starting at 0; bounds are inclusive and each tier's fromQuantity must be exactly the previous tier's toQuantity + 1 (e.g. 0-100, 101-500, 501-open). |
replaceGroups[].addLines[].tiers[].fromQuantity |
decimal | yes | Lower bound of quantity range (inclusive). First tier must start at 0. |
replaceGroups[].addLines[].tiers[].toQuantity |
decimal | no | Upper bound of quantity range (inclusive). Omit on the last tier for open-ended ranges. |
replaceGroups[].addLines[].tiers[].unitPrice |
decimal | yes | Per-unit price for quantities in this tier after discount |
replaceGroups[].addLines[].tiers[].listPrice |
decimal | no | Per-unit list price before discount. Defaults to unitPrice. |
replaceGroups[].addLines[].tiers[].priceModel |
any | no | Per-tier price model (flat, perUnit). Defaults to perUnit. One of: "flat", "perUnit". |
replaceGroups[].addLines[].rateCardEntries |
array<object> | no | Rate card entries for this product line. Required when priceModel is rateCard and the product line has no template entries. |
replaceGroups[].addLines[].rateCardEntries[].identifier |
string | yes | BillableComponent identifier for this meter |
replaceGroups[].addLines[].rateCardEntries[].description |
string | no | Free-text description of the rate card entry |
replaceGroups[].addLines[].rateCardEntries[].unitOfMeasure |
string | yes | Unit of measure for this meter |
replaceGroups[].addLines[].rateCardEntries[].unitPrice |
decimal | yes | Per-unit rate negotiated for this modification |
replaceGroups[].addLines[].rateCardEntries[].listPrice |
decimal | no | Per-unit list price. Honored only when product line enforceListPrice is false. |
replaceGroups[].addLines[].rateCardEntries[].conversion |
decimal | no | Conversion factor between billable and reporting units |
replaceGroups[].addLines[].rampDeal |
object | no | Ramp deal definition for phased additions. Mutually exclusive with top-level quantity/unitPrice. |
replaceGroups[].addLines[].rampDeal.interval |
any | yes | How ramps are defined. annually = auto-derive yearly ramps; specificDates = caller provides explicit serviceStartDate/serviceEndDate per ramp. One of: "annually", "specificDates". |
replaceGroups[].addLines[].rampDeal.invoiceTiming |
any | yes | perInterval invoices at each ramp start; allAtOnce invoices the whole deal upfront and requires every ramp invoiceFrequency = allAtOnce. One of: "perInterval", "allAtOnce". |
replaceGroups[].addLines[].rampDeal.ramps |
array<object> | yes | One entry per ramp, in chronological order. Minimum 2 ramps. |
replaceGroups[].addLines[].rampDeal.ramps[].serviceStartDate |
date | no | Ramp service start date (ISO 8601, YYYY-MM-DD). Required for specificDates; omit for annually. |
replaceGroups[].addLines[].rampDeal.ramps[].serviceEndDate |
date | no | Ramp service end date (ISO 8601, YYYY-MM-DD). Required for specificDates; omit for annually. |
replaceGroups[].addLines[].rampDeal.ramps[].quantity |
decimal | yes | Quantity for this ramp |
replaceGroups[].addLines[].rampDeal.ramps[].listPrice |
decimal | no | Ramp list price. Defaults to the ramp unitPrice when omitted; must be omitted when the product line has enforceListPrice set. |
replaceGroups[].addLines[].rampDeal.ramps[].unitPrice |
decimal | yes | Ramp unit price after discount |
replaceGroups[].addLines[].rampDeal.ramps[].totalPrice |
decimal | no | Total price of this ramp period, stored as given. Required when externalizedCalculations is true; ignored otherwise. |
replaceGroups[].addLines[].rampDeal.ramps[].invoiceFrequency |
any | no | Ramp invoice frequency. Must be allAtOnce on every ramp when invoiceTiming is allAtOnce. One of: "monthly", "biMonthly", "quarterly", "semiAnnually", "annually", "once", "custom", "template", "milestone", "allAtOnce". |
replaceGroups[].addLines[].serviceStartDate |
date | no | Service start date of the added product = the group's activation date (ISO 8601, YYYY-MM-DD). Defaults to the modificationDate. |
replaceGroups[].addLines[].serviceEndDate |
date | no | Service end date of the added product (ISO 8601, YYYY-MM-DD). Defaults to coterminous with the subscription. |
replaceGroups[].addLines[].externalIdentifiers |
array<object> | no | External identifiers to attach, e.g. from NetSuite or Salesforce |
replaceGroups[].addLines[].externalIdentifiers[].fieldName |
string | yes | Field name defined in the corresponding ExternalIdentifierConfiguration |
replaceGroups[].addLines[].externalIdentifiers[].value |
string | yes | External identifier value |
replaceGroups[].addLines[].externalIdentifiers[].externalUrl |
string | no | Optional link to record in originating system |
{
"customerId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"externalOrderId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"modificationType": "midTermModification",
"bookDate": "2026-01-15",
"effectiveDate": "2026-01-15",
"oneTimeDiscountAmount": "19.99",
"oneTimeDiscountAllocation": "firstInvoice",
"billToAddressId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"soldToAddressId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"signDate": "2026-01-15",
"purchaseOrder": "<purchaseOrder>",
"opportunityId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"opportunityName": "<opportunityName>",
"approvalStatus": "pendingApproval",
"externalizedCalculations": true,
"modificationDate": "2026-01-15",
"term": 0,
"priceChangePercentage": "19.99",
"note": "<note>",
"addLines": [
{
"productLineId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"quantity": "19.99",
"invoiceFrequency": "monthly",
"invoiceTiming": "advance",
"lineInvoiceDay": "<lineInvoiceDay>",
"priceModel": "flat",
"unitOfMeasure": "instance",
"listPrice": "19.99",
"unitPrice": "19.99",
"totalPrice": "19.99",
"altProductName": "<altProductName>",
"discount": "19.99",
"discountType": "amount",
"pricingTerm": "monthly",
"tiers": [
{
"fromQuantity": "19.99",
"toQuantity": "19.99",
"unitPrice": "19.99",
"listPrice": "19.99",
"priceModel": "flat"
}
],
"rateCardEntries": [
{
"identifier": "<identifier>",
"description": "<description>",
"unitOfMeasure": "<unitOfMeasure>",
"unitPrice": "19.99",
"listPrice": "19.99",
"conversion": "19.99"
}
],
"rampDeal": {
"interval": "annually",
"invoiceTiming": "perInterval",
"ramps": [
{
"serviceStartDate": "2026-01-15",
"serviceEndDate": "2026-01-15",
"quantity": "19.99",
"listPrice": "19.99",
"unitPrice": "19.99",
"totalPrice": "19.99",
"invoiceFrequency": "monthly"
}
]
},
"serviceStartDate": "2026-01-15",
"serviceEndDate": "2026-01-15",
"externalIdentifiers": [
{
"fieldName": "<fieldName>",
"value": "<value>",
"externalUrl": "<externalUrl>"
}
]
}
],
"changeLines": [
{
"subscriptionLineId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"newQuantity": "19.99",
"unitPrice": "19.99",
"totalPrice": "19.99",
"newUnitPrice": "19.99",
"newListPrice": "19.99",
"newDiscount": "19.99",
"newDiscountType": "amount",
"newTiers": [
{
"fromQuantity": "19.99",
"toQuantity": "19.99",
"unitPrice": "19.99",
"listPrice": "19.99",
"priceModel": "flat"
}
]
}
],
"cancelLines": [
{
"subscriptionLineId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"serviceEndDate": "2026-01-15"
}
],
"replaceGroups": [
{
"cancelLines": [
{
"subscriptionLineId": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
],
"addLines": [
{
"productLineId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"quantity": "19.99",
"invoiceFrequency": "monthly",
"invoiceTiming": "advance",
"lineInvoiceDay": "<lineInvoiceDay>",
"priceModel": "flat",
"unitOfMeasure": "instance",
"listPrice": "19.99",
"unitPrice": "19.99",
"totalPrice": "19.99",
"altProductName": "<altProductName>",
"discount": "19.99",
"discountType": "amount",
"pricingTerm": "monthly",
"tiers": [
{
"fromQuantity": null,
"toQuantity": null,
"unitPrice": null,
"listPrice": null,
"priceModel": null
}
],
"rateCardEntries": [
{
"identifier": null,
"description": null,
"unitOfMeasure": null,
"unitPrice": null,
"listPrice": null,
"conversion": null
}
],
"rampDeal": {
"interval": "annually",
"invoiceTiming": "perInterval",
"ramps": [
null
]
},
"serviceStartDate": "2026-01-15",
"serviceEndDate": "2026-01-15",
"externalIdentifiers": [
{
"fieldName": null,
"value": null,
"externalUrl": null
}
]
}
]
}
]
}
Response
200 Success
Under data (modifySubscriptionOutput):
| Field | Type | Required | Description |
|---|---|---|---|
salesOrderId |
string | no | Id of the generated sales order (a UUID). Absent when a midTermModification payload contains only cancellations (no sales order is created). |
subscriptionModificationId |
string | no | Id of the created SubscriptionModification record (a UUID). Absent for renewal (a renewal creates no SubscriptionModification). |
approvalStatus |
string | yes | Approval status of the result (pendingApproval, approved) |
serviceStartDate |
date | no | renew and earlyRenew only: service start date of the new term (the day after the current service end date for renew, the modificationDate for earlyRenew) |
serviceEndDate |
date | no | renew and earlyRenew only: service end date of the new term |
term |
number | no | renew and earlyRenew only: renewal term in months that was applied |
{
"data": {
"salesOrderId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"subscriptionModificationId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"approvalStatus": "<approvalStatus>",
"serviceStartDate": "2026-01-15",
"serviceEndDate": "2026-01-15",
"term": 0
},
"diagnostics": [
{
"code": "<code>",
"message": "<message>",
"severity": "error",
"path": [
"<path>"
],
"details": "<details>"
}
]
}
Response headers
Idempotency-Replayed— Present andtrueonly when this response replays a previously stored one for the same Idempotency-Key, rather than reflecting a live execution. Absent on a live response - never sent asfalse.
Errors
| Code | Status |
|---|---|
SUBSCRIPTION_NOT_FOUND |
400 |
SUBSCRIPTION_LINE_NOT_FOUND |
400 |
MODIFICATION_DATE_OUTSIDE_SERVICE_PERIOD |
400 |
QUANTITY_DECREASE_NOT_SUPPORTED |
400 |
CHANGE_QUANTITY_UNSUPPORTED_LINE_TYPE |
400 |
CHANGE_LINE_NO_CHANGES |
400 |
REPLACED_LINE_NOT_ACTIVE |
400 |
REPLACE_GROUP_INCOMPLETE |
400 |
REPLACE_GROUP_START_DATE_MISMATCH |
400 |
DUPLICATE_EXTERNAL_ORDER_ID |
400 |
DUPLICATE_CANCEL_TARGET |
400 |
SUBSCRIPTION_NOT_RENEWABLE |
400 |
EARLY_RENEWAL_DATE_INVALID |
400 |
SUBSCRIPTION_NOT_EARLY_RENEWABLE |
400 |
EARLY_RENEWAL_ALREADY_PENDING |
400 |
CHANGE_KIND_NOT_SUPPORTED |
400 |
RENEWAL_TERM_MISSING |
400 |
RENEWAL_ALREADY_PENDING |
400 |
NOTHING_TO_MODIFY |
400 |
SUBSCRIPTION_LINE_NOT_ACTIVE |
400 |
MODIFICATION_DATE_REQUIRED |
400 |
UNSUPPORTED_FIELDS |
400 |
PRICE_CHANGE_PERCENTAGE_NEGATIVE |
400 |
VALIDATION_FAILED |
400 |
REPLACE_GROUP_RAMP_NOT_SUPPORTED |
400 |
TOTAL_PRICE_REQUIRED |
400 |
CHANGE_LINE_TOTAL_PRICE_REQUIRED |
400 |
EXTERNALIZED_RAMP_CHANGE_NOT_SUPPORTED |
400 |
IDEMPOTENCY_KEY_CONFLICT |
409 |
IDEMPOTENCY_PAYLOAD_MISMATCH |
422 |
Statuses
400— Invalid request or business failure. Codes: SUBSCRIPTION_NOT_FOUND, SUBSCRIPTION_LINE_NOT_FOUND, MODIFICATION_DATE_OUTSIDE_SERVICE_PERIOD, QUANTITY_DECREASE_NOT_SUPPORTED, CHANGE_QUANTITY_UNSUPPORTED_LINE_TYPE, CHANGE_LINE_NO_CHANGES, REPLACED_LINE_NOT_ACTIVE, REPLACE_GROUP_INCOMPLETE, REPLACE_GROUP_START_DATE_MISMATCH, DUPLICATE_EXTERNAL_ORDER_ID, DUPLICATE_CANCEL_TARGET, SUBSCRIPTION_NOT_RENEWABLE, EARLY_RENEWAL_DATE_INVALID, SUBSCRIPTION_NOT_EARLY_RENEWABLE, EARLY_RENEWAL_ALREADY_PENDING, CHANGE_KIND_NOT_SUPPORTED, RENEWAL_TERM_MISSING, RENEWAL_ALREADY_PENDING, NOTHING_TO_MODIFY, SUBSCRIPTION_LINE_NOT_ACTIVE, MODIFICATION_DATE_REQUIRED, UNSUPPORTED_FIELDS, PRICE_CHANGE_PERCENTAGE_NEGATIVE, VALIDATION_FAILED, REPLACE_GROUP_RAMP_NOT_SUPPORTED, TOTAL_PRICE_REQUIRED, CHANGE_LINE_TOTAL_PRICE_REQUIRED, EXTERNALIZED_RAMP_CHANGE_NOT_SUPPORTED401— The request carries no valid access token.403— Not authorized404— Not found409— The Idempotency-Key is still being processed by another request.422— The Idempotency-Key was already used with a different request payload.429— Too many requests from this client address. The response has no body and noRetry-Afterheader.500— Internal server error