---
title: Migrate to the SubscriptionContractCalculation API
description: >-
  Learn how to migrate from the SubscriptionDraft API to the new
  SubscriptionContractCalculation API for managing subscription contracts.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/migrate-to-subscription-calculation-api
  md: >-
    https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/migrate-to-subscription-calculation-api.md
api_name: admin
---

# Migrate to the Subscription​Contract​Calculation API

This guide walks you through migrating from the [SubscriptionDraft](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionDraft) API to the new `SubscriptionContractCalculation` API for managing [subscription contracts](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts).

***

## Requirements

* Access scope: [`write_own_subscription_contracts`](https://shopify.dev/docs/api/usage/access-scopes#write_own_subscription_contracts).
* API version: `2026-10`.

***

## What's changing and why

The new API integrates with Shopify's unified checkout and provides the following benefits:

* **Simplified API surface**: Contract mutations are consolidated into four calculate operations plus a shared commit.
* **Consistent pricing**: Tax and discount calculations align with checkout.
* **Function support**: [Cart transforms](https://shopify.dev/docs/api/functions/latest/cart-transform) and [delivery customizations](https://shopify.dev/docs/api/functions/latest/delivery-customization). Other [Shopify Functions](https://shopify.dev/docs/apps/build/functions) will be supported in later releases.
* **Accurate cost breakdown**: Totals for lines, delivery, taxes, duties, and discounts are available through the API.

The following table summarizes the main differences between `SubscriptionDraft` and the new `SubscriptionContractCalculation` API.

| Aspect | SubscriptionDraft | SubscriptionContractCalculation |
| - | - | - |
| **Approach** | Multi-step draft mutations | Single contract calculation |
| **Processing** | Synchronous | Asynchronous (requires polling) |
| **State management** | Server maintains draft state | Client provides desired state. On update, omitted top-level fields are preserved, but a list you provide (such as `lines`) replaces the stored list. |
| **Webhooks** | None | Webhooks on success or failure |

***

## Understand the new API model

### From drafts to contract calculations

With the current `SubscriptionDraft` API, you create a draft, apply changes through multiple mutations, and then commit the draft. With the new `SubscriptionContractCalculation` API, you submit the desired state in a single request. The server calculates pricing, applies taxes, executes functions, and returns an immutable result snapshot. On contract updates, any top-level field you omit is left unchanged — you don't need to resend the entire contract. When you provide a list field such as `lines` or `manualDiscounts`, the list you send replaces the whole stored list, and each entry is a complete restatement rather than a patch. See [Preserve a line's state when you change it](#preserve-a-lines-state-when-you-change-it).

### Asynchronous processing

Calculations run asynchronously. You can poll for results or subscribe to [webhooks](#webhook-integration). Here's the flow:

1. Call the calculate mutation.
2. Receive a `SubscriptionContractCalculationPending` response.
3. Poll the `subscriptionContractCalculation` query, or wait for a webhook.
4. Receive a `SubscriptionContractCalculationSuccess` or `SubscriptionContractCalculationFailure` response when complete.
5. Call `subscriptionContractCalculationCommit` to apply the changes.

### Feature flags

The following Boolean fields control contract calculation behavior:

| Field | Location | Description |
| - | - | - |
| `withMerchandiseCustomizations` | Top-level create or update input | When set to `true`, enables cart transforms and other function-based merchandise modifications. |
| `withDeliveryCustomizations` | `deliveryMethod.fetchAvailableDeliveryOptions` | When `true` (the default), runs delivery customization functions while fetching delivery options, so the returned options reflect the merchant's configured customizations. Set to `false` to bypass these functions and return the raw options. |

***

## API migration reference

### Mutation mapping

| Old mutation | New approach |
| - | - |
| [`subscriptionContractCreate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractCreate) | Use `subscriptionContractCreateCalculate` |
| [`subscriptionContractUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractUpdate) | Use `subscriptionContractUpdateCalculate` |
| [`subscriptionContractAtomicCreate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractAtomicCreate) | Use `subscriptionContractCreateCalculate` |
| [`subscriptionContractProductChange`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractProductChange) | Use `subscriptionContractUpdateCalculate` |
| [`subscriptionDraftLineAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftLineAdd) | Include in `lines[]` input |
| [`subscriptionDraftLineUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftLineUpdate) | Include updated line with the same `id` in `lines[]` |
| [`subscriptionDraftLineRemove`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftLineRemove) | Omit line from `lines[]` |
| [`subscriptionDraftDiscountAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftDiscountAdd) | Include `orderDiscount` in `manualDiscounts[]` input |
| [`subscriptionDraftDiscountUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftDiscountUpdate) | Include updated `orderDiscount` with the same `id` in `manualDiscounts[]` |
| [`subscriptionDraftDiscountRemove`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftDiscountRemove) | Omit discount from `manualDiscounts[]` |
| [`subscriptionDraftDiscountCodeApply`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftDiscountCodeApply) | Include in `discountCodes[]` input |
| [`subscriptionDraftFreeShippingDiscountAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftFreeShippingDiscountAdd) | Include `deliveryDiscount` in `manualDiscounts[]` |
| [`subscriptionDraftFreeShippingDiscountUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftFreeShippingDiscountUpdate) | Include updated `deliveryDiscount` with the same `id` in `manualDiscounts[]` |
| [`subscriptionDraftUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftUpdate) | Recalculate with additional input |
| [`subscriptionDraftCommit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftCommit) | Use `subscriptionContractCalculationCommit` |
| [`subscriptionBillingCycleContractEdit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractEdit) | Use `subscriptionBillingCycleContractEditCalculate` |
| [`subscriptionBillingCycleContractDraftConcatenate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractDraftConcatenate) | Use `subscriptionBillingCycleContractConcatenateCalculate` (early access). It concatenates billing cycles only. To combine contracts permanently, use `subscriptionContractUpdateCalculate`. See [Concatenate billing cycles](#concatenate-billing-cycles). |
| [`subscriptionBillingCycleContractDraftCommit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractDraftCommit) | Use `subscriptionContractCalculationCommit` |
| [`subscriptionBillingCycleEditDelete`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleEditDelete) | Unchanged. Also removes a concatenation. See [Remove a concatenation](#remove-a-concatenation). |

### Deprecated and renamed fields

The `SubscriptionContractCalculation` API introduces changes to how certain contract attributes are managed. The following fields have been deprecated, renamed, or moved.

#### Contract status

Contract status is now managed using dedicated mutations instead of being set through the draft or contract calculation input. This change decouples contract status from the contract versioning model.

| Old approach | New approach |
| - | - |
| Set `status` field in `SubscriptionDraftInput` during commit. | Use dedicated status mutations: [`subscriptionContractActivate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractActivate), [`subscriptionContractPause`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractPause), [`subscriptionContractCancel`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractCancel), [`subscriptionContractExpire`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractExpire), [`subscriptionContractFail`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractFail). |

#### Line fields

[`SubscriptionLineInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/SubscriptionLineInput) and [`SubscriptionLineUpdateInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/SubscriptionLineUpdateInput) map to `SubscriptionContractCalculationProductVariantLineInput` as follows. Three fields are renamed, and two have no draft API equivalent.

| Draft API field (`SubscriptionLineInput`, `SubscriptionLineUpdateInput`) | Calculate API field (`SubscriptionContractCalculationProductVariantLineInput`) | Notes |
| - | - | - |
| — | `id` | The ID of the existing line, read from `SubscriptionLine.id`. Include it to update a line in place. Omit it to add a new line. |
| `productVariantId` | `productVariantId` | Unchanged. |
| `quantity` | `quantity` | Unchanged. |
| `currentPrice` (`Decimal`) | `priceOverride` ([`MoneyInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/MoneyInput)) | The per-unit price your app charges for the line. See [Line price](#line-price). |
| `customAttributes` | `customAttributes` | Optional. Defaults to `[]` when omitted, which clears the line's custom attributes. |
| `sellingPlanId` | `originSellingPlanId` | Used to find the line's delivery profile. It isn't applied as a selling plan during calculation. |
| `sellingPlanName` | `sellingPlanName` | Unchanged. When omitted, defaults to the current name of `originSellingPlanId`, or to no name when that's also omitted. Restate the stored name to keep it. |
| `pricingPolicy` | `appManagedPricingPolicy` | Renamed. Same metadata, with `Money` values instead of `Decimal` values. See [Line pricing policy](#line-pricing-policy). |
| — | `discounts` | Line-scoped discounts. Required; pass `[]` for none. Replaces line-targeted `subscriptionDraftDiscountAdd`. See [Line-scoped discounts](#line-scoped-discounts). |

A `SubscriptionLineUpdateInput` is a patch: a field you omit keeps its stored value. A `SubscriptionContractCalculationProductVariantLineInput` is a complete restatement of the line: a field you omit is cleared or recalculated, even when you include the line's `id`. To change one field on one line, restate every field of every line from the stored contract. Other contract fields, such as `deliveryMethod` or `billingPolicy`, can still be omitted and are preserved. See [Preserve a line's state when you change it](#preserve-a-lines-state-when-you-change-it).

#### Line price

In the draft API, your app sets the line price with `currentPrice`. In the calculate API, the same price is `priceOverride`, a [`MoneyInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/MoneyInput) in the contract's currency. When you provide `priceOverride`, the calculation uses it as the line's per-unit price. When you omit it, the calculation prices the line from the product variant's current price, and any stored `currentPrice` is lost.

| Old field | New field |
| - | - |
| `currentPrice` | `priceOverride` |

**Omitted priceOverride reprices the line:**

A line that you restate without `priceOverride` is repriced from the variant. Always read `currentPrice` from the contract and pass it as `priceOverride` when you want to keep the price.

#### Line pricing policy

The `pricingPolicy` field on subscription lines is renamed to `appManagedPricingPolicy`. It's the drop-in replacement for the draft API field and carries the same data: a base price and the expected price adjustments per billing cycle.

In both APIs, this policy is metadata that your app stores on the line. It doesn't drive the calculated price. Your app remains responsible for setting the price it charges each cycle, through `currentPrice` in the draft API and through `priceOverride` in the calculate API. The name change makes that explicit.

| Old field | New field |
| - | - |
| `pricingPolicy.basePrice` (`Decimal`) | `appManagedPricingPolicy.basePrice` (`MoneyInput`) |
| `pricingPolicy.cycleDiscounts` | `appManagedPricingPolicy.cyclePriceAdjustments` |
| `cycleDiscounts[].afterCycle` | `cyclePriceAdjustments[].afterCycle` |
| `cycleDiscounts[].adjustmentType` | `cyclePriceAdjustments[].adjustmentType` |
| `cycleDiscounts[].adjustmentValue` | `cyclePriceAdjustments[].adjustmentValue` |
| `cycleDiscounts[].computedPrice` (`Decimal`) | `cyclePriceAdjustments[].computedPrice` (`MoneyInput`) |

`cyclePriceAdjustments` must contain at least one entry. To restate a stored policy, read `SubscriptionLine.pricingPolicy` from the contract and map each `cycleDiscounts` entry to a `cyclePriceAdjustments` entry.

**Omitted appManagedPricingPolicy clears the stored policy:**

Because a line input is a complete restatement, a line that you restate without `appManagedPricingPolicy` loses its stored pricing policy on commit. The calculation succeeds with no warning. Restate the policy on every line that has one.

#### Billing configuration

The `nextBillingDate`, `minCycles`, and `maxCycles` fields have been moved into a new `AppManagedBillingConfig` object. This consolidates app-managed billing metadata that isn't used during contract calculation into a single location.

| Old fields | New field |
| - | - |
| `nextBillingDate`, `minCycles`, `maxCycles` | `appManagedBillingConfig.nextBillingDate`, `appManagedBillingConfig.minCycles`, `appManagedBillingConfig.maxCycles` |

#### Delivery price

The draft API sets the delivery charge with a standalone `deliveryPrice` field on `SubscriptionDraftInput`. The calculate API has no top-level `deliveryPrice`. The price moves onto the delivery method itself, so each committed method carries its own charge.

| Old field | New field |
| - | - |
| `SubscriptionDraftInput.deliveryPrice` (`Decimal`) | `deliveryMethod.shipping.deliveryPrice`, `deliveryMethod.localDelivery.deliveryPrice`, or `deliveryMethod.pickup.deliveryPrice` (`MoneyInput`) |

An app-supplied delivery price is still possible, and delivery isn't recalculated when you commit a method:

* `deliveryPrice` is required on `shipping`, `localDelivery`, and `pickup`. You can't provide one of these methods without it.
* The calculation uses the `deliveryPrice` you provide as the contract's delivery charge. Delivery discounts in `manualDiscounts[].deliveryDiscount` apply on top of it.
* When you omit `deliveryMethod` on an update, the contract keeps its existing delivery method, including its stored price.
* To get Shopify's current rates for an address instead of supplying a price, use `fetchAvailableDeliveryOptions`, then commit the chosen option with its `price` as `deliveryPrice`. See [Fetch delivery options](#fetch-delivery-options).

#### Multiple fulfillment configuration

**Multi fulfillment is now optional:**

Passing `multiFulfillment` is only required for pre-paid subscriptions that have multiple deliveries per billing period. Omit the multi fulfillment input to use the billing cadence as the delivery cadence.

The `SubscriptionContractCalculation` API introduces explicit control over the number of fulfillments per billing cycle through a new `multiFulfillment` field. Previously, the number of deliveries per billing cycle was implicitly derived from the relationship between billing and delivery policy intervals. The new approach makes this configuration explicit.

The `multiFulfillment` field accepts a `SubscriptionMultipleFulfillmentConfigInput` with the following fields:

| Field | Type | Required | Description |
| - | - | - | - |
| `cadence` | Object | Yes | The cadence for calculating fulfillment dates. |
| `numberOfFulfillments` | Integer | Yes | The number of fulfillments per billing cycle. Must be at least 2. |

### Explore the API

Use the [GraphQL Admin API docs](https://shopify.dev/docs/api/admin-graphql/2026-10) to explore the new API mutations, input types, and return types.

***

## Create a subscription contract

### Old approach (Subscription​Draft)

With the SubscriptionDraft API, creating a contract requires multiple sequential mutations:

1. Create a draft for the new contract using [`subscriptionContractCreate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractCreate).
2. Add lines to the draft using [`subscriptionDraftLineAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftLineAdd).
3. Commit the draft to create the contract using [`subscriptionDraftCommit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftCommit).

### New approach (Subscription​Contract​Calculation)

With the `SubscriptionContractCalculation` API, you submit the complete desired state for the new contract in a single mutation. The server calculates pricing, applies taxes, and returns an immutable result snapshot.

1. Submit the new contract's desired state to create a contract calculation:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Create contract calculation

   ```graphql
   mutation CreateCalculation {
     subscriptionContractCreateCalculate(
       contractCreateInput: {
         # Control contract calculation behavior
         withMerchandiseCustomizations: true


         # Customer to create the contract for (must belong to the current shop)
         customerId: "gid://shopify/Customer/123"


         # Currency for the contract
         currencyCode: USD


         # Define all lines (at least one required)
         lines: [
           {
             productVariantLine: {
               productVariantId: "gid://shopify/ProductVariant/111"
               quantity: 1
               customAttributes: []
               discounts: []  # Line-scoped discounts; pass [] for none
             }
           }
         ]


         # Define billing policy
         billingPolicy: {
           cadence: {
             unit: MONTH
             count: 1
           }
         }


         # Define delivery policy
         deliveryPolicy: {
           multiFulfillment: {
             cadence: { unit: WEEK, count: 2 }
             numberOfFulfillments: 2
           }
         }


         # Define delivery method (use { none: true } for digital-only subscriptions)
         deliveryMethod: {
           shipping: {
             address: {
               firstName: "Quinn"
               lastName: "Ishida"
               address1: "123 Main St"
               city: "Toronto"
               provinceCode: "ON"
               countryCode: CA
               zip: "M5V 1A1"
             }
             deliveryPrice: {
               amount: "5.00"
               currencyCode: USD
             }
           }
         }


         # Define payment method (use { none: true } for no payment method)
         paymentMethod: {
           customerPaymentMethod: {
             id: "gid://shopify/CustomerPaymentMethod/456"
           }
         }


         # Define discount codes to apply (pass an empty array for none)
         discountCodes: []


         # Define manual discounts (pass an empty array for no manual discounts)
         # Supports two types: orderDiscount, deliveryDiscount
         manualDiscounts: []


         # Define custom attributes (pass an empty array for none)
         customAttributes: []
       }
     ) {
       subscriptionContractCalculation {
         ... on SubscriptionContractCalculationPending {
           id
         }
       }
       userErrors {
         field
         message
         code
       }
     }
   }
   ```

   ## JSON response

   ```json
   {
     "data": {
       "subscriptionContractCreateCalculate": {
         "subscriptionContractCalculation": {
           "id": "gid://shopify/SubscriptionContractCalculation/789"
         },
         "userErrors": []
       }
     }
   }
   ```

2. Poll for the contract calculation result:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Poll for result

   ```graphql
   query PollCalculation {
     subscriptionContractCalculation(
       id: "gid://shopify/SubscriptionContractCalculation/789"
     ) {
       __typename
       ... on SubscriptionContractCalculationPending {
         id
       }
       ... on SubscriptionContractCalculationSuccess {
         id
         calculatedContract {
           lines(first: 10) {
             edges {
               node {
                 id
                 variantId
                 quantity
               }
             }
           }
         }
       }
       ... on SubscriptionContractCalculationFailure {
         id
         errors { code }
       }
     }
   }
   ```

   ## JSON response (pending)

   ```json
   {
     "data": {
       "subscriptionContractCalculation": {
         "__typename": "SubscriptionContractCalculationPending",
         "id": "gid://shopify/SubscriptionContractCalculation/789"
       }
     }
   }
   ```

3. Commit the contract calculation to create the contract:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Commit contract calculation

   ```graphql
   mutation CommitCalculation {
     subscriptionContractCalculationCommit(
       id: "gid://shopify/SubscriptionContractCalculation/789"
     ) {
       # The return type is a union: SubscriptionContract (create/update)
       # or SubscriptionBillingCycleEditedContract (billing cycle edit).
       contract {
         ... on SubscriptionContract {
           id
           status
         }
       }
       userErrors {
         field
         message
       }
     }
   }
   ```

   ## JSON response

   ```json
   {
     "data": {
       "subscriptionContractCalculationCommit": {
         "contract": {
           "id": "gid://shopify/SubscriptionContract/999",
           "status": "ACTIVE"
         },
         "userErrors": []
       }
     }
   }
   ```

***

## Update a subscription contract

### Old approach (Subscription​Draft)

With the SubscriptionDraft API, updating a contract requires multiple sequential mutations:

1. Create a draft from the existing contract using [`subscriptionContractUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractUpdate).
2. Add, update, or remove lines using [`subscriptionDraftLineAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftLineAdd), [`subscriptionDraftLineUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftLineUpdate), or [`subscriptionDraftLineRemove`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftLineRemove).
3. Apply discounts using [`subscriptionDraftDiscountCodeApply`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftDiscountCodeApply), [`subscriptionDraftDiscountAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftDiscountAdd), or [`subscriptionDraftFreeShippingDiscountAdd`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftFreeShippingDiscountAdd).
4. Commit the draft to apply changes using [`subscriptionDraftCommit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftCommit).

### New approach (Subscription​Contract​Calculation)

With the `SubscriptionContractCalculation` API, you submit only the top-level fields you want to change in a single mutation. Omitted top-level fields are left unchanged. A list you provide, such as `lines`, replaces the stored list.

Fetch the existing [SubscriptionContract](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionContract) state using the [subscriptionContract](https://shopify.dev/docs/api/admin-graphql/latest/queries/subscriptionContract) query, then apply any changes before submitting an updated version of the `SubscriptionContract` attributes for contract calculation.

1. Submit the desired state to create a contract calculation. On an update, only `withMerchandiseCustomizations` must be provided; all other top-level fields are optional, and omitted top-level fields are left unchanged:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Create contract calculation

   ```graphql
   mutation UpdateCalculation {
     subscriptionContractUpdateCalculate(
       contractId: "gid://shopify/SubscriptionContract/123"
       contractUpdateInput: {
         # Control contract calculation behavior
         withMerchandiseCustomizations: true


         # Define all lines (replaces existing lines when provided)
         lines: [
           {
             productVariantLine: {
               # Include id to keep existing line, and restate its stored
               # fields: an omitted priceOverride reprices the line from
               # the variant, and an omitted appManagedPricingPolicy
               # clears the stored policy.
               id: "gid://shopify/SubscriptionLine/existing-line-uuid"
               productVariantId: "gid://shopify/ProductVariant/111"
               quantity: 1
               priceOverride: { amount: "8.02", currencyCode: GBP }
               customAttributes: []
               discounts: []  # Line-scoped discounts; pass [] for none
             }
           }
           {
             productVariantLine: {
               # Omit id to add new line
               productVariantId: "gid://shopify/ProductVariant/789"
               quantity: 2
               customAttributes: []
               discounts: []
             }
           }
         ]


         # Define discount codes to apply (resolved into manual discounts; not persisted as codes)
         discountCodes: [
           { redeemCode: "SAVE10" }
         ]


         # Define all manual discounts (replaces existing manual discounts)
         # Supports two types: orderDiscount, deliveryDiscount
         manualDiscounts: [
           {
             orderDiscount: {
               # Include id to keep an existing order discount
               id: "gid://shopify/SubscriptionDiscount/existing-discount-uuid"
               title: "10% off subscription"
               value: {
                 percentage: 10
               }
               recurringCycleLimit: 0  # 0 = no limit
             }
           }
           {
             deliveryDiscount: {
               # Omit id for a new delivery discount
               title: "Free shipping for 3 months"
               value: {
                 percentage: 100
               }
               recurringCycleLimit: 3  # Apply for 3 billing cycles
             }
           }
         ]


         # Define billing policy (replaces existing billing policy)
         billingPolicy: {
           anchors: [
             {
               monthday: {
                 dayOfMonth: 7
               }
             }
           ]
           cadence: {
             unit: MONTH
             count: 2
           }
         }


         # Define delivery policy (replaces existing delivery policy)
         deliveryPolicy: {
           anchors: {
             weekday: {
               dayOfWeek: TUESDAY
             }
           }
           multiFulfillment: {
             cadence: { unit: WEEK, count: 1 }
             numberOfFulfillments: 8
           }
         }


         # Define delivery method (replaces existing delivery method when provided)
         deliveryMethod:{
           pickup: {
             title: "Test",
             locationId: "gid://shopify/Location/1234",
             deliveryPrice: {
               amount: "0",
               currencyCode: GBP
             }
           }
         }


         # Define payment method (replaces existing payment method when provided)
         paymentMethod: {
           customerPaymentMethod: {
             id: "gid://shopify/CustomerPaymentMethod/1234"
           }
         }


         # Define note (replaces existing note)
         note: "Test"
       }
     ) {
       subscriptionContractCalculation {
         ... on SubscriptionContractCalculationPending {
           id
         }
       }
       userErrors {
         field
         message
       }
     }
   }
   ```

   ## JSON response

   ```json
   {
     "data": {
       "subscriptionContractUpdateCalculate": {
         "subscriptionContractCalculation": {
           "id": "gid://shopify/SubscriptionContractCalculation/789"
         },
         "userErrors": []
       }
     }
   }
   ```

2. Poll for the contract calculation result:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Poll for result

   ```graphql
   query PollCalculation {
     subscriptionContractCalculation(
       id: "gid://shopify/SubscriptionContractCalculation/789"
     ) {
       __typename
       ... on SubscriptionContractCalculationPending {
         id
       }
       ... on SubscriptionContractCalculationSuccess {
         id
         calculatedContract {
           lines(first: 10) {
             edges {
               node {
                 id
                 variantId
                 quantity
               }
             }
           }
         }
         warnings {
           code
           message
         }
         projectedOrderTotals {
           subtotal { amount currencyCode }
           totalDelivery { amount currencyCode }
           totalTax { amount currencyCode }
           totalMerchandiseDiscounts { amount currencyCode }
           totalDeliveryDiscounts { amount currencyCode }
           total { amount currencyCode }
         }
       }
       ... on SubscriptionContractCalculationFailure {
         id
         errors { code }
       }
     }
   }
   ```

   ## JSON response (pending)

   ```json
   {
     "data": {
       "subscriptionContractCalculation": {
         "__typename": "SubscriptionContractCalculationPending",
         "id": "gid://shopify/SubscriptionContractCalculation/789"
       }
     }
   }
   ```

3. Commit the contract calculation to apply changes:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Commit contract calculation

   ```graphql
   mutation CommitCalculation {
     subscriptionContractCalculationCommit(
       id: "gid://shopify/SubscriptionContractCalculation/789"
     ) {
       # The return type is a union: SubscriptionContract (create/update)
       # or SubscriptionBillingCycleEditedContract (billing cycle edit).
       contract {
         ... on SubscriptionContract {
           id
           status
         }
       }
       userErrors {
         field
         message
       }
     }
   }
   ```

   ## JSON response

   ```json
   {
     "data": {
       "subscriptionContractCalculationCommit": {
         "contract": {
           "id": "gid://shopify/SubscriptionContract/123",
           "status": "ACTIVE"
         },
         "userErrors": []
       }
     }
   }
   ```

### Preserve a line's state when you change it

The `lines` array replaces all existing lines, and each `productVariantLine` entry is a complete restatement of that line, even when you include its `id`. Including the `id` keeps the line's identity but it doesn't carry over its stored fields. Any field you omit from the entry is cleared or recalculated, and the calculation succeeds with no warning. To change one field on one line, read every line from the contract and restate every field of every line, as described in [Line fields](#line-fields).

***

## Edit a single billing cycle

Apply a one-time change to a single billing cycle of a subscription without changing the recurring contract. Later cycles continue to bill from the underlying contract. A billing cycle can contain more than one delivery (for example, prepaid or multi-fulfillment subscriptions), and the edit applies to the whole cycle.

### Old approach (Subscription​Draft)

With the [`SubscriptionDraft`](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionDraft) object, editing one billing cycle requires multiple sequential mutations:

1. Create a draft scoped to the target cycle using [`subscriptionBillingCycleContractEdit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractEdit).
2. Add, update, or remove lines and discounts on the draft using the `subscriptionDraft*` mutations.
3. Commit the draft using [`subscriptionBillingCycleContractDraftCommit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractDraftCommit).

### New approach (Subscription​Contract​Calculation)

With the `SubscriptionContractCalculation` API, you submit the complete desired state for the cycle in a single mutation and identify the cycle with a selector, then poll and commit exactly as you do for a contract update.

1. Submit the desired state for the target cycle to create a contract calculation, identifying the cycle with a [`billingCycleSelector`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/SubscriptionBillingCycleSelector). Select the cycle either:

   1. By its `index`:

      ```graphql
      mutation {
        subscriptionBillingCycleContractEditCalculate(
          contractId: "gid://shopify/SubscriptionContract/1"
          billingCycleSelector: { index: 2 }
          billingCycleEditInput: {
            withMerchandiseCustomizations: true,
            # The complete desired state for this cycle (lines, discounts, delivery, and so on).
            lines: [
              {
                productVariantLine: {
                  productVariantId: "gid://shopify/ProductVariant/1"
                  quantity: 2
                  customAttributes: []
                  discounts: []  # Line-scoped discounts; pass [] for none
                }
              }
            ]
          }
        ) {
          subscriptionContractCalculation {
            ... on SubscriptionContractCalculationPending {
              id
            }
          }
          userErrors {
            field
            message
          }
        }
      }
      ```

   2. Or by a `date` that falls within the cycle:

      ```graphql
      billingCycleSelector: { date: "2025-06-01T00:00:00Z" }
      ```

2. Poll the calculation and commit it as described in [Update a subscription contract](#update-a-subscription-contract). You wait for the calculation to succeed, then commit it with `subscriptionContractCalculationCommit`.

Committing creates and commits a new contract version scoped to that single billing cycle, leaving the recurring contract unchanged.

***

## Concatenate billing cycles

When a customer has several subscription contracts whose billing cycles fall on the same date, you can concatenate those cycles so that they bill as one order. One billing attempt on any of the concatenated cycles creates one order that's linked to every contract in the group. For the background on why you'd do this, see [Combine subscription contracts](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/combine-subscription-contracts).

**Early access:**

`subscriptionBillingCycleContractConcatenateCalculate` is available on the `unstable` API version for apps that Shopify has enabled. To request access or send feedback, email <subscriptions-calculate-api-early-access@shopify.com>.

### What's different about concatenation

A concatenation is a billing cycle edit that spans several contracts. It's scoped to the selected billing cycles only:

* **The recurring contracts don't change.** Committing the calculation applies the result to the selected cycle of each contract. Every contract keeps its own lines, policies, payment method, and next billing date for the cycles that follow.
* **You describe the whole order.** The draft API merges the lines and discounts of every concatenated contract into the draft for you. The calculate API doesn't merge anything: `lines`, `manualDiscounts`, and `discountCodes` are the complete order, and nothing is inherited from any contract. A line you leave out isn't billed.
* **Contract-level fields aren't part of the input.** The draft API accepts contract-level fields on the draft, such as `paymentMethodId`. The concatenate input has none of these. The payment method, billing policy, and delivery policy come from the contract you concatenate into, and status and next billing date stay on each recurring contract.
* **The delivery method is required.** The combined order ships as one, so you provide its delivery method instead of inheriting one.

The calculate API concatenates at billing cycle scope only. To merge contracts permanently, add the other contract's lines to one contract with `subscriptionContractUpdateCalculate` as described in [Update a subscription contract](#update-a-subscription-contract), and then cancel the contract you merged.

The contract you pass as `contractId` is the anchor. Its billing cycle is the one the order bills on, and its payment method and policies apply to that order. The cycles you list in `concatenatedBillingCycles` are the members. Committing attaches each member cycle to the anchor's edited contract, so one billing attempt bills the whole group.

The following table maps each step of the draft concatenation flow to `subscriptionBillingCycleContractConcatenateCalculate`.

| Draft API | Calculate API |
| - | - |
| `subscriptionBillingCycleContractEdit` on the first contract's cycle | The `contractId` and `billingCycleSelector` arguments. |
| `subscriptionBillingCycleContractDraftConcatenate` with `concatenatedBillingCycleContracts` | The `concatenatedBillingCycles` field on `billingCycleConcatenateInput`. |
| Lines merged from every contract automatically | `lines[]`. Restate the anchor's lines with their `id`, and the members' lines with `originLineId`. See [Carry lines over from each contract](#carry-lines-over-from-each-contract). |
| `subscriptionDraftDiscountAdd`, `subscriptionDraftDiscountCodeApply`, `subscriptionDraftFreeShippingDiscountAdd` | `manualDiscounts[]`, `discountCodes[]`, and `lines[].productVariantLine.discounts[]`. See [Manage discounts](#manage-discounts). |
| `subscriptionDraftUpdate` with `deliveryMethod` and `deliveryPrice` | `deliveryMethod`. Required. See [Delivery price](#delivery-price). |
| `subscriptionDraftUpdate` with `note` and `customAttributes` | `note` and `customAttributes`. Not inherited from the anchor. |
| `subscriptionDraftUpdate` with `paymentMethodId`, `status`, or `nextBillingDate` | Not available. These belong to the recurring contracts. |
| `subscriptionBillingCycleContractDraftCommit` | `subscriptionContractCalculationCommit`. |
| `subscriptionBillingCycleEditDelete` | Unchanged. See [Remove a concatenation](#remove-a-concatenation). |

#### Requirements on the cycles

The calculation is rejected with a `userErrors` entry when any of the following isn't true. At commit, Shopify locks the group and checks the requirements again against the cycles' state at that moment. If a cycle was billed, skipped, or joined another concatenation in between, or a member contract no longer meets the requirements, the commit returns a `userErrors` entry with code `STALE_CONTRACT`. Recalculate and commit the new calculation. A contract edit made on a member cycle in between doesn't make the commit stale: the commit replaces that edit with the concatenated edit. Schedule edits on the cycles stay in place.

* No cycle in the group has ended, is skipped, has a billing attempt that hasn't failed, or is already part of a concatenation. To change a group, [remove the concatenation](#remove-a-concatenation) first and create a new one.
* Every contract in the group is active and isn't prepaid.
* Every member contract belongs to the same customer, uses the same currency, and is owned by the same app as the anchor.
* `concatenatedBillingCycles` has at least one entry and at most 50, doesn't include the anchor, and names each contract once. To edit one cycle on its own, use `subscriptionBillingCycleContractEditCalculate`.

A member cycle that already has its own billing cycle edit is accepted. Committing the concatenation supersedes that edit, because the concatenate input is the complete order.

### Old approach (Subscription​Draft)

With the `SubscriptionDraft` API, concatenating contracts requires multiple sequential mutations:

1. Create a draft scoped to one contract's cycle using [`subscriptionBillingCycleContractEdit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractEdit).
2. Join the other contracts' cycles to the draft using [`subscriptionBillingCycleContractDraftConcatenate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractDraftConcatenate). Their lines and discounts are merged into the draft.
3. Optionally, update the draft using the `subscriptionDraft*` mutations.
4. Commit the draft using [`subscriptionBillingCycleContractDraftCommit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleContractDraftCommit).

### New approach (Subscription​Contract​Calculation)

With the `SubscriptionContractCalculation` API, you submit the anchor, the member cycles, and the complete order in a single mutation, then poll and commit exactly as you do for a billing cycle edit.

1. Submit the concatenation to create a contract calculation. Identify the anchor cycle with `contractId` and a [`billingCycleSelector`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/SubscriptionBillingCycleSelector), and each member cycle with a [`SubscriptionBillingCycleInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/SubscriptionBillingCycleInput):

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Create concatenation calculation

   ```graphql
   mutation ConcatenateCalculation {
     subscriptionBillingCycleContractConcatenateCalculate(
       # The anchor: the order bills on this contract's cycle, with its payment method and policies
       contractId: "gid://shopify/SubscriptionContract/123"
       billingCycleSelector: { index: 2 }
       billingCycleConcatenateInput: {
         # Control contract calculation behavior
         withMerchandiseCustomizations: true


         # The members: the cycles this order satisfies. At least one is required.
         concatenatedBillingCycles: [
           {
             contractId: "gid://shopify/SubscriptionContract/456"
             selector: { index: 2 }
           }
         ]


         # The complete set of lines for the combined order. Nothing is inherited.
         lines: [
           {
             productVariantLine: {
               # A line of the anchor contract: include its id
               id: "gid://shopify/SubscriptionLine/anchor-line-uuid"
               productVariantId: "gid://shopify/ProductVariant/111"
               quantity: 1
               priceOverride: { amount: "20.00", currencyCode: CAD }
               customAttributes: []
               discounts: []
             }
           }
           {
             productVariantLine: {
               # A line of a member contract: name it with originLineId, not id
               originLineId: "gid://shopify/SubscriptionLine/member-line-uuid"
               productVariantId: "gid://shopify/ProductVariant/222"
               quantity: 2
               priceOverride: { amount: "15.00", currencyCode: CAD }
               customAttributes: []
               discounts: []
             }
           }
         ]


         # The delivery method for the combined order. Required, not inherited.
         deliveryMethod: {
           shipping: {
             address: {
               firstName: "Quinn"
               lastName: "Ishida"
               address1: "123 Main St"
               city: "Toronto"
               provinceCode: "ON"
               countryCode: CA
               zip: "M5V 1A1"
             }
             title: "Standard"
             code: "Standard"
             deliveryPrice: {
               amount: "5.00"
               currencyCode: CAD
             }
           }
         }


         # Discounts for the combined order (pass empty arrays for none)
         discountCodes: []
         manualDiscounts: []


         # Custom attributes for the combined order (pass an empty array for none)
         customAttributes: []
       }
     ) {
       subscriptionContractCalculation {
         ... on SubscriptionContractCalculationPending {
           id
         }
       }
       userErrors {
         field
         message
         code
       }
     }
   }
   ```

   ## JSON response

   ```json
   {
     "data": {
       "subscriptionBillingCycleContractConcatenateCalculate": {
         "subscriptionContractCalculation": {
           "id": "gid://shopify/SubscriptionContractCalculation/789"
         },
         "userErrors": []
       }
     }
   }
   ```

2. Poll for the contract calculation result as described in [Update a subscription contract](#update-a-subscription-contract). The `SubscriptionContractCalculationSuccess` result carries the `projectedOrderTotals` for the combined order.

3. Commit the contract calculation. For a concatenation, the `contract` field in the response is a `SubscriptionBillingCycleEditedContract`, and its `billingCycles` connection lists every cycle in the group:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Commit concatenation calculation

   ```graphql
   mutation CommitCalculation {
     subscriptionContractCalculationCommit(
       id: "gid://shopify/SubscriptionContractCalculation/789"
     ) {
       contract {
         ... on SubscriptionBillingCycleEditedContract {
           billingCycles(first: 10) {
             nodes {
               cycleIndex
               sourceContract { id }
             }
           }
         }
       }
       userErrors {
         field
         message
       }
     }
   }
   ```

   ## JSON response

   ```json
   {
     "data": {
       "subscriptionContractCalculationCommit": {
         "contract": {
           "billingCycles": {
             "nodes": [
               { "cycleIndex": 2, "sourceContract": { "id": "gid://shopify/SubscriptionContract/123" } },
               { "cycleIndex": 2, "sourceContract": { "id": "gid://shopify/SubscriptionContract/456" } }
             ]
           }
         },
         "userErrors": []
       }
     }
   }
   ```

After the commit, the [`subscriptionBillingCycle`](https://shopify.dev/docs/api/admin-graphql/latest/queries/subscriptionBillingCycle) query for any cycle in the group returns the same `editedContract`, with `edited: true`. Its `billingCycles` connection lists the whole group, so you can read group membership from any member. This is the same query you use after a draft concatenation.

### Carry lines over from each contract

Because the calculate API doesn't merge lines, you build the combined `lines` array yourself. Read the lines of each contract's cycle from `subscriptionBillingCycle.editedContract` (or from the contract when the cycle has no edit), then restate each one as described in [Line fields](#line-fields). Two fields identify where a line comes from:

| Line belongs to | Field to set | Effect |
| - | - | - |
| The anchor contract | `id` | Keeps the line's identity, as on a billing cycle edit. |
| A member contract | `originLineId` | Records the member contract on the resulting order line, so that contract still shows the order it was billed in. Omit `id`. |
| No contract (new) | Neither | Adds a new line to the combined order. |

`originLineId` must name a line on one of the member contracts, not on the anchor, and can't be combined with `id`.

**Members without lines are still billed:**

Every contract you name in `concatenatedBillingCycles` is billed by the combined order, even when none of your `lines` carry an `originLineId` from it. Its cycle is marked as billed and points to an order that contains none of its products. Include a line for every member unless you intend this.

### Bill the concatenated cycles

Billing doesn't change. When the billing date comes, create one billing attempt on any contract in the group with [`subscriptionBillingAttemptCreate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingAttemptCreate) or [`subscriptionBillingCycleCharge`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleCharge), selecting that contract's concatenated cycle. Shopify creates one order that's linked to every contract in the group and marks every cycle in the group as billed.

A billing attempt on a concatenated cycle can return the following `BillingAttemptUserError` codes in addition to the usual ones:

| Code | Meaning |
| - | - |
| `BILLING_CYCLE_GROUP_ALREADY_ATTEMPTED` | A billing cycle concatenated with this one has already been billed, or has a billing attempt that hasn't finished. Wait for any unfinished attempt to finish and check its result. To charge the cycles separately, [remove the concatenation](#remove-a-concatenation) first. |
| `BILLING_CYCLE_GROUP_CYCLE_SKIPPED` | A billing cycle concatenated with this one is skipped. |
| `BILLING_CYCLE_GROUP_CONTENDED` | Another process is modifying a billing cycle concatenated with this one. Retry. |

### Remove a concatenation

To dissolve a group before it bills, call [`subscriptionBillingCycleEditDelete`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleEditDelete) on any one cycle in the group. This is the same mutation the draft API uses. It removes the shared edit from every cycle in the group in one operation, and each cycle goes back to billing from its own recurring contract:

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Remove concatenation

```graphql
mutation RemoveConcatenation {
  subscriptionBillingCycleEditDelete(
    # Any contract in the group, with its concatenated cycle
    billingCycleInput: {
      contractId: "gid://shopify/SubscriptionContract/456"
      selector: { index: 2 }
    }
  ) {
    billingCycles {
      cycleIndex
      edited
      sourceContract { id }
    }
    userErrors {
      field
      message
      code
    }
  }
}
```

## JSON response

```json
{
  "data": {
    "subscriptionBillingCycleEditDelete": {
      "billingCycles": [
        { "cycleIndex": 2, "edited": false, "sourceContract": { "id": "gid://shopify/SubscriptionContract/123" } },
        { "cycleIndex": 2, "edited": false, "sourceContract": { "id": "gid://shopify/SubscriptionContract/456" } }
      ],
      "userErrors": []
    }
  }
}
```

The response lists every cycle that was in the group. A second call on any of them returns a `NO_CYCLE_EDITS` error, because the cycles no longer carry an edit.

**Schedule edits are removed too:**

`subscriptionBillingCycleEditDelete` removes both the contract edit and any schedule edit on every cycle in the group. A cycle whose billing date was rescheduled before it was concatenated goes back to its original schedule. Reapply the schedule edit with [`subscriptionBillingCycleScheduleEdit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingCycleScheduleEdit) if you still need it.

Remove a concatenation before you bill it. While a billing attempt is in progress on the cycle you target, the mutation returns an `INCOMPLETE_BILLING_ATTEMPTS` error. To change the members or the lines of a group you've committed, remove the concatenation and then submit a new `subscriptionBillingCycleContractConcatenateCalculate`.

A calculation you haven't committed doesn't lock the cycles. To change the members or the lines before you commit, submit a new calculation and commit that one instead. Shopify deletes the calculations you don't commit after seven days, as described in [Contract calculation states](#contract-calculation-states).

***

## Manage discounts

The `SubscriptionContractCalculation` API splits discounts into two separate input fields that replace the multiple draft-based discount mutations:

* **`discountCodes[]`**: Discount codes to apply during the calculation. Applied codes are resolved into manual discounts on the resulting contract; codes aren't persisted as codes, so there's nothing to preserve or replace across calculations. Defaults to an empty array.
* **`manualDiscounts[]`**: Manual order and delivery discounts. This is a `@oneOf` input — each entry is either an `orderDiscount` or a `deliveryDiscount`.

For line-scoped discounts (discounts that apply to a single line), use the `discounts[]` field on each line input. See [Line-scoped discounts](#line-scoped-discounts).

**Manual discounts replacement behavior:**

The `manualDiscounts` array replaces **all** existing manual discounts on the contract. To keep an existing discount, include it in the array with its `id`. To remove a discount, omit it from the array. To add a new discount, include it without an `id`. To remove all manual discounts, pass an empty array (`[]`).

**Bundles and omitted lines:**

The order and delivery discount examples omit `lines` and set `withMerchandiseCustomizations: false` so the calculation leaves the contract's lines and bundles alone. With `true`, an omitted `lines` rebuilds expanded and merged bundles and fails on a custom bundle. The [line-scoped example](#line-scoped-discounts) supplies `lines`, so it sets `true`.

### Discount types

| Discount type | Old mutation(s) | New input field | Description |
| - | - | - | - |
| Code discount | `subscriptionDraftDiscountCodeApply` | `discountCodes[]` | Apply a discount code by its redeem code. |
| Order discount | `subscriptionDraftDiscountAdd`, `subscriptionDraftDiscountUpdate`, `subscriptionDraftDiscountRemove` | `manualDiscounts[].orderDiscount` | Apply a fixed or percentage discount to all lines. |
| Delivery discount | `subscriptionDraftFreeShippingDiscountAdd`, `subscriptionDraftFreeShippingDiscountUpdate` | `manualDiscounts[].deliveryDiscount` | Apply a discount to shipping or delivery charges. |
| Line-scoped discount | `subscriptionDraftDiscountAdd` (line-scoped) | `lines[].productVariantLine.discounts[]` | Apply a fixed or percentage discount to a single line. |

### Apply a discount code

To apply a discount code to an existing contract, include an entry in the `discountCodes` array:

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Apply code discount

```graphql
mutation ApplyCodeDiscount {
  subscriptionContractUpdateCalculate(
    contractId: "gid://shopify/SubscriptionContract/123"
    contractUpdateInput: {
      withMerchandiseCustomizations: false
      discountCodes: [
        { redeemCode: "SAVE10" }
      ]
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

### Apply an order discount

Order discounts apply to all lines on the contract. They support percentage or fixed amount values:

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Percentage order discount

```graphql
mutation ApplyOrderDiscount {
  subscriptionContractUpdateCalculate(
    contractId: "gid://shopify/SubscriptionContract/123"
    contractUpdateInput: {
      withMerchandiseCustomizations: false
      manualDiscounts: [
        {
          orderDiscount: {
            title: "10% loyalty discount"
            value: {
              percentage: 10
            }
            recurringCycleLimit: 0  # 0 = applies indefinitely
          }
        }
      ]
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Fixed amount order discount

```graphql
mutation ApplyFixedOrderDiscount {
  subscriptionContractUpdateCalculate(
    contractId: "gid://shopify/SubscriptionContract/123"
    contractUpdateInput: {
      withMerchandiseCustomizations: false
      manualDiscounts: [
        {
          orderDiscount: {
            title: "$5 off subscription"
            value: {
              fixedAmount: {
                appliesOnEachItem: true
                amount: { amount: "5.00", currencyCode: USD }
              }
            }
            recurringCycleLimit: 3  # Applies for 3 billing cycles
          }
        }
      ]
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

### Apply a delivery discount

Delivery discounts apply to shipping or delivery charges. For example, to offer free shipping:

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Free shipping discount

```graphql
mutation ApplyDeliveryDiscount {
  subscriptionContractUpdateCalculate(
    contractId: "gid://shopify/SubscriptionContract/123"
    contractUpdateInput: {
      withMerchandiseCustomizations: false
      manualDiscounts: [
        {
          deliveryDiscount: {
            title: "Free shipping"
            value: {
              percentage: 100
            }
            recurringCycleLimit: 0  # 0 = free shipping indefinitely
          }
        }
      ]
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

### Combine multiple discounts

You can apply multiple discounts of different types in a single calculation. Include discount codes in `discountCodes[]` and manual discounts in `manualDiscounts[]`:

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Multiple discount types

```graphql
mutation ApplyMultipleDiscounts {
  subscriptionContractUpdateCalculate(
    contractId: "gid://shopify/SubscriptionContract/123"
    contractUpdateInput: {
      withMerchandiseCustomizations: false
      discountCodes: [
        { redeemCode: "SAVE10" }
      ]
      manualDiscounts: [
        {
          orderDiscount: {
            title: "Loyalty reward"
            value: { percentage: 5 }
            recurringCycleLimit: 0
          }
        }
        {
          deliveryDiscount: {
            title: "Free shipping promo"
            value: { percentage: 100 }
            recurringCycleLimit: 6
          }
        }
      ]
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

### Line-scoped discounts

To apply a discount to a single line, include it in the `discounts[]` field on that line's input. Each line-scoped discount takes `title`, `value`, and `recurringCycleLimit` fields, and optionally an `id` to update an existing line discount:

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Line-scoped discount

```graphql
mutation ApplyLineDiscount {
  subscriptionContractUpdateCalculate(
    contractId: "gid://shopify/SubscriptionContract/123"
    contractUpdateInput: {
      withMerchandiseCustomizations: true
      lines: [
        {
          productVariantLine: {
            id: "gid://shopify/SubscriptionLine/line-uuid-1"
            productVariantId: "gid://shopify/ProductVariant/111"
            quantity: 1
            customAttributes: []
            discounts: [
              {
                title: "10% off this line"
                value: { percentage: 10 }
                recurringCycleLimit: 0
              }
            ]
          }
        }
      ]
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

### Remove all discounts

To remove all manual discounts from a contract, pass an empty `manualDiscounts` array and an empty `discountCodes` array:

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Remove all discounts

```graphql
mutation RemoveAllDiscounts {
  subscriptionContractUpdateCalculate(
    contractId: "gid://shopify/SubscriptionContract/123"
    contractUpdateInput: {
      withMerchandiseCustomizations: false
      manualDiscounts: []
      discountCodes: []
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
    }
  }
}
```

***

## Fetch delivery options

The `deliveryOptions` field on `SubscriptionContractCalculationSuccess` returns the available delivery options that the calculation computed. This field replaces the [`SubscriptionDraft.deliveryOptions`](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionDraft#field-SubscriptionDraft.fields.deliveryOptions) field from the `SubscriptionDraft` API, and returns all available options.

The `SubscriptionContractCalculationSuccess` type also exposes:

* `warnings`: Non-fatal warnings produced during the calculation. The calculation still succeeded; warnings inform the merchant about issues that should be reviewed before committing.
* `projectedOrderTotals`: Projected order totals (subtotal, total delivery, estimated tax, merchandise discounts, delivery discounts, and grand total) for the calculated contract. Null when the calculation only discovered delivery options for an address rather than calculating committed totals.

Each option is a `SubscriptionContractCalculationDeliveryOption`, which resolves to one of the following types:

* `SubscriptionContractCalculationShippingOption`
* `SubscriptionContractCalculationLocalDeliveryOption`
* `SubscriptionContractCalculationPickupOption`

Fetching delivery options is opt-in. A calculation that sets or keeps a committed delivery method uses a faster path that doesn't look up the full set of rates, so it doesn't return the complete set of options. To fetch all available options for an address, provide `fetchAvailableDeliveryOptions` in the `deliveryMethod` input instead of a method. This is a discovery calculation. It doesn't change the contract's committed delivery method, and it can't be committed.

**Caution:**

A discovery calculation can't be committed. `subscriptionContractCalculationCommit` returns the `DISCOVERY_CALCULATION_NOT_COMMITTABLE` user error. To commit a change, create a new calculation with the chosen delivery method, then commit it.

**Note:**

`deliveryMethod` is a [`@oneOf` input](https://spec.graphql.org/draft/#sec--oneOf). Provide exactly one of `shipping`, `localDelivery`, `pickup`, `none`, or `fetchAvailableDeliveryOptions`. Providing a committed method and `fetchAvailableDeliveryOptions` in the same calculation is rejected.

### Old approach (Subscription​Draft)

With the SubscriptionDraft API, fetching and setting a delivery option requires multiple sequential mutations and a separate asynchronous query:

1. Create a draft using [`subscriptionContractUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractUpdate) (or [`subscriptionContractCreate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionContractCreate)).
2. Query the [`deliveryOptions`](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionDraft#field-SubscriptionDraft.fields.deliveryOptions) field on the [SubscriptionDraft](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionDraft) with a `deliveryAddress`, polling until it returns a non-null result. Delivery option lookup is asynchronous and returns `null` while pending.
3. Set the selected method using [`subscriptionDraftUpdate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftUpdate) with a `deliveryMethod`.
4. Commit the draft using [`subscriptionDraftCommit`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionDraftCommit).

### New approach (Subscription​Contract​Calculation)

With the `SubscriptionContractCalculation` API, you fetch delivery options with a calculation, read them off the result, then create a new calculation with the chosen delivery method. Only that second calculation can be committed.

1. Submit a contract calculation that fetches the delivery options by providing `fetchAvailableDeliveryOptions` in the `deliveryMethod` input:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Fetch delivery options

   ```graphql
   mutation FetchDeliveryOptions {
     subscriptionContractUpdateCalculate(
       contractId: "gid://shopify/SubscriptionContract/123"
       contractUpdateInput: {
         withMerchandiseCustomizations: true


         # Fetch delivery options for this address without committing a method
         deliveryMethod: {
           fetchAvailableDeliveryOptions: {
             # Run delivery customization functions while discovering options (default)
             withDeliveryCustomizations: true


             address: {
               firstName: "Quinn"
               lastName: "Ishida"
               address1: "123 Main St"
               city: "Toronto"
               provinceCode: "ON"
               countryCode: CA
               zip: "M5V 1A1"
             }
           }
         }
       }
     ) {
       subscriptionContractCalculation {
         ... on SubscriptionContractCalculationPending {
           id
         }
       }
       userErrors {
         field
         message
       }
     }
   }
   ```

   ## JSON response

   ```json
   {
     "data": {
       "subscriptionContractUpdateCalculate": {
         "subscriptionContractCalculation": {
           "id": "gid://shopify/SubscriptionContractCalculation/789"
         },
         "userErrors": []
       }
     }
   }
   ```

2. Poll for the contract calculation result (see the [recommended polling strategy](#polling-pattern)) and read the `deliveryOptions`. Each option type is part of a union, so use inline fragments to select its fields:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Read delivery options

   ```graphql
   query PollDeliveryOptions {
     subscriptionContractCalculation(
       id: "gid://shopify/SubscriptionContractCalculation/789"
     ) {
       __typename
       ... on SubscriptionContractCalculationPending {
         id
       }
       ... on SubscriptionContractCalculationSuccess {
         id
         deliveryOptions {
           __typename
           ... on SubscriptionContractCalculationShippingOption {
             title
             code
             price { amount currencyCode }
           }
           ... on SubscriptionContractCalculationLocalDeliveryOption {
             title
             code
             phoneRequired
             price { amount currencyCode }
           }
           ... on SubscriptionContractCalculationPickupOption {
             title
             code
             pickupTime
             price { amount currencyCode }
             location { id name }
           }
         }
       }
       ... on SubscriptionContractCalculationFailure {
         id
         errors { code }
       }
     }
   }
   ```

   ## JSON response (success)

   ```json
   {
     "data": {
       "subscriptionContractCalculation": {
         "__typename": "SubscriptionContractCalculationSuccess",
         "id": "gid://shopify/SubscriptionContractCalculation/789",
         "deliveryOptions": [
           {
             "__typename": "SubscriptionContractCalculationShippingOption",
             "title": "Standard",
             "code": "Standard",
             "price": { "amount": "5.00", "currencyCode": "CAD" }
           },
           {
             "__typename": "SubscriptionContractCalculationShippingOption",
             "title": "Express",
             "code": "Express",
             "price": { "amount": "15.00", "currencyCode": "CAD" }
           }
         ]
       }
     }
   }
   ```

3. Submit a second contract calculation that commits the selected option as the `deliveryMethod`. Map the chosen option's `title` and `code` directly, and map its `price` to the method's `deliveryPrice` field:

   ## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

   ## Select a delivery option

   ```graphql
   mutation SelectDeliveryOption {
     subscriptionContractUpdateCalculate(
       contractId: "gid://shopify/SubscriptionContract/123"
       contractUpdateInput: {
         withMerchandiseCustomizations: true


         # Commit the option chosen from deliveryOptions
         deliveryMethod: {
           shipping: {
             address: {
               firstName: "Quinn"
               lastName: "Ishida"
               address1: "123 Main St"
               city: "Toronto"
               provinceCode: "ON"
               countryCode: CA
               zip: "M5V 1A1"
             }
             title: "Standard"
             code: "Standard"
             deliveryPrice: {
               amount: "5.00"
               currencyCode: CAD
             }
           }
         }
       }
     ) {
       subscriptionContractCalculation {
         ... on SubscriptionContractCalculationPending {
           id
         }
       }
       userErrors {
         field
         message
       }
     }
   }
   ```

4. Poll for the second contract calculation result, then commit it with `subscriptionContractCalculationCommit` to apply the selected delivery method to the contract. This follows the same poll-then-commit pattern as the create and update flows above.

### Delivery customization functions

When a calculation fetches delivery options, the `withDeliveryCustomizations` field on `fetchAvailableDeliveryOptions` controls whether [delivery customization](https://shopify.dev/docs/api/functions/latest/delivery-customization) functions run:

* `true` (the default): Functions run, so the returned `deliveryOptions` reflect any options the merchant's customizations hide, rename, or re-order.
* `false`: Functions are bypassed, and the raw delivery options are returned.

The `SubscriptionDraft` API doesn't run delivery customization functions when computing `deliveryOptions`. For shops with active delivery customizations, the set of options returned by the new API can therefore differ from the old field.

**Note:**

`withDeliveryCustomizations` applies only to calculations that include `fetchAvailableDeliveryOptions`. Calculations that set a committed delivery method and recurring billing attempts always bypass delivery customization functions, because the contract's committed delivery method is fixed and re-running functions can remove it.

***

## Input types reference

**Exploring input types:**

[Explore the API](#explore-the-api) to understand the full input schema, starting from the top-level input types.

### Top-level input types

| Input type | Description |
| - | - |
| `SubscriptionContractCalculationContractCreateInput` | Inputs for creating a new subscription contract. |
| `SubscriptionContractCalculationContractUpdateInput` | Input for updating an existing subscription contract. |
| `SubscriptionContractCalculationBillingCycleEditInput` | Input for editing a single billing cycle of an existing contract. |
| `SubscriptionContractCalculationBillingCycleConcatenateInput` | Input for concatenating the billing cycles of several contracts into one order. See [Concatenate billing cycles](#concatenate-billing-cycles). |

### Union input types

**Note:**

The inputs for `lines`, `manualDiscounts`, and `deliveryMethod` fields use the GraphQL [`@oneOf` directive](https://spec.graphql.org/draft/#sec--oneOf). You must provide exactly one of the available input options for each entry. `discountCodes` is a separate non-union array. Refer to the following sections for the specific options available for each field.

#### `SubscriptionContractCalculationLineInput`

Lines use a `@oneOf` input pattern. Provide exactly one of the following options:

* `productVariantLine`: For product variant lines.
* `customLine`: For custom lines without a variant.
* `productVariantParentLine`: For product variant bundle parent lines (available when bundle support is enabled).

**Lines replacement behavior:**

The `lines` array replaces all existing lines. Include all lines that you want to keep and omit any that you want to remove. Use line IDs to identify existing lines for updates. Each entry is a complete restatement of the line, not a patch: to keep an existing line unchanged, restate all of its fields from the stored contract. See [Preserve a line's state when you change it](#preserve-a-lines-state-when-you-change-it).

#### `SubscriptionContractCalculationProductVariantLineInput`

Product variant lines accept the following fields:

| Field | Type | Required | Description |
| - | - | - | - |
| `id` | `ID` | No | The ID of an existing line to update. Omit for new lines. |
| `productVariantId` | `ID` | Yes | The ID of the product variant for this line. |
| `quantity` | `Integer` | Yes | The quantity of the product variant. Must be at least 1. |
| `priceOverride` | [`MoneyInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/MoneyInput) | No | The per-unit price your app charges for the line. Replaces the draft API's `currentPrice`. When omitted, the line is priced from the product variant's current price. |
| `customAttributes` | `[AttributeInput]` | No (default `[]`) | Custom attributes for this subscription line. Omitting it clears the line's custom attributes. |
| `appManagedPricingPolicy` | `SubscriptionContractCalculationAppManagedPricingPolicyInput` | No | App-managed pricing policy metadata for this line. Replaces the draft API's `pricingPolicy`. Doesn't drive the calculated price. When omitted on a restated line, the stored policy is cleared. |
| `originSellingPlanId` | `ID` | No | The ID of the selling plan this line was originally created with. Replaces the draft API's `sellingPlanId`. Used to find the delivery profile. |
| `sellingPlanName` | `String` | No | The selling plan name for this line. When omitted, defaults to the current name of `originSellingPlanId`, or to no name when that's also omitted. |
| `discounts` | `[SubscriptionContractCalculationLineDiscountInput]` | Yes | Line-scoped manual discounts. Pass `[]` for none. |
| `originLineId` | `ID` | No | Concatenation only. The line on a concatenated contract that this line is carried over from. Can't be combined with `id`. Ignored outside `subscriptionBillingCycleContractConcatenateCalculate`. See [Carry lines over from each contract](#carry-lines-over-from-each-contract). |

#### `SubscriptionContractCalculationManualDiscountInput`

Manual discounts use a `@oneOf` input pattern. Provide exactly one of the following options:

* `orderDiscount`: For order discounts that apply to all lines on the contract. Takes `title`, `value`, and `recurringCycleLimit` fields. Optionally takes an `id` to update an existing discount.
* `deliveryDiscount`: For delivery or shipping discounts. Takes `title`, `value`, and `recurringCycleLimit` fields. Optionally takes an `id` to update an existing discount.

**Manual discounts replacement behavior:**

The `manualDiscounts` array replaces all existing manual discounts. Include all discounts that you want to keep and omit any that you want to remove. Use discount IDs to identify existing discounts for updates.

#### `SubscriptionContractCalculationDiscountCodeInput`

Discount codes are provided in the separate `discountCodes[]` array (not part of `manualDiscounts`). Each entry takes:

* `redeemCode`: The discount code string to apply.

Applied codes are resolved into manual discounts on the resulting contract; codes aren't persisted as codes, so there's nothing to preserve or replace across calculations.

#### `SubscriptionContractCalculationDiscountValueInput`

Discount values use a `@oneOf` input pattern. Provide exactly one of the following options:

* `percentage`: An integer percentage value (0–100).
* `fixedAmount`: A fixed money amount with `appliesOnEachItem` (boolean) and `amount` ([`MoneyInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/MoneyInput)).

#### `SubscriptionContractCalculationDeliveryMethodInput`

Delivery methods use a `@oneOf` input pattern. Provide exactly one of the following options:

* `shipping`: For shipping deliveries.
* `localDelivery`: For local delivery.
* `pickup`: For pickup.
* `none`: Explicitly set no delivery method (digital-only subscriptions). Must be `true`.
* `fetchAvailableDeliveryOptions`: To fetch the available delivery options for an address without committing a delivery method. The resulting discovery calculation can't be committed. See [Fetch delivery options](#fetch-delivery-options).

`shipping`, `localDelivery`, and `pickup` each require a `deliveryPrice` ([`MoneyInput`](https://shopify.dev/docs/api/admin-graphql/latest/input-objects/MoneyInput)). This is where the draft API's `deliveryPrice` lives. See [Delivery price](#delivery-price).

#### `SubscriptionContractCalculationPaymentMethodInput`

Payment methods use a `@oneOf` input pattern. Provide exactly one of the following options:

* `customerPaymentMethod`: A vaulted customer payment method. Takes an `id` field (`ID`) for the customer payment method.
* `none`: Explicitly set no payment method. Must be `true`.

#### `SubscriptionContractCalculationFetchDeliveryOptionsInput`

Use this input under `deliveryMethod.fetchAvailableDeliveryOptions` to fetch available delivery options without setting a delivery method.

* `address`: The delivery address to fetch options for.
* `withDeliveryCustomizations`: Optional Boolean. When `true` (the default), delivery customization functions run while fetching options. When `false`, delivery customization functions are bypassed and the raw options are returned.

***

## Handle asynchronous results

The `SubscriptionContractCalculation` API uses asynchronous processing because it aligns contract editing with all other checkout surfaces across Shopify, including subscription billing attempts, checkout, and draft orders.

Most contract calculations complete in less than one second, but the system needs to account for network latency and errors in third-party services. The asynchronous model handles these situations without exposing transient errors or imposing strict API request timeouts.

You can handle contract calculation results by polling the contract calculation query or [subscribing to webhooks](#webhook-integration) for event-driven processing.

### Contract calculation states

A contract calculation progresses through several states from creation to completion. Understanding these states helps you build integrations that handle all possible outcomes.

| State | Description | Webhook |
| - | - | - |
| **Initiated** | The contract calculation is created and waiting to be processed. | — |
| **Processing** | The contract calculation is running with functions and external services. | — |
| **Succeeded** | The contract calculation is ready for review and commit. | `subscription_contract_calculations/succeed` |
| **Failed** | The contract calculation failed. Errors are available on the result. | `subscription_contract_calculations/fail` |
| **Voided** | The contract calculation wasn't processed due to infrastructure issues. | — |
| **Committed** | The contract calculation has been committed and is now active. | `subscription_contracts/create` or `subscription_contracts/update` |

The `subscriptionContractCalculation` query returns a union with three possible GraphQL types. The internal states map to these types as follows:

| GraphQL type | Internal states |
| - | - |
| `SubscriptionContractCalculationPending` | Initiated, Processing |
| `SubscriptionContractCalculationSuccess` | Succeeded, Committed |
| `SubscriptionContractCalculationFailure` | Failed, Voided |

**Uncommitted calculation retention:**

Shopify automatically deletes uncommitted calculations seven days after they're created. The `subscriptionContractCalculation` query returns `null` for a deleted calculation, and committing it returns a `CALCULATION_NOT_FOUND` error.

### Polling pattern

After creating a contract calculation, poll the `subscriptionContractCalculation` query until processing completes.

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## GraphQL query

```graphql
query PollCalculation($id: ID!) {
  subscriptionContractCalculation(id: $id) {
    __typename
    ... on SubscriptionContractCalculationPending {
      id
    }
    ... on SubscriptionContractCalculationSuccess {
      id
    }
    ... on SubscriptionContractCalculationFailure {
      id
    }
  }
}
```

### Recommended polling strategy

1. **Initial wait**: Wait 1 second after the mutation before the first poll.
2. **Poll interval**: Poll every 500ms.
3. **Timeout**: Stop polling after 30 seconds, or when the contract calculation result is in a failed state.

### Retry safety

All contract calculation operations are safe to retry:

* **Calculate**: Safe to retry. Creates a new contract calculation each time.
* **Commit**: Safe to retry. If already committed, it returns success.
* **Polling**: Safe to call as many times as needed.

### Webhook integration

[Subscribe to webhooks](https://shopify.dev/docs/apps/build/webhooks/subscribe) for event-driven processing instead of polling.

| Webhook topic | Description |
| - | - |
| `subscription_contract_calculations/succeed` | Fires when a contract calculation succeeds and the contract calculation is ready to commit. |
| `subscription_contract_calculations/fail` | Fires when a contract calculation fails and errors are available on the result. |

## POST https://{shop}.myshopify.com/admin/api/{api\_version}/graphql.json

## Create webhook subscription

```graphql
mutation CreateWebhookSubscription {
  webhookSubscriptionCreate(
    topic: SUBSCRIPTION_CONTRACT_CALCULATIONS_SUCCEED
    webhookSubscription: {
      uri: "https://example.com/webhooks/calculation-success"
      format: JSON
    }
  ) {
    webhookSubscription {
      id
    }
    userErrors {
      field
      message
    }
  }
}
```

## JSON response

```json
{
  "data": {
    "webhookSubscriptionCreate": {
      "webhookSubscription": {
        "id": "gid://shopify/WebhookSubscription/123456789"
      },
      "userErrors": []
    }
  }
}
```

## Webhook payload

```json
{
  "id": 123,
  "admin_graphql_api_id": "gid://shopify/SubscriptionContractCalculation/123",
  "state": "succeeded"
}
```

***

## Backwards compatibility

The `SubscriptionDraft` API will remain available but will not support the new capabilities of the `SubscriptionContractCalculation` API.

### Switch between the draft and calculation APIs

You can use both the [SubscriptionDraft](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionDraft) API and the [SubscriptionContractCalculation](https://shopify.dev/docs/api/admin-graphql/latest/unions/SubscriptionContractCalculation) API on the same contracts, but only one API per editing session. The two APIs maintain their own pending state, and uncommitted drafts and calculation outputs aren't shared between them. A draft you create with one API isn't visible to the other, and a calculation output isn't visible to the draft API.

To switch from one API to the other between sessions:

1. Abandon any pending draft or uncommitted calculation.
2. Refetch the latest [SubscriptionContract](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionContract).
3. Resubmit your complete remaining intent against the latest contract version using the API you're switching to.

***
