Reservations
Holder-keyed holds — reserve, consume, and release are idempotent by construction.
A holder is an opaque string the engine does not interpret, conventionally
type:id (order:9421). All three verbs are safe to retry.
Reserve
/inventory/reservationsScope: inventory:reserve. Honors Idempotency-Key.
curl -X POST "https://apis.cloud.feeef.org/v1/inventory/reservations" \
-H "Authorization: Bearer $FEEEF_CLOUD_KEY" \
-H "Content-Type: application/json" \
-d '{
"holderRef": "order:9421",
"lines": [{ "key": "tshirt/Red/XL", "quantity": 2, "namespace": "wh-main" }],
"expiresAt": "2030-01-01T09:00:00Z"
}'201 for a new hold, 200 when the same lines are already active.
Different lines: the previous hold is released and the new one taken.
422 insufficient_stock carries per-line { key, namespace, requested, available, lineIndex }.
When allowBackorder is false (the default), available must cover the
request. missingKeyPolicy: reject turns an unknown key into
422 key_not_found instead of creating a zero-quantity object.
Consume and release
/inventory/reservations/holder/:holderRef/inventory/reservations/holder/:holderRef/consume/inventory/reservations/holder/:holderRef/releaseConsume turns the hold into a fulfill operation (on-hand and reserved
decrement together). Release of an active hold frees reserved quantity.
Release of an already-consumed holder restocks via a customer_return
operation and reports "restocked": true.
Active reservations past expiresAt are released by the engine's reaper
(movement reason expire).