Get current billing cycle number for a subscription contract
Retrieves the current billing cycle number for a specific subscription contract. The cycle number represents how many successful billing attempts have occurred for this subscription, starting from 1 for the initial order.
Full behavior, validation rules, and side effects
What is a Billing Cycle? A billing cycle represents one completed billing period in a subscription’s lifetime. Each successful billing attempt increments the cycle count. This number is crucial for:
- Tracking subscription progress towards minimum/maximum cycle limits
- Applying cycle-based pricing adjustments (discounts after N cycles)
- Determining eligibility for cancellation (minimum cycles requirement)
- Calculating customer lifetime value
- Analyzing subscription retention metrics
How Cycle Counting Works:
Initial Order:
- Cycle 1 starts when subscription is first created
- Initial order counts as the first billing cycle
- Includes origin order that created the subscription
Subsequent Orders:
- Each successful billing attempt increments cycle by 1
- Only SUCCESS status billing attempts are counted
- Failed/skipped billing attempts do NOT increment cycle
- Paused subscriptions maintain their current cycle number
Calculation Formula:
Current Cycle = 1 + (Number of Successful Billing Attempts)
Example Timeline:
- Day 1: Subscription created, initial order → Cycle 1
- Day 30: First recurring order successful → Cycle 2
- Day 60: Second recurring order successful → Cycle 3
- Day 90: Billing fails (payment declined) → Still Cycle 3
- Day 95: Retry successful → Cycle 4
Use Cases:
1. Cancellation Eligibility:
- Verify customer has met minimum cycle requirement
- Enforce contract terms (e.g., “3 month minimum”)
- Display “Can cancel after N more orders” messaging
- Block premature cancellations
2. Pricing Adjustments:
- Apply introductory pricing for first N cycles
- Trigger loyalty discounts after X cycles
- Calculate when pricing changes take effect
- Implement “First 3 months 50% off” promotions
3. Customer Retention:
- Identify subscriptions at risky cycle counts
- Send retention campaigns at specific milestones
- Track average cycles before churn
- Celebrate subscription anniversaries
4. Analytics & Reporting:
- Calculate customer lifetime value (cycle × price)
- Analyze subscription duration distribution
- Track retention curves by cohort
- Measure success of lifecycle campaigns
5. Customer Portal Display:
- Show “Order #X of Y” progress indicators
- Display remaining cycles until cancellation allowed
- Show subscription tenure/loyalty status
- Calculate and display subscription value earned
Response Format:
Returns a single integer representing the current cycle number:
3
Response Examples:
New subscription (just created):
1
After 5 successful billing attempts:
6
Note: Initial order (1) + 5 successful renewals = Cycle 6
Important Considerations:
Cycle vs. Billing Attempts:
- Failed billing attempts don’t increment cycle
- Skipped orders don’t increment cycle
- Manual order creation may not increment cycle
- Cycle represents successful billing events only
Paused Subscriptions:
- Cycle number remains frozen while paused
- Resumes at same cycle when un-paused
- Pause duration doesn’t affect cycle count
Minimum/Maximum Cycles:
minCycles: Minimum cycles before cancellation allowedmaxCycles: Subscription auto-expires after this many cycles- Use this endpoint to check progress towards these limits
Data Source:
- Queries Appstle database (not Shopify API)
- Counts records in subscription_billing_attempt table
- Filters by SUCCESS status only
- Fast response time (< 100ms typically)
Integration Example:
Check if customer can cancel:
// Get subscription details
const contract = await getSubscriptionContract(contractId);
const currentCycle = await fetch(
`/api/external/v2/subscription-contract-details/current-cycle/${contractId}`,
{ headers: { 'X-API-Key': 'your-key' } }
).then(r => r.json());
const minCycles = contract.minCycles || 0;
if (currentCycle >= minCycles) {
console.log('Customer can cancel now');
showCancelButton();
} else {
const cyclesRemaining = minCycles - currentCycle;
console.log(`Must complete ${cyclesRemaining} more orders before canceling`);
showMinimumCommitmentMessage(cyclesRemaining);
}
Display progress to max cycles:
const currentCycle = await getCycleNumber(contractId);
const maxCycles = contract.maxCycles;
if (maxCycles) {
const progress = (currentCycle / maxCycles) * 100;
console.log(`Subscription ${progress.toFixed(0)}% complete (${currentCycle}/${maxCycles})`);
if (currentCycle === maxCycles) {
console.log('This is the final cycle - subscription will expire after this order');
}
}
Performance Characteristics:
Fast Query:
- Simple database count query
- Indexed by shop and contractId
- Typical response time: 50-150ms
- Suitable for real-time UI updates
Best Practices:
- Cache Results: Cache cycle number briefly (few minutes) to reduce API calls
- Combine with Contract Data: Fetch contract details simultaneously for min/max cycles
- Handle Edge Cases: Account for subscriptions with no successful billings yet
- Display Progress: Show cycle number in customer-friendly format (“Order 3 of 12”)
- Sync with Billing: Update cycle number after each billing attempt completes
Common Misunderstandings:
Myth: Cycle = Months Subscribed
- Reality: Cycle = Successful billing attempts, not time elapsed
- A paused subscription stays at same cycle for months
- Failed payments don’t advance the cycle
Myth: First order is Cycle 0
- Reality: Cycles start at 1, not 0
- Initial/origin order is Cycle 1
Related Fields:
minCycles: Minimum cycles before cancellation (from contract)maxCycles: Maximum cycles before auto-expiry (from contract)billingInterval: Frequency between cycles (from contract)
Authentication: Requires valid X-API-Key header
Documentation Index
Fetch the complete documentation index at: https://developers.appstle.com/llms.txt
Use this file to discover all available pages before exploring further.