Update a subscription contract
Subscription contracts often require updates, such as when a customer needs to update their payment method or requests a change to their subscription.
This guide shows you how to submit the desired changes to subscriptionContractUpdateCalculate, review Shopify's calculated result, and commit a new active version of the contract. Fields that you omit remain unchanged.
The SubscriptionContractCalculation API is available in the GraphQL Admin API 2026-10 release candidate. If your app uses the SubscriptionDraft API, refer to the legacy contract update guide.
The SubscriptionContractCalculation API is available in the GraphQL Admin API 2026-10 release candidate. If your app uses the SubscriptionDraft API, refer to the legacy contract update guide.
Anchor to RequirementsRequirements
- Most subscriptions, pre-order and try before you buy apps need to request API access through the Partner Dashboard. We give API access to apps that are designed according to our principles for subscriptions, pre-order and TBYB apps.
- Public apps that use subscriptions, pre-order or TBYB need to meet specific requirements to be published on the Shopify App Store.
- Custom apps created in the Shopify admin can't use subscriptions, pre-order or TBYB because these apps can't use extensions or request access to protected scopes. If you're building a solution for a single store, then build your custom app in the Partner Dashboard.
- Most subscriptions, pre-order and try before you buy apps need to request API access through the Partner Dashboard. We give API access to apps that are designed according to our principles for subscriptions, pre-order and TBYB apps.
- Public apps that use subscriptions, pre-order or TBYB need to meet specific requirements to be published on the Shopify App Store.
- Custom apps created in the Shopify admin can't use subscriptions, pre-order or TBYB because these apps can't use extensions or request access to protected scopes. If you're building a solution for a single store, then build your custom app in the Partner Dashboard.
- Your app can make authenticated requests to the GraphQL Admin API.
- Your app has the
read_own_subscription_contractsandwrite_own_subscription_contractsaccess scopes. Learn how to configure your access scopes using Shopify CLI. - You've created products and product variants in your development store.
- Use the GraphQL Admin API version
2026-10or later. - Create a subscription contract.
Anchor to How contract calculation worksHow contract calculation works
Contract updates use an asynchronous calculate and commit flow:
- Query the current contract state.
- Submit the fields that you want to change.
- Poll the calculation or wait for a webhook. Shopify emits
subscription_contract_calculations/succeedwhen a calculation succeeds andsubscription_contract_calculations/failwhen it fails or is voided. - Review the complete calculated contract, projected totals, warnings, or errors.
- Commit a successful calculation.
Committing creates a new version of the contract. It doesn't modify orders or fulfillments that have already been created. Use orderEditBegin to edit an existing order.
Anchor to Step 1: Query the subscription contractStep 1: Query the subscription contract
Query the contract before calculating an update. Include the IDs and complete values for any collection that you plan to replace, such as lines or manual discounts. When you rebuild the lines array, a line's variantId is the value that you pass as productVariantId in the input:
POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json
GraphQL query
Variables
Anchor to Step 2: Calculate the updateStep 2: Calculate the update
Call subscriptionContractUpdateCalculate with the contract ID and desired changes. The following example changes an existing line's quantity and applies a discount code. Because lines replaces the entire collection, this example assumes a single-line contract. For a contract with multiple lines, include every line you want to keep:
POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json
GraphQL mutation
JSON response
If the mutation returns a user error, then correct the input before polling. Shopify doesn't create an asynchronous calculation when input validation fails.
When you provide lines or manualDiscounts, the array replaces the complete existing collection. Include the IDs and values for every existing item that you want to keep. Omit an existing item to remove it, and omit id from a new item.
Providing a line also replaces that line's customAttributes and discounts, and you must state both whenever you include the line. Pass the line's existing customAttributes (queried in Step 1) and re-declare any line-level discounts to keep them, or pass an empty list to clear either.
When you provide lines or manualDiscounts, the array replaces the complete existing collection. Include the IDs and values for every existing item that you want to keep. Omit an existing item to remove it, and omit id from a new item.
Providing a line also replaces that line's customAttributes and discounts, and you must state both whenever you include the line. Pass the line's existing customAttributes (queried in Step 1) and re-declare any line-level discounts to keep them, or pass an empty list to clear either.
Anchor to Step 3: Poll for the calculation resultStep 3: Poll for the calculation result
The calculate mutation returns a pending calculation. Poll for the result and review it before committing.
Contract calculations run asynchronously. Most calculations finish in less than three seconds, but Functions and external services can increase processing time. Use the calculation ID returned by the calculate mutation to query subscriptionContractCalculation:
POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json
GraphQL query
Variables
Pending response
The query returns one of the following types:
| Type | Meaning | Action |
|---|---|---|
SubscriptionContractCalculationPending | Shopify initiated or is processing the calculation. | Continue polling. |
SubscriptionContractCalculationSuccess | The calculated contract is ready to review and commit. | Review the result before committing. |
SubscriptionContractCalculationFailure | The calculation failed (processed with errors) or Shopify voided it (never processed, for example, because of an infrastructure issue). | If it failed, read errors and correct the input before calculating again. If it was voided, errors is empty and there's nothing to fix in the input, so retry the calculation. |
Wait two seconds before the first poll, poll every second, and stop after 30 seconds. If the calculation is still pending, then retry later or wait for a webhook instead of increasing the polling frequency.
Anchor to Review the calculated contractReview the calculated contract
Before committing, inspect the following fields on SubscriptionContractCalculationSuccess:
calculatedContract: The complete contract snapshot that the commit applies.projectedOrderTotals: The projected merchandise, delivery, discount, tax, and total amounts.warnings: Existing-data or compatibility problems that don't prevent the calculation from succeeding.
A successful calculation is immutable. If you need to change the input, then start a new calculation and commit only the result that you want to make active.
A successful calculation can contain warnings. Review them before committing because they can identify disabled currencies, delivery configuration problems, or other existing contract data that Shopify preserved instead of blocking the update.
A successful calculation can contain warnings. Review them before committing because they can identify disabled currencies, delivery configuration problems, or other existing contract data that Shopify preserved instead of blocking the update.
Anchor to Use webhooks instead of pollingUse webhooks instead of polling
For event-driven processing, subscribe to the following webhook topics:
| Topic | Description |
|---|---|
subscription_contract_calculations/succeed | The calculation succeeded and is ready to review and commit. |
subscription_contract_calculations/fail | The calculation failed or Shopify voided it. A failed calculation has errors to query; a voided one has empty errors, so retry it. |
Create a webhook subscription with webhookSubscriptionCreate:
POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json
GraphQL mutation
Webhook payload
Use admin_graphql_api_id to query the completed calculation. Webhook delivery doesn't commit the result automatically.
Anchor to Step 4: Commit the calculationStep 4: Commit the calculation
After the calculation succeeds and you've reviewed the result, call subscriptionContractCalculationCommit. The commit makes the calculated contract active for billing:
POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json
GraphQL mutation
JSON response
Handle commit user errors by code:
| Code | Meaning | Action |
|---|---|---|
NOT_READY_TO_COMMIT | The calculation hasn't succeeded yet. | Continue polling before retrying the commit. |
CALCULATION_NOT_FOUND | The calculation ID doesn't exist or isn't available to the app. | Verify the ID and app access. |
STALE_CONTRACT | The contract changed after this calculation started. | Query the latest contract state and calculate again. |
INVALID | Shopify can't commit the calculation. | Use field and message to correct the request. |
You can safely retry polling and commit requests. Retrying a calculate mutation creates a new calculation, so retain the ID for the result that you intend to commit. Retrying a commit for an already committed calculation returns the committed result.
Anchor to Update common contract attributesUpdate common contract attributes
Use the following update semantics when preparing contractUpdateInput:
| Input | Behavior |
|---|---|
withMerchandiseCustomizations | Required. Set to true to run merchandise transformations, both fixed bundle expansion from a stored definition and Shopify Functions that customize merchandise, such as cart transforms. Set to false to bypass all merchandise transformations. |
lines | Replaces all lines. Include an id to keep or update an existing line. Omit id to add a line. Omit the field to leave all lines unchanged. |
manualDiscounts | Replaces all manual order and delivery discounts. Pass [] to remove all manual discounts. |
discountCodes | Applies codes during this calculation. Shopify resolves them into manual discounts on the contract instead of storing the codes. |
billingPolicy | Replaces the billing cadence and anchors. |
deliveryPolicy | Replaces the delivery anchors and optional multi-fulfillment configuration. |
deliveryMethod | Replaces the delivery method. Pass none to remove it, or fetchAvailableDeliveryOptions to discover options without changing the committed method. |
paymentMethod | Replaces the payment method. Pass none to remove it. |
note | Replaces the note. Pass null to clear it. |
customAttributes | Replaces all contract attributes. Pass [] to remove them. |
appManagedBillingConfig | Replaces app-managed minCycles and maxCycles metadata. These are stored on the contract but don't affect calculated billing cycle dates. |
Manage contract status separately with subscriptionContractActivate, subscriptionContractPause, subscriptionContractCancel, subscriptionContractExpire, or subscriptionContractFail.
Anchor to Discover delivery optionsDiscover delivery options
To retrieve shipping options for a new address without changing the committed delivery method, provide fetchAvailableDeliveryOptions:
When you poll the calculation in Step 3, read the results from the deliveryOptions field on SubscriptionContractCalculationSuccess, a union of shipping, local delivery, and pickup options. Then start a new calculation with the selected shipping or local delivery option. Delivery customization Functions run only when withDeliveryCustomizations is true.
Anchor to Next stepsNext steps
- Learn how to edit contracts that contain bundles.
- Learn how to manage and edit billing cycles.
- Refer to the
SubscriptionContractCalculationContractUpdateInputfields. - Use the legacy
SubscriptionDraftupdate guide while maintaining an older integration.