Docs
Firmly Agentic Commerce
Set theme to dark (⇧+D)

Add Line Item

POST https://api.firmly.work/api/v2/domains/{domain}/cart/line-items

​​ Overview

The Add Line Item endpoint adds a new product to the shopping cart with these features:

  • Automatic Shipment Assignment: Once a shipping address is set, items are automatically grouped into shipments based on their fulfillment requirements — see Shipping & Fulfillment
  • Catalog Integration: Uses add_to_cart_ref object directly from catalog API responses
  • Variant Support: Handles configurable products with variant handles
  • Cart Creation: Automatically creates a new cart if one doesn’t exist
  • Optional Cart Clearing: Can clear existing cart before adding new item

​​ Authentication

  • x-firmly-authorization (string, required) — Device access token from Browser Session

​​ Path Parameters

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

​​ Query Parameters

  • flush_cart (string "true" | "false", default "false") — When "true", clears the cart before adding the new item. This is a string, not a boolean — only the exact lowercase strings "true"/"false" are accepted; any other value (1, 0, True, empty string) returns 400 InvalidInputQuery rather than being treated as falsy.

​​ Request Body

  • add_to_cart_ref (object, required) — Product reference from catalog API containing variant information Properties:

    • variant_id (string, required): Product variant identifier
    • product_id (string, optional): Parent product identifier
    • variant_handles (array, optional): Array of variant configuration handles (e.g., ["color:blue", "size:large"])
  • quantity (integer, required) — Quantity to add (minimum 1). Numeric strings (e.g. "2") are also accepted and coerced to a number.

​​ Response

Returns the complete shopping cart including the newly added item. See Get Cart for full response schema.

​​ Key Response Features:

  • shipments (array) — Empty until a shipping address is set. Shipment grouping is populated by Set Shipping Info.

  • addons.offers (array) — Available addon services for the updated cart. Offer fields such as coverage_mode, eligible_line_item_ids, and child_offers are documented in Addon Management.

  • schema_version (string) — Indicates the cart schema version

​​ Code Examples


curl --request POST \
--url https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/line-items \
--header 'Content-Type: application/json' \
--header 'x-firmly-authorization: YOUR_TOKEN' \
--data '{
"add_to_cart_ref": {
"variant_id": "WS12-XS-Orange"
},
"quantity": 1
}'

const response = await fetch('https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/line-items', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-firmly-authorization': 'YOUR_TOKEN'
},
body: JSON.stringify({
add_to_cart_ref: {
variant_id: 'WS12-XS-Orange'
},
quantity: 1
})
});
const cart = await response.json();
console.log(cart);

import requests
response = requests.post(
'https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/line-items',
headers={
'Content-Type': 'application/json',
'x-firmly-authorization': 'YOUR_TOKEN'
},
json={
'add_to_cart_ref': {
'variant_id': 'WS12-XS-Orange'
},
'quantity': 1
}
)
cart = response.json()
print(cart)

<?php
$curl = curl_init();
$data = [
'add_to_cart_ref' => [
'variant_id' => 'WS12-XS-Orange'
],
'quantity' => 1
];
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/line-items",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-firmly-authorization: YOUR_TOKEN"
],
CURLOPT_POSTFIELDS => json_encode($data)
]);
$response = curl_exec($curl);
curl_close($curl);
$cart = json_decode($response, true);
print_r($cart);
?>

​​ Advanced Examples

​​ With Variant Handles

For configurable products with multiple options:


{
"add_to_cart_ref": {
"variant_id": "MH07-XS-Gray",
"variant_handles": ["color:gray", "size:xs"]
},
"quantity": 1
}

​​ Clear Cart First

To replace cart contents with a new item:


curl --request POST \
--url 'https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/line-items?flush_cart=true' \
--header 'Content-Type: application/json' \
--header 'x-firmly-authorization: YOUR_TOKEN' \
--data '{
"add_to_cart_ref": {
"variant_id": "WT09-XS-White"
},
"quantity": 2
}'

​​ Catalog Integration

The add_to_cart_ref object should be passed directly from catalog API responses:


{
"products": [
{
"product_id": "WS12",
"variants": [
{
"add_to_cart_ref": {
"variant_id": "WS12-XS-Orange",
"variant_handles": ["color:orange", "size:xs"]
}
}
]
}
]
}

{
"add_to_cart_ref": {
"variant_id": "WS12-XS-Orange",
"variant_handles": ["color:orange", "size:xs"]
},
"quantity": 1
}

​​ Response Example


{
"line_items": [
{
"line_item_id": "9b13b973-8d55-5d00-b22a-1b1b788d80f9",
"platform_line_item_id": "0",
"sku": "WS12-XS-Orange",
"variant_description": "Color: Orange, Size: XS",
"description": "Radiant Tee",
"base_sku": "WS12",
"quantity": 1,
"price": {
"currency": "USD",
"value": 22.00,
"number": 2200,
"symbol": "$"
},
"line_price": {
"currency": "USD",
"value": 22.00,
"number": 2200,
"symbol": "$"
},
"msrp": {
"currency": "USD",
"value": 22.00,
"number": 2200,
"symbol": "$"
},
"image": {
"url": "https://cdn.staging.luma.gift/product/radiant-tee-orange.jpg",
"alt": "Radiant Tee in Orange",
"type": "default"
},
"requires_shipping": true
}
],
"shipments": [],
"sub_total": {
"currency": "USD",
"value": 22.00,
"number": 2200,
"symbol": "$"
},
"shipping_total": {
"currency": "USD",
"value": 0,
"number": 0,
"symbol": "$"
},
"tax_total": {
"currency": "USD",
"value": 0,
"number": 0,
"symbol": "$"
},
"fees": [
{
"description": "Recycle fee",
"currency": "USD",
"value": 2.00,
"number": 200,
"symbol": "$"
}
],
"fee_total": {
"currency": "USD",
"value": 2.00,
"number": 200,
"symbol": "$"
},
"total": {
"currency": "USD",
"value": 24.00,
"number": 2400,
"symbol": "$"
},
"addons": {
"offers": [
{
"addon_id": "protection-new-item-12345",
"display": {
"name": "Product Protection Plan"
},
"price": {
"currency": "USD",
"value": 0,
"number": 0,
"symbol": "$"
},
"scope": "ITEM",
"coverage_mode": "PER_ITEM",
"eligible_line_item_ids": [
"9b13b973-8d55-5d00-b22a-1b1b788d80f9"
],
"child_offers": [
{
"addon_id": "A0-FURN-2y",
"display": {
"name": "2 Year Protection"
},
"scope": "INHERIT",
"coverage_mode": "PER_ITEM",
"eligible_line_item_ids": [
"9b13b973-8d55-5d00-b22a-1b1b788d80f9"
],
"price": {
"currency": "USD",
"value": 149.99,
"number": 14999,
"symbol": "$"
}
},
{
"addon_id": "A0-FURN-3y",
"display": {
"name": "3 Year Protection"
},
"scope": "INHERIT",
"coverage_mode": "PER_ITEM",
"eligible_line_item_ids": [
"9b13b973-8d55-5d00-b22a-1b1b788d80f9"
],
"price": {
"currency": "USD",
"value": 199.99,
"number": 19999,
"symbol": "$"
}
}
]
}
],
"selections": []
},
"addon_total": {
"currency": "USD",
"value": 0,
"number": 0,
"symbol": "$"
},
"schema_version": "2.0"
}

​​ Error Responses

Errors return a JSON body with code, error, and description. Program against the error value — descriptions are human-readable and may change.

400 — MissingAuthHeader

The x-firmly-authorization header is missing or empty.


{
"code": 400,
"error": "MissingAuthHeader",
"description": "x-firmly-authorization header is missing or invalid."
}
400 — InvalidToken

The authorization token is not a valid JWT structure.


{
"code": 400,
"error": "InvalidToken",
"description": "Jwt token is invalid."
}
400 — InvalidAPIToken

The API token (server-to-server secret) is invalid or has been revoked.


{
"code": 400,
"error": "InvalidAPIToken",
"description": "API token is invalid."
}
400 — BadRequest

Server-to-server auth was attempted but the required headers (x-firmly-authorization plus x-firmly-device-id) are missing or malformed.


{
"code": 400,
"error": "BadRequest",
"description": "Bad request."
}
401 — Unauthorized

The authorization token was rejected.


{
"code": 401,
"error": "Unauthorized",
"description": "Unauthorized."
}
401 — InvalidJWTToken

The device JWT signature does not verify, or required claims are missing.


{
"code": 401,
"error": "InvalidJWTToken",
"description": "Jwt token is invalid."
}
404 — PartnerNotFound

The appid claim on the device JWT does not map to a known partner / tenant — typically a token from a different environment.


{
"code": 404,
"error": "PartnerNotFound",
"description": "Partner not found."
}
404 — DomainNotFound

The {domain} path parameter does not match any merchant configured with Firmly, or the merchant has been disabled. Verify the domain string (case-sensitive, no protocol or trailing slash).


{
"code": 404,
"error": "DomainNotFound",
"description": "This domain was not found in firmly servers."
}
404 — ProductNotFound

The variant_id supplied in add_to_cart_ref does not exist in the merchant catalog. Refresh from the Catalog API and retry with a current ID.


{
"code": 404,
"error": "ProductNotFound",
"description": "Product not found."
}
409 — NotEnoughStockError

The requested quantity exceeds available inventory for the variant. Reduce quantity or wait for restock.


{
"code": 409,
"error": "NotEnoughStockError",
"description": "Not enough stock."
}
409 — CannotCreateCart

The merchant system rejected creation of a new cart. Often transient — retry; if it persists, check merchant system health.


{
"code": 409,
"error": "CannotCreateCart",
"description": "Cannot create cart."
}
412 — ProductNotSupported

The product type is not supported by this merchant’s adapter (e.g. some adapters reject gift cards, digital-only SKUs, or subscription items).


{
"code": 412,
"error": "ProductNotSupported",
"description": "Product is not supported."
}
412 — PostalCodeRequired

The merchant requires a postal code before items can be added. Call Set Postal Code, then retry.


{
"code": 412,
"error": "PostalCodeRequired",
"description": "Postal code is required."
}
412 — OperationNotSupported

The merchant’s platform does not support this operation. Some platform adapters do not implement every cart operation; check with Firmly whether this endpoint is available for the merchant.


{
"code": 412,
"error": "OperationNotSupported",
"description": "This operation is not supported for this store."
}
412 — NoLineItemError

The merchant accepted the request but did not return a line item — typically indicates a product was silently rejected by merchant validation. Verify the variant is purchasable and try again.


{
"code": 412,
"error": "NoLineItemError",
"description": "No line item."
}
400 — InvalidInputBody

Request body is missing required fields or fails schema validation. Ensure add_to_cart_ref.variant_id and quantity are present and quantity >= 1.


{
"code": 400,
"error": "InvalidInputBody",
"description": "The body is not processable"
}