Carts and the cart token
Create a cart, add and change lines, apply coupons, set addresses and shipping, and read totals, tax, gifts and nudges.
A cart holds what a shopper is about to buy. You create one, get back a cart_token, and send that token as X-Cart-Token on every cart and checkout call. There are no cookies or sessions on the API side: the token is the cart's identity.
The flow
POST /v1/cartcreates a cart and returns itscart_token.POST /v1/cart/linesadds variants.PATCHandDELETEon/v1/cart/lines/{id}change or remove them.POST /v1/cart/couponapplies a promotion code (optional).PUT /v1/cart/addressessets the shipping and billing addresses.GET /v1/cart/shipping-optionslists the delivery and collection options for that address, andPUT /v1/cart/shipping-optionpicks one.- Checkout takes payment and places the order.
Every write returns the whole cart, recalculated, so you never need a second call to refresh it.
Create a cart
curl -X POST https://api.elaraone.app/api/v1/cart \
-H "X-Tenant-Key: $ELARAONE_TENANT_KEY" \
-H "X-Tenant-Secret: $ELARAONE_TENANT_SECRET"{
"data": {
"cart_token": "01JB9K3N7Q2W5X8Z4C6V1T0R3M",
"cart": {
"id": 812,
"currency": "GBP",
"lines": [],
"sub_total": { "amount": 0, "currency": "GBP", "formatted": "£0.00" },
"tax_total": { "amount": 0, "currency": "GBP", "formatted": "£0.00" },
"total": { "amount": 0, "currency": "GBP", "formatted": "£0.00" }
}
}
}- A cart token lasts 30 days from when it is issued.
- An unknown or expired token, or the token of a cart that has become an order, returns
404 CART_NOT_FOUND. Create a new cart. - Create the cart with a signed-in customer's bearer token and it belongs to that customer. A signed-in customer can also call
GET /v1/cartwithoutX-Cart-Tokento resume their current cart; the token comes back in theX-Cart-Tokenresponse header and inmeta.cart_token. - Send
X-Cart-TokenwithPOST /v1/auth/loginorPOST /v1/auth/registerto merge a guest's cart into the customer's. See customers.
Add a line
Send either a variant_id or a sku, with a quantity of at least 1. Send an Idempotency-Key so a retried request never adds the line twice.
curl -X POST https://api.elaraone.app/api/v1/cart/lines \
-H "X-Tenant-Key: $ELARAONE_TENANT_KEY" \
-H "X-Tenant-Secret: $ELARAONE_TENANT_SECRET" \
-H "X-Cart-Token: $CART_TOKEN" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{ "sku": "MUG-STONE", "quantity": 2 }'To change the quantity, send PATCH /v1/cart/lines/{id} with { "quantity": 3 }. To remove a line, send DELETE /v1/cart/lines/{id}. Both accept an Idempotency-Key too. The {id} is the line's id from the cart, not the variant's. A line id that is not in this cart returns 404 CART_LINE_NOT_FOUND.
The cart object
| Field | Meaning |
|---|---|
id, currency | The cart's id and currency |
lines | The lines, described below |
shippable | false when nothing in the cart ships (a digital-only or empty cart), so you can skip the delivery step |
addresses | shipping and billing addresses |
shipping | The chosen option and its sub_total, tax_total, total and breakdown |
coupon_code, coupon | The code on the cart and its state |
discounts | Each promotion applied, with its label, kind, amount, and how much came off the items and off the delivery |
sub_total | The lines before promotions |
discount_total | What promotions took off the lines |
shipping_discount | What promotions took off the delivery, already applied to shipping and total |
savings | "You saved": the promotion discounts plus the shipping discount |
tax_total, tax_breakdown, tax_zone | Tax, per rate, and how prices should be labelled. See money. |
nudges | Messages that tell the shopper how to qualify for an offer |
rewards | Free gifts and "choose a free product" offers the cart has earned |
total | What the shopper pays |
Each line has an id, quantity, variant (id, sku, name), unit_price, sub_total, discount_total, sub_total_discounted, discounts, gift, tax_amount and total.
All amounts are money objects. Show them as they are; do not recompute them.
Coupons
POST /v1/cart/coupon with { "code": "WELCOME10" } applies a code. DELETE /v1/cart/coupon removes it.
A code that cannot go on the cart is refused with 422, and the cart is left exactly as it was:
error.code | When | error.details.reason |
|---|---|---|
COUPON_INVALID | No such code | unknown |
COUPON_EXPIRED | The code or its offers have not started yet, or have ended | not_started, ended |
COUPON_USED_UP | The code has reached its usage limit | used_up |
COUPON_LIMIT_REACHED | This customer (or, for a guest, this email) has used it as often as allowed | limit_reached |
COUPON_NOT_APPLICABLE | Nothing in this basket qualifies | threshold, customer, items |
For threshold, error.details.remaining is the money still to spend, and error.message says it in words ("Spend £20.00 more to use this code."). Show error.message next to the code field.
A code that was applied can stop qualifying later, for example when the shopper removes items. It stays on the cart, and coupon.status changes from applied to not_applicable, with coupon.reason_code and, for a spend threshold, coupon.remaining.
Addresses
PUT /v1/cart/addresses sets both addresses in one call. billing is required; shipping can be left out for a click-and-collect order, whose shipping address is the collection point. Set billing_same_as_shipping: true to copy the shipping address.
{
"shipping": {
"first_name": "Grace",
"last_name": "Hopper",
"line_one": "12 Mill Lane",
"city": "York",
"postcode": "YO1 7HH",
"country_id": 235,
"contact_email": "[email protected]",
"contact_phone": "+447700900123"
},
"billing_same_as_shipping": true
}Address fields are title, first_name, last_name, company_name, line_one, line_two, line_three, city, state, postcode, country_id, delivery_instructions, contact_email and contact_phone. country_id comes from GET /v1/countries.
For a signed-in customer you can send { "address_id": 42 } instead of the fields to use a saved address, or add "save_to_account": true to a new address to save it to their address book once the order is placed. A guest cannot use address_id: it returns 422 ADDRESS_NOT_FOUND.
If a shipping option was already chosen, changing the address re-prices it for the new destination or clears it. meta.shipping_option_cleared tells you which.
Shipping options
GET /v1/cart/shipping-options lists exactly what PUT /v1/cart/shipping-option will accept for the cart's current address. Before a shipping address is set it returns 422 SHIPPING_ADDRESS_REQUIRED.
{
"data": [
{
"identifier": "standard",
"name": "Standard delivery",
"description": "2 to 4 working days",
"price": { "amount": 495, "currency": "GBP", "formatted": "£4.95" },
"discounted_price": null,
"collect": false,
"kind": "delivery",
"collection_location": null
}
]
}Pick one with PUT /v1/cart/shipping-option and { "identifier": "standard" }. A click-and-collect option has collect: true and a collection_location with the address and opening hours. discounted_price shows the price after a free-delivery or delivery-discount promotion.
The engine remembers the price you showed. If the merchant changes a rate, or the basket crosses a weight or spend band, before the shopper pays, checkout refuses with 409 SHIPPING_OPTION_CHANGED rather than charge a price the shopper never saw. See checkout.
Gifts, rewards and nudges
Promotions can add to the cart as well as take off it.
- Free gifts. A gift line has
gift: true. Its quantity belongs to the promotion, soPATCHreturns422 GIFT_LINE_LOCKED. The shopper can remove it withDELETE, and it is then not offered again on that cart. - "Choose a free product" offers.
rewardslists them withtype: "choice". Add one of the listed variants or products as a normal line and the promotion makes it free.choose_qtyis how many free units the cart has earned andchosen_qtyhow many are already in it.itemsgives picker rows when the offer lists specific products. - Nudges. Each entry in
nudgeshas amessage, such as "Spend £12.00 more for free delivery", and theremainingamount. Show them near the basket total.
Stock
Adding a line checks that the variant can be bought in that quantity, and refuses with 422 VALIDATION_FAILED when it cannot. A cart does not reserve stock: two shoppers can have the last item in their carts at the same time.
Stock is locked when it matters: as the order is placed. Checkout locks the stock of every variant in the cart, checks it again, and takes it off in the same step that creates the order, so the last item can only be sold once. If the stock has gone, checkout returns 422 VALIDATION_FAILED and no order is created.