Build a subscription contract
A subscription contract 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 create subscription contracts by illustrating two use cases: "Subscribe and save" subscriptions and "Prepaid" subscriptions.
Requirements
Anchor link to section titled "Requirements"- Your app can make authenticated requests to the GraphQL Admin API.
- Your app has the
read_own_subscription_contracts
andwrite_own_subscription_contracts
access scopes. Learn how to configure your access scopes using Shopify CLI. You've created products and product variants in your development store.
You've familiarized yourself with the concept of subscription contracts.
Step 1: Create a new subscription draft
Anchor link to section titled "Step 1: Create a new subscription draft"A subscription draft captures the intent to create a subscription contract. Apps can incrementally build subscription drafts and then commit the draft to create or update a subscription contract.
A subscription draft provides a way to get the projected state of the contract with all of the updates applied. Subscription contracts should always be up-to-date and accurate so that you can report on subscriptions and email subscribers, and build flows based on subscription changes.
Depending on your selling strategy, you might create a "Subscribe and save" or a "Prepaid" subscription.
Subscribe and save subscriptions
Anchor link to section titled "Subscribe and save subscriptions"The following example shows the creation of a new subscription draft for a monthly "Subscribe and save" subscription, with a minimum commitment of three orders.
For error codes related to subscription contracts, refer to SubscriptionDraftErrorCode
.
Prepaid subscriptions
Anchor link to section titled "Prepaid subscriptions"Prepaid contracts are created by defining a delivery policy that is more frequent than the billing policy. In the following example, the policies combine to define a prepaid subscription with three monthly deliveries.
For error codes related to subscription contracts, refer to SubscriptionDraftErrorCode
.
Step 2: Add a line to the subscription draft
Anchor link to section titled "Step 2: Add a line to the subscription draft"You can call the subscriptionDraftLineAdd
mutation to add a subscription line to the subscription draft. In the following example, a subscription line is added to specify a product variant with its quantity and price:
Step 3: Commit the subscription draft
Anchor link to section titled "Step 3: Commit the subscription draft"When you're satisfied with the state of the subscription draft, you can commit it. When you commit a draft subscription, all of the changes are made active:
Viewing subscription contract details
Anchor link to section titled "Viewing 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
Anchor link to section titled "Customers page in the Shopify admin"Order page in the Shopify admin
Anchor link to section titled "Order page in the Shopify admin"Redirecting to the subscription contract within the app
Anchor link to section titled "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 in your Partner Dashboard:
You can modify the link target URL, save the changes, or remove the app extension if it's already present:
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
Anchor link to section titled "Step 4: Create a billing attempt"To bill a subscription contract and create an order, apps need to create a billing attempt. 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 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.
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, then a 3D Secure challenge can occur before the billing attempt transitions to a terminal state.
Example call
Anchor link to section titled "Example call"To create a billing attempt, specify the following inputs in the 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 providedoriginTime
value. The UTC offset oforiginTime
should match the shop'stimezoneOffset
.
Billing attempts are processed asynchronously, which means the resulting order won't be available right away. You can fetch the billing attempt and inspect the ready
field to find out whether the order has been created (true
) or not (false
).
Because the order isn't ready immediately, you can query the subscriptionBillingAttempt to get the resulting order information.
About 3D Secure
Anchor link to section titled "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:
You can poll the subscriptionBillingAttempt
object until the nextActionUrl
field is available to see the URL.
About re-billing failed payment attempts
Anchor link to section titled "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
. - 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 leveraging the payment_session_id
and payment_group_id
fields. Retrying billing for the same contract identity will result in billing attempts with the same payment_group_id
. 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 will share the same payment_session_id
. When surfacing merchants' payment success metrics, ensure that only the last billing attempt in a group that shares the same payment_session_id
and payment_group_id
is counted, as all the billing attempts in that group were retries of one another.
Inventory tracking
Anchor link to section titled "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. 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 or a inventory location error.
- Learn how to update a subscription contract with new information.