# Subscription One-Time Products APIs for managing one-time add-on products that can be purchased alongside recurring subscription items. ## Add one-time product to subscription order - [PUT /api/external/v2/subscription-contract-one-offs-by-contractId-and-billing-attempt-id](https://developers.subscription.appstle.com/external-api-swagger/subscription-one-time-products/saveoneoffbyv2.md): Adds a one-time product (add-on) to a specific subscription order. The product will be included only in the specified billing attempt and will not recur in future orders. This endpoint is idempotent - attempting to add the same product to the same billing attempt will return success without creating duplicates. Important Behaviors: - If the specified billingAttemptId is not valid or not QUEUED, the system will automatically add the product to the next upcoming order - The system prevents duplicate products (same variantId) in the same billing attempt - Products are automatically removed after the associated order is processed - Activity logs are created for audit trails Validation Rules: - Contract must belong to the authenticated shop - Contract must not be frozen (minimum cycles restriction) - At least one QUEUED billing attempt must exist - Variant must be a valid Shopify product variant Use Cases: - Allow customers to add special items to their next delivery - Enable upselling opportunities in customer portals - Programmatically add promotional or seasonal items - Implement "try before you subscribe" features Authentication: Requires valid X-API-Key header that identifies the shop ## Remove one-time product from subscription order - [DELETE /api/external/v2/subscription-contract-one-offs-by-contractId-and-billing-attempt-id](https://developers.subscription.appstle.com/external-api-swagger/subscription-one-time-products/deleteoneoffbyv2.md): Removes a previously added one-time product from a specific subscription order. This permanently deletes the one-time product from the specified billing attempt. The operation is idempotent - attempting to delete a non-existent product will succeed without error. Important Notes: - Only removes the product from the specified billing attempt - Cannot remove products from billing attempts that are already processed - Activity logs are created for audit trails - Returns the updated list of all one-time products for the contract Use Cases: - Allow customers to remove unwanted add-ons before order processing - Clean up cart-like functionality in customer portals - Programmatically manage one-time product selections - Implement "undo" functionality for product additions Business Rules: - Contract must belong to the authenticated shop - The specific combination of contractId + billingAttemptId + variantId identifies the product to remove - No error is thrown if the product doesn't exist (idempotent operation) Authentication: Requires valid X-API-Key header that identifies the shop ## Get one-time products for next upcoming order - [GET /api/external/v2/upcoming-subscription-contract-one-offs-by-contractId](https://developers.subscription.appstle.com/external-api-swagger/subscription-one-time-products/getoneoffforcontractnextorderexternal.md): Retrieves one-time products that will be included in the next scheduled order for a subscription contract. This endpoint specifically returns products associated with the earliest queued billing attempt, making it ideal for showing customers what additional items will be in their next delivery. Key Differences from /subscription-contract-one-offs-by-contractId: - Returns ONLY products for the next upcoming order (not all future orders) - Finds the earliest QUEUED billing attempt by date - Returns empty array if no queued billing attempts exist - Useful for "Your Next Order" previews in customer portals Use Cases: - Display a preview of the next order including one-time add-ons - Calculate the total cost of the upcoming delivery - Show customers their next delivery date with associated one-time items - Allow last-minute modifications before order processing Business Logic: 1. Searches for billing attempts with status = QUEUED 2. Selects the one with the earliest billing date 3. Returns all one-time products for that specific billing attempt 4. Returns empty array if no queued orders exist (e.g., subscription paused/cancelled) Authentication: Requires valid X-API-Key header that identifies the shop