Skip to content
v0 protocol for deterministic budget governance (reserve/commit) with optional decide + balance queries, plus debt/overdraft support with soft-limit reconciliation.

PURPOSE (v0):

  • Provide a minimal, language-agnostic protocol to enforce deterministic spend exposure for agent runtimes
    via concurrency-safe reservations and idempotent commits.
  • Include optional integration endpoints: /decide (soft landing) and /balances (operator visibility).

NON-GOALS (v0) (NORMATIVE):

  • Budget establishment and funding operations are out of scope for v0.
    v0 defines the reservation/commit/release enforcement plane and balance reporting only.
  • v0 provides no API for budget CRUD (create/update/delete), allocation setting, credit/deposit, or debit/withdrawal.
    Implementations MAY provide these via an operator/admin plane or a separate API; future versions may standardize them.
  • A reservation lifecycle is denominated in exactly one unit (single-unit reserve/commit/release).
    Multi-unit atomic reservation/settlement is a v1+ concern.

AUTH & TENANCY (NORMATIVE):

  • Requests are authenticated via X-Cycles-API-Key.
  • Server determines an "effective tenant" from the API key (or other auth context).
  • Subject.tenant is a budgeting dimension and MUST be validated against the effective tenant.
    If mismatched, server MUST return 403 FORBIDDEN.
  • Reservation ownership MUST be enforced: every reservation is bound to the effective tenant at creation.
    Any subsequent GET/commit/release for a reservation that exists but is owned by a different tenant
    MUST return 403 FORBIDDEN.
  • Balance visibility MUST be tenant-scoped: the server MUST only return balances within the effective tenant.
    If a request attempts to query another tenant (e.g., tenant filter mismatches), server MUST return 403 FORBIDDEN.

EVOLUTION CONTRACT:

  • This API starts at v0.1.0 with /v1 paths to avoid future client churn.
  • v1+ evolution MUST be backward-compatible by default: new fields are additive, existing field meanings MUST NOT change.
  • Breaking changes (e.g., new required fields, semantic changes) require a new major API path (e.g., /v2).

CORE INVARIANTS:

  • Reserve is atomic across all derived scopes.
  • Commit and release are idempotent.
  • No double-charge on retries (idempotency key enforced).

ERROR SEMANTICS (NORMATIVE):

  • Budget denials MUST return HTTP 409 with error=BUDGET_EXCEEDED.
  • Overdraft limit exceeded MUST return HTTP 409 with error=OVERDRAFT_LIMIT_EXCEEDED in two cases:
    1. During commit: when overage_policy=ALLOW_WITH_OVERDRAFT and (current_debt + delta) > overdraft_limit at commit time
    2. During reservation: when the scope is in over-limit state (debt > overdraft_limit due to prior concurrent commits)
  • Outstanding debt blocking reservation MUST return HTTP 409 with error=DEBT_OUTSTANDING
    (when debt > 0 and new reservation is attempted).
  • Finalized reservations MUST return HTTP 409 with error=RESERVATION_FINALIZED.
  • Expired reservations MUST return HTTP 410 with error=RESERVATION_EXPIRED.
    (commit/release: beyond expires_at_ms + grace_period_ms; extend: beyond expires_at_ms).
  • Reservations that never existed MUST return HTTP 404 with error=NOT_FOUND.
  • HTTP 429 is reserved for server-side throttling/rate limiting (optional in v0), not deterministic budget exhaustion.
  • Unit mismatch on commit (actual.unit ≠ reservation unit) or event (actual.unit not supported for the target scope) MUST return HTTP 400 with error=UNIT_MISMATCH.
  • For expiry comparisons, “now” refers to server time (not client-provided time).
  • When is_over_limit=true, server MUST return 409 OVERDRAFT_LIMIT_EXCEEDED for new reservations.
    This takes precedence over DEBT_OUTSTANDING even when debt > 0.

OVERDRAFT RECONCILIATION (NORMATIVE):

  • When concurrent commits cause debt > overdraft_limit on a scope, the server MUST mark that scope as "over-limit" (is_over_limit=true).
  • Over-limit scopes MUST reject ALL new reservation attempts with 409 OVERDRAFT_LIMIT_EXCEEDED until debt is reduced below overdraft_limit.
  • Operators reconcile over-limit scopes via budget funding operations (out-of-scope for this API).
    When debt is repaid below overdraft_limit, is_over_limit automatically returns to false.
  • Servers SHOULD provide monitoring/alerting when scopes enter over-limit state:
    • Log events with scope identifier, current debt, and overdraft_limit
    • Optionally emit webhooks or notifications to operators
    • Optionally expose metrics endpoint showing over-limit scope count
  • Clients SHOULD handle 409 OVERDRAFT_LIMIT_EXCEEDED on reservation as a signal to wait/retry with exponential backoff, or escalate to operators.

IDEMPOTENCY (NORMATIVE):

  • If X-Idempotency-Key header is present and body.idempotency_key is present, they MUST match.
  • Server MUST enforce idempotency per (effective tenant, endpoint, idempotency_key).
  • On replay of an idempotent request that previously succeeded, server MUST return the original successful
    response payload (including any server-generated identifiers such as reservation_id).
  • If the same key is reused with a different request payload, server MUST return 409 IDEMPOTENCY_MISMATCH.
  • Servers SHOULD compare idempotency payloads using a canonical JSON representation
    (e.g., RFC 8785 JSON Canonicalization Scheme) or an equivalent stable serialization.

SCOPE DERIVATION (NORMATIVE):

  • Server derives canonical scope identifiers and a canonical scope_path from Subject fields.
  • Canonical ordering is: tenant → workspace → app → workflow → agent → toolset.
  • Only explicitly provided subject levels are included in scope paths; intermediate gaps are skipped (not filled with "default").
  • Scopes without budgets are skipped during enforcement; at least one derived scope MUST have a budget.
  • affected_scopes returned by the server MUST be in that canonical order.

RESERVATION LEASING (GUIDANCE):

  • To mitigate "zombie reservations" (client crash after reserve), SDKs SHOULD:
    • keep ttl_ms short (typically 10s–30s),
    • include modest estimation buffers when using overage_policy=REJECT,
    • reserve in small initial leases and increase gradually ("slow start") for long or bursty operations,
    • prefer chunked reserve/commit cycles for long-running actions rather than a single large reservation.

OVERDRAFT MONITORING (GUIDANCE):

  • Implementations SHOULD provide visibility into over-limit states:
    • Dashboard showing scopes with is_over_limit=true
    • Alerts when debt exceeds overdraft_limit
    • Time-series metrics: debt_utilization = debt / overdraft_limit
  • Recommended alerting thresholds:
    • Warning at 80% of overdraft_limit
    • Critical at 100% (over-limit state)
  • Recommended operator runbook:
    1. Investigate which reservations caused the over-limit state
    2. Determine if overdraft_limit should be increased (normal variance) or if this represents anomalous consumption (incident)
    3. Fund the scope to repay debt below limit
    4. Monitor that is_over_limit returns to false
    5. Resume operations automatically

CHANGELOG:
v0.1.23 (2026-02-21):
- Renamed Subject.toolGroup → Subject.toolset across all endpoints, schemas,
and normative text for consistency with scope hierarchy naming conventions.
- Added ALLOW_WITH_OVERDRAFT semantics to EventCreateRequest.overage_policy
(finding: behavior was previously unspecified for events).
- Clarified DecisionResponse.decision description: DENY is a valid live-path
outcome on /decide; removed erroneous dry_run framing copied from
ReservationCreateResponse.
- Added ERROR SEMANTICS precedence rule: when is_over_limit=true, server MUST
return 409 OVERDRAFT_LIMIT_EXCEEDED for new reservations, taking precedence
over DEBT_OUTSTANDING even when debt > 0.
- Added DEBT/OVERDRAFT STATE normative block to /decide: server SHOULD return
decision=DENY under debt or over-limit conditions; MUST NOT return 409.

v0.1.22 (2026-02-18):
- Added overdraft/debt model: ALLOW_WITH_OVERDRAFT overage policy, debt and
overdraft_limit fields on Balance, is_over_limit flag, OVERDRAFT_LIMIT_EXCEEDED
and DEBT_OUTSTANDING error codes.
- Added SignedAmount schema to support negative remaining in overdraft state.
- Added OVERDRAFT RECONCILIATION normative section and OVERDRAFT MONITORING
guidance section including recommended alerting thresholds and operator runbook.
- Added OVER-LIMIT BLOCKING normative block to createReservation.

v0.1.0 → v0.1.21:
- Initial protocol definition: reserve/commit/release lifecycle, idempotency,
scope derivation, /decide, /balances, /events, dry_run shadow mode,
reservation extend/list/get endpoints, soft enforcement via Caps.

Servers

https://api.cycles.localReplace with your implementation endpoint

Decisions

Optional preflight checks (no reservation created)


Optional preflight policy decision (no reservation created)

POST
/v1/decide

Returns ALLOW / DENY, optionally with Caps for soft landing. This endpoint does not reserve budget. Clients that require concurrency safety MUST use /v1/reservations.
IDEMPOTENCY (NORMATIVE): - On replay with the same idempotency_key, the server MUST return the original successful response payload.
TENANCY (NORMATIVE): - subject.tenant MUST match the effective tenant derived from auth; otherwise the server MUST return 403 FORBIDDEN.
DEBT/OVERDRAFT STATE (NORMATIVE): - If the subject scope has debt > 0 or is_over_limit=true, server SHOULD return decision=DENY with reason_code=DEBT_OUTSTANDING or reason_code=OVERDRAFT_LIMIT_EXCEEDED respectively. Server MUST NOT return 409 for these conditions on /decide.
Idempotency on /decide is for request deduplication only. A replayed ALLOW response reflects budget state at the time of the original call; clients MUST NOT treat a replayed decision as current budget authorization.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Header Parameters

X-Idempotency-Key

Optional idempotency key header. If both header and body idempotency_key are provided, they MUST match. Server MUST enforce idempotency per endpoint by (effective tenant, endpoint, idempotency_key). On replay of an idempotent request that previously succeeded, server MUST return the original successful response payload (including any server-generated identifiers such as reservation_id).

Type
string
Min Length
1
Max Length
256

Request Body

application/json
JSON
{
  
"idempotency_key": "string",
  
"subject": "string",
  
"action": {
  
  
"kind": "string",
  
  
"name": "string",
  
  
"tags": [
  
  
  
"string"
  
  
]
  
},
  
"estimate": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"metadata": {
  
  
"additionalProperties": "string"
  
}
}

Responses

Decision result

application/json
JSON
{
  
"decision": "string",
  
"caps": {
  
  
"max_tokens": 0,
  
  
"max_steps_remaining": 0,
  
  
"tool_allowlist": [
  
  
  
"string"
  
  
],
  
  
"tool_denylist": [
  
  
  
"string"
  
  
],
  
  
"cooldown_ms": 0
  
},
  
"reason_code": "string",
  
"retry_after_ms": 0,
  
"affected_scopes": [
  
  
"string"
  
]
}

Playground

Authorization
Headers
Body

Samples


List reservations (optional recovery/debug endpoint)

GET
/v1/reservations

Lists reservations visible to the effective tenant. This endpoint is OPTIONAL in v0 deployments.

RECOVERY (NORMATIVE):

  • If a client loses reservation_id, it MAY recover it by querying with idempotency_key and/or subject filters.
  • If idempotency_key is provided, the server SHOULD return at most one matching reservation (uniqueness is expected per (effective tenant, endpoint, idempotency_key)).
  • Servers SHOULD support filtering by status=ACTIVE to identify "stuck" reservations.

SUBJECT FILTERS (GUIDANCE):

  • Query parameters tenant/workspace/app/workflow/agent/toolset filter on the canonical Subject fields.
  • Filtering on Subject.dimensions is out of scope for v0 unless explicitly implemented by the server.

TENANCY (NORMATIVE):

  • The server MUST scope results to the effective tenant derived from auth.
  • If the tenant query parameter is provided, it is validation-only and MUST match the effective tenant; otherwise the server MUST return 403 FORBIDDEN.
  • If tenant is omitted, the effective tenant is used.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Query Parameters

idempotency_key

Lookup handle to recover the reservation_id from a prior createReservation call.

Type
string
Min Length
1
Max Length
256
status

Filter by reservation status (e.g., ACTIVE).

Type
string
Valid values
"ACTIVE""COMMITTED""RELEASED""EXPIRED"
tenant
Type
string
workspace
Type
string
app
Type
string
workflow
Type
string
agent
Type
string
toolset
Type
string
limit

Maximum number of results to return

Type
integer
Minimum
1
Maximum
200
Default
50
cursor

Opaque cursor from previous response

Type
string

Responses

Reservations list

application/json
JSON
{
  
"reservations": [
  
  
{
  
  
  
"reservation_id": "string",
  
  
  
"status": "string",
  
  
  
"idempotency_key": "string",
  
  
  
"subject": "string",
  
  
  
"action": {
  
  
  
  
"kind": "string",
  
  
  
  
"name": "string",
  
  
  
  
"tags": [
  
  
  
  
  
"string"
  
  
  
  
]
  
  
  
},
  
  
  
"reserved": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"created_at_ms": 0,
  
  
  
"expires_at_ms": 0,
  
  
  
"scope_path": "string",
  
  
  
"affected_scopes": [
  
  
  
  
"string"
  
  
  
]
  
  
}
  
],
  
"next_cursor": "string",
  
"has_more": true
}

Playground

Authorization
Variables
Key
Value

Samples


Reserve budget for a planned action (concurrency-safe)

POST
/v1/reservations

Atomically reserves the estimated amount across server-derived scopes and returns a reservation_id. Reservations expire at expires_at_ms; commits are accepted through (expires_at_ms + grace_period_ms).
If dry_run=true, server MUST evaluate the full reservation request and return decision/caps/affected_scopes/balances as if the reservation were live, but MUST NOT modify balances, persist a reservation, or require commit/release.
DRY-RUN RESPONSE RULES (NORMATIVE): - reservation_id and expires_at_ms MUST be absent. - affected_scopes MUST be populated regardless of decision outcome (ALLOW / ALLOW_WITH_CAPS / DENY). - If decision=ALLOW_WITH_CAPS, caps MUST be present; otherwise caps MUST be absent. - If decision=DENY, reason_code SHOULD be populated; it is the primary diagnostic signal for why the dry_run was denied. - balances MAY be populated (recommended for operator visibility), but MUST reflect a non-mutating evaluation.
OVER-LIMIT BLOCKING (NORMATIVE): - If ANY affected scope has debt > overdraft_limit (is_over_limit=true), the reservation MUST be rejected
with 409 OVERDRAFT_LIMIT_EXCEEDED, regardless of available remaining budget.

  • This blocks new work when overdraft reconciliation is needed.
    IDEMPOTENCY (NORMATIVE): - On replay with the same idempotency_key, the server MUST return the original successful response payload, including the original reservation_id (if any).
    TENANCY (NORMATIVE): - subject.tenant MUST match the effective tenant derived from auth; otherwise the server MUST return 403 FORBIDDEN.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Header Parameters

X-Idempotency-Key

Optional idempotency key header. If both header and body idempotency_key are provided, they MUST match. Server MUST enforce idempotency per endpoint by (effective tenant, endpoint, idempotency_key). On replay of an idempotent request that previously succeeded, server MUST return the original successful response payload (including any server-generated identifiers such as reservation_id).

Type
string
Min Length
1
Max Length
256

Request Body

application/json
JSON
{
  
"idempotency_key": "string",
  
"subject": "string",
  
"action": {
  
  
"kind": "string",
  
  
"name": "string",
  
  
"tags": [
  
  
  
"string"
  
  
]
  
},
  
"estimate": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"ttl_ms": 60000,
  
"grace_period_ms": 5000,
  
"overage_policy": "REJECT",
  
"dry_run": false,
  
"metadata": {
  
  
"additionalProperties": "string"
  
}
}

Responses

Reservation decision (ALLOW/DENY with optional caps)

application/json
JSON
{
  
"decision": "string",
  
"reservation_id": "string",
  
"reserved": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"expires_at_ms": 0,
  
"scope_path": "string",
  
"affected_scopes": [
  
  
"string"
  
],
  
"caps": {
  
  
"max_tokens": 0,
  
  
"max_steps_remaining": 0,
  
  
"tool_allowlist": [
  
  
  
"string"
  
  
],
  
  
"tool_denylist": [
  
  
  
"string"
  
  
],
  
  
"cooldown_ms": 0
  
},
  
"balances": [
  
  
{
  
  
  
"scope": "string",
  
  
  
"scope_path": "string",
  
  
  
"remaining": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"reserved": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"spent": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"debt": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"allocated": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"overdraft_limit": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"is_over_limit": true
  
  
}
  
],
  
"reason_code": "string",
  
"retry_after_ms": 0
}

Playground

Authorization
Headers
Body

Samples


Get reservation details (optional, for debugging)

GET
/v1/reservations/{reservation_id}

Retrieve current status and details of a reservation by ID. Useful for debugging and monitoring long-running operations.
TENANCY (NORMATIVE): - If the reservation exists but is owned by a different effective tenant, the server MUST return 403 FORBIDDEN.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Path Parameters

reservation_id*
Type
string
Required
Min Length
1
Max Length
128

Responses

Reservation details

application/json
JSON
{
  
"reservation_id": "string",
  
"status": "string",
  
"idempotency_key": "string",
  
"subject": "string",
  
"action": {
  
  
"kind": "string",
  
  
"name": "string",
  
  
"tags": [
  
  
  
"string"
  
  
]
  
},
  
"reserved": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"committed": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"created_at_ms": 0,
  
"expires_at_ms": 0,
  
"finalized_at_ms": 0,
  
"scope_path": "string",
  
"affected_scopes": [
  
  
"string"
  
],
  
"metadata": {
  
  
"additionalProperties": "string"
  
}
}

Playground

Authorization
Variables
Key
Value

Samples


Commit actual spend for a reservation (auto-releases delta)

POST
/v1/reservations/{reservation_id}/commit

Commits actual spend. If actual < reserved, delta is released automatically. If actual > reserved, behavior is controlled by the reservation's overage_policy.
IDEMPOTENCY (NORMATIVE): - On replay with the same idempotency_key, the server MUST return the original successful response payload.
TENANCY (NORMATIVE): - If the reservation exists but is owned by a different effective tenant, the server MUST return 403 FORBIDDEN.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Header Parameters

X-Idempotency-Key

Optional idempotency key header. If both header and body idempotency_key are provided, they MUST match. Server MUST enforce idempotency per endpoint by (effective tenant, endpoint, idempotency_key). On replay of an idempotent request that previously succeeded, server MUST return the original successful response payload (including any server-generated identifiers such as reservation_id).

Type
string
Min Length
1
Max Length
256

Path Parameters

reservation_id*
Type
string
Required
Min Length
1
Max Length
128

Request Body

application/json
JSON
{
  
"idempotency_key": "string",
  
"actual": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"metrics": {
  
  
"tokens_input": 0,
  
  
"tokens_output": 0,
  
  
"latency_ms": 0,
  
  
"model_version": "string",
  
  
"custom": {
  
  
  
"additionalProperties": "string"
  
  
}
  
},
  
"metadata": {
  
  
"additionalProperties": "string"
  
}
}

Responses

Commit succeeded

application/json
JSON
{
  
"status": "string",
  
"charged": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"released": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"balances": [
  
  
{
  
  
  
"scope": "string",
  
  
  
"scope_path": "string",
  
  
  
"remaining": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"reserved": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"spent": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"debt": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"allocated": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"overdraft_limit": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"is_over_limit": true
  
  
}
  
]
}

Playground

Authorization
Headers
Variables
Key
Value
Body

Samples


Release an unused reservation

POST
/v1/reservations/{reservation_id}/release

Releases reserved amount back to remaining budget.
IDEMPOTENCY (NORMATIVE): - On replay with the same idempotency_key, the server MUST return the original successful response payload.
TENANCY (NORMATIVE): - If the reservation exists but is owned by a different effective tenant, the server MUST return 403 FORBIDDEN.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Header Parameters

X-Idempotency-Key

Optional idempotency key header. If both header and body idempotency_key are provided, they MUST match. Server MUST enforce idempotency per endpoint by (effective tenant, endpoint, idempotency_key). On replay of an idempotent request that previously succeeded, server MUST return the original successful response payload (including any server-generated identifiers such as reservation_id).

Type
string
Min Length
1
Max Length
256

Path Parameters

reservation_id*
Type
string
Required
Min Length
1
Max Length
128

Request Body

application/json
JSON
{
  
"idempotency_key": "string",
  
"reason": "string"
}

Responses

Release succeeded

application/json
JSON
{
  
"status": "string",
  
"released": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"balances": [
  
  
{
  
  
  
"scope": "string",
  
  
  
"scope_path": "string",
  
  
  
"remaining": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"reserved": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"spent": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"debt": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"allocated": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"overdraft_limit": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"is_over_limit": true
  
  
}
  
]
}

Playground

Authorization
Headers
Variables
Key
Value
Body

Samples


Extend reservation TTL (lease refresh / heartbeat)

POST
/v1/reservations/{reservation_id}/extend

Extends the expiry of an ACTIVE reservation to support long-running agent workflows.
SEMANTICS (NORMATIVE): - Extension updates expires_at_ms only; it MUST NOT change reserved amount, unit, subject, action, scope_path, or affected_scopes. - Extensions MUST be applied in a concurrency-safe way. - Server MUST accept extend only when status is ACTIVE and the reservation has not yet expired
(i.e., server time ≤ expires_at_ms). If the reservation is expired, server MUST return 410 with error=RESERVATION_EXPIRED.

IDEMPOTENCY (NORMATIVE): - On replay with the same idempotency_key, the server MUST return the original successful response payload.
TENANCY (NORMATIVE): - If the reservation exists but is owned by a different effective tenant, the server MUST return 403 FORBIDDEN.
ERROR SEMANTICS (NORMATIVE): - If the reservation is COMMITTED or RELEASED, server MUST return 409 with error=RESERVATION_FINALIZED. - If the reservation is expired (server time > expires_at_ms), server MUST return 410 with error=RESERVATION_EXPIRED. - If the reservation never existed, server MUST return 404 with error=NOT_FOUND.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Header Parameters

X-Idempotency-Key

Optional idempotency key header. If both header and body idempotency_key are provided, they MUST match. Server MUST enforce idempotency per endpoint by (effective tenant, endpoint, idempotency_key). On replay of an idempotent request that previously succeeded, server MUST return the original successful response payload (including any server-generated identifiers such as reservation_id).

Type
string
Min Length
1
Max Length
256

Path Parameters

reservation_id*
Type
string
Required
Min Length
1
Max Length
128

Request Body

application/json
JSON
{
  
"idempotency_key": "string",
  
"extend_by_ms": 0,
  
"metadata": {
  
  
"additionalProperties": "string"
  
}
}

Responses

Reservation expiry extended

application/json
JSON
{
  
"status": "string",
  
"expires_at_ms": 0,
  
"balances": [
  
  
{
  
  
  
"scope": "string",
  
  
  
"scope_path": "string",
  
  
  
"remaining": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"reserved": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"spent": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"debt": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"allocated": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"overdraft_limit": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"is_over_limit": true
  
  
}
  
]
}

Playground

Authorization
Headers
Variables
Key
Value
Body

Samples


Balances

Query balances for operator visibility


Query current budget balances across scopes (nice-to-have)

GET
/v1/balances

Returns balances for scopes matching the provided subject filter. include_children MAY be ignored by v0 implementations.
SUBJECT FILTER REQUIREMENT (NORMATIVE): - At least one of tenant/workspace/app/workflow/agent/toolset MUST be provided. - If all of these filters are omitted, server MUST return 400 with error=INVALID_REQUEST.
TENANCY (NORMATIVE): - The server MUST scope results to the effective tenant derived from auth. - If the tenant query parameter is provided, it is validation-only and MUST match the effective tenant; otherwise the server MUST return 403 FORBIDDEN. - If tenant is omitted, the effective tenant is used.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Query Parameters

tenant
Type
string
workspace
Type
string
app
Type
string
workflow
Type
string
agent
Type
string
toolset
Type
string
include_children
Type
boolean
Default
false
limit

Maximum number of results to return

Type
integer
Minimum
1
Maximum
200
Default
50
cursor

Opaque cursor from previous response

Type
string

Responses

Balance response

application/json
JSON
{
  
"balances": [
  
  
{
  
  
  
"scope": "string",
  
  
  
"scope_path": "string",
  
  
  
"remaining": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"reserved": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"spent": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"debt": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"allocated": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"overdraft_limit": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"is_over_limit": true
  
  
}
  
],
  
"next_cursor": "string",
  
"has_more": true
}

Playground

Authorization
Variables
Key
Value

Samples


Events

Optional post-only accounting for non-estimable actions


Optional post-only accounting when pre-estimation is not available

POST
/v1/events

Records an accounting event without a reservation. This endpoint is optional in v0 deployments. The event MUST be applied atomically across all derived scopes before the server returns 201.
IDEMPOTENCY (NORMATIVE): - On replay with the same idempotency_key, the server MUST return the original successful response payload.
TENANCY (NORMATIVE): - subject.tenant MUST match the effective tenant derived from auth; otherwise the server MUST return 403 FORBIDDEN.

Authorizations

ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)

Parameters

Header Parameters

X-Idempotency-Key

Optional idempotency key header. If both header and body idempotency_key are provided, they MUST match. Server MUST enforce idempotency per endpoint by (effective tenant, endpoint, idempotency_key). On replay of an idempotent request that previously succeeded, server MUST return the original successful response payload (including any server-generated identifiers such as reservation_id).

Type
string
Min Length
1
Max Length
256

Request Body

application/json
JSON
{
  
"idempotency_key": "string",
  
"subject": "string",
  
"action": {
  
  
"kind": "string",
  
  
"name": "string",
  
  
"tags": [
  
  
  
"string"
  
  
]
  
},
  
"actual": {
  
  
"unit": "string",
  
  
"amount": 0
  
},
  
"overage_policy": "REJECT",
  
"metrics": {
  
  
"tokens_input": 0,
  
  
"tokens_output": 0,
  
  
"latency_ms": 0,
  
  
"model_version": "string",
  
  
"custom": {
  
  
  
"additionalProperties": "string"
  
  
}
  
},
  
"client_time_ms": 0,
  
"metadata": {
  
  
"additionalProperties": "string"
  
}
}

Responses

Event created and atomically applied to balances

application/json
JSON
{
  
"status": "string",
  
"event_id": "string",
  
"balances": [
  
  
{
  
  
  
"scope": "string",
  
  
  
"scope_path": "string",
  
  
  
"remaining": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"reserved": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"spent": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"debt": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"allocated": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"overdraft_limit": {
  
  
  
  
"unit": "string",
  
  
  
  
"amount": 0
  
  
  
},
  
  
  
"is_over_limit": true
  
  
}
  
]
}

Playground

Authorization
Headers
Body

Samples


Powered by VitePress OpenAPI