Skip to content

Cart

Try the interactive example ↓

Temporary purchase-intent carts and checkout preparation: line items backed by real Item Engine inventory reservations, per-line price locks, guest-cart merge, shareable carts, split-checkout grouping, and a freeze step that commits the holds and hands checkout off to your order flow.

When to reach for it: e-commerce and in-game purchase carts where stock must be held while the buyer decides, guest-to-user merge on login, checkout preparation that must survive stock races.

When not to: the durable inventory itself - definitions, containers, stock - lives in the Item Engine; carts only borrow it through reservations. Actual payment is out of scope platform-wide - checkout-ready ends with a handoff token for your own order and payment layer.

Concepts

  • Carts are ephemeral - each cart carries an expires_at (30 minutes by default), refreshed on every mutation. A background sweeper abandons overdue and inactive carts and releases their holds.
  • Every line holds real stock. Adding an item creates an Item Engine reservation against a seller's container; the line stores its snapshot (id, fencing token, expiry, status). Item Engine remains the stock authority - the cart never keeps its own counters.
  • Price locks are separate - each line locks its unit_amount for a price-lock TTL independent of the reservation TTL.
  • Lifecycle: only active and shared carts accept mutations (else 409 cart_not_active); freezing moves to checkout_ready, a merge leaves its source converted, the sweeper produces abandoned.
  • Add is add-or-update. Adding an item_id already in the cart grows that line; an idempotency_key makes retries safe instead of doubling.

Create a cart and add items

Adding a line names the Item Engine coordinates the stock is reserved from: the domain, the seller's container and its owner, and the definition (SKU).

snug cart create --currency USD
snug cart add docs4-world-pass --qty 2 --cart ryLqjXLpyDPNThWdTNDL \
  --domain docs4-shop --source-container cont_CmREXGyNvQKN \
  --definition HctVYVhHbdBKyrcsYFGF --inventory-owner docs-wave \
  --currency USD --unit-amount 4999
{
  "cart_id": "ryLqjXLpyDPNThWdTNDL",
  "line_id": "QXUhFTjaeQrSwMuBCfNd",
  "quantity": 2,
  "reservation_expires_at": "2026-08-28T13:02:09.141568Z",
  "reservation_status": "held",
  "totals": { "subtotal": 9998, "discount": 0, "estimated_tax": 0, "total": 9998, "currency": "USD" }
}

snug cart get --cart <id> returns the full cart with per-line reservation and price-lock snapshots; snug cart view shows the CLI's current cart (cart add without --cart starts one). Only the owner or a platform admin can touch a cart - anyone else gets 403 insufficient_permissions.

Reservations hold real stock

The hold is not advisory. With 50 units in the container and 2 already held by the cart above, a second cart asking for 49 was refused. Changing a line re-reserves at the new quantity; removing it gives the stock back immediately ("Line removed and reservation released"). Reservations default to strict mode; --reservation-mode soft or availability_check relax the hold.

snug cart add docs4-world-pass --qty 49 --cart RtqjeSPBjYZBpsYerbny ...
# 409 reservation_conflict: "only 48 of HctVYVhHbdBKyrcsYFGF available to reserve"
snug cart update-item --cart ryLqjXLpyDPNThWdTNDL --line-id QXUhFTjaeQrSwMuBCfNd --qty 3
snug cart remove --cart ryLqjXLpyDPNThWdTNDL --line-id KuShdFrFVBfYyQJXscqE

Keeping a cart valid

Reservations and price locks expire on their own clocks (15 minutes each by default), so an open cart goes stale. revalidate reports per-line health without mutating anything; price-lock re-locks prices:

snug cart revalidate --cart ryLqjXLpyDPNThWdTNDL   # per-line reservation_valid / price_lock_valid + "valid": true
snug cart price-lock --cart ryLqjXLpyDPNThWdTNDL   # returns refreshed_line_ids

Merging a guest cart

On login, fold a guest cart into the user's cart. Lines merge by item_id, per-item conflicts come back in a conflicts array with reason codes, and the source cart is drained: its status becomes converted.

snug cart merge --cart ryLqjXLpyDPNThWdTNDL --source-cart RtqjeSPBjYZBpsYerbny
# { "merged_lines": 1, "conflicts": [], "totals": { ... } }

Sharing

share mints a permission-scoped token (view, clone, or contribute) with a TTL, and flips an active cart to shared; --revoke deletes the token and flips it back.

snug cart share --cart ryLqjXLpyDPNThWdTNDL --mode view --ttl-seconds 3600
# { "share": { "token": "share_ATSMbycdFWtZhzuctshc", "permission": "view", ... } }
snug cart share --cart ryLqjXLpyDPNThWdTNDL --revoke

The token is state for your application layer to redeem - no cart endpoint accepts it in this version, so sharing does not by itself open the cart: a second user's direct GET still fails with 403 while sharing is enabled (verified). A TTL above the maximum fails with 400 share_ttl_exceeded.

Checkout

split-checkout is a read-only preview of how the lines partition for downstream orders - group by seller, warehouse, currency, availability, or fulfillment (default inventory_source):

snug cart split-checkout --cart ryLqjXLpyDPNThWdTNDL --group-by currency

checkout-ready is the point of no return: it verifies every reservation is still held, commits them in the Item Engine (stock is now consumed), freezes the cart, and returns a handoff token for your order flow. Raw HTTP, enveloped:

curl -X POST -H "Authorization: Bearer $SNUG_API_TOKEN" \
  http://localhost:4000/api/v1/carts/ryLqjXLpyDPNThWdTNDL/checkout-ready
{
  "status": 200,
  "msg": "OK",
  "data": {
    "cart_id": "ryLqjXLpyDPNThWdTNDL",
    "status": "checkout_ready",
    "checkout_token": "checkout_AQemDHpjrJFRxxDdqLxe",
    "totals": { "subtotal": 20995, "discount": 0, "estimated_tax": 0, "total": 20995, "currency": "USD" }
  }
}

A frozen cart rejects further mutation (409 cart_not_active), and freezing an empty cart or one with a lapsed reservation fails (400 / 409 reservation_conflict) - revalidate first if the cart has been sitting.

Abandonment and recovery

When a cart is abandoned - TTL expiry, inactivity, or a merge draining the source - its holds are released and a recovery record is written with reason (ttl_expired, inactivity, merged, cancelled), item_count, estimated_value, and recovery_eligible, the raw material for win-back flows. Both endpoints require a platform admin token:

snug cart abandoned --filter 'created_at[gte]=2026-08-28T00:00:00Z'
snug cart sweep-abandoned                          # force a sweep pass now; returns { "swept": n }

The list speaks the standard list contract: it filters on cart_id, owner_id, reason, recovery_eligible, and created_at, and sorts by created_at (the default, newest first) or item_count.

Limits and configuration

100 lines per cart, 999 units per line, 30-minute cart TTL, 15-minute reservation and price-lock windows, 7-day share-token maximum, and the sweeper's cadence are all tunable via the CART_* variables.

Reference

Interactive example

Reserve inventory while a customer shops and keep the quoted price with their cart. Prepare the cart for checkout or release holds when they expire.

An illustrative example that runs in your browser. No account or API calls required.