---
title: Build a subscription contract
description: >-
  Learn how to create a subscription, and how to make a billing attempt to
  schedule and automate the billing of subscriptions in your app.
source_url:
  html: >-
    https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/build-a-subscription-contract
  md: >-
    https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/build-a-subscription-contract.md
api_name: admin
---

# Build a subscription contract

A [subscription contract](https://shopify.dev/docs/api/admin-graphql/2026-10/objects/SubscriptionContract) is the agreement between a customer and a merchant over a specific term for recurring purchases over a set or undefined period of time.

This guide shows you how to submit a complete desired state to [`subscriptionContractCreateCalculate`](https://shopify.dev/docs/api/admin-graphql/2026-10/mutations/subscriptionContractCreateCalculate), review Shopify's calculated result, and commit it as an active subscription contract. It includes examples for "Subscribe and save" and prepaid subscriptions.

**Available in the 2026-10 release candidate:**

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 creation guide](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/create-a-subscription-contract-with-subscription-draft).

***

## Requirements

**Note:**

* Most subscriptions, pre-order and try before you buy apps need to request API access through the [Partner Dashboard](https://partners.shopify.com/current/apps). We give API access to apps that are designed according to our [principles for subscriptions, pre-order and TBYB apps](https://shopify.dev/docs/apps/build/purchase-options#shopifys-principles).
* Public apps that use subscriptions, pre-order or TBYB need to meet [specific requirements](https://shopify.dev/docs/apps/launch/shopify-app-store/app-store-requirements#purchase-option) to be published on the Shopify App Store.
* Custom apps [created in the Shopify admin](https://shopify.dev/docs/apps/build/authentication-authorization/legacy/admin-custom-apps) 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 [create your custom app in the Dev Dashboard](https://shopify.dev/docs/apps/build/dev-dashboard/create-apps-using-dev-dashboard).

- Your app can make [authenticated requests](https://shopify.dev/docs/api/admin-graphql#authentication) to the GraphQL Admin API.
- Your app has the `read_own_subscription_contracts` and `write_own_subscription_contracts` [access scopes](https://shopify.dev/docs/api/usage/access-scopes#authenticated-access-scopes). Learn how to [configure your access scopes using Shopify CLI](https://shopify.dev/docs/apps/build/cli-for-apps/app-configuration).
- You've created [products](https://shopify.dev/docs/api/admin-graphql/latest/mutations/productcreate) and [product variants](https://shopify.dev/docs/api/admin-graphql/latest/mutations/productVariantsBulkCreate) in your development store.

* Use the GraphQL Admin API version `2026-10` or later.
* Familiarize yourself with [subscription contracts](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts).
* Identify the customer, product variants, delivery method, and customer payment method for the contract.
* Use an existing customer payment method that's vaulted for subscriptions or a card on file. Customers can also add a payment method in [customer accounts](https://help.shopify.com/manual/customers/customer-accounts/new-customer-accounts). Subscribe to the [`customer_payment_methods/create`](https://shopify.dev/docs/api/webhooks) webhook topic to receive new payment method events.

**Note:**

You can create and commit a contract without a payment method by passing `paymentMethod: { none: true }`. To create an order for that contract, pass `paymentProcessingPolicy: SKIP_PAYMENT_AND_CREATE_UNPAID_ORDER` to the billing-attempt mutation. Otherwise, add a valid payment method before billing.

***

## How contract calculation works

Contract creation uses an asynchronous calculate and commit flow:

1. Submit the complete desired contract state.
2. Poll the calculation or wait for a webhook. Shopify emits `subscription_contract_calculations/succeed` when a calculation succeeds and `subscription_contract_calculations/fail` when it fails or is voided.
3. Review the calculated contract, projected totals, warnings, or errors.
4. Commit a successful calculation.

The calculated result is an immutable snapshot. Committing creates an active contract. The create input doesn't accept a status. After committing, use [`subscriptionContractPause`](https://shopify.dev/docs/api/admin-graphql/2026-10/mutations/subscriptionContractPause), [`subscriptionContractCancel`](https://shopify.dev/docs/api/admin-graphql/2026-10/mutations/subscriptionContractCancel), [`subscriptionContractExpire`](https://shopify.dev/docs/api/admin-graphql/2026-10/mutations/subscriptionContractExpire), or [`subscriptionContractFail`](https://shopify.dev/docs/api/admin-graphql/2026-10/mutations/subscriptionContractFail) to change the contract status.

***

## Step 1: Calculate the contract

Call `subscriptionContractCreateCalculate` with the complete desired state for the contract. The input includes at least one line, the customer and currency, billing and delivery policies, delivery and payment methods, and arrays for discounts and custom attributes. Set the required `withMerchandiseCustomizations` field to `true` to run merchandise transformations — both fixed bundle expansion from a stored definition and Shopify Functions that customize merchandise, such as cart transforms — or `false` to bypass them. For how each value affects bundles, refer to [Edit subscription contracts with bundles](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/edit-contracts-with-bundles).

Depending on your selling strategy, you might create a "Subscribe and save" or a prepaid subscription.

### Subscribe and save subscriptions

For a subscription that's billed each delivery period, set the billing cadence and omit `multiFulfillment` from the delivery policy. The following example bills and delivers monthly:

## POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json

## GraphQL mutation

```graphql
mutation CreateSubscriptionContract {
  subscriptionContractCreateCalculate(
    contractCreateInput: {
      withMerchandiseCustomizations: true
      customerId: "gid://shopify/Customer/123"
      currencyCode: USD
      lines: [
        {
          productVariantLine: {
            productVariantId: "gid://shopify/ProductVariant/111"
            quantity: 1
            customAttributes: []
            discounts: []
          }
        }
      ]
      billingPolicy: {
        anchors: []
        cadence: { unit: MONTH, count: 1 }
      }
      deliveryPolicy: { anchors: [] }
      deliveryMethod: {
        shipping: {
          address: {
            firstName: "Quinn"
            lastName: "Ishida"
            address1: "123 Main St"
            city: "Toronto"
            provinceCode: "ON"
            countryCode: CA
            zip: "M5V 1A1"
          }
          deliveryPrice: {
            amount: "14.99"
            currencyCode: USD
          }
        }
      }
      paymentMethod: {
        customerPaymentMethod: {
          id: "gid://shopify/CustomerPaymentMethod/456"
        }
      }
      discountCodes: []
      manualDiscounts: []
      customAttributes: []
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
      code
    }
  }
}
```

## JSON response

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

### Prepaid subscriptions

For a prepaid subscription, bill less frequently than you deliver. Use `multiFulfillment` to define the delivery cadence and the number of fulfillments in each billing cycle. The billing cadence must be a whole-number multiple of the delivery cadence. The following example bills every three months and delivers monthly:

## POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json

## GraphQL mutation

```graphql
mutation CreatePrepaidSubscriptionContract {
  subscriptionContractCreateCalculate(
    contractCreateInput: {
      withMerchandiseCustomizations: true
      customerId: "gid://shopify/Customer/123"
      currencyCode: USD
      lines: [
        {
          productVariantLine: {
            productVariantId: "gid://shopify/ProductVariant/111"
            quantity: 1
            customAttributes: []
            discounts: []
          }
        }
      ]
      billingPolicy: {
        anchors: []
        cadence: { unit: MONTH, count: 3 }
      }
      deliveryPolicy: {
        anchors: []
        multiFulfillment: {
          cadence: { unit: MONTH, count: 1 }
          numberOfFulfillments: 3
        }
      }
      deliveryMethod: {
        shipping: {
          address: {
            firstName: "Quinn"
            lastName: "Ishida"
            address1: "123 Main St"
            city: "Toronto"
            provinceCode: "ON"
            countryCode: CA
            zip: "M5V 1A1"
          }
          deliveryPrice: {
            amount: "14.99"
            currencyCode: USD
          }
        }
      }
      paymentMethod: {
        customerPaymentMethod: {
          id: "gid://shopify/CustomerPaymentMethod/456"
        }
      }
      discountCodes: []
      manualDiscounts: []
      customAttributes: []
    }
  ) {
    subscriptionContractCalculation {
      ... on SubscriptionContractCalculationPending {
        id
      }
    }
    userErrors {
      field
      message
      code
    }
  }
}
```

## JSON response

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

If the mutation returns a user error, then correct the input before polling. Shopify doesn't create an asynchronous calculation when input validation fails.

***

## Step 2: 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`](https://shopify.dev/docs/api/admin-graphql/2026-10/queries/subscriptionContractCalculation):

## POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json

## GraphQL query

```graphql
query PollSubscriptionContractCalculation($id: ID!) {
  subscriptionContractCalculation(id: $id) {
    __typename
    ... on SubscriptionContractCalculationPending {
      id
    }
    ... on SubscriptionContractCalculationSuccess {
      id
      calculatedContract {
        lines(first: 10) {
          nodes {
            id
            quantity
            title
            variantId
          }
        }
      }
      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
        message
      }
    }
  }
}
```

## Variables

```json
{
  "id": "gid://shopify/SubscriptionContractCalculation/789"
}
```

## Pending response

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

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.

### Review 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.

**Review warnings:**

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.

### Use 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`](https://shopify.dev/docs/api/admin-graphql/2026-10/mutations/webhookSubscriptionCreate):

## POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json

## GraphQL mutation

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

## Webhook payload

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

Use `admin_graphql_api_id` to query the completed calculation. Webhook delivery doesn't commit the result automatically.

***

## Step 3: Commit the calculation

After the calculation succeeds and you've reviewed the result, call [`subscriptionContractCalculationCommit`](https://shopify.dev/docs/api/admin-graphql/2026-10/mutations/subscriptionContractCalculationCommit). The commit makes the calculated contract active for billing:

## POST https://{shop}.myshopify.com/admin/api/2026-10/graphql.json

## GraphQL mutation

```graphql
mutation CommitSubscriptionContractCalculation {
  subscriptionContractCalculationCommit(
    id: "gid://shopify/SubscriptionContractCalculation/789"
  ) {
    contract {
      ... on SubscriptionContract {
        id
        status
      }
    }
    userErrors {
      field
      message
      code
    }
  }
}
```

## JSON response

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

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.

***

## View subscription contract details

The **View subscription** button on the customer subscriptions card and the order subscriptions card allows merchants to navigate to the app and view the subscription contract details.

### Customers page in the Shopify admin

![Customers page screenshot](https://shopify.dev/assets/assets/images/api/subscriptions/active-product-subscriptions-DXdvD6gN.png)

### Order page in the Shopify admin

![Order page screenshot](https://shopify.dev/assets/assets/images/api/subscriptions/order-page-shopify-admin-C4tPNjM-.png)

### Redirecting to the subscription contract within the app

To redirect merchants to the relevant subscription contract, the app needs to implement a specific endpoint. After it's implemented, the endpoint redirects to the subscription contract page within the app for the subscription defined by `subscription_contract_id`.

You can customize the **View subscription** link by managing the **Subscription link** app extension from your app through the Shopify CLI.

To learn how to create and manage a subscription link extension from the Shopify CLI, refer to [Start building subscription link extensions](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/subscription-link-extensions/start-building).

If you don't customize the **View subscription** link, then the link is hardcoded. The hardcoded link has the following format:

`{app_application_url}/subscriptions?customer_id={customer_id}&hmac={hmac}&id={subscription_contract_id}&shop={myshopify_domain}`

***

## Step 4: Create a billing attempt

To bill a subscription contract and create an order, apps need to create a [billing attempt](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionBillingAttemptCreate). A subscription is renewed when an app makes a billing attempt.

A billing attempt represents an attempt at executing a billing cycle and charging the customer payment method for a subscription contract. A billing attempt executes a contract based on the [billing cycle](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/billing-cycles) at the origin time if provided. Otherwise, the billing attempt is created for the current billing cycle by default. You can also create a billing attempt on a specific billing cycle.

### Statuses

A billing attempt starts in a pending status. After it has been processed, it either transitions to successful or failed, both of which are terminal states:

* If the billing attempt is successful, then an order is created.

* If the billing attempt fails, then it means that the transaction has failed.

  If an action is pending on the part of the customer in regards to [3D Secure](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/build-a-subscription-contract#about-3d-secure), then a 3D Secure challenge can occur before the billing attempt transitions to a terminal state.

**Note:**

A billing attempt can fail if Shopify's [fraud analysis service](https://help.shopify.com/manual/orders/fraud-analysis) has flagged a subscription contract's origin order. Before you create a billing attempt, check the [order risk assessment](https://shopify.dev/docs/api/admin-graphql/latest/objects/Order#field-Order.fields.risk) of the contract's [origin order](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionContract#field-SubscriptionContract.fields.originOrder).

### Example call

To create a billing attempt, specify the following inputs in the [`subscriptionBillingAttemptCreate`](https://shopify.dev/docs/api/admin-graphql/latest/mutations/subscriptionbillingattemptcreate) mutation:

* `subscriptionContractId`: The ID of the subscription contract.

* `subscriptionBillingAttemptInput`

  * `idempotencyKey`: A unique key generated by the client to avoid duplicate payments.
  * `originTime`: An optional field that changes the way fulfillment intervals are calculated. If nothing is provided, fulfillment is calculated using the date that the billing attempt was successful. Otherwise, fulfillment is calculated using the provided `originTime` value. The UTC offset of `originTime` should match the shop's [`timezoneOffset`](https://shopify.dev/docs/api/admin-graphql/latest/objects/shop#fields-Shop-OBJECT).

  Billing attempts are processed asynchronously, so the resulting order isn't available right away. Fetch the billing attempt and check its [`state`](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionBillingAttempt#field-SubscriptionBillingAttempt.fields.state). `SubscriptionBillingAttemptPendingState` means the attempt is still processing, `SubscriptionBillingAttemptSuccessState` contains the order, `SubscriptionBillingAttemptFailedState` contains the error, and `SubscriptionBillingAttemptActionRequiredState` means the customer needs to complete a 3D Secure challenge. The challenge URL is in the `nextActionUrl` field of its `action`.

**Note:**

If you have adopted [Subscriptions Billing Cycle APIs](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/billing-cycles), you can [create orders by charging a billing cycle directly](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/billing-cycles/manage-billing-cycle-contracts#step-6-create-an-order). This approach enables more precise management of billing cycles by directly linking order creation to the specific cycle being billed.

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

## GraphQL query

```graphql
mutation {
  subscriptionBillingAttemptCreate(
    subscriptionContractId: "gid://shopify/SubscriptionContract/33"
    subscriptionBillingAttemptInput: {
      idempotencyKey: "abc123"
      originTime: "2022-10-30T04:05:02+14:00"
    }
  )
  {
    subscriptionBillingAttempt {
      id
      originTime
      state {
        __typename
        ... on SubscriptionBillingAttemptSuccessState {
          order {
            id
          }
        }
        ... on SubscriptionBillingAttemptFailedState {
          error {
            __typename
            ... on SubscriptionBillingAttemptPaymentError {
              code
            }
          }
        }
        ... on SubscriptionBillingAttemptActionRequiredState {
          action {
            ... on SubscriptionBillingAttemptPaymentChallenge {
              nextActionUrl
            }
          }
        }
      }
    }
  }
}
```

## JSON response

```json
{
  "data": {
    "subscriptionBillingAttemptCreate": {
      "subscriptionBillingAttempt": {
        "id": "gid://shopify/SubscriptionBillingAttempt/82",
        "originTime": "2022-10-30T04:05:02+14:00",
        "state": {
          "__typename": "SubscriptionBillingAttemptPendingState"
        }
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 11,
      "actualQueryCost": 11
    }
  }
}
```

Because the order isn't ready immediately, you can query the [subscriptionBillingAttempt](https://shopify.dev/docs/api/admin-graphql/latest/queries/subscriptionbillingattempt) to get the resulting order information.

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

## GraphQL query

```graphql
query {
  subscriptionBillingAttempt(
    id: "gid://shopify/SubscriptionBillingAttempt/524310"
  ) {
    id
    state {
      __typename
      ... on SubscriptionBillingAttemptSuccessState {
        order {
          id
        }
      }
      ... on SubscriptionBillingAttemptFailedState {
        error {
          __typename
          ... on SubscriptionBillingAttemptPaymentError {
            code
          }
        }
      }
      ... on SubscriptionBillingAttemptActionRequiredState {
        action {
          ... on SubscriptionBillingAttemptPaymentChallenge {
            nextActionUrl
          }
        }
      }
    }
  }
}
```

## JSON response

```json
{
    "data": {
        "subscriptionBillingAttempt": {
            "id": "gid://shopify/SubscriptionBillingAttempt/524310",
            "state": {
                "__typename": "SubscriptionBillingAttemptSuccessState",
                "order": {
                    "id": "gid://shopify/Order/2014567596054"
                }
            }
        }
    },
    "extensions": {
        "cost": {
            "requestedQueryCost": 2,
            "actualQueryCost": 2,
            "throttleStatus": {
                "maximumAvailable": 1000.0,
                "currentlyAvailable": 998,
                "restoreRate": 50.0
            }
        }
    }
}
```

### About 3D Secure

Shopify handles 3D Secure authentication by emailing the customer when the financial institution requires a challenge. This flow is demonstrated in the diagram below:

![Subscription contracts objects diagram](https://shopify.dev/assets/assets/images/api/3ds-flow-CNO7Vmvl.png)

You can poll the [`subscriptionBillingAttempt`](https://shopify.dev/docs/api/admin-graphql/latest/queries/subscriptionbillingattempt) query until `state` is `SubscriptionBillingAttemptActionRequiredState`. The challenge URL is in `action.nextActionUrl`. The challenge `status` is `OFF_SESSION_REJECTED` until the customer opens the challenge, and `ON_SESSION_CHALLENGED` after that.

**Note:**

The [subscription\_billing\_attempts/success](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts#subscription-related-webhooks) and [subscription\_billing\_attempts/failure](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts#subscription-related-webhooks) webhooks aren't triggered until the challenge is completed. If the customer doesn't complete the challenge, then your app won't be notified.

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

## GraphQL query

```graphql
query {
  subscriptionBillingAttempt(
    id: "gid://shopify/SubscriptionBillingAttempt/123"
  ) {
    id
    state {
      __typename
      ... on SubscriptionBillingAttemptActionRequiredState {
        action {
          ... on SubscriptionBillingAttemptPaymentChallenge {
            nextActionUrl
            status
          }
        }
      }
    }
  }
}
```

## JSON response

```json
{
  "data": {
    "subscriptionBillingAttempt": {
      "id": "gid:\/\/shopify\/SubscriptionBillingAttempt\/123",
      "state": {
        "__typename": "SubscriptionBillingAttemptActionRequiredState",
        "action": {
          "nextActionUrl": "https:\/\/example.com\/subscriptions\/billing\/959c1a7cec286e06bfe7f16ff351c101\/challenge",
          "status": "OFF_SESSION_REJECTED"
        }
      }
    }
  },
  "extensions": {
    "cost": {
      "requestedQueryCost": 2,
      "actualQueryCost": 2
    }
  }
}
```

### About re-billing failed payment attempts

It's up to apps to attempt re-billing for failed payment attempts. We expose many signals to help you make the right decision about when to re-bill failed payment attempts and how often.

* Only rebill payment attempts that failed with error codes that make sense to retry, such as [`INSUFFICIENT_FUNDS`](https://shopify.dev/docs/api/admin-graphql/latest/enums/SubscriptionBillingAttemptPaymentErrorCode#enums-INSUFFICIENT_FUNDS).
* Avoid re-billing failed payments with the same customer payment method more than 30 times in 35 days. These requests will be failed and the payment method will be revoked.

You can keep track of how Shopify correlates failed payments by using the [`paymentSessionId`](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionBillingAttempt#field-SubscriptionBillingAttempt.fields.paymentSessionId) and [`paymentGroupId`](https://shopify.dev/docs/api/admin-graphql/latest/objects/SubscriptionBillingAttempt#field-SubscriptionBillingAttempt.fields.paymentGroupId) fields. Retrying billing for the same contract identity results in billing attempts with the same `paymentGroupId`. You can use this to track all failed, or the final successful, billing attempt linked to a final order. All billing attempts that kept their payment details identical share the same `paymentSessionId`. When surfacing merchants' payment success metrics, make sure that only the last billing attempt in a group that shares the same `paymentSessionId` and `paymentGroupId` is counted, because all the billing attempts in that group were retries of one another.

### Inventory tracking

Similar to creating a new order through checkout, the availability of inventory is checked during the billing attempt process. Merchants can adjust inventory tracking so that they can [continue to sell product variants when out of stock](https://help.shopify.com/manual/products/inventory/getting-started-with-inventory/selling-when-out-of-stock). They can also adjust inventory tracking to prevent selling product variants when out of stock.

If one or more of a subscription's product variants are out of stock (and aren't configured to continue selling), then the billing attempt moves to a failed state with either an [insufficient inventory](https://shopify.dev/docs/api/admin-graphql/latest/enums/SubscriptionBillingAttemptInventoryErrorCode#enums-INSUFFICIENT_INVENTORY) or an [inventory location](https://shopify.dev/docs/api/admin-graphql/latest/enums/SubscriptionBillingAttemptInventoryErrorCode#enums-INVENTORY_ALLOCATIONS_NOT_FOUND) error.

***

## Next steps

* Learn how to [update a subscription contract](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/update-a-subscription-contract).
* Learn how to [manage billing cycles](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/billing-cycles).
* Use the [legacy `SubscriptionDraft` creation guide](https://shopify.dev/docs/apps/build/purchase-options/subscriptions/contracts/create-a-subscription-contract-with-subscription-draft) while maintaining an older integration.

***
