
August 13, 2026
9 min read
Table of Contents
By Kokil Thapa | Last reviewed: August 2026
Building a recurring revenue model requires precise execution of Shopify subscription app development, not just installing a pre-made plugin. Merchants often need custom billing logic, specific delivery schedules, or localized payment gateways that off-the-shelf solutions cannot provide. This guide covers the architectural realities of building subscription apps on the 2026 Shopify platform, from Billing API integration to handling complex contract states.
Before writing a single line of code, understand that subscription apps are fundamentally different from standard Shopify apps because they own critical post-purchase infrastructure. If your app fails, the merchant loses revenue immediately. For teams evaluating whether to build custom or configure existing tools, reading about Shopify vs WooCommerce comparisons provides essential context on platform trade-offs before committing to the Shopify ecosystem. In my experience shipping eCommerce systems, the decision to build a custom subscription layer usually stems from unique business rules around bundling, regional payment methods like eSewa or Khalti, or complex B2B contract terms that generic apps simply do not support.
How does the Shopify Subscription Contracts API work?
The core of modern Shopify subscription app development is the Subscription Contracts API. Unlike legacy implementations that created draft orders manually, the Contracts API treats subscriptions as first-class citizens within Shopify Admin. This means merchants can view, edit, and pause subscriptions directly in their dashboard without leaving Shopify.
Understanding Contract States
A subscription contract moves through a strict state machine. You cannot arbitrarily update fields; transitions must follow valid paths. The primary states include:
- ACTIVE: The subscription is live and will generate orders on the next billing cycle.
- PAUSED: Billing is temporarily halted. No orders are generated until resumed.
- CANCELLED: Terminal state. The contract cannot be reactivated; a new one must be created.
- EXPIRED: Reached its defined end date or maximum number of billing cycles.
- FAILED: Payment could not be processed after all retry attempts.
In practice, most bugs occur when developers attempt invalid transitions, such as trying to update line items on a CANCELLED contract. Always validate state before mutation.
Mandatory Webhooks
You cannot poll for subscription changes. Your app must subscribe to these mandatory topics during installation:
<!-- Required webhook subscriptions in shopify.app.toml -->
[[webhooks.subscriptions]]
topics = [ "SUBSCRIPTION_CONTRACTS_CREATE" ]
uri = "/api/webhooks/contracts/create"
[[webhooks.subscriptions]]
topics = [ "SUBSCRIPTION_CONTRACTS_UPDATE" ]
uri = "/api/webhooks/contracts/update"
[[webhooks.subscriptions]]
topics = [ "SUBSCRIPTION_BILLING_ATTEMPTS_CHALLENGED" ]
uri = "/api/webhooks/billing/challenged" Missing any of these will cause your app to fail verification. The SUBSCRIPTION_BILLING_ATTEMPTS_CHALLENGED webhook is particularly critical for 3D Secure flows in regions like Nepal and India where SCA/RBI regulations require customer authentication.
What are the best practices for implementing Selling Plans?
Selling Plans define the purchasing options presented to customers on the product page. They link products to subscription contracts via the Storefront API. A common mistake in Shopify subscription app development is creating overly rigid selling plans that force merchants into binary choices.
Structuring Flexible Pricing Policies
Your selling plan should support multiple pricing adjustments simultaneously. For example, a "Subscribe & Save" offer might include both a percentage discount and free shipping. Use the GraphQL Admin API to create these structures:
mutation CreateSellingPlanGroup {
sellingPlanGroupCreate(input: {
name: "Weekly Coffee Subscription"
merchantCode: "COFFEE-WEEKLY"
options: ["Delivery Frequency"]
position: 1
sellingPlansToCreate: [{
name: "Deliver every week"
options: ["1 Week"]
billingPolicy: {
recurring: {
interval: WEEK
intervalCount: 1
}
}
deliveryPolicy: {
recurring: {
interval: WEEK
intervalCount: 1
}
}
pricingPolicies: [{
fixed: {
adjustmentType: PERCENTAGE
adjustmentValue: 15
}
}]
}]
}) {
sellingPlanGroup {
id
sellingPlans(first: 5) {
nodes { id name }
}
}
userErrors { field message }
}
} Note that merchantCode must be unique per group. Reusing codes causes silent failures during product association. I have seen this break entire catalog integrations during migrations.
Product Association Strategy
Do not associate selling plans with individual variants unless absolutely necessary. Associate at the product level whenever possible. Variant-level associations create maintenance nightmares when merchants add new sizes or colors. If you must use variant-level granularity, implement an automated sync job that propagates new variants to existing selling plan groups.
How do you handle billing cycles and payment failures?
Billing reliability separates production-grade subscription apps from prototypes. Shopify handles the actual charge, but your app orchestrates the attempt schedule and failure response.
Dunning Management Logic
When a payment fails, Shopify triggers SUBSCRIPTION_BILLING_ATTEMPTS_CHALLENGED. Your app must decide whether to retry, notify, or cancel. Implement exponential backoff with jitter to avoid thundering herd problems if a payment processor experiences partial outage:
- Attempt 1 (Day 0): Immediate retry. Many failures are transient network issues.
- Attempt 2 (Day 3): Send email notification to customer with update-payment link.
- Attempt 3 (Day 7): Final retry. If failed, move contract to FAILED state.
- Grace Period (Day 14): If still unresolved, transition to CANCELLED or PAUSED based on merchant configuration.
Store retry metadata in app-owned storage, not in Shopify metafields. Metafields have size limits and are not designed for high-frequency transactional logging.
Regional Payment Considerations
For merchants serving South Asian markets, standard Stripe/PayPal billing may not suffice. When integrating local gateways like eSewa, Khalti, or ConnectIPS, remember that many do not support true recurring billing tokens. In these cases, you must implement a "billing agreement" flow where the customer authorizes future charges via OTP, then your app initiates subsequent charges server-side. This pattern is documented in my article on Laravel Khalti and eSewa payment integration and applies equally to Shopify app backends built with Node.js or PHP.
Custom vs native subscription solutions comparison
Not every merchant needs custom Shopify subscription app development. Understanding when to build versus when to configure saves significant engineering budget.
| Criteria | Native Apps (Recharge/Skio) | Custom App Development |
|---|---|---|
| Time to Launch | Days to weeks | Months (3-6 typical) |
| Monthly Cost | $99-$999+ USD plus transaction fees | Hosting + maintenance (~$50-200 USD/mo) |
| Customization Ceiling | Limited to app's exposed settings/API | Unlimited (full API access) |
| Local Payment Support | Rarely supports NPR/regional gateways | Full control over payment orchestration |
| Data Ownership | Vendor lock-in, export difficulties | Complete ownership of contract data |
| Maintenance Burden | Zero (vendor managed) | High (you own uptime, security, upgrades) |
| Best For | Standard DTC subscription boxes | B2B, regional markets, complex bundles |
If your requirements fit within a native app's capabilities, use it. Custom development only makes sense when you hit hard ceilings: regulatory compliance, unsupported payment rails, or business logic that would cost more in native app overages than building from scratch.
How do you secure subscription app data and comply with GDPR?
Subscription apps handle sensitive PII and financial metadata. Security is non-negotiable.
Session Token Authentication
Never use legacy cookie-based auth. All 2026 Shopify apps must use session tokens signed by Shopify. Validate the HMAC signature on every request. Store session tokens securely and rotate them according to Shopify's TTL recommendations.
Data Minimization and Retention
Only store what you need for billing operations. Do not cache full customer profiles. Implement automated data deletion workflows triggered by the CUSTOMERS_DATA_REQUEST and CUSTOMERS_REDACT mandatory webhooks. These are required for GDPR compliance and app store approval.
API Rate Limit Management
Subscription apps generate high API call volumes during billing cycles. Implement leaky bucket rate limiting in your app backend. Monitor cost.throttled fields in GraphQL responses. Batch operations using bulkOperationRunMutation for large-scale contract updates rather than individual calls. Teams familiar with backend optimization patterns from frameworks like Laravel will find similar principles apply; see Laravel API best practices for transferable rate-limiting strategies.
What testing strategies prevent subscription billing bugs?
Testing subscription apps is uniquely difficult because time-dependent logic cannot be easily accelerated. Standard unit tests miss race conditions in billing cycles.
Shopify Partner Dashboard Test Stores
Use unlimited test stores in your Partner account. Never test billing logic on development stores with real payment gateways enabled. Configure test gateway providers that simulate success, failure, and 3DS challenges deterministically.
Time Travel Testing
Implement a debug-only endpoint that advances contract billing dates without actually waiting. This allows QA to validate dunning sequences, renewal notifications, and expiration logic in minutes rather than weeks. Guard this endpoint behind strict environment checks and never deploy to production.
Webhook Replay Testing
Capture real webhook payloads from test stores and replay them against your local/staging environment. Tools like ngrok or Shopify CLI tunneling facilitate this. Verify idempotency by replaying the same webhook multiple times; your handler must produce identical results without duplicate side effects.
Conclusion
Successful Shopify subscription app development demands respect for platform constraints, rigorous testing of time-sensitive billing logic, and honest assessment of whether custom development truly serves the merchant better than configured alternatives. The Contracts API and Selling Plans provide powerful primitives, but they punish sloppy implementation with immediate revenue impact. Build with defensive coding practices, prioritize webhook reliability over feature velocity, and maintain clear documentation for merchants who depend on your app for recurring income.
If you are planning a subscription app project or need architectural review for an existing implementation, reach out to discuss your specific requirements. I help teams navigate the technical and business trade-offs of custom Shopify development with practical, production-focused guidance.

