Skip to content

External APIs (0.0.1)

Comprehensive API documentation for managing subscriptions, payments, and related operations. These APIs allow you to programmatically manage subscription lifecycles, handle payments, configure products, and integrate subscription functionality into your applications.

Languages
Servers
https://subscription-admin.appstle.com

Subscription Management

Core APIs for managing the complete subscription lifecycle including creation, updates, pausing, resuming, and cancellation of subscriptions.

Operations

Get current billing cycle number for a subscription contract

Request

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.

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 allowed
  • maxCycles: 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:

  1. Cache Results: Cache cycle number briefly (few minutes) to reduce API calls
  2. Combine with Contract Data: Fetch contract details simultaneously for min/max cycles
  3. Handle Edge Cases: Account for subscriptions with no successful billings yet
  4. Display Progress: Show cycle number in customer-friendly format ("Order 3 of 12")
  5. 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

Path
contractIdinteger(int64)required
Headers
X-API-Keystringrequired

API Key for authentication

Example: sk_live_1234567890abcdef
curl -i -X GET \
  'https://subscription-admin.appstle.com/api/external/v2/subscription-contract-details/current-cycle/{contractId}' \
  -H 'X-API-Key: sk_live_1234567890abcdef'

Responses

Successfully retrieved current billing cycle number

Bodyapplication/json
integer(int32)
Response
application/json
1

Get available billing intervals for selling plan(s)

Request

Retrieves all available billing frequency options configured for specific Shopify selling plan(s). Returns the complete set of billing intervals that customers can choose from, including frequency, interval type, and any associated discounts or pricing policies.

What This Endpoint Does: Queries the subscription group plans database to find all frequency configurations associated with given selling plan ID(s). This is essential for building subscription frequency selectors in customer portals or during subscription modifications.

Key Concepts:

Selling Plans:

  • Shopify's mechanism for defining subscription options
  • Each product variant can have multiple selling plans
  • Selling plans define billing/delivery frequency
  • Plans are grouped in subscription groups

Frequency Info:

  • Specific billing interval configuration
  • E.g., "Every 2 weeks", "Every month", "Every 3 months"
  • Includes pricing policies and discounts
  • Customers select from available frequencies

Request Parameters:

sellingPlanIds (required):

  • Comma-separated list of Shopify selling plan IDs
  • Example: "123456,123457,123458"
  • Can query single or multiple plans
  • Returns frequencies for ALL provided plans

Lookup Process:

  1. Parse selling plan IDs from comma-separated string
  2. Find subscription groups containing these plans
  3. Extract frequency configurations from group JSON
  4. Return all matching frequency options
  5. Deduplicate if same frequency appears multiple times

Response Data Included:

For Each Frequency Option:

  • id: Selling plan ID
  • frequencyName: Display name (e.g., "Monthly")
  • interval: WEEK, MONTH, or YEAR
  • intervalCount: Number of intervals (e.g., 2 for bi-weekly)
  • deliveryInterval: Same or different from billing
  • deliveryIntervalCount: Delivery frequency
  • pricingPolicy: Discount configuration
  • billingPolicy: Min/max cycles, anchor settings

Pricing Policy Details:

  • Discount type (percentage, fixed amount)
  • Discount value
  • After cycle discounts (e.g., "50% off first 3 months")
  • Adjustment type

Use Cases:

1. Frequency Selection UI:

  • Build dropdown/radio list of frequency options
  • Show available intervals to customers
  • Display pricing for each frequency
  • Enable subscription frequency changes

2. Subscription Modification:

  • Show current frequency and alternatives
  • Allow customers to switch frequencies
  • Validate new frequency selection
  • Preview pricing changes

3. Product Page:

  • Display subscription frequency options
  • Show "Subscribe and save" pricing
  • Calculate savings per frequency
  • Build subscription purchase selectors

4. Customer Portal:

  • "Change Frequency" functionality
  • Show all available options
  • Highlight current selection
  • Display pricing differences

Response Format:

[
  {
    "id": "123456",
    "frequencyName": "Every 2 Weeks",
    "interval": "WEEK",
    "intervalCount": 2,
    "deliveryInterval": "WEEK",
    "deliveryIntervalCount": 2,
    "pricingPolicy": {
      "adjustmentType": "PERCENTAGE",
      "adjustmentValue": "10.0"
    }
  },
  {
    "id": "123457",
    "frequencyName": "Monthly",
    "interval": "MONTH",
    "intervalCount": 1,
    "deliveryInterval": "MONTH",
    "deliveryIntervalCount": 1,
    "pricingPolicy": {
      "adjustmentType": "PERCENTAGE",
      "adjustmentValue": "15.0"
    }
  }
]

Integration Example:

Customer Portal - Frequency Selector:

// Get selling plan from current subscription
const currentSellingPlanId = subscription.sellingPlanId;

// Fetch available frequencies
const frequencies = await fetch(
  `/api/external/v2/subscription-contract-details/billing-interval?sellingPlanIds=${currentSellingPlanId}`,
  { headers: { 'X-API-Key': 'your-key' } }
).then(r => r.json());

// Build selector
const selector = frequencies.map(freq => `
  <option value="${freq.id}" 
    ${freq.id === currentSellingPlanId ? 'selected' : ''}>
    ${freq.frequencyName} - Save ${freq.pricingPolicy.adjustmentValue}%
  </option>
`).join('');

document.querySelector('#frequency-select').innerHTML = selector;

Important Considerations:

Data Source:

  • Queries Appstle database (NOT Shopify API)
  • Based on subscription group configuration
  • Fast response (< 100ms typically)
  • Data synced when groups are updated

Multiple Selling Plans:

  • Can query multiple plans at once
  • Returns union of all frequencies
  • Useful for products with multiple subscription options
  • Results may contain duplicates if plans share frequencies

Empty Results:

  • Returns empty array [] if no plans found
  • Returns empty if selling plan ID invalid
  • Not an error - handle gracefully

Best Practices:

  1. Query Relevant Plans: Only query selling plans for current product/variant
  2. Display Discounts: Show savings clearly in UI
  3. Sort by Interval: Order options logically (weekly → monthly → yearly)
  4. Highlight Current: Clearly mark customer's current frequency
  5. Cache Results: Cache frequency data per selling plan

Authentication: Requires valid X-API-Key header

Query
api_keystring

API Key (Deprecated - Use Header X-API-Key instead)

sellingPlanIdsstringrequired

Selling Plan ID

Headers
X-API-Keystring
curl -i -X GET \
  'https://subscription-admin.appstle.com/api/external/v2/subscription-contract-details/billing-interval?api_key=string&sellingPlanIds=string' \
  -H 'X-API-Key: string'

Responses

Successfully retrieved billing intervals (may be empty array)

Bodyapplication/jsonArray [
frequencyCountinteger(int32)
frequencyIntervalstring
Enum"DAY""WEEK""MONTH""YEAR"
billingFrequencyCountinteger(int32)
payAsYouGoPrepaidBillingFrequencyCountinteger(int32)
billingFrequencyIntervalstring
Enum"DAY""WEEK""MONTH""YEAR"
frequencyNamestring
frequencyDescriptionstring
discountOffernumber(double)
discountOffer2number(double)
afterCycle1integer(int32)
afterCycle2integer(int32)
discountTypestring
Enum"PERCENTAGE""FIXED""PRICE"
discountType2string
Enum"PERCENTAGE""FIXED""PRICE"
discountEnabledboolean
discountEnabled2boolean
discountEnabledMaskedboolean
discountEnabled2Maskedboolean
idstring
frequencyTypestring
Enum"ON_PURCHASE_DAY""ON_SPECIFIC_DAY"
specificDayValueinteger(int32)
specificMonthValueinteger(int32)
specificDayEnabledboolean
maxCyclesinteger(int32)
minCyclesinteger(int32)
cutOffinteger(int32)
prepaidFlagstring
idNewstring
planTypestring
Enum"PAY_AS_YOU_GO""PREPAID""ADVANCED_PREPAID""PAY_AS_YOU_GO_PREPAID"
deliveryPolicyPreAnchorBehaviorstring
Enum"ASAP""NEXT""$UNKNOWN"
freeTrialEnabledboolean
freeTrialCountinteger(int32)
freeTrialIntervalstring
Enum"DAY""WEEK""MONTH""YEAR"
memberOnlyboolean
nonMemberOnlyboolean
memberInclusiveTagsstring
memberExclusiveTagsstring
formFieldJsonstring
upcomingOrderEmailBufferinteger(int32)
frequencySequenceinteger(int32)
groupNamestring
groupIdinteger(int64)
repeatingCycleboolean
repeatingNumberOfCycleinteger(int32)
keepOriginalNextBillingDateAfterTrialboolean
defaultSelectedPlanboolean
inventoryPolicyReservestring
Enum"ON_FULFILLMENT""ON_SALE""$UNKNOWN"
appstleCyclesArray of objects(AppstleCycle)
]
Response
application/json
[ { "frequencyCount": 0, "frequencyInterval": "DAY", "billingFrequencyCount": 0, "payAsYouGoPrepaidBillingFrequencyCount": 0, "billingFrequencyInterval": "DAY", "frequencyName": "string", "frequencyDescription": "string", "discountOffer": 0.1, "discountOffer2": 0.1, "afterCycle1": 0, "afterCycle2": 0, "discountType": "PERCENTAGE", "discountType2": "PERCENTAGE", "discountEnabled": true, "discountEnabled2": true, "discountEnabledMasked": true, "discountEnabled2Masked": true, "id": "string", "frequencyType": "ON_PURCHASE_DAY", "specificDayValue": 0, "specificMonthValue": 0, "specificDayEnabled": true, "maxCycles": 0, "minCycles": 0, "cutOff": 0, "prepaidFlag": "string", "idNew": "string", "planType": "PAY_AS_YOU_GO", "deliveryPolicyPreAnchorBehavior": "ASAP", "freeTrialEnabled": true, "freeTrialCount": 0, "freeTrialInterval": "DAY", "memberOnly": true, "nonMemberOnly": true, "memberInclusiveTags": "string", "memberExclusiveTags": "string", "formFieldJson": "string", "upcomingOrderEmailBuffer": 0, "frequencySequence": 0, "groupName": "string", "groupId": 0, "repeatingCycle": true, "repeatingNumberOfCycle": 0, "keepOriginalNextBillingDateAfterTrial": true, "defaultSelectedPlan": true, "inventoryPolicyReserve": "ON_FULFILLMENT", "appstleCycles": [] } ]

Get subscription contract analytics and revenue metrics

Request

Retrieves comprehensive analytics for a specific subscription contract, including total revenue generated, number of successful orders, and formatted revenue display. This endpoint provides key performance metrics for understanding the financial impact of individual subscriptions.

What This Endpoint Returns: Financial and operational analytics for a single subscription contract, calculated from all successful billing attempts throughout the subscription's lifetime. Unlike realtime contract queries, this provides historical aggregated data.

Metrics Included:

Revenue Metrics:

  • totalOrderAmount: Total revenue in decimal format (e.g., 299.95)
  • totalOrderRevenue: Formatted currency string (e.g., "$299.95")
  • Calculated from all SUCCESS status billing attempts
  • Includes taxes, shipping, and discounts
  • Does NOT include failed or pending payments

Order Count:

  • totalOrders: Count of successful billing attempts
  • Represents number of orders generated by subscription
  • Does NOT include failed billing attempts
  • Starts at 0 for brand new subscriptions

Currency Formatting:

  • Uses shop's configured money_format
  • Respects shop's currency code (USD, EUR, GBP, etc.)
  • Handles currency symbols and decimal places correctly
  • Falls back to USD if currency unknown

Calculation Logic:

Data Source:

SELECT 
  COUNT(*) as totalOrders,
  SUM(order_amount) as totalOrderAmount
FROM subscription_billing_attempt
WHERE shop = ? 
  AND contract_id = ?
  AND status = 'SUCCESS'

What Gets Counted:

  • ✅ Initial subscription order
  • ✅ All successful recurring orders
  • ✅ Manual billing attempts that succeeded
  • ✅ Retry attempts that eventually succeeded
  • ❌ Failed payment attempts
  • ❌ Skipped billing cycles
  • ❌ Cancelled/voided orders
  • ❌ Pending/in-progress billing

Use Cases:

1. Customer Lifetime Value:

  • Calculate total revenue from specific customer
  • Measure subscription ROI
  • Identify high-value subscriptions
  • Track revenue growth over time

2. Subscription Performance:

  • Analyze revenue per subscription
  • Compare subscriptions by total value
  • Identify most profitable subscription types
  • Calculate average order value

3. Customer Portal:

  • Display "You've saved $XXX" messaging
  • Show "X orders delivered" stats
  • Celebrate subscription milestones
  • Build customer loyalty through transparency

4. Reporting & Analytics:

  • Build subscription revenue dashboards
  • Generate customer value reports
  • Track subscription health metrics
  • Forecast future revenue

5. Business Intelligence:

  • Segment customers by subscription value
  • Identify churn risk (low order count)
  • Calculate retention rates
  • Measure subscription program success

Response Format:

{
  "totalOrders": 12,
  "totalOrderAmount": 599.88,
  "totalOrderRevenue": "$599.88"
}

Response Fields:

  • totalOrders (integer): Count of successful billing attempts
  • totalOrderAmount (decimal): Numeric revenue total
  • totalOrderRevenue (string): Formatted currency display

Example Scenarios:

Brand New Subscription:

{
  "totalOrders": 0,
  "totalOrderAmount": 0.00,
  "totalOrderRevenue": "$0.00"
}

After First Successful Order:

{
  "totalOrders": 1,
  "totalOrderAmount": 49.99,
  "totalOrderRevenue": "$49.99"
}

Established Subscription (EUR):

{
  "totalOrders": 24,
  "totalOrderAmount": 1199.76,
  "totalOrderRevenue": "€1.199,76"
}

Integration Examples:

Customer Portal - Loyalty Display:

const analytics = await fetch(
  `/api/external/v2/subscription-contract-details/analytics/${contractId}`,
  { headers: { 'X-API-Key': 'your-key' } }
).then(r => r.json());

const loyaltyMessage = `
  <div class="loyalty-badge">
    <h3>Thank you for your loyalty!</h3>
    <p>You've received ${analytics.totalOrders} orders</p>
    <p>Total value: ${analytics.totalOrderRevenue}</p>
  </div>
`;

Revenue Dashboard:

// Fetch analytics for multiple subscriptions
const contractIds = [123, 456, 789];
const analyticsPromises = contractIds.map(id => 
  getContractAnalytics(id)
);

const allAnalytics = await Promise.all(analyticsPromises);
const totalRevenue = allAnalytics.reduce(
  (sum, a) => sum + a.totalOrderAmount, 0
);

console.log(`Total subscription revenue: $${totalRevenue.toFixed(2)}`);

Important Considerations:

Data Accuracy:

  • Based on Appstle's billing attempt records
  • May differ slightly from Shopify order totals
  • Includes only what Appstle successfully billed
  • Updated after each billing attempt completes

Currency Handling:

  • Formatting uses shop's money_format setting
  • Different shops may have different decimal separators
  • Currency symbol placement varies by locale
  • Always use totalOrderAmount for calculations

Performance:

  • Fast database aggregation query
  • Typical response time: 100-300ms
  • Indexed by shop and contract ID
  • Suitable for real-time display

Best Practices:

  1. Use for Display: Use totalOrderRevenue for customer-facing display
  2. Calculate with Amount: Use totalOrderAmount for mathematical operations
  3. Cache Strategically: Cache for dashboards, fetch real-time for critical displays
  4. Handle Zero: Gracefully handle new subscriptions with 0 orders
  5. Validate Contract: Ensure contract exists before querying analytics

Limitations:

What's NOT Included:

  • Future projected revenue
  • Failed payment attempt counts
  • Refunds or chargebacks
  • Pending/processing orders
  • Orders from other subscriptions

Related Calculations:

Average Order Value:

const aov = analytics.totalOrderAmount / analytics.totalOrders;
console.log(`Average order value: $${aov.toFixed(2)}`);

Customer Lifetime Value (projected):

const monthsActive = calculateMonthsActive(contract.createdAt);
const monthlyRevenue = analytics.totalOrderAmount / monthsActive;
const projectedLTV = monthlyRevenue * 12; // Annual LTV

Authentication: Requires valid X-API-Key header

Path
contractIdstringrequired

Contract ID

Query
api_keystring

API Key (Deprecated - Use Header X-API-Key instead)

Headers
X-API-Keystring
curl -i -X GET \
  'https://subscription-admin.appstle.com/api/external/v2/subscription-contract-details/analytics/{contractId}?api_key=string' \
  -H 'X-API-Key: string'

Responses

Successfully retrieved contract analytics

Bodyapplication/json
totalOrderCountinteger(int64)
totalOrderAmountnumber(double)
totalOrderRevenuestring
Response
application/json
{ "totalOrders": 12, "totalOrderAmount": 599.88, "totalOrderRevenue": "$599.88" }

Subscription Payments

APIs for managing subscription payment methods, processing payments, handling payment retries, and updating billing information.

Operations

Subscription Contracts

APIs for managing subscription contracts including delivery schedules, pricing, order notes, billing cycles, and shipping addresses.

Operations

Subscription Products

APIs for managing products within subscriptions including adding, removing, updating quantities, and swapping products.

Operations

Billing & Payments

APIs for handling billing operations, payment processing, and financial transactions related to subscriptions.

Operations

Subscription Discounts

APIs for managing discounts and promotional codes applied to subscriptions.

Operations

Subscription One-Time Products

APIs for managing one-time add-on products that can be purchased alongside recurring subscription items.

Operations

Subscription Plans

APIs for managing subscription plans, pricing tiers, and plan configurations.

Operations

Build-a-Box & Bundles

APIs for managing customizable product boxes and bundles where customers can select multiple items.

Operations

Product Catalog

APIs for managing the product catalog including product information, variants, and inventory.

Operations

Operations & Settings

APIs for managing operational settings, configurations, and administrative functions.

Operations

Customer Portal

APIs powering the customer-facing portal where subscribers can manage their own subscriptions.

Operations

Customers

APIs for managing customer information, profiles, and account details.

Operations