Skip to content

Change a subscription

Pause, resume, skip, reschedule or cancel a subscription, schedule a pause, change its plan, and edit its products and address with the Subrise API.

These endpoints change one subscription. They need a key with Write permission. See Developer API for the base URL and authentication.

Every change goes through Shopify, then Subrise records it in the subscription's activity log as made by an admin. Customer emails, tags, webhooks and integrations fire the same way they do when you make the change in the Subrise admin.

{contractId} in every path is the subscription's numeric ID, such as 12704383255.

Before you start

Check the result

Shopify can refuse a change, for example resuming a subscription it has already expired. Most refusals come back as a 400 with Shopify's userErrors. For pause, resume and cancel, also check status in the response: it shows the state the subscription is actually in after the request.

Send the state you expect

The endpoints marked Safe write accept the X-Subrise-Expected-Status and X-Subrise-Expected-Next-Billing-Date headers. Send them to avoid overwriting a change someone else made since you last read the subscription. See Safe writes.

bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/skip \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "X-Subrise-Expected-Status: ACTIVE" \
  -H "X-Subrise-Expected-Next-Billing-Date: 2026-11-05"

Pause a subscription

text
PUT /subscription-contracts/{contractId}/pause-subscription

Safe write. Pauses the subscription. No orders are created while it is paused.

Body fieldTypeDescription
pauseCyclesintegerOptional. Pause for this many billing cycles, then resume on its own. Leave it out to pause until you resume.
bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/pause-subscription \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "pauseCycles": 2 }'

Without pauseCycles, the response is the updated subscription in Shopify's shape:

json
{
  "id": "gid://shopify/SubscriptionContract/12704383255",
  "status": "PAUSED",
  "nextBillingDate": "2026-11-05T14:00:00Z"
}

With pauseCycles, the response is the subscription in Subrise's shape, as returned by Search subscriptions, with status set to PAUSED and nextBillingDate moved to the resume date.

A pauseCycles that isn't a whole number of 1 or more returns 400:

json
{ "success": false, "message": "pauseCycles must be a whole number of 1 or more" }

Resume a subscription

text
PUT /subscription-contracts/{contractId}/resume-subscription

Safe write. Makes a paused or cancelled subscription active again.

If the pause pushed the next order date out, Subrise moves it back to the date it had before the pause. A next order date in the past moves to the near future, so the customer is not charged the moment you resume.

bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/resume-subscription \
  -H "x-api-key: $SUBRISE_API_KEY"
json
{
  "success": true,
  "data": {
    "id": "gid://shopify/SubscriptionContract/12704383255",
    "status": "ACTIVE",
    "nextBillingDate": "2026-11-05T14:00:00Z"
  }
}

Skip the next order

text
PUT /subscription-contracts/{contractId}/skip

Safe write. Moves the next order date forward by one billing interval. A monthly subscription due on 5 November moves to 5 December.

bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/skip \
  -H "x-api-key: $SUBRISE_API_KEY"
json
{
  "success": true,
  "data": {
    "id": "gid://shopify/SubscriptionContract/12704383255",
    "status": "ACTIVE",
    "nextBillingDate": "2026-12-05T14:00:00Z"
  }
}

If Shopify can't apply the skip, for example because it would pass the subscription's last order, you get a 400:

json
{
  "success": false,
  "message": "<Shopify's message>",
  "userErrors": [{ "field": ["date"], "message": "<Shopify's message>" }]
}

Set the next order date

text
PUT /subscription-contracts/{contractId}/set-date

Safe write. Sets the next order date to a date you choose.

ParameterInTypeDescription
datebodystringRequired. The new next order date, as an ISO date or date-time. Subrise uses only the date and sets the time to midnight in your store's time zone, so the time in the example below is ignored.
sendEmailquerybooleanOptional. true emails the customer about the new date. Default false.
bash
curl -X PUT "https://backend-production.subrise.app/api/subscription-contracts/12704383255/set-date?sendEmail=true" \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "date": "2026-11-20T14:00:00Z" }'

The response has the same shape as Skip the next order. A missing or unreadable date returns 400 with "message": "Missing or invalid date".

Cancel a subscription

text
DELETE /subscription-contracts/{contractId}

Safe write. Cancels the subscription. No more orders are created. You can bring it back later with Resume a subscription.

Body fieldTypeDescription
reasonstringOptional. The cancellation reason, up to 200 characters. Default Admin-Cancelled.
detailsstringOptional. More detail, up to 500 characters.
bash
curl -X DELETE https://backend-production.subrise.app/api/subscription-contracts/12704383255 \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Moving abroad", "details": "Asked by phone on 18 October" }'
json
{
  "success": true,
  "data": {
    "id": "gid://shopify/SubscriptionContract/12704383255",
    "status": "CANCELLED"
  }
}

Cancelling twice is safe. A subscription that is already cancelled returns 200 with "message": "Already cancelled (idempotent no-op)", and nothing is sent to the customer again. A subscription Subrise doesn't know returns 404.

Schedule a pause

text
PUT /subscription-contracts/{contractId}/scheduled-pause

Pauses the subscription automatically after a number of further successful orders. Only active subscriptions can schedule a pause. Prepaid subscriptions, gift subscriptions and subscriptions with a charge limit can't; pause those now instead.

Body fieldTypeDescription
pauseAfterBillingsintegerRequired. Pause after this many more successful orders. 1 or more.
scheduledPauseCyclesintegerOptional. Once paused, resume on its own after this many billing cycles. Leave it out to stay paused.
bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/scheduled-pause \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "pauseAfterBillings": 2, "scheduledPauseCycles": 1 }'
json
{
  "success": true,
  "message": "Scheduled pause set",
  "subscription": {
    "id": "12704383255",
    "status": "ACTIVE",
    "pauseAfterBillings": 2,
    "scheduledPauseCycles": 1
  }
}

If the schedule can't be set, you get a 400 that says why, for example "Only ACTIVE subscriptions can schedule a pause".

Clear a scheduled pause

text
DELETE /subscription-contracts/{contractId}/scheduled-pause

Removes the schedule. The response has the same shape, with "message": "Scheduled pause cleared".

Change the plan

text
PUT /subscription-contracts/{contractId}/change-selling-plan

Safe write. Moves every product on the subscription to another plan, with that plan's delivery schedule. The new plan must include all of the subscription's products. To get the plans that fit, use List the plans a subscription can move to. Subscription plans lists every plan, including ones that don't fit.

One-time add-ons stay where they are. The products keep their current price unless Plan changes apply the new plan's pricing is on in Customer portal settings. With it on, every product takes the new plan's price and discount, and a plan whose billing and delivery schedule Subrise can't price is refused with 400 and "This plan's billing and delivery schedule can't be priced automatically".

Body fieldTypeDescription
sellingPlanIdstringRequired. The plan's Shopify global ID, or its numeric ID.
bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/change-selling-plan \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "sellingPlanId": "gid://shopify/SellingPlan/689892753687" }'

The response is { "success": true, "data": { ... } }, where data is the updated subscription in Subrise's shape. A plan that doesn't fit returns 400 with an error that says why. Bundle subscriptions can't change plan.

List the plans a subscription can move to

text
GET /subscription-contracts/{contractId}/plan-options

Returns every plan whose plan group carries all of the subscription's products, in any group. Gift plans and bundle plans aren't included. This is the same list the admin and the customer portal offer.

bash
curl https://backend-production.subrise.app/api/subscription-contracts/12704383255/plan-options \
  -H "x-api-key: $SUBRISE_API_KEY"

The response is { "success": true, "plans": [ ... ], "repriceOnPlanChange": true }. Each plan has its id, name, groupId and groupName. When repriceOnPlanChange is true, each plan also has preview: the subscription's new price per order on that plan, as { "total", "currencyCode" }, or null when it can't be priced. A live bundle subscription returns an empty plans list with "bundleLocked": true. A subscription Subrise doesn't know returns 404.

Change the shipping address

text
PUT /subscription-contracts/{contractId}/update-address

Replaces the address future orders ship to. Send the fields you want to change. Fields you leave out keep their current value.

Body fieldTypeDescription
firstName, lastNamestringThe recipient's name.
address1stringThe street address.
address2stringApartment or suite. Send "" to clear it.
citystringThe city.
provincestringThe US state, as a name or two-letter code, such as Rhode Island or RI. Subrise recognises US states only.
zipstringThe postal code.
countryCodestringThe two-letter country code, such as US.
phonestringThe recipient's phone number.

Include at least one of address1 or zip, or the address is left unchanged.

bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/update-address \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "address1": "55 Water Street",
    "address2": "",
    "city": "Providence",
    "province": "Rhode Island",
    "zip": "02903",
    "countryCode": "US"
  }'

The response is { "success": true, "data": { ... } }, where data is the updated subscription in Subrise's shape. Shopify rejects addresses it can't ship to with a 400.

Add a product

text
PUT /subscription-contracts/{contractId}/add-line-item

Safe write. Adds a product variant to the subscription.

Body fieldTypeDescription
lineItem.productVariantIdstringRequired. The variant's Shopify global ID, or its numeric ID.
lineItem.quantityintegerRequired. How many to add.
lineItem.sellingPlanIdstringOptional. The plan the line renews on. Use the subscription's own plan.
lineItem.pricenumberOptional. The price per item. Leave it out to use the variant's price. On a recurring product (not an add-on), leaving it out also gives the product the subscription's plan or bundle discount, unless Added products get the subscription's discount is off in Customer portal settings.
isAddonbooleanOptional. true adds the product to the next order only. Default false, which adds it to every order. Add-ons are refused with 400 while the subscription is paused: "Add-ons can't be added while the subscription is paused. Resume it first."
bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/add-line-item \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "lineItem": {
      "productVariantId": "gid://shopify/ProductVariant/44406306767127",
      "quantity": 1,
      "sellingPlanId": "gid://shopify/SellingPlan/689892688151"
    },
    "isAddon": false
  }'

The response is { "success": true, "data": { ... } } with the updated subscription in Subrise's shape. The new product appears in data.lines, or in data.addons when isAddon is true.

If the subscription already has a line with the same variant and plan, Subrise adds the quantity to that line instead of creating a second one.

Change a product

text
PUT /subscription-contracts/{contractId}/line-item/{lineItemId}

Safe write. Changes the quantity, variant or price of one line.

ParameterInTypeDescription
lineItemIdpathstringThe last part of the line's ID. For gid://shopify/SubscriptionLine/8380c059-ca4f-4fb6-b2f2-89158b66b754, send 8380c059-ca4f-4fb6-b2f2-89158b66b754.
quantitybodyintegerOptional. The new quantity.
productVariantIdbodystringOptional. Swap to this variant.
pricebodynumberOptional. The new price per item.
bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/line-item/8380c059-ca4f-4fb6-b2f2-89158b66b754 \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "quantity": 2 }'

The response is { "success": true, "data": { ... } } with the updated subscription in Subrise's shape.

Remove a product

text
PUT /subscription-contracts/{contractId}/remove-line-item

Safe write. Removes one line from the subscription. This uses PUT, not DELETE.

Body fieldTypeDescription
lineIdstringRequired. The line's full Shopify global ID, from lines[].id or addons[].id.
bash
curl -X PUT https://backend-production.subrise.app/api/subscription-contracts/12704383255/remove-line-item \
  -H "x-api-key: $SUBRISE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "lineId": "gid://shopify/SubscriptionLine/8380c059-ca4f-4fb6-b2f2-89158b66b754" }'

The response is { "success": true, "data": { ... } } with the updated subscription in Subrise's shape. Shopify won't remove the last line of a subscription. Cancel the subscription instead.