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

Remove Addon

POST https://api.firmly.work/api/v2/domains/{domain}/cart/addons/_remove

POST /api/v2/domains/{domain}/cart/addons/_remove

Removes a single addon from cart.addons.selections. The request can target three granularities:

  • Whole addon — supply addon_id only. Removes the addon entirely (and all its children).
  • One line item — supply addon_id + deselected_line_item_id. Removes the addon from that line item only; other items keep it.
  • One child — supply addon_id + deselected_child_id. Deselects that child while leaving the parent (and other children) intact.

To set the cart’s addons in bulk (clear all, or replace), use Add Addons.

​​ Authentication

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

​​ Path Parameters

  • domain (string, required) — The merchant’s domain (e.g. staging.luma.gift).

​​ Request Body

  • addon_id (string, required) — The addon_id of the addon to remove from cart.addons.selections.

  • deselected_line_item_id (string) — Limit removal to one line item. Omit to remove the addon from every line item where it was attached.

  • deselected_child_id (string) — Limit removal to one child selection (when the addon has child_offers).

​​ Response

Returns the full cart (same schema as Get Cart). After removal:

  • cart.addons.selections is updated.
  • cart.addons.offers may be re-evaluated (e.g. previously-locked offers become available again).
  • cart.addon_total, cart.total are recalculated.

​​ Examples


curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/addons/_remove \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addon_id": "shipping_protection"
}'

curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/addons/_remove \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addon_id": "extended_warranty",
"deselected_line_item_id": "38d3f385-ea8d-8bb2-dcfc-759ac85af6ef"
}'

curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/addons/_remove \
-H "x-firmly-authorization: YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"addon_id": "extended_warranty",
"deselected_child_id": "EW-2YR"
}'

​​ Response Example


{
"cart_id": "a5600193-2c13-3356-d063-711da63b7cd7",
"platform_id": "example_commerce",
"shop_id": "staging.luma.gift",
"cart_status": "active",
"line_items": [
{
"line_item_id": "761ff52b-8e6d-d373-fdf2-91a1a70df20c",
"sku": "MH07-XS-Gray",
"quantity": 1,
"price": {
"currency": "USD",
"value": 54.0,
"number": 5400,
"symbol": "$"
},
"line_price": {
"currency": "USD",
"value": 54.0,
"number": 5400,
"symbol": "$"
},
"msrp": {
"currency": "USD",
"value": 64.8,
"number": 6480,
"symbol": "$"
},
"image": {
"url": "https://staging.luma.gift/mh07-xs-gray.jpg",
"alt": "MH07-XS-Gray",
"type": "default"
}
}
],
"addons": {
"offers": [
{
"addon_id": "shipping_protection",
"display": {
"name": "Shipping Protection"
},
"scope": "CART",
"coverage_mode": "PREDEFINED_GROUP",
"price": {
"currency": "USD",
"value": 12.99,
"number": 1299,
"symbol": "$"
}
}
],
"selections": []
},
"sub_total": {
"currency": "USD",
"value": 54.0,
"number": 5400,
"symbol": "$"
},
"fees": [
{
"description": "Recycle fee",
"currency": "USD",
"value": 2.00,
"number": 200,
"symbol": "$"
}
],
"fee_total": {
"currency": "USD",
"value": 2.00,
"number": 200,
"symbol": "$"
},
"addon_total": {
"currency": "USD",
"value": 0,
"number": 0,
"symbol": "$"
},
"total": {
"currency": "USD",
"value": 56.00,
"number": 5600,
"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 required headers 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.


{ "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.


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

No cart exists for this device on this domain.


{ "code": 404, "error": "CartNotFound", "description": "Cart was not found." }
412 — OperationNotSupported

The merchant’s platform does not support addon operations.


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

Request body fails schema validation. addon_id must be a string; the optional deselected_line_item_id / deselected_child_id must also be strings when present.


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

The body is well-formed, but the merchant rejected a value in it — typically an addon_id that is not selected on this cart, or a missing deselected_line_item_id on an item-scoped add-on. Same error name as the 400 above, raised one layer deeper, so branch on code and not on error alone.


{ "code": 422, "error": "InvalidInputBody", "description": "deselected_line_item_id is required for ITEM-scoped addons" }
422 — UnprocessableEntity

The supplied addon_id is not in cart.addons.selections, or deselected_line_item_id / deselected_child_id does not match a currently-selected item / child.


{ "code": 422, "error": "UnprocessableEntity", "description": "The given payload has unprocessable, invalid or non-existent data. Please check the data and try again." }
503 — StoreUnavailable

The merchant’s API returned an unexpected response and the request could not be fulfilled. Retry with backoff.


{ "code": 503, "error": "StoreUnavailable", "description": "Store is unavailable." }