Create price lock
Freeze the current checkout preview's prices.
Cart
/api/v1/scent/cart/{customerRef}/price-lockAPI Docs Review effort, Phase F (D33): recomputes the SAME checkout preview
GET /api/v1/scent/cart/{customerRef}/checkout-preview would report, and — ONLY when that
recomputed preview reports canCheckout: true — persists a price-lock snapshot (default TTL
15 minutes, admin-configurable) that order-create references via its own lockId field to
charge EXACTLY these prices regardless of routine live price drift in either direction. The
locked figures are still checked at create time: if a locked price is no longer available,
create rejects with 422 BUSINESS_PRICE_NOT_AVAILABLE rather than silently honoring it. A broken basket (canCheckout: false) is never locked — this call
rejects outright with 422 BUSINESS_CART_NOT_CHECKOUT_READY instead (re-run the checkout
preview to see why). Any cart mutation (add/set/remove/clear) invalidates the cart’s active
lock; stock is never locked — it is always re-checked live at create time. Previously nested
on the checkout-preview GET behind a ?lock=true query flag — D33 split the side-effecting
lock create out into this dedicated POST.
Path parameters
customerRefstringRequiredThe per-customer cart/registration selector this endpoint operates on (max 128 chars, URL-encoded) — every cart/wishlist/stock-notification endpoint carries it in the path (API Docs Review effort, Phase F/G, D29/R-CUSTOMERREF). Also the value a per-customer redemption cap, if any, is checked against.
Response
idstring (uuid)Pass this as lockId on the order-create call.
expiresAtstring (date-time)Default TTL is 15 minutes from the moment the lock was taken.
Other responses
401No bearer token (UNAUTHORIZED_MISSING_TOKEN), an invalid token (UNAUTHORIZED_INVALID_TOKEN) or an expired one (UNAUTHORIZED_TOKEN_EXPIRED — mint a new token). UPSTREAM_AUTH_FAILED is different: a dependent service refused the Gateway itself. That is a server-side fault — retry later and do NOT re-mint your token. See the Errors guide.403The route is not available to your credential (FORBIDDEN).404No API route matches this path (NOT_FOUND_ROUTE). A missing resource on a real route returns that service’s own NOT_FOUND_* code instead.409A concurrent lock request on the same cart exhausted its retry budget.422The recomputed preview reports canCheckout:false — nothing was locked.429Too many requests — see the Rate limits guide. Retry after the Retry-After header (seconds).502A dependent service returned an invalid response (BAD_GATEWAY). Retry with backoff.503The service is temporarily unavailable (SERVICE_UNAVAILABLE). Retry with backoff.504A dependent service did not respond in time (GATEWAY_TIMEOUT). Retry with backoff.curl --request POST \ --url https://api-omni.linra.net/api/v1/scent/cart/value/price-lock \ --header 'Authorization: Bearer $TOKEN'const res = await fetch('https://api-omni.linra.net/api/v1/scent/cart/value/price-lock', { method: 'POST', headers: { Authorization: `Bearer ${token}`, },});const { payload } = await res.json();var response = await httpClient.PostAsync("https://api-omni.linra.net/api/v1/scent/cart/value/price-lock", null);
var envelope = await response.Content.ReadFromJsonAsync<ApiResponse<PriceLockResponse>>();Response
{ "state": "SUCCESS", "payload": { "id": "5b1e3a1c-9d2e-4f3a-8b1c-9f0a2e3d4c5b", "expiresAt": "2026-08-22T09:14:03Z" }, "details": null}
