Add Promo Codes
POST https://api.firmly.work/api/v2/domains/{domain}/cart/promo-codes
Applies one or more promotional codes to the cart. The merchant validates each code and applies any eligible discount. The response is the updated cart with applied codes in coupons and recalculated totals.
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
promo_codes(string[], required) — Array of promotional codes to apply. Length 1–10. Each entry is a non-empty trimmed string.
Response
Returns the full cart (same schema as Get Cart). Promotion-relevant fields after a successful apply:
coupons— array of currently applied codes (strings).cart_discount— total discount applied to the cart (Amount).cart_discount_breakdown— per-promotion breakdown (when the merchant exposes it).line_items[].discount/line_items[].line_discount— per-line amounts (when the merchant exposes them).sub_total,tax_total,total— recalculated.
Examples
curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/promo-codes \-H "x-firmly-authorization: YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"promo_codes": ["SAVE20"]}'
curl -X POST https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/promo-codes \-H "x-firmly-authorization: YOUR_TOKEN" \-H "Content-Type: application/json" \-d '{"promo_codes": ["SAVE20", "FREESHIP", "LOYALTY10"]}'
const response = await fetch('https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/promo-codes', {method: 'POST',headers: {'x-firmly-authorization': 'YOUR_TOKEN','Content-Type': 'application/json'},body: JSON.stringify({promo_codes: ['SAVE20']})});const cart = await response.json();
import requestsresponse = requests.post('https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/promo-codes',headers={'x-firmly-authorization': 'YOUR_TOKEN','Content-Type': 'application/json'},json={'promo_codes': ['SAVE20']})cart = response.json()
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": "bd3710bc-97ef-408d-7382-43b7e5de712f","sku": "WS12-XS-Orange","description": "Radiant Tee","quantity": 2,"price": { "currency": "USD", "value": 22.00, "number": 2200, "symbol": "$" },"line_price": { "currency": "USD", "value": 44.00, "number": 4400, "symbol": "$" },"msrp": { "currency": "USD", "value": 28.00, "number": 2800, "symbol": "$" },"discount": { "currency": "USD", "value": 10.00, "number": 1000, "symbol": "$" },"line_discount": { "currency": "USD", "value": 20.00, "number": 2000, "symbol": "$" },"image": {"url": "https://staging.luma.gift/radiant-tee.jpg","alt": "Radiant Tee","type": "default"},"requires_shipping": true}],"coupons": ["SAVE20"],"sub_total": { "currency": "USD", "value": 44.00, "number": 4400, "symbol": "$" },"cart_discount": { "currency": "USD", "value": 20.00, "number": 2000, "symbol": "$" },"shipping_total": { "currency": "USD", "value": 9.99, "number": 999, "symbol": "$" },"tax_total": { "currency": "USD", "value": 2.40, "number": 240, "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": 38.39, "number": 3839, "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. Add an item first via Add Line Item.
{ "code": 404, "error": "CartNotFound", "description": "Cart was not found." }
409 — InvalidPromoCode
One or more codes are invalid, expired, or not recognized by the merchant.
{ "code": 409, "error": "InvalidPromoCode", "description": "Invalid promo code." }
409 — PromoNotAvailable
The code exists but is not available for the current cart (e.g. minimum-purchase not met, product-restricted, customer-segment-restricted).
{ "code": 409, "error": "PromoNotAvailable", "description": "Promo is not available." }
409 — MultipleDiscountCodesNotSupported
The merchant does not allow more than one discount code to be applied at once, but the request (or the resulting cart) would carry multiple codes. Apply a single code instead.
{ "code": 409, "error": "MultipleDiscountCodesNotSupported", "description": "Multiple discount codes are not supported." }
412 — OperationNotSupported
The merchant’s platform does not support applying promo codes via API.
{ "code": 412, "error": "OperationNotSupported", "description": "This operation is not supported for this store." }
400 — InvalidInputBody
Request body fails schema validation. promo_codes must be an array of 1–10 non-empty trimmed strings.
{ "code": 400, "error": "InvalidInputBody", "description": "The body is not processable" }