Once
Work done once per run, with the result stored for every caller.
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.
POST /once/acquire
Section titled “POST /once/acquire”POST /v1/spaces/{spaceId}/once/acquireStart once-per-run work, or learn its state.
ACQUIRED (201) hands this caller a fenced lease and token. DONE returns the stored result, FAILED the last error (lastError), HELD means another holder is working on it (wait with GET /once).
- Key permission:
coordination_write - TypeScript SDK:
runstate.once(fn) - Python SDK:
@runstate.once
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
scopeId |
string (uuid) | yes | |
key |
string | yes | length 1–512 |
holder |
string | yes | |
holderSession |
string | yes | |
leaseSeconds |
integer | no | 5–600; default 30 |
Responses
| Status | Meaning |
|---|---|
200 |
HELD, DONE or FAILED |
201 |
ACQUIRED: {state, token, generation, leaseExpiresAt, attempts} |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/once/acquire" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"scopeId":"<run id>","key":"<key>","holder":"worker-1","holderSession":"<session id>"}'POST /once/renew
Section titled “POST /once/renew”POST /v1/spaces/{spaceId}/once/renewExtend the lease on once work.
- Key permission:
coordination_write - TypeScript SDK:
runstate.once(fn) (automatic while fn runs) - Python SDK:
@runstate.once (automatic while fn runs)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
scopeId |
string (uuid) | yes | |
key |
string | yes | |
token |
string | yes | |
leaseSeconds |
integer | no | 5–600; default 30 |
Responses
| Status | Meaning |
|---|---|
200 |
New lease expiry |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/once/renew" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"scopeId":"<run id>","key":"<key>","token":"<lease token>"}'POST /once/complete
Section titled “POST /once/complete”POST /v1/spaces/{spaceId}/once/completeStore the result of once work (64 KiB max); allowed after the run stops.
- Key permission:
coordination_write - TypeScript SDK:
runstate.once(fn) - Python SDK:
@runstate.once
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
scopeId |
string (uuid) | yes | |
key |
string | yes | |
token |
string | yes | |
result |
any JSON | no | JSON result |
Responses
| Status | Meaning |
|---|---|
200 |
DONE |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/once/complete" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"scopeId":"<run id>","key":"<key>","token":"<lease token>"}'POST /once/fail
Section titled “POST /once/fail”POST /v1/spaces/{spaceId}/once/failRecord a failed attempt; FAILED for everyone once maxAttempts is reached.
- Key permission:
coordination_write - TypeScript SDK:
runstate.once(fn) (when fn throws) - Python SDK:
@runstate.once (when fn raises)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
scopeId |
string (uuid) | yes | |
key |
string | yes | |
token |
string | yes | |
error |
string | yes | max length 2000 |
maxAttempts |
integer | no | 1–100; default 3 |
Responses
| Status | Meaning |
|---|---|
200 |
OPEN or FAILED, with attempts |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/once/fail" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"scopeId":"<run id>","key":"<key>","token":"<lease token>","error":"<error>"}'GET /once
Section titled “GET /once”GET /v1/spaces/{spaceId}/onceRead once work; with waitMs, hold until it is no longer HELD.
- Key permission:
coordination_read - TypeScript SDK:
runstate.once(fn) (waiting for another worker) - Python SDK:
@runstate.once (waiting for another worker)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Query parameters
| Name | Type | Notes |
|---|---|---|
scopeId |
string (uuid) | |
key |
string | |
waitMs |
integer | 0–120000 |
Responses
| Status | Meaning |
|---|---|
200 |
{key, scopeId, state: OPEN|HELD|DONE|FAILED, generation, holder, leaseExpiresAt, attempts, result, lastError} |
404 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/once" \ -H "Authorization: Bearer $RUNSTATE_API_KEY"