# Subscription Management Core APIs for managing the complete subscription lifecycle including creation, updates, pausing, resuming, and cancellation of subscriptions. ## Update delivery price for a subscription contract - [PUT /api/external/v2/subscription-contracts-update-delivery-price](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updatedeliveryprice.md): Updates the fixed delivery price for all future orders in a subscription contract. This allows manual override of calculated shipping rates with a custom delivery fee. Key Features: - Sets a fixed delivery price regardless of shipping calculations - Overrides any dynamic shipping rates from carriers - Applies to all future orders immediately - Can set to 0 for free delivery - Automatically handles invalid discount codes - Tracks price changes in activity log How Delivery Pricing Works: - Calculated Rates: Default behavior uses carrier rates and rules - Manual Override: This endpoint sets a fixed price - Precedence: Manual price overrides all calculations - Currency: Always in shop's base currency Common Use Cases: - Free Shipping Promotions: Set to 0.00 - Flat Rate Shipping: Fixed price regardless of location - VIP Customer Rates: Special shipping prices - Subscription Perks: Reduced delivery fees - Price Corrections: Fix shipping calculation errors - Regional Adjustments: Custom rates for specific areas Impact on Orders: - Next order uses new delivery price - All future recurring orders affected - Existing orders keep original pricing - Customer sees updated total immediately - No recalculation on address changes Price Validation: - Must be a valid decimal number - Can be 0 for free shipping - No maximum limit enforced - Negative values typically rejected by Shopify - Currency precision respected (e.g., 2 decimals for USD) Side Effects: - Invalid discount codes automatically removed - Activity log created with old/new prices - No customer email notification sent - Shipping tax recalculated if applicable - Total order value updated Reverting to Calculated Rates: To restore dynamic shipping calculations: 1. Use the sync shipping price endpoint 2. Or update delivery method 3. Manual price remains until explicitly changed Important Notes: - Price includes all delivery charges (shipping + handling) - Does not affect delivery method or speed - Consider customer communication for increases - May affect subscription profitability - Some payment methods may decline on total changes Authentication: Requires valid X-API-Key header ## Update subscription contract status - [PUT /api/external/v2/subscription-contracts-update-status](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updatestatusv2.md): Updates the status of a subscription contract to ACTIVE, PAUSED, or CANCELLED. This endpoint manages the lifecycle of subscriptions with automatic state tracking and notifications. Status Transitions: - ACTIVE: Resumes a paused subscription, enabling future billing and deliveries - PAUSED: Temporarily suspends all billing and deliveries until manually resumed - CANCELLED: Permanently terminates the subscription (irreversible) Key Features: - Validates status transitions (prevents same-status updates) - Tracks status change timestamps for audit trails - Sends automated email notifications to customers - Creates detailed activity logs for each status change - Handles concurrent modifications with automatic retry - Adjusts next billing date when resuming subscriptions Permission Requirements (Customer Portal): When called from customer portal context: - PAUSED status requires 'pauseResumeSub' permission - ACTIVE status (resuming) requires 'resumeSub' permission - CANCELLED status requires 'cancelSub' permission - External API calls bypass these permission checks Status Change Side Effects: - Activating: Recalculates next billing date, marks activation timestamp - Pausing: Stops all scheduled orders, marks pause timestamp - Cancelling: Terminates subscription permanently, marks cancellation timestamp Error Recovery: The system automatically handles: - Invalid discount codes by removing them and retrying - Concurrent modifications by retrying the operation - This ensures reliable status updates in production environments Important Notes: - Status values are case-insensitive - Cancelled subscriptions cannot be reactivated - Paused subscriptions retain all settings and can be resumed - Email notifications are sent automatically unless internally suppressed Authentication: Requires valid X-API-Key header ## Update subscription delivery address and method - [PUT /api/external/v2/subscription-contracts-update-shipping-address](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updateshippingaddressv2.md): Updates the shipping address or delivery method for a subscription contract. Supports standard shipping, local delivery, and pickup options with comprehensive address validation. Delivery Method Types: - SHIPPING: Standard shipping to customer address (default) - LOCAL: Local delivery within specified zip codes - PICK_UP: Customer pickup at designated location Key Features: - Zip code restrictions for customer portal access - Optional ShipperHQ address validation - Automatic phone number handling for local delivery - Email notifications to customers - Shipping price recalculation - Activity log tracking with old/new addresses Zip Code Validation (Customer Portal Only): When called from customer portal: - Standard shipping: Validates against 'allowToSpecificZipCode' setting - Local delivery: Validates against 'allowToSpecificZipCodeForLocalDelivery' setting - External API calls bypass zip code restrictions Address Validation: - If ShipperHQ is configured, addresses are validated for deliverability - Invalid addresses will return appropriate error messages - Helps prevent failed deliveries and shipping issues Special Handling: - Local delivery addresses missing phone numbers are auto-populated - Uses customer's phone if available, otherwise defaults to placeholder - Handles missing address components gracefully Post-Update Actions: - Sends 'SHIPPING_ADDRESS_UPDATED' email to customer - Creates activity log with address change details - Triggers asynchronous shipping price recalculation - May remove invalid discount codes automatically Important Notes: - Province codes should use ISO 3166-2 format (e.g., 'NY' for New York) - Country codes should use ISO 3166-1 alpha-2 format (e.g., 'US') - Phone numbers should include country code for international addresses - Pickup locations must be pre-configured in Shopify Authentication: Requires valid X-API-Key header ## Update order note for subscription - [PUT /api/external/v2/subscription-contracts-update-order-note/{contractId}](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updateordernotev2.md): Updates the order note that will be added to all future orders generated by this subscription. Order notes help merchants track special instructions, customer preferences, or internal information about the subscription. Key Features: - Note is automatically added to all future recurring orders - Visible in both merchant portal and customer portal - Appears in Shopify order details for easy reference - Changes apply to future orders only (existing orders unchanged) Common Use Cases: - Customer preferences: "No nuts - severe allergy" - Delivery instructions: "Leave package at side door" - Gift messages: "Happy Birthday from Mom!" - Internal notes: "VIP customer - priority handling" - Processing instructions: "Include sample with each order" Important Notes: - Empty string clears the existing note - No character limit imposed by API (check Shopify limits) - HTML is not rendered - stored as plain text - Updates are logged in activity history - Note persists until explicitly changed Order Generation: When Appstle creates recurring orders: 1. Retrieves current order note from subscription 2. Adds note to new Shopify order 3. Note appears in order details immediately 4. Merchants can still edit individual order notes Authentication: Requires valid X-API-Key header ## Update minimum cycles for a subscription contract - [PUT /api/external/v2/subscription-contracts-update-min-cycles](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updatemincyclesv2.md): Updates the minimum number of billing cycles (orders) that a customer must complete before they can cancel their subscription. This creates a commitment period that helps with customer retention and business predictability. What are Minimum Cycles? Minimum cycles represent a commitment period where: - Customers must complete a specified number of orders - Cancellation is blocked until the minimum is met - Often tied to special pricing or promotional offers - Counted from the subscription start date Key Features: - Updates commitment period for existing subscriptions - Can increase or decrease minimum cycles - Setting to null removes the minimum commitment - Preserves all other subscription settings - Automatically handles invalid discount codes - Updates future billing queue after change Common Use Cases: - Promotional Offers: '3-month minimum for 50% off' - Hardware Subsidies: '12-month commitment with free device' - Loyalty Programs: Reduce minimum after customer proves loyalty - Seasonal Campaigns: Temporary commitment requirements - Contract Adjustments: Customer service exceptions Impact on Customers: - Cannot cancel via portal until minimum cycles complete - Pause/resume typically still allowed (check settings) - Shows commitment status in customer portal - No automatic notification sent (consider sending separately) Cycle Counting: - Only successful billing attempts count toward minimum - Failed payments don't increment the cycle count - Skipped orders (if allowed) don't count - Current cycle = successful past orders + 1 Interaction with Max Cycles: - Min cycles must be less than or equal to max cycles - If max cycles exist, subscription auto-cancels after maximum - Common pattern: 3 min cycles, 12 max cycles Best Practices: - Clearly communicate commitment terms upfront - Consider grandfathering existing customers - Use reasonable minimums (typically 3-12 cycles) - Document reason for changes in activity logs - Send customer notification for transparency Important Notes: - Changes apply immediately to cancellation logic - Doesn't affect past or in-progress orders - Customer portal respects this setting automatically - Activity log tracks old and new values - Consider legal requirements in your jurisdiction Authentication: Requires valid X-API-Key header ## Update maximum cycles for a subscription contract - [PUT /api/external/v2/subscription-contracts-update-max-cycles](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updatemaxcyclesv2.md): Updates the maximum number of billing cycles (orders) after which a subscription will automatically terminate. This creates a fixed-duration subscription that ends after a specific number of orders. What are Maximum Cycles? Maximum cycles define subscription duration limits where: - Subscription automatically cancels after the specified number of orders - No further orders are generated once maximum is reached - Useful for fixed-term offers, trials, or seasonal subscriptions - Customer is notified before final order (if configured) Key Features: - Cannot set below current cycle count (prevents immediate cancellation) - Setting to null creates an indefinite subscription - Automatically reschedules order queue based on new limit - Preserves all other subscription settings - Validates against current subscription progress Current Cycle Calculation: - Current cycle = Successful billing attempts + 1 - Failed payments don't count toward maximum - First order is cycle 1, second is cycle 2, etc. - System prevents setting max below current position Common Use Cases: - Trial Subscriptions: '3-box trial' that auto-ends - Seasonal Programs: '6-month summer subscription' - Limited Series: '12-issue magazine subscription' - Promotional Offers: 'First 5 boxes at special price' - Gift Subscriptions: Fixed duration gifts that don't renew What Happens at Maximum: When a subscription reaches its maximum cycles: 1. Final order is processed normally 2. Subscription status changes to CANCELLED 3. No future orders are scheduled 4. Customer receives cancellation notification 5. Cannot be reactivated (new subscription required) Interaction with Min Cycles: - Can have both min and max (e.g., 3 min, 12 max) - Min cycles enforces commitment period - Max cycles enforces termination - Common pattern: Commitment with defined end Queue Management: After updating max cycles: - System recalculates future order schedule - Removes orders beyond the new maximum - Adjusts upcoming order notifications - Updates subscription end date projections Important Notes: - Validation prevents accidental immediate cancellation - Changes apply to future billing cycles only - Activity log tracks old and new values - Consider customer communication for changes - Setting null removes any duration limit Authentication: Requires valid X-API-Key header ## Update subscription delivery method - [PUT /api/external/v2/subscription-contracts-update-delivery-method](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updatedeliverymethod.md): Updates the delivery method for a subscription contract, supporting standard shipping, local delivery, and customer pickup options. The delivery method determines how future orders will be fulfilled. Delivery Method Types: The system automatically determines the type based on the subscription's current delivery address: - SHIPPING: Standard shipping to customer address (default) - LOCAL: Local delivery within merchant's delivery zones - PICK_UP: Customer pickup at designated location Two Ways to Update: 1. Manual Parameters: Provide title, code, and presentment title directly 2. Delivery Method ID: Provide a Shopify DeliveryMethodDefinition ID to auto-populate all fields Using Delivery Method ID: When providing a delivery-method-id: - System fetches the method from Shopify's delivery profiles - Automatically sets title, code, and presentment title - Applies associated delivery price if defined - ID can be numeric or full GraphQL ID format Delivery Type Requirements: - Standard Shipping: No additional requirements - Local Delivery: Phone number must exist in delivery address - Pickup: Pickup location must be configured in subscription Price Updates: - If using delivery-method-id with a fixed price, updates delivery price - Manual updates don't change the delivery price - Price changes affect all future orders Side Effects: - Creates activity log entry with method details - May remove invalid discount codes automatically - Updates apply to all future orders immediately - No customer notification sent Common Use Cases: - Switch from standard shipping to express shipping - Change pickup location for customer convenience - Update local delivery options based on availability - Apply seasonal delivery methods Important Notes: - Cannot change the delivery type (shipping/local/pickup) - only the method within that type - Delivery methods must be configured in Shopify's shipping settings - Changes don't affect orders already in fulfillment Authentication: Requires valid X-API-Key header ## Update delivery interval for a subscription contract - [PUT /api/external/v2/subscription-contracts-update-delivery-interval](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updatedeliveryintervalv2.md): Updates the delivery interval for the specified subscription contract. This endpoint allows external API consumers to change the delivery interval count and type (of type SellingPlanInterval) used for scheduling deliveries. The service validates that the contract exists, that the new delivery interval differs from the current setting, and that it meets all business rules. Authentication is enforced via the X-API-Key header (the 'api_key' parameter is deprecated). ## Update custom attributes on a subscription contract - [POST /api/external/v2/update-custom-note-attributes](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/updateordernoteattributes.md): Updates or replaces custom key-value attributes on a subscription contract. These attributes are stored with the subscription and can be used to track custom data, preferences, or metadata that's important for your business processes. Custom Attributes Overview: Custom attributes are key-value pairs that allow you to store additional information on subscriptions. They are: - Visible in the Shopify admin and accessible via API - Included in order data when subscription orders are created - Preserved across subscription lifecycle events - Useful for integrations and custom workflows Update Modes: - Merge Mode (overwriteExistingAttributes=false): Adds new attributes and updates existing ones with matching keys. Other attributes remain unchanged. - Replace Mode (overwriteExistingAttributes=true): Completely replaces all existing attributes with the provided list. Common Use Cases: - Store gift messages or special instructions - Track referral sources or marketing campaigns - Add internal reference numbers or tracking codes - Store customer preferences or customization options - Integration data for third-party systems Important Notes: - Attribute keys should not conflict with Shopify's reserved attributes - Both keys and values are stored as strings - Changes are logged in the activity history - Invalid discount codes may be automatically removed during update Authentication: Requires valid X-API-Key header ## Split or duplicate an existing subscription contract - [POST /api/external/v2/subscription-contract-details/split-existing-contract](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/splitexistingcontract.md): Creates a new subscription contract by either splitting (moving) or duplicating selected line items from an existing contract. This endpoint allows you to divide a subscription into multiple contracts or create a copy with specific products. Split vs Duplicate Mode: - Split (isSplitContract=true): Moves the selected line items from the original contract to a new contract. The original contract will no longer contain these items. - Duplicate (isSplitContract=false): Creates a new contract with copies of the selected line items while keeping them in the original contract. Important Notes: - When splitting, at least one subscription product must remain in the original contract - The new contract inherits all settings from the original: customer, payment method, billing/delivery policies, shipping address, and custom attributes - Billing schedule is automatically generated for the new contract - One-time products and free products don't count towards the minimum product requirement Use Cases: - Split a subscription when customer wants different delivery schedules for different products - Create a gift subscription from an existing subscription - Separate products for different shipping addresses - Duplicate a subscription for testing or backup purposes Authentication: Requires valid X-API-Key header ## Replace product variants in a subscription contract - [POST /api/external/v2/subscription-contract-details/replace-variants-v3](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/replacevariantsv3.md): Replaces existing product variants with new ones in a subscription contract. This endpoint supports both regular subscription products and one-time products, allowing you to swap products, update quantities, and manage the product mix in a subscription. Key Features: - Bulk Replace: Replace multiple products at once by providing lists of old and new variants - Line-Specific Replace: Target a specific line item using oldLineId for precise replacement - Quantity Management: Set new quantities for replaced products - One-Time Products: Add or remove one-time purchase products independently - Discount Preservation: Configurable discount carry-forward logic Discount Carry Forward Options: - PRODUCT_THEN_EXISTING: First tries to apply the new product's selling plan discount, then falls back to existing discount - PRODUCT_PLAN: Always uses the new product's selling plan discount - EXISTING_PLAN: Maintains the existing product's discount structure Important Notes: - At least one regular subscription product must remain in the contract - One-time products and free products don't count towards the minimum product requirement - The system automatically handles pricing adjustments based on billing/delivery intervals - Shipping prices are automatically recalculated after changes Use Cases: - Product upgrades/downgrades (e.g., switching coffee blend or size) - Quantity adjustments during product swap - Adding limited-time or seasonal products as one-time purchases - Bulk product replacements for subscription migrations Authentication: Requires valid X-API-Key header ## Create a new subscription contract - [POST /api/external/v2/subscription-contract-details/create-subscription-contract](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/createsubscriptioncontractv2.md): Creates a new subscription contract for a customer with specified products, billing frequency, and delivery details. This endpoint allows you to programmatically create subscriptions with custom pricing, delivery schedules, and multiple line items. The subscription will be created in Shopify and synchronized with the Appstle system. Important Notes: - Customer must have at least one valid payment method - If paymentMethodId is not provided, the default payment method will be used - If delivery interval is not specified, it defaults to the billing interval - Custom pricing policies can be applied per line item - All monetary values are in the store's base currency unless currencyCode is specified - CustomAttributes and line item customAttributes use Shopify's AttributeInput format: {"key": "string", "value": "string"} Pricing Policy Types: - SELLING_PLAN_PRICING_POLICY: Uses the default pricing from the selling plan - CUSTOM_PRICING_POLICY: Allows custom discount cycles defined in pricingPolicy array - NO_PRICING_POLICY: Uses the base price without any discounts Authentication: Requires valid X-API-Key header ## Get raw Shopify GraphQL contract response - [GET /api/external/v2/subscription-contracts/contract-external/{contractId}](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/getsubscriptioncontractrawexternalv2.md): Retrieves the complete, unprocessed subscription contract data directly from Shopify's GraphQL API. This endpoint returns the full Shopify subscription contract object exactly as Shopify provides it, including all nested fields, relationships, and GraphQL metadata. What This Endpoint Returns: Unlike processed/transformed endpoints, this returns Shopify's raw SubscriptionContract GraphQL object with all available fields. This is the same data structure you would receive if querying Shopify's GraphQL API directly, making it ideal for: - Debugging Shopify data synchronization issues - Accessing fields not exposed in other endpoints - Understanding complete Shopify contract structure - Building custom integrations requiring full data - Comparing Shopify source data with processed data Data Included: Contract Core: - Full subscription contract object from Shopify - All GraphQL __typename fields preserved - Complete nested object structures - All available Shopify contract fields Customer Information: - Complete customer object with all fields - Default address details - Customer tags and metadata - Marketing preferences Line Items: - Full line item details with edges/nodes structure - Product and variant complete objects - Pricing policies with all cycle discounts - Line item custom attributes - Current and original prices Billing & Delivery: - Complete billing policy object - Full delivery policy details - Delivery method with all fields - Delivery price breakdown - Billing anchor details Payment Information: - Payment method details (if available) - Customer payment instrument - Payment gateway information Orders & History: - Origin order details - Last payment status - Historical billing attempts (in Appstle) Use Cases: 1. Debugging & Troubleshooting: - Investigate data sync discrepancies - Verify what Shopify actually stores - Debug webhook payload issues - Compare expected vs actual data 2. Advanced Integrations: - Access Shopify-specific fields not in standard APIs - Build custom analytics using raw data - Integrate with Shopify GraphQL directly - Extract fields for custom processing 3. Data Analysis: - Analyze complete contract structure - Extract all available metadata - Build comprehensive data exports - Perform deep data audits 4. Development & Testing: - Understand Shopify's data model - Test new feature development - Verify API responses - Documentation and examples Response Structure: Returns SubscriptionContractQuery.SubscriptionContract object: json { "id": "gid://shopify/SubscriptionContract/123456789", "status": "ACTIVE", "nextBillingDate": "2024-03-15T00:00:00Z", "customer": { "id": "gid://shopify/Customer/987654321", "email": "customer@example.com", "displayName": "John Doe", "__typename": "Customer" }, "lines": { "edges": [ { "node": { "id": "gid://shopify/SubscriptionLine/111111", "quantity": 2, "variantId": "gid://shopify/ProductVariant/222222", "title": "Monthly Coffee Box", "variantTitle": "Medium Roast", "currentPrice": { "amount": "29.99", "currencyCode": "USD" }, "pricingPolicy": {...}, "__typename": "SubscriptionLine" } } ] }, "billingPolicy": { "interval": "MONTH", "intervalCount": 1, "minCycles": 3, "maxCycles": 12 }, "deliveryPolicy": {...}, "deliveryMethod": {...}, "__typename": "SubscriptionContract" } Important Considerations: Data Source: - Queries Shopify GraphQL API in real-time - NOT cached in Appstle database - Always returns current Shopify state - Subject to Shopify API rate limits Performance: - Slower than database queries (500-1500ms typical) - Makes real-time call to Shopify - Response size can be large (10-50 KB) - Use sparingly to avoid rate limits GraphQL Structure: - Includes __typename fields throughout - Uses GraphQL ID format (gid://shopify/...) - Nested edges/nodes structure for lists - All fields as defined in Shopify's schema Best Practices: 1. Use for Debugging: Perfect for troubleshooting data issues 2. Avoid Polling: Don't call repeatedly - use cached/processed endpoints instead 3. Cache Response: Cache the response if using for display 4. Parse Carefully: Handle GraphQL structure (edges/nodes) 5. Monitor Rate Limits: Each call counts against Shopify API limits When to Use vs Other Endpoints: Use this endpoint when: - Need complete Shopify contract data - Debugging synchronization issues - Accessing Shopify-specific fields - Building Shopify GraphQL integrations Use /api/external/v2/subscription-contract-details when: - Need processed, filtered contract data - Want faster response times - Querying multiple contracts - Building customer-facing UIs Authentication: Requires valid X-API-Key header ## Get subscription fulfillment details for latest order - [GET /api/external/v2/subscription-contract-details/subscription-fulfillments/{contractId}](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/getsubscriptionfulfillmentsexternalv2.md): Retrieves fulfillment information for the most recent successful order associated with a subscription contract. This includes tracking details, shipment status, delivery estimates, and fulfillment line items from Shopify. What This Endpoint Returns: Complete fulfillment data for the subscription's last successfully billed order, queried in real-time from Shopify's GraphQL API. Shows customers when and how their subscription items will be (or were) delivered. Fulfillment Data Included: Shipment Tracking: - Tracking numbers and URLs - Carrier information (USPS, FedEx, UPS, etc.) - Tracking company details - Tracking status updates Delivery Status: - Fulfillment status (fulfilled, in_transit, out_for_delivery, delivered, etc.) - Estimated delivery date - Actual delivery timestamp (if delivered) - Delivery method (shipping, pickup, local delivery) Fulfillment Details: - Fulfilled line items (which products shipped) - Quantities fulfilled - Fulfillment service (manual, automated, 3PL) - Fulfillment created/updated dates - Multiple fulfillments (if order shipped in parts) Location Information: - Fulfillment location/warehouse - Origin address details - Fulfillment service name Order Determination Logic: Which Order is Retrieved: 1. Finds most recent SUCCESS billing attempt for contract 2. If found: Uses that order's Shopify order ID 3. If none: Falls back to subscription's origin order ID 4. Queries Shopify for that order's fulfillments Why This Matters: - Shows CURRENT/LATEST fulfillment status - Not historical fulfillments from months ago - Reflects what customer is waiting for NOW - Updates after each new billing cycle Use Cases: 1. Customer Portal "Where's My Order": - Display tracking information - Show estimated delivery date - Provide carrier tracking links - Update fulfillment status 2. Subscription Order Tracking: - Track recurring order deliveries - Monitor fulfillment progress - Identify delayed shipments - Provide proactive delivery updates 3. Customer Support: - Answer "where is my order" questions - Verify shipment details - Troubleshoot delivery issues - Provide accurate tracking info 4. Automated Notifications: - Send tracking emails automatically - Notify customers of shipments - Alert on delivery completion - Trigger review request flows 5. Subscription Management: - Show fulfillment in subscription history - Display delivery patterns - Track fulfillment reliability - Monitor shipping performance Response Structure: Returns Shopify Order object with fulfillments: json { "id": "gid://shopify/Order/123456789", "name": "#1001", "fulfillmentOrders": { "edges": [ { "node": { "id": "gid://shopify/FulfillmentOrder/111111", "status": "SUCCESS", "fulfillments": { "edges": [ { "node": { "trackingInfo": [ { "number": "1Z999AA10123456784", "url": "https://wwwapps.ups.com/tracking/...", "company": "UPS" } ], "status": "IN_TRANSIT", "estimatedDeliveryAt": "2024-03-20T00:00:00Z", "deliveredAt": null } } ] } } } ] } } Common Scenarios: Scenario: Order Fulfilled & Shipped json { "trackingInfo": [{"number": "9400...", "company": "USPS"}], "status": "IN_TRANSIT", "estimatedDeliveryAt": "2024-03-18T00:00:00Z" } Scenario: Order Delivered json { "status": "DELIVERED", "deliveredAt": "2024-03-15T14:23:00Z" } Scenario: Not Yet Fulfilled json { "fulfillmentOrders": { "edges": [ { "node": { "status": "OPEN", "fulfillments": {"edges": []} } } ] } } Scenario: No Order Yet (New Subscription) Returns null or empty response Important Considerations: Real-Time Shopify Query: - Makes live call to Shopify GraphQL API - NOT cached data - Response time: 500-1500ms - Subject to Shopify rate limits Data Freshness: - Returns current fulfillment status from Shopify - Tracking updates reflect Shopify's data - May lag behind carrier's actual status - Shopify updates tracking periodically Null Responses: - Returns null if no orders exist yet - Returns null if order ID not found - Handle gracefully in UI Multiple Fulfillments: - Order may have multiple fulfillments (split shipments) - Each fulfillment has own tracking - Iterate through all fulfillment nodes Integration Example: Customer Portal - Track Shipment: javascript const order = await fetch( /api/external/v2/subscription-contract-details/subscription-fulfillments/${contractId}, { headers: { 'X-API-Key': 'your-key' } } ).then(r => r.json()); if (!order) { return 'No shipment information available yet.'; } const fulfillments = order.fulfillmentOrders?.edges || []; fulfillments.forEach(fo => { fo.node.fulfillments?.edges?.forEach(f => { const tracking = f.node.trackingInfo?.[0]; if (tracking) { console.log(Track with ${tracking.company}: ${tracking.number}); console.log(URL: ${tracking.url}); } }); }); Best Practices: 1. Cache Response: Cache for 30-60 minutes to reduce Shopify API calls 2. Handle Nulls: Always check for null/empty responses 3. Parse GraphQL: Navigate edges/nodes structure carefully 4. Show All Tracking: Display all fulfillments if multiple shipments 5. Link to Carrier: Provide clickable tracking URLs Authentication: Requires valid X-API-Key header ## Get current billing cycle number for a subscription contract - [GET /api/external/v2/subscription-contract-details/current-cycle/{contractId}](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/getcurrentcycleofsubscriptioncontractv2.md): 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: json 3 Response Examples: New subscription (just created): json 1 After 5 successful billing attempts: json 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 ( 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: javascript 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 ## Get available billing intervals for selling plan(s) - [GET /api/external/v2/subscription-contract-details/billing-interval](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/getsubscriptioncontractbillinginterval.md): 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: json [ { "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: javascript // 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 => ${freq.frequencyName} - Save ${freq.pricingPolicy.adjustmentValue}% ).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 ## Get subscription contract analytics and revenue metrics - [GET /api/external/v2/subscription-contract-details/analytics/{contractId}](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/getsubscriptioncontractanalyticsbycontractidexternalv2.md): 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: sql 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: json { "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: json { "totalOrders": 0, "totalOrderAmount": 0.00, "totalOrderRevenue": "$0.00" } After First Successful Order: json { "totalOrders": 1, "totalOrderAmount": 49.99, "totalOrderRevenue": "$49.99" } Established Subscription (EUR): json { "totalOrders": 24, "totalOrderAmount": 1199.76, "totalOrderRevenue": "€1.199,76" } Integration Examples: Customer Portal - Loyalty Display: javascript const analytics = await fetch( /api/external/v2/subscription-contract-details/analytics/${contractId}, { headers: { 'X-API-Key': 'your-key' } } ).then(r => r.json()); const loyaltyMessage = Thank you for your loyalty! You've received ${analytics.totalOrders} orders Total value: ${analytics.totalOrderRevenue} ; Revenue Dashboard: javascript // 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: javascript const aov = analytics.totalOrderAmount / analytics.totalOrders; console.log(Average order value: $${aov.toFixed(2)}); Customer Lifetime Value (projected): javascript const monthsActive = calculateMonthsActive(contract.createdAt); const monthlyRevenue = analytics.totalOrderAmount / monthsActive; const projectedLTV = monthlyRevenue * 12; // Annual LTV Authentication: Requires valid X-API-Key header ## Get delivery options for subscription contract - [GET /api/external/v2/data/contract-delivery-options](https://developers.subscription.appstle.com/external-api-swagger/subscription-management/getcontractdeliveryoptions.md): Retrieves all valid delivery methods available for a specific subscription contract. Returns shipping profiles and delivery options based on the contract's delivery address and product characteristics. Delivery Information Returned: - Available shipping profiles - Delivery methods for each profile - Shipping rates and costs - Delivery speed (standard, express, etc.) - Method names and descriptions - Eligibility based on address and products Filtering Behavior: By default, returns only delivery methods valid for the contract: - Matches delivery address country/region - Compatible with subscription products - Available for contract weight/dimensions Include All Methods: Use header X-Include-All-Methods: true to return all delivery methods regardless of eligibility. Useful for admin UIs where you want to show all options. Use Cases: - Display delivery method selector in customer portal - Allow customers to change shipping method - Calculate shipping costs for subscription - Validate delivery method during subscription updates - Show upgrade options (standard to express) Common Scenarios: Customer Portal - Change Delivery Speed: 1. Call this endpoint with contractId 2. Display available methods to customer 3. Customer selects preferred method 4. Update subscription with new delivery method ID Subscription Creation - Delivery Selection: 1. Get delivery options for draft contract 2. Present options during checkout/signup 3. Create subscription with selected method Important Notes: - Delivery options depend on current contract address - Changing address may change available methods - Costs may vary based on products in subscription - Some methods may have minimum order requirements - International shipping may have additional restrictions Authentication: Requires X-API-Key header