← All articles

October 12, 2026 · Muhammad Rehan · More by Muhammad Rehan

Shopify's New Subscription API: Calculate, Then Commit

The SubscriptionContractCalculation API replaces draft mutations with calculate-poll-commit — and only one half of that flow is safe to retry.

Shopify's New Subscription API: Calculate, Then Commit — ASSOSIATIX Journal

From a dozen mutations to calculate-poll-commit

Shopify's GraphQL Admin API version 2026-10 introduces the SubscriptionContractCalculation object as the successor to SubscriptionDraft for creating, updating, and editing subscription contracts. It shipped as a release candidate and becomes stable in the 2026-10 release. The old SubscriptionDraft flow needed a dozen-plus stateful mutations to make a single edit — create a draft, add a line, update a line, remove a line, add a discount, apply a discount code, update delivery, then commit. The new API consolidates that into one calculate mutation (subscriptionContractCreateCalculate, subscriptionContractUpdateCalculate, or subscriptionBillingCycleContractEditCalculate, depending on what you're doing) plus a shared commit, running through the same checkout engine that powers Checkout, Draft Orders, and subscription billing attempts.

The retry trap: calculate vs. commit

The two steps have different retry semantics, and conflating them is the easiest way to get this wrong. A calculate mutation is not safe to retry blindly — retrying one creates a brand-new calculation with a new ID, so an integration has to track which ID's result it actually intends to commit before retrying anything upstream of it. Commit, by contrast, is safe to retry: calling subscriptionContractCalculationCommit again for a calculation that's already been committed returns the already-committed result instead of erroring or creating a duplicate. Build retry logic around that asymmetry, not around treating the whole flow as one idempotent unit.

Lists are replaced, not patched

On an update, the client sends the desired state, not a diff. Top-level fields you omit are preserved. But any list field you do include — lines, manualDiscounts — replaces the entire stored list rather than patching individual entries. To keep one line unchanged while editing another, you have to resend that line's full state, not just the line you're actually changing. This is the detail most likely to produce a silent data-loss bug during migration: a partial line payload that "succeeds" by clearing fields you didn't mean to touch.

Polling cadence and what to branch on

Calculation is asynchronous. Shopify's documented cadence is to wait two seconds before the first poll, then poll every second, stopping after 30 seconds — polling more frequently doesn't speed it up. The result lands in one of several states: Pending (keep polling), Success (ready to review and commit), or Failure, which covers both an actual processing failure and a case Shopify voided outright, for example because of an infrastructure issue, with no errors to read — just retry. Committing introduces its own error codes to handle: NOT_READY_TO_COMMIT, CALCULATION_NOT_FOUND, STALE_CONTRACT (the contract changed after calculation started — re-query and recalculate), and INVALID. Contract status changes — pause, cancel, expire, fail — never go through calculation input at all; they run through separate dedicated mutations.

Sources

Operations & Fulfillment

ASSOSIATIX works on this every day. See our Shopify Operations Automation service

$./start-project.sh

READY TO BUILD
WHAT'S NEXT?

Tell us where you are and where you want to go. We'll help you choose the right path—storefront, system, product, or a focused growth sprint.