Skip to main content
POST
https://api.firmly.work
/
api
/
v2
/
domains
/
{domain}
/
cart
/
addons
Add Addon
curl --request POST \
  --url https://api.firmly.work/api/v2/domains/{domain}/cart/addons \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "selections": [
    {}
  ]
}
'
{
  "cart_id": "cart-12345",
  "platform_id": "shopify",
  "shop_id": "staging.luma.gift",
  "display_name": "Luma Store",
  "cart_status": "active",
  "line_items": [
    {
      "line_item_id": "item-1",
      "variant_id": "MH07-XS-Gray",
      "quantity": 1,
      "price": {
        "currency": "USD",
        "value": 54.00,
        "number": 5400,
        "symbol": "$"
      }
    },
    {
      "line_item_id": "item-2",
      "variant_id": "WS12-XS-Orange",
      "quantity": 1,
      "price": {
        "currency": "USD",
        "value": 22.00,
        "number": 2200,
        "symbol": "$"
      }
    }
  ],
  "shipments": [
    {
      "shipment_id": "shipment-1",
      "line_item_ids": ["item-1", "item-2"],
      "fulfillment_type": {
        "id": "SHIP_TO_ADDRESS",
        "name": "Ship to Address"
      }
    }
  ],
  "addons": {
    "offers": [
      {
        "addon_id": "shipping_protection",
        "display": {
          "name": "Shipping Protection",
          "description": "Protect your entire order against shipping damage"
        },
        "scope": "CART",
        "coverage_mode": "PREDEFINED_GROUP",
        "price": {
          "currency": "USD",
          "value": 4.99,
          "number": 499,
          "symbol": "$"
        }
      },
      {
        "addon_id": "extended_warranty",
        "display": {
          "name": "Extended Warranty - 3 Year",
          "description": "Comprehensive coverage beyond manufacturer warranty"
        },
        "scope": "ITEM",
        "coverage_mode": "PER_ITEM",
        "eligible_line_item_ids": ["item-1", "item-2"],
        "line_item_pricing": {
          "item-1": {
            "price": {
              "currency": "USD",
              "value": 5.40,
              "number": 540,
              "symbol": "$"
            }
          },
          "item-2": {
            "price": {
              "currency": "USD",
              "value": 2.20,
              "number": 220,
              "symbol": "$"
            }
          }
        }
      }
    ],
    "selections": [
      {
        "addon_id": "shipping_protection",
        "price": {
          "currency": "USD",
          "value": 4.99,
          "number": 499,
          "symbol": "$"
        }
      }
    ]
  },
  "sub_total": {
    "currency": "USD",
    "value": 76.00,
    "number": 7600,
    "symbol": "$"
  },
  "addon_total": {
    "currency": "USD",
    "value": 4.99,
    "number": 499,
    "symbol": "$"
  },
  "total": {
    "currency": "USD",
    "value": 80.99,
    "number": 8099,
    "symbol": "$"
  },
  "schema_version": "2.0"
}

Overview

The Add Addon endpoint enables customers to select value-added services offered by the merchant. Addons can apply at different scopes:

Cart-Level

Applies to entire order (e.g., shipping protection)

Item-Level

Applies to specific items (e.g., protection plans)

Group-Level

Applies to item groups (e.g., service bundles)

Authentication

x-firmly-authorization
string
required
Device authentication token to identify and map the session

Path Parameters

domain
string
required
Domain of the merchant website (e.g., staging.luma.gift)

Request Body

selections
array
required
Array containing a single addon selection. Only one addon should be modified per request to map to UI events like checkbox or radio button clicks.Selection Object Properties:
  • addon_id (string, required): Unique identifier for the addon to select
  • selected_line_item_ids (array, optional): For item-level addons: array of line item IDs to apply the addon to
  • selected_child_ids (array, optional): For hierarchical addons: array of child addon IDs to include

Response

Returns the complete shopping cart with updated addon selections and recalculated pricing.

Key Response Fields:

addons.offers
array
All available addon options based on cart contents
addons.selections
array
Currently selected addons with pricing details
addon_total
object
Total cost of all selected addons
schema_version
string
API schema version

Code Examples by Tier

Cart-Level Addon (Shipping Protection)

curl --request POST \
  --url https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/addons \
  --header 'Content-Type: application/json' \
  --header 'x-firmly-authorization: YOUR_TOKEN' \
  --data '{
    "selections": [
      {
        "addon_id": "shipping_protection"
      }
    ]
  }'

Item-Level Addon (Extended Warranty)

Apply extended warranty to specific items with per-item pricing:
{
  "selections": [
    {
      "addon_id": "extended_warranty",
      "selected_line_item_ids": ["item-1", "item-2"]
    }
  ]
}

Group-Level Addon

Apply service to a predefined group of items:
{
  "selections": [
    {
      "addon_id": "remove-mattress123",
      "selected_line_item_ids": ["item-1", "item-2"]
    }
  ]
}

Hierarchical Addon (Protection Plans)

Select a parent addon with child options:
{
  "selections": [
    {
      "addon_id": "protection-sofa-001",
      "selected_line_item_ids": ["item-1"],
      "selected_child_ids": ["FPP-3YR"]
    }
  ]
}

Advanced Examples

Adding Multiple Addons

To add multiple addons to a cart, make separate API calls for each addon:
// Add shipping protection
await addAddon({
  selections: [{
    addon_id: "shipping_protection"
  }]
});

// Add extended warranty
await addAddon({
  selections: [{
    addon_id: "extended_warranty",
    selected_line_item_ids: ["item-1", "item-2"]
  }]
});

// Add gift wrapping
await addAddon({
  selections: [{
    addon_id: "gift_wrap",
    selected_line_item_ids: ["item-3"]
  }]
});
Each addon selection requires a separate API call. This design maps to individual UI events like checkbox or radio button clicks, ensuring proper tracking and state management.

Complex Addon Selection

Some addons support hierarchical selections with child options:
{
  "selections": [
    {
      "addon_id": "personalization",
      "selected_line_item_ids": ["item-1"],
      "selected_child_ids": ["engraving_option"]
    }
  ]
}
{
  "cart_id": "cart-12345",
  "platform_id": "shopify",
  "shop_id": "staging.luma.gift",
  "display_name": "Luma Store",
  "cart_status": "active",
  "line_items": [
    {
      "line_item_id": "item-1",
      "variant_id": "MH07-XS-Gray",
      "quantity": 1,
      "price": {
        "currency": "USD",
        "value": 54.00,
        "number": 5400,
        "symbol": "$"
      }
    },
    {
      "line_item_id": "item-2",
      "variant_id": "WS12-XS-Orange",
      "quantity": 1,
      "price": {
        "currency": "USD",
        "value": 22.00,
        "number": 2200,
        "symbol": "$"
      }
    }
  ],
  "shipments": [
    {
      "shipment_id": "shipment-1",
      "line_item_ids": ["item-1", "item-2"],
      "fulfillment_type": {
        "id": "SHIP_TO_ADDRESS",
        "name": "Ship to Address"
      }
    }
  ],
  "addons": {
    "offers": [
      {
        "addon_id": "shipping_protection",
        "display": {
          "name": "Shipping Protection",
          "description": "Protect your entire order against shipping damage"
        },
        "scope": "CART",
        "coverage_mode": "PREDEFINED_GROUP",
        "price": {
          "currency": "USD",
          "value": 4.99,
          "number": 499,
          "symbol": "$"
        }
      },
      {
        "addon_id": "extended_warranty",
        "display": {
          "name": "Extended Warranty - 3 Year",
          "description": "Comprehensive coverage beyond manufacturer warranty"
        },
        "scope": "ITEM",
        "coverage_mode": "PER_ITEM",
        "eligible_line_item_ids": ["item-1", "item-2"],
        "line_item_pricing": {
          "item-1": {
            "price": {
              "currency": "USD",
              "value": 5.40,
              "number": 540,
              "symbol": "$"
            }
          },
          "item-2": {
            "price": {
              "currency": "USD",
              "value": 2.20,
              "number": 220,
              "symbol": "$"
            }
          }
        }
      }
    ],
    "selections": [
      {
        "addon_id": "shipping_protection",
        "price": {
          "currency": "USD",
          "value": 4.99,
          "number": 499,
          "symbol": "$"
        }
      }
    ]
  },
  "sub_total": {
    "currency": "USD",
    "value": 76.00,
    "number": 7600,
    "symbol": "$"
  },
  "addon_total": {
    "currency": "USD",
    "value": 4.99,
    "number": 499,
    "symbol": "$"
  },
  "total": {
    "currency": "USD",
    "value": 80.99,
    "number": 8099,
    "symbol": "$"
  },
  "schema_version": "2.0"
}

Understanding Addon Pricing

Single price for entire order
{
  "addon_id": "shipping_protection",
  "scope": "CART",
  "price": { "value": 4.99 }  // One price for whole cart
}

Error Responses

Invalid request format or missing required parameters
{
  "code": 400,
  "error": "ErrorInvalidInputBody",
  "description": "Request body validation failed"
}
Cart does not exist
{
  "code": 404,
  "error": "ErrorCartNotFound",
  "description": "Cart not found for this domain"
}
Addon constraints violated
{
  "code": 422,
  "error": "ErrorUnprocessableEntity",
  "description": "Addon not eligible for selected items"
}

Addon Eligibility Rules

Addons are offered based on merchant rules:
  • Item eligibility and categories
  • Business logic and thresholds
  • Merchant configuration
  • Product-specific requirements

Common Constraints

Required Addons

Some addons must be selected before checkout
{
  "required": true,
  "message": "Please select a delivery option"
}

Exclusive Selection

Only one addon from a group can be selected
{
  "selection_group": "warranty_options",
  "multiple": false
}

Best Practices

Implementation Tips:
  1. Always check eligible_line_item_ids before applying addons
  2. Make one API call per addon selection (don’t batch multiple addons)
  3. For hierarchical addons, select appropriate child IDs
  4. Handle group addons by including all related line items
  5. Update UI immediately after each addon selection
  6. Show clear pricing breakdown for transparency
  7. For radio button groups, remove the previous selection before adding the new one