> ## 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.

# Add one-time product to subscription order

> 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



## OpenAPI

````yaml /subscription/admin-api-swagger.json put /api/external/v2/subscription-contract-one-offs-by-contractId-and-billing-attempt-id
openapi: 3.0.1
info:
  description: >-
    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.
  title: Admin APIs
  version: 0.0.1
servers:
  - url: https://subscription-admin.appstle.com
security: []
tags:
  - description: >-
      Core APIs for managing the complete subscription lifecycle including
      creation, updates, pausing, resuming, and cancellation of subscriptions.
    name: Subscription Management
  - description: >-
      APIs for managing subscription payment methods, processing payments,
      handling payment retries, and updating billing information.
    name: Subscription Payments
  - description: >-
      APIs for managing subscription contracts including delivery schedules,
      pricing, order notes, billing cycles, and shipping addresses.
    name: Subscription Contracts
  - description: >-
      APIs for managing products within subscriptions including adding,
      removing, updating quantities, and swapping products.
    name: Subscription Products
  - description: >-
      APIs for handling billing operations, payment processing, and financial
      transactions related to subscriptions.
    name: Billing & Payments
  - description: >-
      APIs for managing discounts and promotional codes applied to
      subscriptions.
    name: Subscription Discounts
  - description: >-
      APIs for managing one-time add-on products that can be purchased alongside
      recurring subscription items.
    name: Subscription One-Time Products
  - description: >-
      APIs for managing subscription plans, pricing tiers, and plan
      configurations.
    name: Subscription Plans
  - description: >-
      APIs for managing customizable product boxes and bundles where customers
      can select multiple items.
    name: Build-a-Box & Bundles
  - description: >-
      APIs for managing the product catalog including product information,
      variants, and inventory.
    name: Product Catalog
  - description: >-
      APIs for managing operational settings, configurations, and administrative
      functions.
    name: Operations & Settings
  - description: >-
      APIs powering the customer-facing portal where subscribers can manage
      their own subscriptions.
    name: Customer Portal
  - description: APIs for managing customer information, profiles, and account details.
    name: Customers
  - description: >-
      APIs for retrieving aggregated subscription data, customer subscription
      history, and account-level subscription information.
    name: Subscription Data
  - description: >-
      APIs for managing delivery profiles, shipping rates, free shipping
      configuration, and delivery method options on subscriptions.
    name: Delivery & Shipping
  - description: >-
      APIs for managing storefront customization including custom CSS, theme
      settings, label translations, and merchant-defined widget configuration.
    name: Customization
  - description: >-
      APIs for configuring cancellation flows, retention offers, cancellation
      reason management, and win-back automation.
    name: Customer Retention
paths:
  /api/external/v2/subscription-contract-one-offs-by-contractId-and-billing-attempt-id:
    put:
      tags:
        - Subscription One-Time Products
      summary: Add one-time product to subscription order
      description: >-
        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
      operationId: saveOneOffByV2
      parameters:
        - deprecated: true
          description: API Key (Deprecated - Use X-API-Key header instead)
          example: sk_live_1234567890abcdef
          in: query
          name: api_key
          required: false
          schema:
            type: string
        - description: >-
            API Key for authentication. This key identifies your shop and must
            be included in the X-API-Key header.
          example: sk_live_1234567890abcdef
          in: header
          name: X-API-Key
          required: true
          schema:
            type: string
        - description: The unique identifier of the subscription contract
          example: 98765
          in: query
          name: contractId
          required: true
          schema:
            format: int64
            minimum: 1
            type: integer
        - description: >-
            The billing attempt ID to add the product to. If invalid or not
            QUEUED, the system will automatically use the next upcoming order.
          example: 54321
          in: query
          name: billingAttemptId
          required: true
          schema:
            format: int64
            minimum: 1
            type: integer
        - description: The Shopify product variant ID to add as a one-time purchase
          example: 42549172011164
          in: query
          name: variantId
          required: true
          schema:
            format: int64
            minimum: 1
            type: integer
        - description: >-
            The handle/slug of the product variant for URL-friendly
            identification
          example: premium-coffee-blend-500g
          in: query
          name: variantHandle
          required: true
          schema:
            pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$
            type: string
        - description: The quantity of the product to add. Defaults to 1 if not specified.
          example: 2
          in: query
          name: quantity
          required: false
          schema:
            default: 1
            maximum: 999
            minimum: 1
            type: integer
      responses:
        '200':
          content:
            application/json:
              examples:
                First Product Added:
                  description: First one-time product added to this contract
                  value:
                    - billingAttemptId: 54321
                      id: 12351
                      price: 34.99
                      quantity: 3
                      shop: example-store.myshopify.com
                      subscriptionContractId: 98765
                      variantHandle: limited-edition-roast
                      variantId: 42549172011168
                Product Added Successfully:
                  description: >-
                    New product added to the list. Response includes all
                    one-time products for the contract.
                  value:
                    - billingAttemptId: 54321
                      id: 12345
                      price: 19.99
                      quantity: 2
                      shop: example-store.myshopify.com
                      subscriptionContractId: 98765
                      variantHandle: premium-coffee-blend-500g
                      variantId: 42549172011164
                    - billingAttemptId: 54321
                      id: 12350
                      price: 29.99
                      quantity: 1
                      shop: example-store.myshopify.com
                      subscriptionContractId: 98765
                      variantHandle: coffee-sampler-pack
                      variantId: 42549172011167
                Product Already Exists:
                  description: >-
                    Product already exists in the billing attempt. No duplicate
                    created. Returns existing list.
                  value:
                    - billingAttemptId: 54321
                      id: 12345
                      price: 19.99
                      quantity: 2
                      shop: example-store.myshopify.com
                      subscriptionContractId: 98765
                      variantHandle: premium-coffee-blend-500g
                      variantId: 42549172011164
              schema:
                items:
                  $ref: '#/components/schemas/SubscriptionContractOneOffDTO'
                type: array
          description: >-
            Successfully added one-time product or product already exists.
            Returns all one-time products for the contract.
        '400':
          content:
            application/json:
              examples:
                Contract Frozen:
                  description: >-
                    Contract has minimum cycle requirements that prevent
                    modifications
                  value:
                    detail: >-
                      Order modifications are frozen until minimum cycle
                      requirements are met
                    status: 400
                    title: Bad Request
                    type: https://example.com/probs/bad-request
                    violations:
                      field: contractId
                      message: frozen_until_min_cycles
                Invalid Parameter Format:
                  description: Invalid Parameter Format
                  value:
                    detail: >-
                      Failed to convert value of type 'java.lang.String' to
                      required type 'java.lang.Integer'; For input string: 'abc'
                    status: 400
                    title: Bad Request
                    type: https://example.com/probs/bad-request
                Missing Required Parameter:
                  description: Missing Required Parameter
                  value:
                    detail: >-
                      Required request parameter 'variantId' for method
                      parameter type Long is not present
                    status: 400
                    title: Bad Request
                    type: https://example.com/probs/bad-request
                No Upcoming Orders:
                  description: No QUEUED billing attempts exist for this contract
                  value:
                    detail: There is no upcoming order scheduled.
                    status: 400
                    title: Bad Request
                    type: https://example.com/probs/bad-request
                    violations:
                      field: data
                      message: idnull
              schema:
                $ref: '#/components/schemas/Problem'
          description: Bad request - validation failed or business rule violation
        '401':
          content:
            application/json:
              example:
                detail: Full authentication is required to access this resource
                status: 401
                title: Unauthorized
                type: https://example.com/probs/unauthorized
              schema:
                $ref: '#/components/schemas/Problem'
          description: Authentication required - missing or invalid API key
        '403':
          content:
            application/json:
              example:
                detail: Access denied - contract does not belong to authenticated shop
                status: 403
                title: Forbidden
                type: https://example.com/probs/forbidden
              schema:
                $ref: '#/components/schemas/Problem'
          description: >-
            Forbidden - contract belongs to different shop or insufficient
            permissions
components:
  schemas:
    SubscriptionContractOneOffDTO:
      description: >-
        Represents a one-time product added to a subscription contract for a
        specific billing attempt
      properties:
        billingAttemptId:
          description: >-
            The billing attempt ID this one-time product is associated with.
            This determines which upcoming order will include this product.
          example: 54321
          format: int64
          minimum: 1
          type: integer
        id:
          description: Unique identifier of the one-time product record
          example: 12345
          format: int64
          readOnly: true
          type: integer
        price:
          description: >-
            The price per unit of this product in the shop's base currency. This
            may include any applicable discounts.
          example: 19.99
          format: double
          maximum: 999999.99
          minimum: 0
          type: number
        quantity:
          description: The quantity of this product to include in the order
          example: 2
          format: int32
          maximum: 999
          minimum: 1
          type: integer
        shop:
          description: The Shopify store domain that owns this subscription
          example: example-store.myshopify.com
          pattern: ^[a-zA-Z0-9][a-zA-Z0-9-]*\.myshopify\.com$
          type: string
        subscriptionContractId:
          description: The subscription contract ID this one-time product belongs to
          example: 98765
          format: int64
          minimum: 1
          type: integer
        variantHandle:
          description: >-
            The handle/slug of the product variant for URL-friendly
            identification
          example: premium-coffee-blend-500g
          pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$
          type: string
        variantId:
          description: The Shopify product variant ID for this one-time product
          example: 42549172011164
          format: int64
          minimum: 1
          type: integer
      required:
        - shop
      type: object
    Problem:
      properties:
        detail:
          type: string
        instance:
          format: uri
          type: string
        parameters:
          additionalProperties:
            type: object
          type: object
        status:
          $ref: '#/components/schemas/StatusType'
        title:
          type: string
        type:
          format: uri
          type: string
      type: object
    StatusType:
      properties:
        reasonPhrase:
          type: string
        statusCode:
          format: int32
          type: integer
      type: object

````