Decoding Shopify Subscriptions: Your Guide to Recurring Billing, Webhooks & Testing

Hey everyone! It’s your friendly neighborhood Shopify expert here, and I've been diving deep into some fantastic questions from the community. Recently, Navin3 kicked off a really insightful thread about building a custom subscription app using Shopify’s Selling Plans and the Subscriptions API. These are crucial tools for anyone looking to offer recurring products or memberships, and Navin3’s questions hit on some of the most common complexities. Let's break down what you need to know, drawing from what we’ve seen work best in the real world.

1. Who Handles the Recurring Billing? Shopify or Your App?

This is probably the most common question when starting with subscriptions, and it’s a good one! Navin3 asked if recurring charges are automatically handled by Shopify or if the app needs to manage cron jobs and external payment captures.

Here's the good news: Shopify takes care of the heavy lifting for recurring billing. When you create a subscription contract using Selling Plans, Shopify's robust infrastructure manages the billing cycles, generates new orders at each renewal, and attempts to process payments through Shopify Payments or the customer's chosen gateway. Your app's primary role is to manage the logic around the subscription – things like defining the selling plans, creating and updating subscription contracts, and responding to lifecycle events. You don't need to build your own cron jobs for payment capture or worry about the nitty-gritty of payment retries; Shopify handles that for you.

This means less headache for you, allowing you to focus on the unique features of your subscription offering!

2. Essential Webhooks for Tracking Subscription Billing Events

Knowing which webhooks to listen to is absolutely critical for keeping your app in sync with Shopify’s subscription engine. Navin3 was looking for events related to successful billing, failed payments, retries, and contract updates. Let's clarify which ones are your best friends here:

Webhooks for Subscription Contract Lifecycle:

  • subscription_contracts/create: Fired when a new subscription contract is successfully created.
  • subscription_contracts/update: Triggered when any aspect of a subscription contract changes (e.g., next billing date, price adjustments, status changes).
  • subscription_contracts/approve: Indicates the contract has been approved.
  • subscription_contracts/activate: The contract is now active and billing will commence.
  • subscription_contracts/cancel: The contract has been cancelled.
  • subscription_contracts/fail: This is a big one for payment issues! It indicates that a recurring payment attempt failed, or the contract failed for another reason. Your app should definitely listen to this to handle failed payments gracefully.
  • subscription_contracts/pause: The contract has been paused.
  • subscription_contracts/unpause: A paused contract has been reactivated.

These subscription_contracts/* webhooks are your primary source of truth for the state and health of your subscriptions.

Webhooks for Order Generation:

  • orders/create: When a recurring charge is successful, Shopify automatically generates a new order. This webhook will fire, signaling a successful billing event. You can then inspect the order details to confirm payment status.

While payments/* webhooks exist, they are generally more focused on one-time payment transactions or initial authorizations. For recurring billing via selling plans, you'll get the most reliable and actionable information from the subscription_contracts/* and orders/create webhooks. Shopify's internal retry logic for failed payments doesn't typically expose granular `payments/*` events for each retry attempt directly to apps, but the outcome (success/failure, leading to a contract update or failure) is what you'll see.

3. Where to View Transactions for Test Payments

When you're testing, seeing the results of your recurring charges is key. Navin3 asked if these are visible in the Shopify Admin.

Absolutely! Each time a subscription renews and a recurring charge is processed, Shopify creates a new order in your Shopify Admin. You'll find these orders just like any other order under Shopify Admin → Orders. Within each order, you can click into it to see the payment status (paid, pending, failed), the transaction details, and the customer information. This makes it really straightforward to track successful renewals and see the payment attempts.

For a more holistic view of the subscription itself, you can also navigate to the customer's profile in the Admin. There, you'll often find a section dedicated to their subscriptions, showing the contract status, upcoming billing dates, and a history of charges related to that specific subscription.

4. Best Way to Test Subscription Billing

Testing is where the rubber meets the road! You want to ensure your app handles the full lifecycle: create, renew, fail, retry. Navin3 asked about using Bogus Gateway versus Shopify Payments (test mode).

Here’s the breakdown and our recommended approach:

Bogus Gateway vs. Shopify Payments (Test Mode)

  • Bogus Gateway: This is excellent for initial setup and ensuring your app correctly creates subscription contracts and that orders are generated. It's fast and simple for basic success scenarios. However, it's less ideal for simulating complex payment failures, retries, or the full nuances of a real payment gateway.

  • Shopify Payments (Test Mode): This is your go-to for comprehensive subscription testing. It truly simulates the entire payment flow, including recurring charges, payment failures, and the internal retry mechanisms that Shopify Payments offers. You can use specific test card numbers provided by Shopify (or your payment gateway) to simulate various scenarios like successful payments, declines, insufficient funds, and more.

Recommended Approach for Full Lifecycle Testing:

  1. Enable Shopify Payments in Test Mode: Go to your Shopify Admin, navigate to Settings > Payments, and activate Shopify Payments in test mode. This gives you access to realistic test card numbers.

  2. Use Test Cards: Shopify provides specific test card numbers that simulate different outcomes (success, failure, specific errors). Use these when placing test subscription orders to trigger various scenarios.

  3. Simulate Renewal Cycles: While you can't fast-forward time in a live test store, you can set up short billing cycles (e.g., daily or weekly) for your test selling plans. This allows you to observe renewals more quickly. Alternatively, for testing webhook handling, you might manually trigger contract updates or status changes via the API in your development environment to simulate events like renewal failures or cancellations without waiting for real time to pass.

  4. Trigger Failures and Retries: Use test cards that simulate declines. Observe how your app responds to subscription_contracts/fail webhooks and subsequent subscription_contracts/update events if Shopify attempts retries.

  5. Test Cancellations and Pauses: Programmatically (via API) or manually (through your app's UI or Shopify Admin if your app exposes it) cancel and pause subscriptions. Verify that your app receives the corresponding subscription_contracts/cancel or subscription_contracts/pause webhooks and updates its internal state correctly.

  6. Monitor Shopify Admin: Keep a close eye on the Orders section and the customer's subscription details in the Shopify Admin to verify that orders are created, payments are processed (or failed), and contract statuses are updated as expected.

By following these steps, you'll ensure your custom subscription app integrates seamlessly with Shopify's infrastructure, avoiding duplicated billing logic and ensuring you catch all critical webhook events. It's all about leveraging Shopify's robust tools to build a reliable and scalable subscription service for your store!

Share:

Use cases

Explore use cases

Agencies, store owners, enterprise — find the migration path that fits.

Explore use cases