Skip to main content
Version: 0.3.36

Locks & Inventory API

Atomic locks and inventory reservations over REST. All endpoints are POST, scoped to a repository and branch, and need the locks subsystem enabled. The caller must be authenticated and not anonymous (403 otherwise); the lock owner is derived from the caller's identity, not from the request body. The built-in anonymous user is refused even where anonymous access is enabled and the anonymous role is granted elsewhere.

A 409 Conflict means the lock is currently held or the pool does not have enough units. It is the normal "you lost the race" outcome, not an error. With the subsystem disabled every endpoint returns 400 with code VALIDATION_FAILED and the message Locks subsystem disabled. Enable [locks] in server config.

Acquire a lock​

POST /api/{repo}/{branch}/locks/acquire

Request:

{ "key": "seat:AA123:14A", "ttl_ms": 5000 }

ttl_ms must be between 1 and 300000. Response (200):

{ "acquired": true, "key": "seat:AA123:14A", "token": 348, "expires_at_ms": 1788720658677 }

When the key is already held (409):

{ "acquired": false }

token is a fencing token that increases with every lock handed out. Store it on whatever the lock protects and reject writes that carry an older token to stay correct when a lease expires under a slow holder.

Release a lock​

POST /api/{repo}/{branch}/locks/release
{ "key": "seat:AA123:14A", "token": 348 }

Response (200):

{ "released": true }

released is false when the lock has already expired, was released, or is held with a different token. Releasing is idempotent and safe to call from a finally block.

Renew a lock​

Extend the lease before it expires.

POST /api/{repo}/{branch}/locks/renew
{ "key": "seat:AA123:14A", "token": 348, "ttl_ms": 5000 }
{ "renewed": true }

renewed is false when the lease was already lost.

Claim inventory​

Take n units from a pool. The pool is created with capacity units the first time it is touched; on later calls capacity is ignored.

POST /api/{repo}/{branch}/inventory/claim
{ "pool": "flight:AA123", "n": 1, "capacity": 180 }

Response (200):

{ "claimed": true, "remaining": 179 }

When fewer than n units remain (409):

{ "claimed": false }

Release inventory​

Return units to a pool. The count is not capped at capacity.

POST /api/{repo}/{branch}/inventory/release
{ "pool": "flight:AA123", "n": 1 }
{ "remaining": 180 }

WebSocket​

The same five operations are available on the WebSocket node API as request types locks_acquire, locks_release, locks_renew, inventory_claim and inventory_release, with identical payloads. The responses have the same bodies; a lost race comes back as a normal response with acquired: false or claimed: false rather than a 409.

See also​