Set Cart Attribution
PUT https://api.firmly.work/api/v2/domains/{domain}/cart/attribution
Overview
The Set Cart Attribution endpoint records where the cart came from — the campaign, the referring surface, and the traffic source — and binds that context to the cart session. The values persist for the life of the session and are carried through to the merchant’s order metadata when the order is placed, so downstream attribution and conversion reporting can credit the right source.
- Set it once, early. Call it as soon as the attribution context is known — typically right after the first add-to-cart, before checkout. The values stay bound to the session for its lifetime.
- All fields are optional. Send whichever of the four fields you have. Later calls overwrite the values from earlier calls on the same session.
- Returns the current cart. The response is the full cart state (same schema as Get Cart); attribution itself is stored on the session, not echoed as cart line data.
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)
Request Body
attribution(object, required) — Attribution context to bind to the cart session. Every field is an optional string — send the ones you have. There are exactly four fields; no others are read. Fields (all optional):utm(string): The campaign query string as captured from the entry URL — e.g.utm_source=partner&utm_medium=cpc&utm_campaign=spring_launch. Also the natural carrier for an ad platform’s click identifier (fbclid,gclid,ttclid,epik) when you fold it into the same query string.referrer_url(string): The URL the buyer came from — the ad, article, or referring page that drove the click.referral_code(string): A stable source identifier — a publisher ID, affiliate code, or partner code used to credit the traffic source.landing_page(string): The URL the buyer landed on to begin the purchase.
Response
Returns the current shopping cart — same schema as Get Cart. The attribution values are stored on the cart session and travel through to the merchant’s order metadata at order placement; they are not returned as separate fields on the cart body.
Code Examples
curl --request PUT \--url https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/attribution \--header 'Content-Type: application/json' \--header 'x-firmly-authorization: YOUR_TOKEN' \--data '{"attribution": {"utm": "utm_source=partner&utm_medium=cpc&utm_campaign=spring_launch","referrer_url": "https://ads.example.com/c/abc123","referral_code": "PARTNER-XYZ","landing_page": "https://staging.luma.gift/p/SKU-1?utm_source=partner"}}'
const response = await fetch('https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/attribution', {method: 'PUT',headers: {'Content-Type': 'application/json','x-firmly-authorization': 'YOUR_TOKEN'},body: JSON.stringify({attribution: {utm: 'utm_source=partner&utm_medium=cpc&utm_campaign=spring_launch',referrer_url: 'https://ads.example.com/c/abc123',referral_code: 'PARTNER-XYZ',landing_page: 'https://staging.luma.gift/p/SKU-1?utm_source=partner'}})});const cart = await response.json();console.log(cart);
import requestsresponse = requests.put('https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/attribution',headers={'Content-Type': 'application/json','x-firmly-authorization': 'YOUR_TOKEN'},json={'attribution': {'utm': 'utm_source=partner&utm_medium=cpc&utm_campaign=spring_launch','referrer_url': 'https://ads.example.com/c/abc123','referral_code': 'PARTNER-XYZ','landing_page': 'https://staging.luma.gift/p/SKU-1?utm_source=partner'}})cart = response.json()print(cart)
<?php$curl = curl_init();$data = ['attribution' => ['utm' => 'utm_source=partner&utm_medium=cpc&utm_campaign=spring_launch','referrer_url' => 'https://ads.example.com/c/abc123','referral_code' => 'PARTNER-XYZ','landing_page' => 'https://staging.luma.gift/p/SKU-1?utm_source=partner']];curl_setopt_array($curl, [CURLOPT_URL => "https://api.firmly.work/api/v2/domains/staging.luma.gift/cart/attribution",CURLOPT_RETURNTRANSFER => true,CURLOPT_CUSTOMREQUEST => "PUT",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);?>
Response Example
{"cart_id": "a5600193-2c13-3356-d063-711da63b7cd7","platform_id": "example_commerce","shop_id": "staging.luma.gift","display_name": "Luma Store","cart_status": "active","line_items": [{"line_item_id": "bd3710bc-97ef-408d-7382-43b7e5de712f","sku": "SKU-1","quantity": 1,"description": "Luma Explorer Backpack","price": { "currency": "USD", "value": 79, "number": 7900, "symbol": "$" },"line_price": { "currency": "USD", "value": 79, "number": 7900, "symbol": "$" },"msrp": { "currency": "USD", "value": 95, "number": 9500, "symbol": "$" },"image": { "url": "https://staging.luma.gift/luma-explorer-backpack.jpg", "alt": "Luma Explorer Backpack", "type": "default" }}],"shipments": [],"sub_total": { "currency": "USD", "value": 79, "number": 7900, "symbol": "$" },"fees": [{ "description": "Recycle fee", "currency": "USD", "value": 2, "number": 200, "symbol": "$" }],"fee_total": { "currency": "USD", "value": 2, "number": 200, "symbol": "$" },"total": { "currency": "USD", "value": 81, "number": 8100, "symbol": "$" },"addons": { "offers": [], "selections": [] },"schema_version": "2.0"}
Related Endpoints
- Get Cart — View current cart state and full response schema
- Add Line Item — Add items to the cart
- Place Order — Attribution set here rides through to order metadata
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 — CartNotFound
No cart exists for this device on this domain. Add an item first — attribution attaches to an existing cart session.
{"code": 404,"error": "CartNotFound","description": "Cart was not found."}
412 — OperationNotSupported
The merchant’s platform does not support this 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."}
400 — InvalidInputBody
The request body failed schema validation — for example, a field sent as a non-string value. The description names the failing field.
{"code": 400,"error": "InvalidInputBody","description": "The body is not processable"}