Budgets
Exact-decimal spend budgets: reserve, settle, void.
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 /budgets
Section titled “GET /budgets”GET /v1/spaces/{spaceId}/budgetsRead-only budget list.
- Key permission:
coordination_read
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
Responses
| Status | Meaning |
|---|---|
200 |
Budgets |
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/budgets" \ -H "Authorization: Bearer $RUNSTATE_API_KEY"POST /budgets
Section titled “POST /budgets”POST /v1/spaces/{spaceId}/budgetsConfigure a spending budget in minor units.
- 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 | |
currency |
string | yes | length 3–3 |
scale |
integer | yes | 0–9 |
limitMinor |
string | yes | pattern ^\d+$ |
Responses
| Status | Meaning |
|---|---|
201 |
Created budget |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/budgets" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"name":"<name>","currency":"<currency>","scale":0,"limitMinor":"100"}'GET /budgets/{id}
Section titled “GET /budgets/{id}”GET /v1/spaces/{spaceId}/budgets/{id}Balances (limit/reserved/settled/available) and reservations.
- Key permission:
coordination_read
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Responses
| Status | Meaning |
|---|---|
200 |
Budget detail |
404 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X GET "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/budgets/<id>" \ -H "Authorization: Bearer $RUNSTATE_API_KEY"POST /budgets/{id}/reserve
Section titled “POST /budgets/{id}/reserve”POST /v1/spaces/{spaceId}/budgets/{id}/reserveReserve funds; INSUFFICIENT_BUDGET when unavailable.
- Key permission:
coordination_write(keys withresource_configare also accepted) - Idempotency-Key header: required
- TypeScript SDK:
runstate.budget(name, fn, { reserve }) - Python SDK:
@runstate.budget(name, reserve=...)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
scopeId |
string (uuid) | yes | |
holder |
string | yes | |
amountMinor |
string | yes | pattern ^\d+$ |
settleBy |
string (date-time) | no |
Responses
| Status | Meaning |
|---|---|
201 |
Active reservation |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/budgets/<id>/reserve" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"scopeId":"<run id>","holder":"worker-1","amountMinor":"100"}'POST /budgets/{id}/settle
Section titled “POST /budgets/{id}/settle”POST /v1/spaces/{spaceId}/budgets/{id}/settleSettle actual spend against a reservation; idempotent per work key.
- Key permission:
coordination_write(keys withresource_configare also accepted) - TypeScript SDK:
runstate.budget(name, fn, { cost }) - Python SDK:
@runstate.budget(name, cost=...)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
reservationId |
string (uuid) | yes | |
amountMinor |
string | yes | pattern ^\d+$ |
workKey |
string | yes | length 1–512 |
allowOverrun |
boolean | no | default false; Allow amountMinor to exceed the reservation. The extra is charged from what is left; anything the budget cannot cover is returned as overrunMinor and not charged. |
Responses
| Status | Meaning |
|---|---|
200 |
Settlement entry; replay flag |
400 |
Error envelope {"error":{"code","message","requestId"}} |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/budgets/<id>/settle" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"reservationId":"<reservationId>","amountMinor":"100","workKey":"<workKey>"}'POST /budgets/{id}/void
Section titled “POST /budgets/{id}/void”POST /v1/spaces/{spaceId}/budgets/{id}/voidVoid the unspent remainder of a reservation; explicit only, never automatic.
- Key permission:
coordination_write(keys withresource_configare also accepted) - TypeScript SDK:
runstate.budget(name, fn) (unused reserve, or fn threw) - Python SDK:
@runstate.budget(name) (unused reserve, or fn raised)
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
id |
string (uuid) | required |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
reservationId |
string (uuid) | yes | |
workKey |
string | yes | length 1–512 |
Responses
| Status | Meaning |
|---|---|
200 |
Void entry; replay flag |
409 |
Error envelope {"error":{"code","message","requestId"}} |
curl -X POST "$RUNSTATE_BASE_URL/v1/spaces/$RUNSTATE_SPACE_ID/budgets/<id>/void" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{"reservationId":"<reservationId>","workKey":"<workKey>"}'PUT /budgets/by-name/{name}
Section titled “PUT /budgets/by-name/{name}”PUT /v1/spaces/{spaceId}/budgets/by-name/{name}Look up a budget by name, or create-or-verify it when limitMinor is given.
Creating a missing budget also needs resource_config. currency defaults to USD and scale to 2.
- Key permission:
coordination_read - TypeScript SDK:
runstate.budget(name, fn, { limit }), runstate.setup() - Python SDK:
@runstate.budget(name, limit=...), runstate.setup()
Path parameters
| Name | Type | Notes |
|---|---|---|
spaceId |
string (uuid) | required |
name |
string | length 1–256 |
Request body (JSON)
| Field | Type | Required | Notes |
|---|---|---|---|
currency |
string | no | length 3–3 |
scale |
integer | no | 0–9 |
limitMinor |
string | no | pattern ^\d+$ |
Responses
| Status | Meaning |
|---|---|
200 |
Existing budget |
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/budgets/by-name/<name>" \ -H "Authorization: Bearer $RUNSTATE_API_KEY" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{}'