Apps
Unified billing
Example queries and mutations

GraphQL Account API: Unified Billing

Below are examples of queries and mutations. They demonstrate how to use the Unified Billing features available through the BigCommerce GraphQL Account API.

Use the API by submitting POST requests to https://api.bigcommerce.com/accounts/{{your_partner_account_uuid}}/graphql.

We have prepared a Postman collection you can import into your Postman workspace to interact with the Unified Billing API. It includes example requests for common operations such as creating checkouts, querying checkouts, querying subscriptions, and canceling subscriptions: Unified Billing Postman Collection (opens in a new tab)

Possible Implementation Strategies

Using the information gathered from the prerequisites section (opens in a new tab), you can begin integrating with the Unified Billing API. The following examples are meant to be a helpful guide for implementation. When considering how to utilize the API, keep in mind the specific needs of your app.

Creating Subscriptions

When a merchant wants to purchase a subscription after installing your app, use the Create Checkout Mutation to generate a checkout URL for them to complete the purchase.

Implementation Options:

Option A: Polling Checkout Status

  • Cache the checkout URL for each merchant store
  • Periodically poll the Checkout Query (opens in a new tab) until the status changes to COMPLETE
  • Once complete, retrieve the subscriptionId from the checkout response

Option B: Polling Subscription Status (Recommended)

  • Instead of monitoring individual checkouts, gate access to premium features until the Subscriptions Query (opens in a new tab) returns an active subscription
  • This approach is more efficient and provides better reliability for verifying completed purchases

Managing Access Control

Use the Subscriptions Query (opens in a new tab) to verify which merchants have active subscriptions. Filter by scopeId (store hash) to find the subscription for a specific merchant.

Caching Strategy:

  • Cache subscription results to reduce API calls
  • Invalidate the cache when processing cancellations or when subscriptions expire
  • Consider periodic cache refresh to handle external subscription changes

Handling Subscription Cancellations

When merchants request to cancel their subscription, use the CancelSubscription Mutation (opens in a new tab). The response includes a cancelledAt date indicating when access ends:

  • Regular subscriptions: Access continues until the end of the current billing cycle
  • Trial subscriptions: Cancellation takes effect immediately

Implementation Note: Invalidate any cached subscription data immediately after processing a cancellation to ensure accurate access control.

Updating Subscription Plans

To handle plan changes (upgrades, downgrades, or billing frequency modifications), create a new checkout using the UpdateSubscription Mutation (opens in a new tab). This allows you to modify subscription details while preserving the merchant's billing relationship.

Use Cases:

  • Plan tier changes (Basic → Premium)
  • Billing frequency updates (Monthly → Annual)
  • Price adjustments for existing subscribers

Example queries and mutations

Create a checkout

The first step in charging a merchant for a product is to create a checkout. After creating a checkout through the API, the checkout will be in a pending status, and a checkoutUrl will be included in the response. The checkoutUrl routes to the BigCommerce checkout UI where a merchant must complete the checkout in their store's control panel. After checkout completion, a subscription is created and billed to the merchant, and the checkout status moves to complete. When the merchant exits the BigCommerce checkout UI, they will be redirected to the redirectUrl provided in the request. Use this field to route the merchant back to your app.

When creating a checkout with a product that has a trial period, set the trialDays field to the number of days the trial should last.

The merchant will not be charged during this period. A subscription only generates an invoice once the trial period ends. No charges are made during the trial.

Checkout links are valid for 24 hours and expire automatically to prevent misuse.

To create a checkout, run the createCheckout mutation:

Example Query: Create a checkout
  mutation ($checkout: CreateCheckoutInput!) {
    checkout {
      createCheckout(input: $checkout) {
        checkout {
            id
            accountId
            status
            checkoutUrl
            items(first: 1) {
              edges {
                node {
                  subscriptionId
                  status
                  product {
                    id
                    type
                    productLevel
                  }
                  scope {
                    id
                    type
                  }
                  pricingPlan {
                    interval
                    price {
                      value
                      currencyCode
                    }
                    trialDays
                  }
                  redirectUrl
                  description
                }
              }
            }
          }
        }
      }
    }

Some common errors returned when creating a checkout:

  • Product is not supported for your account. - The application being purchased is not owned by the partner account (opens in a new tab) (in the request URL) making the request.
  • Scope does not belong to account. - The store hash provided does not belong to the merchant account provided.
  • You do not have permission to do this operation. - This failure has multiple possible causes:
    • The account-level API token being used does not have the required auth scope (opens in a new tab) for the given operation.
    • The account-level API token does not match the account UUID being used in the request URL.

Fetch a checkout

Once the checkout is created, you can periodically poll the status of the checkout by calling this endpoint. To fetch an existing checkout, copy and run the following query:

Replace the checkoutId with the following variable:

{
  "checkoutId": "bc/account/checkout/ab0a8354-3caf-423b-a3be-42a59c97fcf5"
}
Example query: Fetch a checkout
query Account($checkoutId: ID!) {
  account {
    checkout(id: $checkoutId) {
      id
      accountId
      checkoutUrl
      status
      items {
        edges {
          node {
            description
            status
            product {
              id
              productLevel
              type
            }
            scope {
              id
              type
            }
            pricingPlan {
              price {
                value
                currencyCode
              }
              interval
              trialDays
            }
            subscriptionId
            redirectUrl
          }
        }
      }
    }
  }
}

Update a subscription

The createCheckout mutation can also be used to update an existing subscription's pricing plan information and product level. A subscriptionId must be passed in the request for this to be processed as an update.

Example Query: Update a subscription
  mutation ($checkout: CreateCheckoutInput!) {
    checkout {
      createCheckout(input: $checkout) {
        checkout {
          accountId
          status
          checkoutUrl
          items(first: 1) {
            edges {
              node {
                subscriptionId
                status
                product {
                  id
                  type
                  productLevel
                }
                scope {
                  id
                  type
                }
                pricingPlan {
                  interval
                  price {
                    value
                    currencyCode
                  }
                  trialDays
                }
                redirectUrl
                description
              }
            }
          }
        }
      }
    }
  }

Cancel a subscription

This mutation cancels the subscription at the end of the merchant's current billing cycle. The cancelledAt value will be the last day of the merchant's billing cycle (i.e., the day through which they have already paid). For trials and subscriptions that have not yet been invoiced, the cancellation takes effect immediately and the cancelledAt value will reflect this immediate time.

Example Query: Cancel a subscription
  mutation ($subscription: CancelSubscriptionInput!) {
    subscription {
      cancelSubscription(input: $subscription) {
        subscriptionId
        cancelledAt
      }
    }
  }

How Cancellations Work During a Free Trial

  • No Billing During Trial

    • A subscription only generates an invoice once the trial period ends. No charges are made during the trial.
  • Immediate Cancellation During Trial

    • If a subscription is canceled while it's still in the trial period, the cancellation takes effect immediately. The trial ends, and no invoice is ever generated.
  • Post Trial Cancellation Behavior

    • Once the trial ends, the subscription begins billing.
    • Any cancellation initiated before the next billing cycle date will be prorated for the period from trial end until cancellation date.
    • Charges for prorated fees will appear on the merchant's next invoice.

Query subscriptions

Subscriptions can be queried using the subscriptions query endpoint.

Fields that can be retrieved are:

  • id - subscription id
  • accountId - account id belonging to the merchant
  • activationDate - date billing began
  • billingInterval - billing frequency
  • createdAt - date and time the subscription was created
  • currentPeriodEnd - date of the end of the current billing period
  • updatedAt - date and time the subscription was last updated
  • pricePerInterval - amount being billed with the following fields:
    • value - the scalar amount
    • currencyCode - the currency of the amount
  • product - product object with the following fields
    • productLevel - the level of the product if it was provided
    • id - product id
    • type - product type
  • status - subscription status
  • scope - scope object with the following fields
    • type - scope type
    • id - scope id

In this example, no filters are passed, so the response will include all subscriptions of the partner. The default number of subscriptions returned per page is 10.

Example Query: Query subscriptions
query {
  account {
    subscriptions {
      pageInfo {
        hasNextPage
        hasPreviousPage
        startCursor
        endCursor
      }
      edges {
        cursor
        node {
          id
          accountId
          activationDate
          pricePerInterval {
            value
            currencyCode
          }
          billingInterval
          status
          scope {
            type
            id
          }
          product {
            productLevel
            id
            type
          }
          createdAt
          currentPeriodEnd
          updatedAt
        }
      }
    }
  }
}

Pagination info is returned with cursors on every subscription node. The pageInfo provides information on the next page along with the cursors to use in traversing the graph.

"pageInfo": {
  "hasNextPage": true,
  "hasPreviousPage": false,
  "startCursor": "WzE3MjQ0MzgzODk0MzY0NzYsODhd",
  "endCursor": "WzE3MTk3NDYxNzUyNjg2NDUsNzdd"
}

Use the endCursor to begin the next query. first can be used to limit how many subscriptions are returned. The max limit is 50 subscriptions at a time.

Example Query: Query subscriptions
query {
  account {
    subscriptions(first: 10, after: "WzE3MTk3NDYxNzUyNjg2NDUsNzdd") {
      pageInfo {
        hasNextPage
        hasPreviousPage
        startCursor
        endCursor
      }
      edges {
        cursor
        node {
          id
          accountId
          activationDate
          pricePerInterval {
            value
            currencyCode
          }
          billingInterval
          status
          scope {
            type
            id
          }
          product {
            productLevel
            id
            type
          }
          createdAt
          currentPeriodEnd
          updatedAt
        }
      }
    }
  }
}

Filters can also be used to query subscriptions.

The supported filters are

  • productId
  • productType
  • scopeId
  • scopeType
  • updatedAfter
  • status
  • ids
Example Query: Query subscriptions with filters
  query ($filters: SubscriptionFiltersInput) {
    account {
      subscriptions(filters: $filters) {
        pageInfo {
          hasNextPage
          hasPreviousPage
          startCursor
          endCursor
        }
        edges {
          cursor
          node {
            id
            accountId
            activationDate
            pricePerInterval {
              value
              currencyCode
            }
            billingInterval
            status
            scope {
              type
              id
            }
            product {
              productLevel
              id
              type
            }
            createdAt
            currentPeriodEnd
            updatedAt
          }
        }
      }
    }
  }
Did you find what you were looking for?