Concurrency pools (permits)
Capacity counters (permits), the leased grants taken from them, and their waiting line.
All paths are relative to the API base URL (https://api.getrunstate.com) and require Authorization: Bearer <api key>. See the API overview for authentication, idempotency and the error envelope.
GET /permits
Section titled “GET /permits”GET /v1/spaces/{spaceId}/permitsRead-only permit list with unit accounting.
- Key permission:
coordination_read
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Responses
| Status | Meaning |
|---|---|
200 |
Permits |
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/permits" \ -H "Authorization: Bearer $RUNSTATE_API_KEY"POST /permits
Section titled “POST /permits”POST /v1/spaces/{spaceId}/permitsConfigure capacity counter.
- Key permission:
resource_config - Idempotency-Key header: required
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | yes | |
units |
integer | yes | min 1 |
Responses
| Status | Meaning |
|---|---|
201 |
Permit id |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/permits" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"name":"<name>","units":1}'POST /permits/{id}/acquire
Section titled “POST /permits/{id}/acquire”POST /v1/spaces/{spaceId}/permits/{id}/acquireTake units when available.
- Key permission:
coordination_write - TypeScript SDK:
runstate.slots(name, fn) - Python SDK:
@runstate.slots(name)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
scopeId |
string (uuid) | yes | |
units |
integer | yes | min 1 |
holder |
string | yes | |
holderSession |
string | yes | |
leaseSeconds |
integer | no | default 30 |
waiterId |
string (uuid) | no |
Responses
| Status | Meaning |
|---|---|
201 |
Grant with token |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/permits/<id>/acquire" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"scopeId":"<run id>","units":1,"holder":"worker-1","holderSession":"<session id>"}'POST /permits/{id}/wait
Section titled “POST /permits/{id}/wait”POST /v1/spaces/{spaceId}/permits/{id}/waitEnqueue durably in FIFO waiter list.
- Key permission:
coordination_write - TypeScript SDK:
runstate.slots(name, fn) (when the pool is full) - Python SDK:
@runstate.slots(name) (when the pool is full)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
scopeId |
string (uuid) | yes | |
units |
integer | yes | min 1 |
holder |
string | yes |
Responses
| Status | Meaning |
|---|---|
202 |
waiterId |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/permits/<id>/wait" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"scopeId":"<run id>","units":1,"holder":"worker-1"}'POST /grants/{id}/renew
Section titled “POST /grants/{id}/renew”POST /v1/spaces/{spaceId}/grants/{id}/renewRenew held grant.
- Key permission:
coordination_write - TypeScript SDK:
runstate.slots(name, fn) (automatic while fn runs) - Python SDK:
@runstate.slots(name) (automatic while fn runs)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
token |
string | yes | |
leaseSeconds |
integer | no | 5–600; default 30 |
Responses
| Status | Meaning |
|---|---|
200 |
Renewed |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/grants/<id>/renew" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"token":"<lease token>"}'POST /grants/{id}/release
Section titled “POST /grants/{id}/release”POST /v1/spaces/{spaceId}/grants/{id}/releaseRelease grant; allowed after scope cancellation (safe cleanup)
- Key permission:
coordination_write - TypeScript SDK:
runstate.slots(name, fn) (when fn finishes) - Python SDK:
@runstate.slots(name) (when fn finishes)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
token |
string | yes | |
observation |
any JSON | no |
Responses
| Status | Meaning |
|---|---|
200 |
Released |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/grants/<id>/release" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"token":"<lease token>"}'PUT /permits/by-name/{name}
Section titled “PUT /permits/by-name/{name}”PUT /v1/spaces/{spaceId}/permits/by-name/{name}Look up a pool by name, or create-or-verify it when units are given.
Creating a missing pool also needs resource_config.
- Key permission:
coordination_read - TypeScript SDK:
runstate.slots(name, fn, { max }), runstate.setup() - Python SDK:
@runstate.slots(name, max=...), runstate.setup()
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
name |
string | length 1–256 |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
units |
integer | no | 1–1000000 |
Responses
| Status | Meaning |
|---|---|
200 |
Existing pool |
201 |
Created |
404 |
Error envelope {"error":{"code","message","requestId"}} |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X PUT "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/permits/by-name/<name>" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{}'GET /permit-waiters/{id}
Section titled “GET /permit-waiters/{id}”GET /v1/spaces/{spaceId}/permit-waiters/{id}Read a pool waiter (SIGNALED means acquire now with this waiterId)
- Key permission:
coordination_read - TypeScript SDK:
runstate.slots(name, fn) (while waiting) - Python SDK:
@runstate.slots(name) (while waiting)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Responses
| Status | Meaning |
|---|---|
200 |
Waiter: {id, permitId, scopeId, holder, units, state, enqueuedAt} |
404 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/permit-waiters/<id>" \ -H "Authorization: Bearer $RUNSTATE_API_KEY"POST /permit-waiters/{id}/cancel
Section titled “POST /permit-waiters/{id}/cancel”POST /v1/spaces/{spaceId}/permit-waiters/{id}/cancelLeave a pool queue; a signaled waiter passes the wake-up on.
- Key permission:
coordination_write - TypeScript SDK:
runstate.slots(name, fn) (on timeout) - Python SDK:
@runstate.slots(name) (on timeout)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Responses
| Status | Meaning |
|---|---|
200 |
Waiter state |
404 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/permit-waiters/<id>/cancel" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)"