# Remove multiple products from subscription Removes multiple product line items from an existing subscription contract in a single request. Products are removed sequentially, allowing partial success if errors occur. Key Features: - Sequential processing - items removed one by one - Partial success allowed - previous removals persist if later ones fail - Validates each removal against current subscription state - Smart discount cleanup for line-specific discounts - Comprehensive validation for each product removal - Triggers all side effects after each successful removal Processing Order Matters: Items are removed in the order provided: 1. First item validated and removed 2. Second item validated against updated state 3. Continue until all processed or error occurs 4. Returns final subscription state Validation Per Item: - Line item must exist in subscription - At least one recurring product must remain - Build-a-Box min/max quantities maintained - Minimum cycle commitments honored - One-time and free products don't count toward minimum Discount Handling: When removeDiscount=true: - Removes discounts applied ONLY to the removed line - Preserves discounts that apply to multiple lines - Each removal evaluates discounts independently - Build-a-Box discounts auto-adjust based on quantity Side Effects Per Removal: Each successful removal triggers: - Activity log entry created - Customer email sent (except one-time products) - Shipping price recalculation - Build-a-Box discount resync - Product discount adjustments Partial Success Scenarios: If removing 3 items and the 2nd fails: - 1st item: Successfully removed - 2nd item: Fails, error returned - 3rd item: Not attempted - Result: Subscription with 1st item removed Performance Considerations: - Each removal is a separate Shopify API transaction - Multiple emails may be sent to customer - Consider using single remove for 1-2 items - Large batches may timeout - Recommended max: 5-10 items per request Build-a-Box Handling: For Build-a-Box subscriptions: - Validates total quantity after EACH removal - May fail mid-batch if minimum breached - Discounts recalculate after each item - Consider removal order carefully Important Notes: - NOT atomic - no rollback on partial failure - Order of line IDs affects success probability - Customer receives email per removed item - All validations apply as if removing individually - Response shows final state after all attempts Authentication: Requires valid X-API-Key header Endpoint: PUT /api/external/v2/subscription-contracts-remove-line-items Version: 0.0.1 ## Query parameters: - `contractId` (integer, required) Subscription contract ID to remove products from Example: 123456789 - `removeDiscount` (boolean) When true, removes discounts that apply only to each removed line item. When false, attempts to retain all discounts. Discounts that apply to multiple lines are always retained regardless of this setting. - `api_key` (string) API Key (Deprecated - Use Header X-API-Key instead) ## Header parameters: - `X-API-Key` (string, required) API Key for authentication ## Response 200 fields (application/json): - `get__typename` (string) - `id` (string) - `createdAt` (object) - `updatedAt` (object) - `nextBillingDate` (object) - `status` (string) Enum: "ACTIVE", "PAUSED", "CANCELLED", "EXPIRED", "FAILED", "$UNKNOWN" - `deliveryPrice` (object) - `deliveryPrice.amount` (object) - `deliveryPrice.currencyCode` (string) Enum: "USD", "EUR", "GBP", "CAD", "AFN", "ALL", "DZD", "AOA", "ARS", "AMD", "AWG", "AUD", "BBD", "AZN", "BDT", "BSD", "BHD", "BIF", "BYN", "BZD", "BMD", "BTN", "BAM", "BRL", "BOB", "BWP", "BND", "BGN", "MMK", "KHR", "CVE", "KYD", "XAF", "CLP", "CNY", "COP", "KMF", "CDF", "CRC", "HRK", "CZK", "DKK", "DJF", "DOP", "XCD", "EGP", "ERN", "ETB", "FKP", "XPF", "FJD", "GIP", "GMD", "GHS", "GTQ", "GYD", "GEL", "GNF", "HTG", "HNL", "HKD", "HUF", "ISK", "INR", "IDR", "ILS", "IRR", "IQD", "JMD", "JPY", "JEP", "JOD", "KZT", "KES", "KID", "KWD", "KGS", "LAK", "LVL", "LBP", "LSL", "LRD", "LYD", "LTL", "MGA", "MKD", "MOP", "MWK", "MVR", "MRU", "MXN", "MYR", "MUR", "MDL", "MAD", "MNT", "MZN", "NAD", "NPR", "ANG", "NZD", "NIO", "NGN", "NOK", "OMR", "PAB", "PKR", "PGK", "PYG", "PEN", "PHP", "PLN", "QAR", "RON", "RUB", "RWF", "WST", "SHP", "SAR", "RSD", "SCR", "SLL", "SGD", "SDG", "SOS", "SYP", "ZAR", "KRW", "SSP", "SBD", "LKR", "SRD", "SZL", "SEK", "CHF", "TWD", "THB", "TJS", "TZS", "TOP", "TTD", "TND", "TRY", "TMT", "UGX", "UAH", "AED", "UYU", "UZS", "VUV", "VES", "VND", "XOF", "YER", "ZMW", "USDC", "BYR", "STD", "STN", "VED", "VEF", "XXX", "$UNKNOWN" - `lastPaymentStatus` (string) Enum: "SUCCEEDED", "FAILED", "$UNKNOWN" - `billingPolicy` (object) - `billingPolicy.interval` (string) Enum: "DAY", "WEEK", "MONTH", "YEAR", "$UNKNOWN" - `billingPolicy.intervalCount` (integer) - `billingPolicy.anchors` (array) - `billingPolicy.anchors.cutoffDay` (integer) - `billingPolicy.anchors.day` (integer) - `billingPolicy.anchors.month` (integer) - `billingPolicy.anchors.type` (string) Enum: "WEEKDAY", "MONTHDAY", "YEARDAY", "$UNKNOWN" - `billingPolicy.maxCycles` (integer) - `billingPolicy.minCycles` (integer) - `deliveryPolicy` (object) - `lines` (object) - `lines.nodes` (array) - `lines.nodes.sellingPlanId` (string) - `lines.nodes.sellingPlanName` (string) - `lines.nodes.productId` (string) - `lines.nodes.sku` (string) - `lines.nodes.title` (string) - `lines.nodes.variantId` (string) - `lines.nodes.quantity` (integer) - `lines.nodes.customAttributes` (array) - `lines.nodes.customAttributes.key` (string) - `lines.nodes.customAttributes.value` (string) - `lines.nodes.lineDiscountedPrice` (object) - `lines.nodes.variantImage` (object) - `lines.nodes.variantImage.transformedSrc` (object) - `lines.nodes.variantTitle` (string) - `lines.nodes.currentPrice` (object) - `lines.nodes.discountAllocations` (array) - `lines.nodes.discountAllocations.discount` (object) - `lines.nodes.pricingPolicy` (object) - `lines.nodes.pricingPolicy.basePrice` (object) - `lines.nodes.pricingPolicy.cycleDiscounts` (array) - `lines.nodes.pricingPolicy.cycleDiscounts.afterCycle` (integer) - `lines.nodes.pricingPolicy.cycleDiscounts.computedPrice` (object) - `lines.nodes.pricingPolicy.cycleDiscounts.adjustmentType` (string) Enum: "PERCENTAGE", "FIXED_AMOUNT", "PRICE", "$UNKNOWN" - `lines.nodes.pricingPolicy.cycleDiscounts.adjustmentValue` (object) - `lines.nodes.taxable` (boolean) - `lines.pageInfo` (object) - `lines.pageInfo.hasPreviousPage` (boolean) - `lines.pageInfo.hasNextPage` (boolean) - `lines.pageInfo.startCursor` (string) - `lines.pageInfo.endCursor` (string) - `customerPaymentMethod` (object) - `customerPaymentMethod.instrument` (object) - `customerPaymentMethod.revokedAt` (object) - `customerPaymentMethod.revokedReason` (string) Enum: "AUTHORIZE_NET_GATEWAY_NOT_ENABLED", "AUTHORIZE_NET_RETURNED_NO_PAYMENT_METHOD", "FAILED_TO_UPDATE_CREDIT_CARD", "STRIPE_API_AUTHENTICATION_ERROR", "STRIPE_API_INVALID_REQUEST_ERROR", "STRIPE_GATEWAY_NOT_ENABLED", "STRIPE_RETURNED_NO_PAYMENT_METHOD", "STRIPE_PAYMENT_METHOD_NOT_CARD", "BRAINTREE_API_AUTHENTICATION_ERROR", "BRAINTREE_GATEWAY_NOT_ENABLED", "BRAINTREE_RETURNED_NO_PAYMENT_METHOD", "BRAINTREE_PAYMENT_METHOD_NOT_CARD", "PAYMENT_METHOD_VERIFICATION_FAILED", "THREE_D_SECURE_FLOW_IN_VERIFICATION_NOT_IMPLEMENTED", "MANUALLY_REVOKED", "FAILED_TO_RETRIEVE_BILLING_ADDRESS", "MERGED", "CUSTOMER_REDACTED", "TOO_MANY_CONSECUTIVE_FAILURES", "CVV_ATTEMPTS_LIMIT_EXCEEDED", "$UNKNOWN" - `deliveryMethod` (object) - `originOrder` (object) - `originOrder.name` (string) - `originOrder.fulfillmentOrders` (object) - `customer` (object) - `customer.displayName` (string) - `customer.firstName` (string) - `customer.lastName` (string) - `customer.email` (string) - `customer.phone` (string) - `discounts` (object) - `note` (string) - `billingAttempts` (object) ## Response 207 fields ## Response 400 fields ## Response 401 fields ## Response 403 fields ## Response 404 fields ## Response 422 fields