Cart
Building a basket from outside the shop, the token that holds it together, and handing the shopper to checkout.
A cart lets you build a basket over several requests before anything becomes an order. Use it when a customer is choosing things in your own interface and will check out later; use Orders when you already know the whole order.
GET /api/v1/cart
POST /api/v1/cart
PATCH /api/v1/cart/{key}
DELETE /api/v1/cart/{key}
DELETE /api/v1/cart
POST /api/v1/cart/checkout
Reading needs read_cart. Changing needs write_cart.
The Cart Token
There is no session here, so the shop cannot work out whose cart you mean from the request. You hold a token and send it back.
Your first write is given one. Every response carries cart_token, and you send it on X-Cart-Token from then on.
curl -s -X POST https://shop.example.com/api/v1/cart \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "product_id": 38, "qty": 2 }'
What comes back, including the token to keep
{
"message": "Item added to cart.",
"cart_token": "5898b86f-5e26-4b1d-a3aa-2d5a50bc39a6",
"data": {
"product_id": 38,
"variant_id": null,
"qty": 2,
"price_snapshot": "5.99",
"name_snapshot": "Rice",
"image_snapshot": null,
"is_digital": false,
"is_bundle": false,
"bundle_items": [],
"custom_fields": [],
"is_damaged": false
}
}
Then every later call names the same cart:
curl -s https://shop.example.com/api/v1/cart \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Cart-Token: e18611a8-4638-4b87-8cfb-0425b08dd362" \
-H "Accept: application/json"
The cart, with its totals
{
"cart_token": "5898b86f-5e26-4b1d-a3aa-2d5a50bc39a6",
"data": {
"items": [
{
"key": "p38",
"product_id": 38,
"variant_id": null,
"qty": 2,
"price_snapshot": "5.99",
"name_snapshot": "Rice",
"image_snapshot": null,
"is_digital": false,
"is_bundle": false,
"bundle_items": [],
"custom_fields": [],
"is_damaged": false,
"line_total": "11.98"
}
],
"totals": {
"subtotal": "11.98",
"shipping": "0.00",
"tax": "0.00",
"discount": "0.00",
"total": "11.98",
"item_count": 2,
"line_count": 1
}
}
}
Lose the Token, Lose the Cart
The token is the only thing that names the cart. It is not derived from the customer, the API token or anything else you could recompute, so if your client forgets it the basket is unreachable and the shopper starts again. Store it wherever you keep the rest of that shopper's state, and treat it the way you would a session id: it is enough on its own to read and change that cart.
A read never creates a cart. Asking without a token returns an empty cart and cart_token: null, because asking about a cart you were never given is an empty cart rather than a new one. Only a write mints one.
A token that is not one we issued is refused and treated as no token at all, so a guessed or malformed value reads as an empty cart rather than reaching anything.
Carts Expire
A cart lives for seven days from its last change. That is long enough for a shopper to come back the next evening and short enough that abandoned baskets do not accumulate for ever. An expired token behaves exactly like an unknown one: an empty cart, no error.
Expiry is from the last write, not from creation, so a cart somebody keeps touching keeps living.
Line Keys
Each line has a key, and that is what PATCH and DELETE take. It is derived from what makes the line distinct, so the same product with different options is two lines with two keys. Read the cart to find a key rather than building one.
curl -s -X PATCH https://shop.example.com/api/v1/cart/p38 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Cart-Token: YOUR_CART_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "qty": 5 }'
DELETE /api/v1/cart/{key} removes one line. DELETE /api/v1/cart empties the whole cart.
What the Cart Checks
Adding goes through the shop's own rules, not a thinner version of them, so the answers are the same ones a shopper would get:
- A product that is not published cannot be added, which includes anything still in draft
- Stock is enforced unless the product allows backorders
- A product with a required option is refused until the option is chosen, with the option's own name in the message
- Prices are resolved for the customer group where one applies, so a wholesale price is the price
That last point matters if you are building something for trade customers: the cart is where group pricing happens.
Checking Out
You cannot take a payment through this API, and you should not want to. Ask for a handoff instead and the shopper finishes in the shop's own checkout:
curl -s -X POST https://shop.example.com/api/v1/cart/checkout \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "X-Cart-Token: YOUR_CART_TOKEN" \
-H "Accept: application/json"
What comes back
{
"cart_token": "8e08d450-edd9-48bf-b0eb-e01f9f4708b8",
"checkout_url": "https://demo.unifycart.com/cart/resume?cart=8e08d450-edd9-48bf&expires=1791086400&signature=5c1f...",
"expires_in": 3600
}
Send the shopper to checkout_url. They arrive in this shop's checkout with the cart already loaded and pay the way every other customer does.
That means you inherit the shop's payment methods, its tax and shipping rules, its fraud checks and its order emails, without implementing any of them, and no card details ever reach you. A shopper who is already signed in keeps their own basket: the two are merged, exactly as they are when somebody signs in holding one.
The Link Is Short Lived, and Worth Treating as a Password
It expires in an hour, it is signed, and changing any part of it including the cart it names makes it a 403. Send the shopper to it and do not store it, log it or email it: for that hour it is enough to walk into a checkout holding that basket.
An empty cart is refused rather than handed a link to a checkout with nothing in it.
What It Still Cannot Do
A cart belongs to nobody: it is not attached to a customer even when you know who they are, so it carries no address and no delivery choice. Those are collected at the checkout you hand over to.
If you need the order without a browser anywhere, create it directly with Orders, which takes the lines and does not use the cart at all.
The cart also belongs to nobody: it is not attached to a customer even when you know who they are, so it carries no addresses and no delivery choice. Those are part of an order.
