Admin API Reference
Interactive reference for the RunCycles Admin API. Use this API to operate tenants, API keys, budget ledgers, policies, webhooks, events, audit logs, and dashboard overview data.
Looking for operator workflows?
Start with the Admin API Guide for curl examples, auth header guidance, tenant lifecycle behavior, budget operations, webhook replay, audit filters, and bulk actions.
Authentication
The admin server runs separately from the runtime API, usually on port 7979.
| Header | Use for |
|---|---|
X-Admin-API-Key | Bootstrap/admin operations such as tenant management, API key lifecycle, audit logs, overview data, auth introspection, and webhook security config. |
X-Cycles-API-Key | Tenant-scoped operations such as budget creation, policy management, tenant self-service webhooks, tenant event reads, and balance reads. |
admin:read and admin:write act as wildcard permissions for read and write operations respectively when an endpoint accepts tenant-scoped API keys.
Common entry points
- Tenant and API key setup — create tenants, issue keys, suspend or close tenants.
- Budget allocation — create, fund, freeze, unfreeze, reset, and inspect budget ledgers.
- Admin overview — understand the dashboard data served by
GET /v1/admin/overview. - Webhooks — create subscriptions, inspect deliveries, replay events, and configure webhook URL security.
- Tenant self-service webhooks — let tenant API keys manage scoped webhook subscriptions and read their own event stream.
- Bulk actions — suspend, reactivate, close, pause, resume, delete, credit, debit, reset, and repay many rows safely.
- Searching and sorting — use
search,sort_by,sort_dir, filters, and cursor rules on list endpoints.
Conformance note
Most admin endpoints are part of the runcycles-reference governance plane rather than the portable runtime protocol. The normative parts are called out in the Admin API Guide and in the YAML spec.
Complete Budget Governance Admin API
CORRELATION AND TRACING (cross-reference):
The admin plane conforms to the cross-surface correlation contract
defined authoritatively in the CORRELATION AND TRACING section of
cycles-protocol-v0.yaml. That contract binds every response from
every plane (runtime, admin, action-kinds, extensions) to echo
X-Cycles-Trace-Id as a response header and to propagate
trace_id onto events, audit-log entries, error responses, and
outbound webhook deliveries. The admin plane's Event,
AuditLogEntry, and ErrorResponse schemas in this document carry a
trace_id property accordingly; the request_id contract on
Event and AuditLogEntry is strengthened to cover async/deferred
work spawned by the originating HTTP request. Readers of this
document in isolation MUST consult cycles-protocol-v0.yaml for
inbound-header precedence, fallback-generation rules, and the
full normative propagation contract. No conflicting contract is
stated here.
CASCADE SEMANTICS (tenant close — terminal-owner contract):
Closing a tenant (status ACTIVE|SUSPENDED → CLOSED, via
updateTenant or bulkActionTenants) is a spec-declared terminal
transition. From the moment the close commits, a closed tenant
acts on its owned objects the way ON DELETE CASCADE acts on
child rows: every owned object becomes terminal (or
effectively-terminal) and every subsequent mutating operation
on an owned object of a CLOSED tenant MUST be rejected. Two
complementary rules make this normative:
RULE 1 — CLOSE CASCADE:
On the tenant-close transition, the server MUST drive each
owned object into its nearest terminal state:
* BudgetLedger (ACTIVE|FROZEN) → CLOSED (stamp closed_at,
preserve final balance snapshot for audit, drain any
outstanding reserved back to remaining)
* ApiKey (ACTIVE) → REVOKED (stamp revoked_at)
* Reservation (ACTIVE, not yet finalized) → RELEASED
(equivalent to RESERVATION_FINALIZED finalization with
reason tenant_closed; no overage debt recorded)
* WebhookSubscription (ACTIVE|PAUSED) → DISABLED (see Rule 2
— DISABLED is re-enableable in general, but for closed-
owner subscriptions Rule 2 blocks re-enable, making
DISABLED effectively-terminal without a new enum value)
A conformant server MUST implement ONE of the following
cascade modes. Both deliver the same client-observable
guarantee: once `tenant.status=CLOSED` is observable to any
reader, NO mutation on any owned object will succeed.
MODE A — ATOMIC CASCADE (preferred):
All owned-object terminal transitions and the tenant
status flip commit in a single transaction. Ordering
within the transaction SHOULD be: drain open reservations
→ close budgets → disable webhooks and revoke API keys
(any order) → flip `tenant.status=CLOSED` last. If any
step fails, the whole transaction rolls back and the
tenant remains in its prior status. Mode A gives the
strongest guarantee — no observer ever sees a closed
tenant with a non-terminal child — and is the preferred
implementation for stores that support multi-key
transactions.
MODE B — FLIP-FIRST WITH GUARDED CASCADE (conformant alternative):
The tenant status flip to CLOSED commits first, before
any child transition. Once the flip is durable, Rule 2's
mutation guard is active and MUST reject every mutating
operation on any owned object with HTTP 409 TENANT_CLOSED,
regardless of that child's own current status. The server
then drives children to their terminal states, either
inline (per-child commit, iterated) or asynchronously via
a reconciler. Mode B is valid ONLY when ALL of the
following hold:
(a) Rule 2's mutation guard takes effect at or before
the moment the CLOSED flip is durable to readers.
A concurrent mutation on a child observed AFTER the
flip MUST NOT succeed, even if the cascade has not
yet touched that child.
(b) The cascade is idempotent. Re-invoking close on an
already-CLOSED tenant MUST complete any outstanding
child transitions without emitting duplicate audit
or event rows for already-terminal children.
(c) Eventual convergence is guaranteed. The server MUST
provide a mechanism (operator-issued re-close,
background reconciler, startup sweep, or
equivalent) by which an interrupted cascade drives
every non-terminal owned child to its terminal
state in bounded time. "Bounded" is
implementation-defined but MUST be documented in
the server's operations guide.
(d) Observable reads of a non-terminal child of a
CLOSED tenant are explicitly permitted and MUST
remain consistent with the child's stored status.
A client that reads a budget as FROZEN under a
CLOSED tenant is observing the pre-cascade state;
the child will converge to its terminal state per
(c). Operators rely on this read-visibility for
post-close audit.
Under Mode B the tenant-flip itself is the atomic commit;
everything else is guarded-eventually-consistent. This
matches Redis-backed and other key-value-store
implementations where a cross-key transaction spanning
tenant + budgets + webhooks + api-keys is not available.
Regardless of mode, the server MUST emit one audit entry
per mutated owned object under the same `correlation_id`
(or equivalent request-scoped identifier) as the
originating `tenant.closed` audit entry. The audit
`event_kind` values are RESERVED in this spec:
* `budget.closed_via_tenant_cascade`
* `webhook.disabled_via_tenant_cascade`
* `api_key.revoked_via_tenant_cascade`
* `reservation.released_via_tenant_cascade`
Idempotency: re-issuing close on an already-CLOSED tenant
is a no-op at the tenant level. Under Mode A, no child
work remains; under Mode B, any outstanding child
transitions complete but emit no duplicate audit/event rows
for already-terminal children.
RULE 2 — TERMINAL-OWNER MUTATION GUARD:
Every mutating admin-plane operation whose target resource
has an owning tenant (resolved via tenant_id on the
resource, or via the parent-scope path parameter) MUST reject
with HTTP 409 and error.error_code=TENANT_CLOSED when that
owning tenant's status is CLOSED. This is defense-in-depth
that covers:
* re-enabling a cascaded webhook (WebhookSubscription has
no spec-level terminal state; Rule 2 makes DISABLED
effectively-terminal for closed-owner rows)
* races between an in-flight mutation and the cascade
transaction
* stale client state (e.g., an operator dashboard tab
opened before the close completes)
Operations scoped in this guard include (non-exhaustive):
any budget freeze/unfreeze/fund/update, any reservation
create/commit/release/extend, any API key create/update/
revoke, any webhook create/update/delete/test/replay, and
any tenant-scoped policy create/update.
Non-mutating operations (GET endpoints) MUST remain
available on owned objects of a CLOSED tenant — operators
need post-mortem read access for audit and compliance.
The `TENANT_CLOSED` code is already declared in the shared
ErrorCode enum; this section defines its normative scope
across mutating routes.
WIRE COMPATIBILITY:
- No new status enum values are introduced on any owned
object (preserves additionalProperties: false contracts
and existing client parsers).
- No new ErrorCode values are introduced (TENANT_CLOSED
is pre-existing).
- The cascade is observable as new audit event_kind
strings — clients that enumerate audit kinds MUST tolerate
additive event kinds per the existing audit-kind
open-enum contract.
OUT OF SCOPE (for this revision):
- Re-opening a CLOSED tenant (close remains irreversible).
- Backfilling the cascade for tenants that were closed
before a conformant server exists — a one-shot migration
is an implementation concern, documented in the admin
server's AUDIT.md.
- Extension-plane cascade (action-kinds, risk-class quotas,
ACLs) — see cycles-governance-extensions-v0.1.26.yaml.
SPEC FAMILY CONTEXT:
This is the STABLE GOVERNANCE BASE for the Cycles Protocol v0.1.x
spec family. The current conformance target is v0.1.25 — this file
alone (plus cycles-protocol-v0.yaml) is sufficient for the active
target, and runcycles' reference servers implement that baseline
today. Document revision 0.1.25.31; semantic base frozen at 0.1.25.9
(see cycles-spec-index.yaml for the versioning model).
The upcoming v0.1.26 target adds new capabilities (action quotas,
risk-class quotas, access control lists, tenant observe_mode,
action_quotas:read permission) via cycles-governance-extensions-v0.1.26.yaml
as additive extensions. v0.1.26 is not yet required for conformance
and runcycles' reference servers do not implement it yet. See
CONFORMANCE.md for the active conformance statement.
For v0.1.25 admin tooling, this file is self-sufficient.
For v0.1.26 admin tooling (upcoming), this file ALONE is NOT
sufficient — it exposes Policy, PolicyCreateRequest, and Tenant
in their base-spec shapes without the v0.1.26 additions. Use one of:
- Read this file together with cycles-governance-extensions-v0.1.26.yaml
and apply the extension manually (small tooling footprint).
- Build merged/cycles-openapi-admin-merged.yaml via the admin_merged
recipe in cycles-spec-index.yaml (SDK codegen, validators, OpenAPI
tooling).
This companion-spec design keeps the base stable across v0.1.x
releases while allowing extensions to evolve independently.
PURPOSE:
This specification defines a complete, interoperable budget governance system
with four integrated pillars:
-
TENANT & BUDGET MANAGEMENT (Configuration Plane)
- Tenant lifecycle: registration, hierarchy, metadata
- Budget lifecycle: creation, allocation, funding, expiry
- Policy configuration: caps, limits, quotas
- API key provisioning and management
-
AUTHENTICATION & AUTHORIZATION (Identity Plane)
- API key validation and tenant resolution
- Permission and scope enforcement
- Key lifecycle: creation, rotation, revocation
- Audit logging and access tracking
-
RUNTIME ENFORCEMENT (Reservation Plane)
- Budget reservations and commits (from Cycles Protocol v0.1.24)
- Real-time enforcement with overdraft support
- Balance queries and monitoring
-
EVENTS & WEBHOOKS (Observability Plane)
- Structured event emission for all state changes
- Webhook subscription management with scope filtering
- Push-based alerting for budget thresholds and anomalies
- Delivery tracking with retry and dead-letter support
DESIGN PRINCIPLES:
- Interoperability: Standard schemas enable tool ecosystem
- Security-first: Explicit trust boundaries and validation
- Operational clarity: All workflows have defined endpoints
- Backward compatibility: Extends Cycles v0.1.24 without breaking changes
DEPLOYMENT MODELS:
- Single-service: All four pillars in one deployment
- Split-plane: Separate admin/auth services from runtime enforcement
- Federated: Multiple runtime enforcement instances, shared admin plane
AUTHORING CONVENTION:
This spec describes a protocol contract. Implementation-specific
version markers (e.g. "v0.1.25.7 servers", "Keys created before
v0.1.25.6", "Added in v0.1.25.13") do not belong in normative
prose — they describe what a specific server binary happened to do
at a specific version, which is out of scope for a contract.
Feature provenance (when a clause was introduced into the spec)
belongs in the external changelog file (./changelogs/), not
inline with the clause it introduced. Backward-compatibility text
MUST describe behavior ("Servers MAY encounter legacy API
keys...") rather than a version ("Keys created before
v0.1.25.6..."). Reviewers should reject PRs that add impl-version
markers to normative prose.
Legitimate version references that MAY appear in prose:
- Filename references ("cycles-governance-admin-v0.1.25.yaml")
- semantic_base values — the frozen wire-contract identity
- Explicit forward migration timelines ("removed in v0.1.27")
License
Apache 2.0Servers
List all tenants
Returns paginated list of all tenants. Useful for admin dashboards and tenant discovery.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
"ACTIVE""SUSPENDED""CLOSED"Optional. Filter by tenant observe_mode value. Only meaningful on servers that implement the observe_mode extension (v0.1.26). Servers that don't recognize this parameter MUST ignore it without error (additive-parameter guarantee).
Free-text case-insensitive substring match. Matches across: tenant_id, name. Combined with other filter params using AND semantics. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). Empty string MUST be treated as absent. Max length 128 characters; longer values MUST be rejected with HTTP 400.
128Sort key. When provided, results are returned in the requested order and the returned cursor encodes the sort key so "Load more" continues in sort order. When omitted, servers use their existing default ordering. Servers that don't recognize the parameter MUST ignore it without error (additive-parameter guarantee).
"tenant_id""name""status""created_at""created_at"Sort direction. Default descending.
"asc""desc""desc"110050Responses
Tenant list
Create a new tenant
Registers a new tenant in the system. This is typically the first operation in onboarding a new organization.
AUTHORIZATION: - Requires admin key (X-Admin-API-Key)
IDEMPOTENCY: - Safe to retry with same tenant_id. Returns existing tenant if already created.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Tenant already exists (idempotent)
Get tenant details
Returns the full tenant configuration including status, defaults, and metadata.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Tenant details
Update tenant properties
Modify tenant metadata, status, or hierarchy.
STATUS TRANSITIONS: - ACTIVE → SUSPENDED: Blocks new reservations, existing active reservations can still commit/release - SUSPENDED → ACTIVE: Resume normal operations - * → CLOSED: Irreversible, archives tenant, and triggers
the tenant-close cascade (see CASCADE SEMANTICS in
info.description). As part of the close, the server MUST
drive all owned objects to their terminal states — either
atomically with the status flip (Mode A) or via a
Rule-2-guarded post-flip cascade (Mode B). Every mutating
call on an owned object after the close commits returns
HTTP 409 TENANT_CLOSED. Re-issuing close on an
already-CLOSED tenant is a no-op at the tenant level;
under Mode B it additionally drives any outstanding child
transitions to completion.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Request Body
Responses
Tenant updated
Apply a lifecycle action to every tenant matching a filter
Apply SUSPEND, REACTIVATE, or CLOSE to every tenant matching the provided filter in a single synchronous request. Lets admin dashboards execute "pause all tenants with status ACTIVE matching 'acme'" without paginating the list and issuing one PATCH per row (which produces partial-failure modes and thundering-herd request bursts at scale).
SEMANTICS: - The filter block mirrors the query params of listTenants
(status, parent_tenant_id, observe_mode, search). Filter
semantics (ILIKE match, AND combination) are identical to the
list endpoint — operators can preview the affected set with
GET /v1/admin/tenants and the same filter before invoking
bulk-action.
- Server counts the filter match BEFORE mutation. If
expected_countis supplied and does not equal the server's
count, the server MUST reject with HTTP 409 COUNT_MISMATCH and
perform no writes. This is the anti-footgun gate — the
dashboard shows "49 tenants match" and passes 49; if the
filter drifted (new tenant created between preview and submit),
the mismatch aborts the run. idempotency_key(operator-supplied, typically a UUID v4) is
remembered by the server for 15 minutes. A repeated submit
with the same key returns the ORIGINAL response without
re-applying the action — safe retry on network error or
accidental double-click.- HARD LIMIT: 500 matching rows per invocation. If the filter
matches more than 500, server MUST reject with HTTP 400
LIMIT_EXCEEDED (body includestotal_matched). Operator must
narrow the filter. This bounds the worst-case transaction
size and keeps the request synchronous. - Per-row failure is recorded in the response
failed[]array;
the bulk op does NOT abort on individual row failure. Each
entry carries a row-level error_code (e.g. INVALID_STATE
TRANSITION). Overall HTTP status is 200 even when some rows
fail — the response envelope reports success/failure counts.
ACTION SEMANTICS: - SUSPEND: tenant.status ACTIVE → SUSPENDED. Idempotent when
already SUSPENDED (row goes into skipped[]). Invalid from
CLOSED (row goes into failed[] with INVALID_TRANSITION).
- REACTIVATE: SUSPENDED → ACTIVE. Idempotent when already
ACTIVE. Invalid from CLOSED. - CLOSE: any status → CLOSED. Terminal — not reversible via
this API. Each matched row triggers the full tenant-close
cascade (see CASCADE SEMANTICS in info.description):
owned budgets → CLOSED, API keys → REVOKED, open
reservations → RELEASED, webhook subscriptions →
DISABLED. Per CASCADE SEMANTICS Rule 1 the server MAY
execute the cascade atomically (Mode A) or
flip-first-with-guarded-post-flip-cascade (Mode B).
Per-row failure handling depends on the mode: under Mode
A, cascade failure leaves the row in its prior status
and lands infailed[]with an implementation-specific
error_code; under Mode B, the tenant status flip succeeds
independently of cascade completion, so a partially-
applied cascade leaves the row infailed[]WITH the
tenant already in CLOSED status (cascade converges via
Rule 1(c)). Successful rows land inupdated[]. Other
rows are unaffected (bulk op does not abort on individual
row failure, per SEMANTICS above). Implementations MAY
require additional confirmation (e.g. requiring
allow_close: truein the request body) in future minor
revisions.
EVENTS (document revision 0.1.25.32): - Server MUST emit one Event per successfully-mutated row,
typed by action: SUSPEND → tenant.suspended,
REACTIVATE → tenant.reactivated, CLOSE → tenant.closed.
Skipped rows (ALREADY_IN_TARGET_STATE) and failed rows
MUST NOT produce an Event — emission is bound to actual
state transition, matching the single-op PATCH path.
- Each emitted Event carries
correlation_id = tenant_bulk_action:<action>:<request_id>
(action lowercased, e.g.tenant_bulk_action:close:req_abc).
Operators retrieve the full bulk fan-out via
GET /v1/admin/events?correlation_id=…; the shared
request_id also ties every emitted row to the invocation's
single AuditLogEntry. - For action=CLOSE, the parent
tenant.closedevent and the
per-child cascade fan-out (budget.closed_via_tenant_cascade,
webhook.disabled_via_tenant_cascade,
api_key.revoked_via_tenant_cascade,
reservation.released_via_tenant_cascade) carry DIFFERENT
correlation_ids: the parent uses
tenant_bulk_action:close:<request_id>; the cascade
children retain the Rule 1 identity
tenant_close_cascade:<tenant_id>:<request_id>
(unchanged from document revision 0.1.25.29). The two
identities are complementary — operators tracing a
specific tenant's close query the cascade id; operators
tracing the bulk invocation as a whole query the bulk id.
AUDIT LOG: - One AuditLogEntry per bulk-action invocation (not per
row). The entry records actor_type=ADMIN_ON_BEHALF_OF,
operation=bulkActionTenants, and embeds the full per-row
outcome in the entry payload. Per-row Events (above) are
the operator-visible audit trail; the AuditLogEntry is
the compliance-facing invocation record.
AUTHORIZATION: - AdminKeyAuth only. No ApiKeyAuth path — tenants cannot
bulk-mutate their own peers.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Bulk action applied (may include per-row failures)
List budget ledgers
Query budget ledgers by tenant, scope pattern, status, or utilization / debt / over-limit state. Returns all units for matching scopes.
AUTHORIZATION: - ApiKeyAuth: Tenant can list their own budgets only (scoped by
authenticated tenant). Filter params (over_limit, has_debt,
utilization_min, utilization_max) are supported and apply
within the authenticated tenant's budgets.
- AdminKeyAuth: Admin operator lists budgets. tenant_id is
OPTIONAL — when omitted, returns budgets across all tenants
(cursor-paginated). When provided, scopes the result to that
tenant. Filter params apply across the selected tenant scope.
FILTER SEMANTICS: - All filter params combine with AND semantics. - Filters apply BEFORE cursor pagination so cursor traversal
is stable across pages for a given filter set.
- Budgets with allocated == 0 are treated as utilization == 0
for the utilization_min / utilization_max bounds. - Servers MUST reject requests where utilization_min >
utilization_max with HTTP 400. This is a cross-parameter
constraint that OpenAPI cannot express in the schema, so
it is stated here normatively.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
When using ApiKeyAuth: ignored — the authenticated tenant from the API key is always used for scoping. When using AdminKeyAuth: OPTIONAL — when omitted, returns budgets across all tenants. When provided, scopes the result to the specified tenant.
Filter by scope prefix, e.g., "tenant:acme-corp/workspace:eng"
"USD_MICROCENTS""TOKENS""CREDITS""RISK_POINTS""ACTIVE""FROZEN""CLOSED"When true, returns only budgets whose overdraft_limit has been breached (is_over_limit == true on the returned ledger). When false, returns only budgets NOT over limit. Absent = no filter.
When true, returns only budgets with debt > 0. When false, returns only budgets with debt == 0. Absent = no filter.
Inclusive lower bound on budget utilization (spent / allocated), expressed as a fraction in [0, 1]. Budgets with allocated == 0 are treated as utilization == 0. Absent = no lower bound.
"double"01Inclusive upper bound on budget utilization (spent / allocated), expressed as a fraction in [0, 1]. Budgets with allocated == 0 are treated as utilization == 0. Absent = no upper bound.
"double"01Free-text case-insensitive substring match. Matches across: tenant_id, scope. Combined with other filter params using AND semantics. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). Empty string MUST be treated as absent. Max length 128 characters; longer values MUST be rejected with HTTP 400.
128Sort key. When provided, results are returned in the requested order and the returned cursor encodes the sort key so "Load more" continues in sort order. utilization is computed as spent / allocated (allocated == 0 is treated as 0). commit_overage_policy is sorted by lexicographic enum order. When omitted, servers use their existing default ordering. Servers that don't recognize the parameter MUST ignore it without error (additive-parameter guarantee).
"tenant_id""scope""unit""status""commit_overage_policy""utilization""debt""utilization"Sort direction. Default descending.
"asc""desc""desc"50Responses
Budget list
Create a budget ledger for a scope
Initializes a new budget ledger for a (scope, unit) pair. This must be done before any reservations can be made against the scope.
AUTHORIZATION: - ApiKeyAuth (X-Cycles-API-Key): tenant creates budgets for their own
scopes only. tenant_id is implicit from the authenticated key and
MUST NOT appear in the request body.
- AdminKeyAuth (X-Admin-API-Key): admin operator creates a budget on
behalf of a tenant. tenant_id is REQUIRED in the request body so
the server can route the operation to the correct tenant. The
audit-log entry records actor_type=ADMIN_ON_BEHALF_OF for these
calls so security review can distinguish admin-driven creates
from tenant self-service. Matches the existing dual-auth pattern
on listBudgets and fundBudget.
SCOPE VALIDATION: - Scope must match pattern: tenant:* or tenant:/workspace: etc. - Tenant must exist and be ACTIVE - Cannot create duplicate (scope, unit) ledgers
INITIAL STATE: - allocated = requested amount - remaining = allocated - reserved = spent = debt = 0
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Budget created
Update budget properties
Update overdraft_limit, commit_overage_policy, or metadata on an existing budget. Recalculates is_over_limit after overdraft_limit changes.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Canonical scope identifier, e.g., "tenant:acme" or "tenant:acme/workspace:prod"
"USD_MICROCENTS""TOKENS""CREDITS""RISK_POINTS"Request Body
Responses
Budget updated
Freeze a budget (ACTIVE → FROZEN)
Transitions a budget from ACTIVE to FROZEN. Frozen budgets block all fund operations and new reservations, but can still be updated (overdraft_limit, commit_overage_policy, metadata).
AUTHORIZATION: - Requires admin key (X-Admin-API-Key)
TRANSITION RULES: - ACTIVE → FROZEN: Allowed - FROZEN → FROZEN: 409 (already frozen) - CLOSED → FROZEN: 409 (closed is irreversible)
EVENTS: - Emits budget.frozen event on successful transition.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Canonical scope identifier
"USD_MICROCENTS""TOKENS""CREDITS""RISK_POINTS"Request Body
Responses
Budget frozen
Unfreeze a budget (FROZEN → ACTIVE)
Transitions a budget from FROZEN back to ACTIVE, resuming normal operations.
AUTHORIZATION: - Requires admin key (X-Admin-API-Key)
TRANSITION RULES: - FROZEN → ACTIVE: Allowed - ACTIVE → ACTIVE: 409 (already active) - CLOSED → ACTIVE: 409 (closed is irreversible)
EVENTS: - Emits budget.unfrozen event on successful transition.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Canonical scope identifier
"USD_MICROCENTS""TOKENS""CREDITS""RISK_POINTS"Request Body
Responses
Budget unfrozen
Credit, debit, or adjust budget allocation
Modifies budget allocation and remaining balance outside the reservation flow. Common operations:
AUTHORIZATION: - ApiKeyAuth: Tenant can fund their own budgets only (scoped by authenticated tenant) - AdminKeyAuth: Accepted as alternative (dual-auth).
When using AdminKeyAuth, tenant_id query parameter is REQUIRED for scoping.
CREDIT (top-up): - allocated += amount - remaining += amount - Use for: monthly allocations, bonus credits
DEBIT (drain): - allocated -= amount - remaining -= amount (fails if would go negative) - Use for: downgrades, refunds, policy enforcement
RESET (resize allocated): - allocated = amount - remaining = amount - reserved - spent - debt - spent, reserved, debt all preserved - Use for: plan changes, limit adjustments, ceiling resize - NOT the operation for billing-period boundaries — see RESET_SPENT
RESET_SPENT (new billing period): - allocated = amount - spent = (request.spent if supplied, else 0) - remaining = allocated - spent - reserved - debt - reserved preserved (active reservations straddle the period
and will land in the new period's spent when they commit)
- debt preserved (periods don't forgive debt; use REPAY_DEBT) - Optional
spentfield supports: migration from other billing
systems (start with existing consumption), prorated mid-period
signup, credit-back/compensation, state correction.
Must be >= 0 when supplied. Default 0 covers routine period
rollovers. - Emits
budget.reset_spentevent (distinct frombudget.reset)
withspent_override_providedflag so compliance dashboards
can distinguish routine rollovers from explicit adjustments.
REPAY_DEBT: - debt -= amount (use remaining if debt < amount) - Use for: manual debt reconciliation
IDEMPOTENCY: - Required idempotency_key prevents double-funding - Replayed requests return original response
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
When using ApiKeyAuth: ignored — the authenticated tenant from the API key is always used for scoping. When using AdminKeyAuth: REQUIRED — specifies which tenant's budget to fund. Returns 400 if missing when using AdminKeyAuth.
Canonical scope identifier, e.g., "tenant:acme" or "tenant:acme/workspace:prod"
"USD_MICROCENTS""TOKENS""CREDITS""RISK_POINTS"Request Body
Responses
Funding operation completed
Look up a single budget by exact scope and unit
Returns a single budget ledger matching the exact (scope, unit) pair. Unlike listBudgets which uses scope_prefix (prefix match), this endpoint performs exact scope matching — the budget is uniquely identified by the (scope, unit) pair.
AUTHORIZATION: - ApiKeyAuth: scope_filter is enforced; only accessible if scope matches key's filter. - AdminKeyAuth: Accepted as alternative (dual-auth).
No tenant_id required — the budget is uniquely identified by (scope, unit).
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Exact canonical scope identifier, e.g., "tenant:acme/workspace:prod"
"USD_MICROCENTS""TOKENS""CREDITS""RISK_POINTS"Responses
Budget ledger found
Apply a balance-mutation to every budget matching a filter
Apply CREDIT, DEBIT, RESET, RESET_SPENT, or REPAY_DEBT to every budget ledger matching the provided filter in a single synchronous request. Mirrors /v1/admin/tenants/bulk-action and /v1/admin/webhooks/bulk-action in body shape, safety semantics (expected_count gate, idempotency_key, 500-row hard cap), and per-row outcome envelope. Resolves the operational pain described in cycles-server-admin issue #99: "Bulk Budget Reset at Tenant or Parent-Scope Level" — when a billing period rolls over, operators no longer iterate listBudgets + per-row fundBudget; they issue one bulk request scoped by tenant_id and (optionally) scope_prefix.
OPERATION-DISCRIMINATED REQUEST: - The action enum names which balance-mutation to apply
uniformly across the matched set. The action determines
which payload fields are required:
- CREDIT, DEBIT, RESET, REPAY_DEBT: require
amount. - RESET_SPENT: requires
amount;spentoptional (defaults to 0).
- Operation semantics MATCH BudgetFundingRequest exactly so
there is one place to read the per-operation balance math.
Anything fundBudget can do to one ledger, this endpoint can
do to a filtered set. - Server MUST validate the action/payload combination BEFORE
counting matches or mutating any row; an invalid combination
→ HTTP 400, no writes.
FILTER SEMANTICS: - Filter block mirrors the query params of listBudgets
(scope_prefix, unit, status, over_limit, has_debt,
utilization_min/max, search), AND combination, ILIKE match
on search. Operators preview the affected set by issuing
GET /v1/admin/budgets with the same filter before invoking
bulk-action and populating expected_count from the count.
tenant_idis REQUIRED (cross-tenant safety — see
BudgetBulkFilter). Cascading reset across a scope subtree
usesscope_prefix; no separatecascadeflag.
SAFETY: - expected_count gate: server counts before mutation;
mismatch → 409 COUNT_MISMATCH with no writes. See
bulkActionTenants for full rationale (operator preview
drifted; refuse rather than over-apply).
- idempotency_key: 15-min replay window; repeat submits
return the original response without re-applying. - HARD LIMIT: 500 matching rows. Larger filters → HTTP 400
LIMIT_EXCEEDED. Operators with > 500 budgets in a
rollover batch must partition by scope_prefix (the natural
partition for cascading resets). - Overall HTTP 200 even when some rows fail; response
envelope reports succeeded / failed / skipped counts.
Common per-row failure codes: BUDGET_EXCEEDED (DEBIT would
take remaining negative), INVALID_TRANSITION (unit
mismatch, ledger CLOSED).
EVENTS (document revision 0.1.25.32): - Server MUST emit one Event per successfully-mutated row,
typed by action:
- CREDIT →
budget.funded - DEBIT →
budget.debited - RESET →
budget.reset - RESET_SPENT →
budget.reset_spent - REPAY_DEBT →
budget.debt_repaid
Skipped rows (idempotent no-ops) and failed rows MUST NOT
produce an Event — emission is bound to actual balance
mutation, matching the single-op fundBudget path.
- Each emitted Event carries
correlation_id = budget_bulk_action:<action>:<request_id>
(action lowercased, e.g.budget_bulk_action:credit:req_abc).
Operators retrieve the full bulk fan-out via
GET /v1/admin/events?correlation_id=…; the shared
request_id also ties every emitted row to the invocation's
single AuditLogEntry.
AUDIT LOG: - One AuditLogEntry per bulk-action invocation (not per
row). The entry records actor_type=ADMIN_ON_BEHALF_OF,
tenant_id from the filter, operation=bulkActionBudgets,
and embeds the full per-row outcome (succeeded / failed /
skipped ledger_ids) in the entry payload so security
review can reconstruct exactly what was changed without
replaying the bulk request.
AUTHORIZATION: - AdminKeyAuth only. Tenants cannot bulk-mutate their own
budgets via this endpoint; per-budget mutation remains
available via fundBudget.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Bulk action applied (may include per-row failures)
List policies
AUTHORIZATION: - ApiKeyAuth: Tenant can list their own policies only (scoped by authenticated tenant) - AdminKeyAuth: Accepted as alternative for read access (dual-auth).
When using AdminKeyAuth, tenant_id query parameter is REQUIRED for scoping.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
When using ApiKeyAuth: ignored — the authenticated tenant from the API key is always used for scoping. When using AdminKeyAuth: REQUIRED — specifies which tenant's policies to list. Returns 400 if missing when using AdminKeyAuth.
"ACTIVE""DISABLED"Optional. Filter to policies that have at least one action quota configured. Only meaningful on servers implementing the v0.1.26 action-quotas extension. Servers that don't recognize this parameter MUST ignore it without error (additive-parameter guarantee).
Optional. Filter to policies that mention the given action_kind in any quota rule or access control list. Enables incident investigation ("which policies block payment.charge?"). Only meaningful on servers implementing the v0.1.26 action-kinds extension. Servers that don't recognize this parameter MUST ignore it without error (additive-parameter guarantee).
6450Responses
Policy list
Create a policy with caps and limits
Defines caps (soft-landing constraints) and rate limits for scopes. Policies are evaluated during reservation requests.
AUTHORIZATION: - ApiKeyAuth (X-Cycles-API-Key): tenant creates policies for their
own scopes only. tenant_id is implicit from the authenticated key
and MUST NOT appear in the request body.
- AdminKeyAuth (X-Admin-API-Key): admin operator creates a policy
on behalf of a tenant. tenant_id is REQUIRED in the request body.
Audit log records actor_type=ADMIN_ON_BEHALF_OF. Matches the
existing dual-auth pattern on read endpoints.
SCOPE PATTERNS: - "tenant:acme-corp" (exact match) - "tenant:acme-corp/" (all descendants) - "agent:" (all agents system-wide) - "*/agent:summarizer" (agent across all tenants)
PRIORITY: - Higher priority policies override lower priority - If multiple policies match, highest priority wins
EFFECTIVE DATES: - Optional time-bounded policies - Useful for temporary restrictions or trials
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Policy created
Update policy properties
Update any mutable field on an existing policy.
AUTHORIZATION: - ApiKeyAuth: tenant scoping enforced — only the owning tenant
can update.
- AdminKeyAuth: admin operator can update policies on behalf of
any tenant. Server validates that the policy belongs to the
tenant owning the path-resolved policy_id; no tenant_id is
needed in the body because policy_id already pins it. Audit
log records actor_type=ADMIN_ON_BEHALF_OF.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Request Body
Responses
Policy updated
List API keys
Returns API keys, optionally filtered by tenant. Full key secrets are never returned, only prefixes and metadata.
AUTHORIZATION: - AdminKeyAuth: admin operator lists keys. tenant_id is OPTIONAL.
When omitted, returns keys across all tenants (cursor-paginated).
When provided, scopes the result to that tenant.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Optional tenant filter. When omitted under AdminKeyAuth, returns keys across all tenants. When provided, scopes the result to the specified tenant.
"ACTIVE""REVOKED""EXPIRED"Free-text case-insensitive substring match. Matches across: key_id, name. Combined with other filter params using AND semantics. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). Empty string MUST be treated as absent. Max length 128 characters; longer values MUST be rejected with HTTP 400.
128Sort key. When provided, results are returned in the requested order and the returned cursor encodes the sort key so "Load more" continues in sort order. When omitted, servers use their existing default ordering. Servers that don't recognize the parameter MUST ignore it without error (additive-parameter guarantee).
"key_id""name""tenant_id""status""created_at""expires_at""created_at"Sort direction. Default descending.
"asc""desc""desc"50Responses
API key list
Create an API key for a tenant
Provisions a new API key bound to a tenant. This is the only time the full key secret is returned. Store it securely.
KEY FORMAT: - Prefix: cyc_live_{random} or cyc_test_{random} - Random part: 32 characters, cryptographically random - Stored as: bcrypt hash of full key
PERMISSIONS: - Default for tenant keys: [reservations:create, reservations:commit,
reservations:release, reservations:extend, reservations:list,
balances:read, budgets:read, budgets:write, policies:read,
policies:write]
- Webhook/event self-service requires explicit opt-in:
webhooks:read, webhooks:write, events:read are NOT in the default set. - This endpoint provisions tenant-scoped API keys only. The admin key
(X-Admin-API-Key) is configured at the server level, not provisioned
through this endpoint. - Admin permissions (admin:read, admin:write, and granular admin
permissions like admin:tenants:read) are accepted for backward
compatibility but SHOULD NOT be assigned to new tenant keys.
Use the granular tenant permissions instead. - Can be restricted to specific scopes via scope_filter
EXPIRY: - Recommended: 90 days for security - Can be set indefinitely but not recommended - Expired keys auto-fail validation
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
API key created
Revoke an API key
Immediately revokes a key. The key will fail validation from this point forward. Active reservations using this key can still be committed/released, but no new operations are permitted.
REVOCATION IS PERMANENT: - Cannot be undone - Revoked keys remain in database for audit trail - Status transitions: ACTIVE → REVOKED
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Query Parameters
512Responses
Key revoked
Update API key properties
Partial update — only provided fields are modified. Allows changing permissions, scope restrictions, and metadata without rotating the key secret.
MUTABLE FIELDS: - permissions: Replace the full permission set - scope_filter: Replace scope restrictions - name, description, metadata: Update display/tagging info
IMMUTABLE FIELDS: - tenant_id, key_id, key_prefix, key_hash, expires_at, status - To change expiry: revoke and recreate - To change tenant: revoke and recreate
EVENTS: - Emits api_key.permissions_changed when permissions or scope_filter change.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Request Body
Responses
Key updated
Validate an API key and resolve tenant
Internal endpoint used by runtime enforcement layer to validate keys and derive effective tenant.
VALIDATION CHECKS: 1. Key exists in database 2. Key hash matches 3. Status is ACTIVE (not REVOKED or EXPIRED) 4. Current time < expires_at 5. Tenant is ACTIVE (not SUSPENDED or CLOSED)
RESPONSE: - If valid: returns tenant_id, permissions, scope_filter - If invalid: returns valid=false with reason
CACHING: - Results should be cached with short TTL (60s) - Invalidate cache on key revocation
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Validation result
Introspect authenticated credential and return effective capabilities
Returns the effective permissions and derived capabilities for the authenticated credential. Used by admin dashboards and by multi-role dashboards that accept both admin and tenant API keys to determine which pages/features the current user can access.
AUTH: - AdminKeyAuth: returns auth_type="admin", permissions=["*"],
capabilities with all flags true. tenant_id and scope_filter MUST
be absent.
- ApiKeyAuth: returns auth_type="tenant", permissions=[concrete
Permission values], tenant_id=<key's tenant>, scope_filter=<key's
filter if any>, capabilities derived from permissions per the
NORMATIVE table in AuthIntrospectResponse.capabilities.
CAPABILITIES: - Derived from raw permissions — the frontend uses booleans for UI
gating. Admin auth yields all-true; tenant auth yields a subset
per the published derivation table.
BACKWARD COMPATIBILITY: - Servers that do not implement ApiKeyAuth on this endpoint
(either because they pre-date the tenant-introspect contract,
or because deployment policy disables it) SHOULD return 401 on
ApiKeyAuth. Clients MUST handle 401 gracefully — a 401 on
introspect means "this key has no accessible dashboard surface,"
regardless of why.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Responses
Authentication introspection result
Get server-aggregated operational dashboard overview
Returns a single-request operational health snapshot for the admin dashboard. Includes entity counts (tenants, budgets, webhooks), top-offender arrays (over-limit budgets, debt scopes, failing webhooks), and recent event summaries (denials, expiries) — all within a server-defined time window (default 1 hour, returned as event_window_seconds).
DESIGN: - Aggregation is performed server-side through existing repositories. - Top-offender arrays are capped at 10 items each. - Recent events use a 1-hour window (event_window_seconds: 3600). - No client-side pagination or aggregation needed.
PERFORMANCE: - Pages through all tenants, budgets, and webhooks for accurate counts. - For large deployments (100+ tenants), consider caching with short TTL.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Responses
Operational overview snapshot
Query audit logs
Returns audit trail of all authenticated operations. Essential for compliance (SOC2, GDPR, etc.).
RETENTION: - Recommended: 90 days hot, 1 year cold storage - Critical for security incident investigation
FILTERING: - By tenant, key, time range, operation, status - Supports complex queries for forensics
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Filter by exact tenant id. Accepts the two documented sentinels in addition to real tenant ids: ?tenant_id=__admin__ surfaces admin-plane activity; ?tenant_id=__unauth__ surfaces the failed-pre-auth stream. See AuditLogEntry.tenant_id for full sentinel semantics.
Filter by operation ID. Exact-or-IN-list. Formal wire contract is the explode=false comma-separated form — a single scalar ?operation=createBudget or a comma- separated list ?operation=createBudget,updateBudget. Servers MAY additionally accept the repeated form ?operation=createBudget&operation=updateBudget as an implementation convenience; clients MUST NOT rely on it for portability. IN-list members are OR-composed; the predicate AND-composes with other filters. maxItems 25. Additive shape promotion — older clients sending a single scalar continue to work byte-identically on servers implementing this revision.
25Filter by exact HTTP status. MUST NOT combine with status_min or status_max (server MUST reject the combination with HTTP 400 INVALID_REQUEST).
Filter by resource type (e.g., budget, tenant, api_key, policy, webhook, config). Exact-or-IN-list. Formal wire contract is the explode=false comma-separated form (single scalar or ?resource_type=budget,tenant). Servers MAY additionally accept the repeated form as an implementation convenience; clients MUST NOT rely on it. maxItems 25. Additive shape promotion — older clients sending a single scalar continue to work byte-identically.
25Filter by resource ID (e.g., ledger ID, key ID, subscription ID)
Filter by audit entry error_code. Exact-or-IN-list. Formal wire contract is the explode=false comma- separated form. Servers MAY additionally accept the repeated form as an implementation convenience; clients MUST NOT rely on it. Case-sensitive. IN-list members are OR-composed; the predicate AND-composes with other filters. maxItems 25.
NULL entry error_code (success entries) MUST NOT match — auditors asking "show me code X" never want success rows.
Forward-compat: values are NOT validated against the ErrorCode enum. Unknown codes match nothing at the filter layer (a newer client sending a newly-added enum value MUST NOT cause a 400 against an older server).
Additive parameter — servers that don't recognize it MUST ignore without error.
25NOT-IN-list filter on audit entry error_code. Removes matching rows from the result set.
NULL entry error_code MUST always pass — hiding noisy codes (e.g., INTERNAL_ERROR) MUST NOT silently hide successful (null-error_code) entries.
MAY combine with error_code (AND-composed: "narrow to set A, minus subset B"). Case-sensitive. maxItems 25.
Additive parameter — servers that don't recognize it MUST ignore without error.
25Inclusive lower bound on audit entry status. MUST be in [100, 599]. MUST NOT combine with exact status (server MUST reject the combination with HTTP 400 INVALID_REQUEST). When both status_min and status_max are present, server MUST reject status_min > status_max with HTTP 400.
NULL entry status MUST NOT silently pass the range predicate; entries with absent status are treated as out-of-range for any numeric bound.
Additive parameter — servers that don't recognize it MUST ignore without error.
100599Inclusive upper bound on audit entry status. MUST be in [100, 599]. MUST NOT combine with exact status. NULL entry status does not satisfy the bound (see status_min for the identical NULL rule).
Additive parameter — servers that don't recognize it MUST ignore without error.
100599"date-time""date-time"Free-text case-insensitive substring match. Matches across: resource_id, log_id, error_code, operation. Combined with other filter params using AND semantics. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). Empty string MUST be treated as absent. Max length 128 characters; longer values MUST be rejected with HTTP 400.
128Filter by exact trace_id. 32 lowercase hex characters (W3C Trace Context trace-id). Narrows the audit log to entries belonging to a single logical operation (may span multiple HTTP requests). When combined with other filters, AND-composed. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). See CORRELATION AND TRACING in cycles-protocol-v0.yaml.
"^[0-9a-f]{32}$"Filter by exact request_id. Narrows the audit log to the entry produced by a single HTTP request. When combined with other filters, AND-composed. Typically yields 0 or 1 row (one audit entry per authenticated request). Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee).
Sort key. When provided, results are returned in the requested order and the returned cursor encodes the sort key so "Load more" continues in sort order. When omitted, servers use their existing default ordering. Servers that don't recognize the parameter MUST ignore it without error (additive-parameter guarantee).
"timestamp""operation""resource_type""tenant_id""key_id""status""timestamp"Sort direction. Default descending.
"asc""desc""desc"50Responses
Audit log entries
Webhooks
Pillar 4: Webhook subscription management (admin and tenant self-service)
Operations
List webhook subscriptions
Returns paginated list of webhook subscriptions. Filter by tenant, status, or event type.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
"ACTIVE""PAUSED""DISABLED"Filter to subscriptions that include this event type
"budget.created""budget.updated""budget.funded""budget.debited""budget.reset""budget.reset_spent""budget.debt_repaid""budget.frozen""budget.unfrozen""budget.closed""budget.threshold_crossed""budget.exhausted""budget.over_limit_entered""budget.over_limit_exited""budget.debt_incurred""budget.burn_rate_anomaly""reservation.denied""reservation.denial_rate_spike""reservation.expired""reservation.expiry_rate_spike""reservation.commit_overage""tenant.created""tenant.updated""tenant.suspended""tenant.reactivated""tenant.closed""tenant.settings_changed""webhook.created""webhook.updated""webhook.paused""webhook.resumed""webhook.disabled""webhook.deleted""api_key.created""api_key.revoked""api_key.expired""api_key.permissions_changed""api_key.auth_failed""api_key.auth_failure_rate_spike""policy.created""policy.updated""policy.deleted""system.store_connection_lost""system.store_connection_restored""system.high_latency""system.webhook_delivery_failed""system.webhook_test"Free-text case-insensitive substring match. Matches across: subscription_id, url. Combined with other filter params using AND semantics. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). Empty string MUST be treated as absent. Max length 128 characters; longer values MUST be rejected with HTTP 400.
128Sort key. When provided, results are returned in the requested order and the returned cursor encodes the sort key so "Load more" continues in sort order. When omitted, servers use their existing default ordering. Servers that don't recognize the parameter MUST ignore it without error (additive-parameter guarantee).
"url""tenant_id""status""consecutive_failures""consecutive_failures"Sort direction. Default descending.
"asc""desc""desc"110050Responses
Subscription list
Create a webhook subscription
Registers a new webhook endpoint to receive events.
The signing_secret is returned ONLY in this response — store it securely. If not provided in the request, the server generates a cryptographically random secret.
TENANT SCOPING: - Provide tenant_id in query to scope the subscription to a specific tenant. - Omit tenant_id to create a system-wide subscription (receives events from all tenants). - System-wide subscriptions still respect scope_filter if provided.
EVENTS (document revision 0.1.25.33): - On success, server MUST emit one webhook.created Event.
Payload conforms to EventDataWebhookLifecycle with
new_status = ACTIVE and previous_status omitted.
correlation_id = webhook_create:<subscription_id>.
AUTHORIZATION: - Requires admin key (X-Admin-API-Key)
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Scope subscription to a specific tenant. Omit for system-wide.
Request Body
Responses
Subscription created
Get webhook subscription details
Returns full subscription configuration and delivery health metrics. signing_secret and custom header values are masked in the response.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Subscription details
Delete webhook subscription
Permanently removes the subscription. Pending deliveries are cancelled. This operation is irreversible.
EVENTS (document revision 0.1.25.33): - On success, server MUST emit one webhook.deleted Event.
Payload conforms to EventDataWebhookLifecycle with
previous_status set to the subscription's status at time
of deletion and new_status omitted.
correlation_id = webhook_delete:<subscription_id>.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Subscription deleted
Update webhook subscription
Partial update — only provided fields are modified.
COMMON OPERATIONS: - Re-enable a DISABLED subscription: set status to ACTIVE (resets consecutive_failures) - Pause delivery: set status to PAUSED - Rotate signing secret: provide new signing_secret value - Change event types: provide new event_types array (replaces, does not merge)
EVENTS (document revision 0.1.25.33): - On every successful PATCH the server MUST emit exactly one
Event, typed by the nature of the change:
* Status unchanged, any other field(s) mutated →
webhook.updated. changed_fields lists the mutated
field names.
* Status ACTIVE → PAUSED → webhook.paused.
* Status PAUSED → ACTIVE → webhook.resumed.
* Status DISABLED → ACTIVE (operator re-enable) →
webhook.resumed.
When a single PATCH both changes status AND mutates other
fields, the server emits the status-typed event
(webhook.paused / webhook.resumed) and changed_fields
lists the non-status mutations for operator visibility.
A no-op PATCH (zero fields mutated) MUST NOT emit an Event.
- Payload conforms to EventDataWebhookLifecycle.
correlation_id =webhook_update:<subscription_id>:<request_id>. - Auto-disable after failure threshold produces
webhook.disabledvia the dispatcher, not via this PATCH
path. See WebhookSubscription.FAILURE HANDLING.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Request Body
Responses
Subscription updated
Send a test event to the webhook endpoint
Sends a synthetic test event to the subscription's URL to verify connectivity and authentication. The test event has event_type "system.webhook_test" and is signed with the subscription's signing_secret.
BEHAVIOR: - Does NOT count toward consecutive_failures. - Does NOT affect subscription status. - Returns the HTTP response status and timing from the endpoint.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Test result
List delivery attempts for a subscription
Returns paginated delivery history for debugging webhook issues. Includes response status, timing, and error details for each attempt.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Query Parameters
Filter by delivery status
"PENDING""SUCCESS""FAILED""RETRYING""date-time""date-time"110050Responses
Delivery list
Replay events to a webhook subscription
Re-delivers historical events to the subscription's endpoint. Useful for recovering from outages or backfilling a new subscription.
BEHAVIOR: - Events are delivered in chronological order. - Each delivery is tracked as a new WebhookDelivery with source "replay". - Replay respects the subscription's retry policy. - Concurrent replays to the same subscription are NOT allowed.
LIMITS: - Maximum 1000 events per replay request. - Use from/to to control the replay window.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Request Body
Responses
Replay accepted (processing asynchronously)
Apply a lifecycle action to every webhook subscription matching a filter
Apply PAUSE, RESUME, or DELETE to every webhook subscription matching the provided filter in a single synchronous request. Mirrors /v1/admin/tenants/bulk-action in body shape, safety semantics (expected_count gate, idempotency_key, 500-row cap), and response envelope. Supports admin-dashboard workflows such as "pause every subscription for tenant acme" or "delete every subscription with url containing staging".
FILTER SEMANTICS: - Filter block mirrors the query params of
listWebhookSubscriptions (tenant_id, status, event_type,
search). AND combination, ILIKE match on search. Operator
previews the affected set via GET /v1/admin/webhooks with the
same filter before invoking bulk-action.
ACTION SEMANTICS: - PAUSE: status ACTIVE → PAUSED. Idempotent when already PAUSED
or DISABLED (row goes into skipped[]).
- RESUME: status PAUSED → ACTIVE. Idempotent when already
ACTIVE. DISABLED subscriptions cannot be resumed (row goes
intofailed[]with INVALID_TRANSITION). - DELETE: removes the subscription record permanently. Not
reversible. Rows missing (already deleted) go into
skipped[].
SAFETY: - expected_count gate: server counts before mutation; mismatch
→ 409 COUNT_MISMATCH with no writes. See bulkActionTenants
for full rationale.
- idempotency_key: 15-min replay window; repeat submits return
the original response without re-applying. - HARD LIMIT: 500 matching rows. Larger filters → HTTP 400
LIMIT_EXCEEDED. - Overall HTTP 200 even when some rows fail; response envelope
reports success/failure counts.
EVENTS (document revision 0.1.25.33): - Server MUST emit one Event per successfully-mutated row,
typed by action: PAUSE → webhook.paused,
RESUME → webhook.resumed, DELETE → webhook.deleted.
Skipped rows (ALREADY_IN_TARGET_STATE, MISSING) and failed
rows MUST NOT produce an Event — emission is bound to actual
state transition, matching the single-op
createWebhookSubscription / updateWebhookSubscription /
deleteWebhookSubscription contract.
- Each emitted Event carries
correlation_id = webhook_bulk_action:<action>:<request_id>
(action lowercased, e.g.
webhook_bulk_action:pause:req_abc). Operators retrieve the
full bulk fan-out via
GET /v1/admin/events?correlation_id=…; the shared request_id
also ties every emitted row to the invocation's single
AuditLogEntry. - Event payload conforms to EventDataWebhookLifecycle. -
webhook.disabledis NOT produced by bulkActionWebhooks —
that EventType is reserved for the auto-health-driven
transition described in
WebhookSubscription.FAILURE HANDLING. Operator PAUSE actions
always emitwebhook.pausedregardless of prior status.
AUDIT LOG: - One AuditLogEntry per bulk-action invocation (not per row).
Per-row Events (above) are the operator-visible audit trail;
the AuditLogEntry is the compliance-facing invocation record.
AUTHORIZATION: - AdminKeyAuth only.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Bulk action applied (may include per-row failures)
Get webhook security configuration
Returns the current server-level webhook security configuration including blocked CIDR ranges and allowed URL patterns.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Responses
Current webhook security config
Update webhook security configuration
Replaces the server-level webhook security configuration. Changes take effect immediately for all subsequent webhook create/update operations. Existing webhook subscriptions are NOT retroactively validated.
CAUTION: Removing blocked CIDR ranges may expose the server to SSRF attacks.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Request Body
Responses
Config updated
List webhooks for the authenticated tenant (or a specified tenant under admin auth)
Returns webhook subscriptions scoped by the authenticated caller.
TENANCY (NORMATIVE):
- Under ApiKeyAuth: results are scoped to the effective tenant
derived from auth. Thetenantquery parameter MUST NOT be
set (or, if accepted, is validation-only and MUST match the
effective tenant). - Under AdminKeyAuth: admin has no effective
tenant. Thetenantquery parameter is REQUIRED as a FILTER.
Omitting it MUST return 400 INVALID_REQUEST with message
"tenant query parameter is required when using admin key
authentication". Same single-param dual-semantic pattern as
listBudgets / listPolicies / listReservations.
PERMISSIONS: - ApiKeyAuth: requires webhooks:read permission on the API key. - AdminKeyAuth: no permission check beyond admin key validity.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Under AdminKeyAuth: REQUIRED — specifies which tenant's webhooks to list. Under ApiKeyAuth: MUST NOT be set (the authenticated key's tenant is used).
"ACTIVE""PAUSED""DISABLED"110050Responses
Subscription list
Create a webhook for the authenticated tenant
Tenant-scoped webhook creation. The subscription is automatically scoped to the authenticated tenant. Tenants can only subscribe to tenant-accessible event types: budget., reservation., tenant.* (26 of 40 types).
api_key., policy., and system.* events require admin access.
PERMISSIONS: - Requires webhooks:write permission on the API key.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Request Body
Responses
Subscription created
Get a tenant's webhook subscription
Returns webhook details.
TENANCY:
- Under ApiKeyAuth: returns 404 if the subscription belongs to
a different tenant (cross-tenant reads look like not-found,
not forbidden). - Under AdminKeyAuth: the owning tenant is
resolved from the subscription record; admin can read any
tenant's subscription. 404 only when no subscription exists
with the given id.
PERMISSIONS: - ApiKeyAuth: requires webhooks:read permission on the API key. - AdminKeyAuth: no permission check beyond admin key validity.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Subscription details
Delete a tenant's webhook subscription
Permanently removes the subscription. Pending deliveries for this subscription will fail.
TENANCY:
- Under ApiKeyAuth: 404 on cross-tenant subscription.
- Under AdminKeyAuth: owning tenant resolved from
the subscription record. Primary ops use case is force-removing
a webhook that a tenant refuses to fix and is impacting
shared infrastructure.
AUDIT (NORMATIVE under AdminKeyAuth):
- Admin-driven deletes MUST record actor_type=admin_on_behalf_of
in the shared audit store. Callers SHOULD populate a
structured reason (e.g.,[WEBHOOK_FORCE_DELETE] abuse-report-42)
in the audit entry metadata for traceability.
PERMISSIONS: - ApiKeyAuth: requires webhooks:write permission on the API key. - AdminKeyAuth: no permission check beyond admin key validity.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Subscription deleted
Update a tenant's webhook subscription
Partial update — only provided fields are modified. Restricted to tenant-accessible event types.
TENANCY:
- Under ApiKeyAuth: 404 on cross-tenant subscription.
- Under AdminKeyAuth: owning tenant resolved from
the subscription record. Primary ops use case is pausing a
flapping webhook (status=PAUSED).
AUDIT (NORMATIVE under AdminKeyAuth):
- Admin-driven updates MUST record actor_type=admin_on_behalf_of
in the shared audit store so the governance audit-query
surface lists them alongside other admin-on-behalf-of
actions. Callers SHOULD include a structured reason in the
request body'smetadata(e.g.,{"reason": "[WEBHOOK_PAUSE] incident INC-1234"}) for grep-ability.
PERMISSIONS: - ApiKeyAuth: requires webhooks:write permission on the API key. - AdminKeyAuth: no permission check beyond admin key validity.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Request Body
Responses
Subscription updated
Send a test event to a tenant's webhook
Sends a synthetic system.webhook_test event. Does not count toward consecutive failures.
TENANCY:
- Under ApiKeyAuth: 404 on cross-tenant subscription.
- Under AdminKeyAuth: owning tenant resolved from
the subscription record. Primary ops use case is verifying
that a paused/failing webhook is reachable after the tenant
fixes their endpoint, before flipping status back to ACTIVE.
AUDIT: test events are not required to produce an audit entry under AdminKeyAuth (diagnostic, idempotent, non-state-mutating on the subscription itself); a delivery record is created as usual. Servers MAY still log for operational visibility.
PERMISSIONS: - ApiKeyAuth: requires webhooks:write permission on the API key. - AdminKeyAuth: no permission check beyond admin key validity.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Test result
List delivery attempts for a tenant's webhook
Returns delivery history with status, response codes, and error details. Supports filtering by status and date range.
TENANCY:
- Under ApiKeyAuth: 404 on cross-tenant subscription.
- Under AdminKeyAuth: owning tenant resolved from
the subscription record. Primary ops use case is diagnosing
which specific delivery failures tripped the auto-disable
threshold (drill down from the PATCH pause flow).
PERMISSIONS: - ApiKeyAuth: requires webhooks:read permission on the API key. - AdminKeyAuth: no permission check beyond admin key validity.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Query Parameters
"PENDING""SUCCESS""FAILED""RETRYING""date-time""date-time"110050Responses
Delivery list
Query the event stream
Returns paginated events with filtering by type, category, tenant, scope, and time range. This is the canonical event log — all events that triggered (or would have triggered) webhooks are queryable here.
USE CASES: - Debug why a webhook fired (or didn't fire) - Reconstruct event history for a scope - Build custom integrations without webhooks (poll-based) - Audit trail supplement (events are more granular than audit logs)
RETENTION: - Same as audit log retention (recommended: 90 days hot, 1 year cold).
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Query Parameters
Filter by specific event type
"budget.created""budget.updated""budget.funded""budget.debited""budget.reset""budget.reset_spent""budget.debt_repaid""budget.frozen""budget.unfrozen""budget.closed""budget.threshold_crossed""budget.exhausted""budget.over_limit_entered""budget.over_limit_exited""budget.debt_incurred""budget.burn_rate_anomaly""reservation.denied""reservation.denial_rate_spike""reservation.expired""reservation.expiry_rate_spike""reservation.commit_overage""tenant.created""tenant.updated""tenant.suspended""tenant.reactivated""tenant.closed""tenant.settings_changed""webhook.created""webhook.updated""webhook.paused""webhook.resumed""webhook.disabled""webhook.deleted""api_key.created""api_key.revoked""api_key.expired""api_key.permissions_changed""api_key.auth_failed""api_key.auth_failure_rate_spike""policy.created""policy.updated""policy.deleted""system.store_connection_lost""system.store_connection_restored""system.high_latency""system.webhook_delivery_failed""system.webhook_test"Filter by event category
"budget""tenant""api_key""policy""reservation""system""webhook"Filter by scope path (prefix match)
Filter by correlation ID to find related events
Filter by exact trace_id. 32 lowercase hex characters (W3C Trace Context trace-id). Narrows the event stream to events belonging to a single logical operation (may span multiple HTTP requests, so typically yields MORE rows than a request_id filter). When combined with other filters, AND-composed. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). See CORRELATION AND TRACING in cycles-protocol-v0.yaml.
"^[0-9a-f]{32}$"Filter by exact request_id. Narrows the event stream to events emitted as side effects of a single HTTP request. When combined with other filters, AND-composed. Complements trace_id for debug scenarios like "show me all events emitted by this specific API call" (e.g., the fan-out from a bulk-action endpoint). Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee).
"date-time""date-time"Free-text case-insensitive substring match. Matches across: correlation_id, scope. Combined with other filter params using AND semantics. Additive parameter — servers that don't recognize it MUST ignore without error (additive-parameter guarantee). Empty string MUST be treated as absent. Max length 128 characters; longer values MUST be rejected with HTTP 400.
128Sort key. When provided, results are returned in the requested order and the returned cursor encodes the sort key so "Load more" continues in sort order. When omitted, servers use their existing default ordering. Servers that don't recognize the parameter MUST ignore it without error (additive-parameter guarantee).
"event_type""category""scope""tenant_id""timestamp""timestamp"Sort direction. Default descending.
"asc""desc""desc"110050Responses
Event list
Get a single event by ID
Returns the full event record including data payload. Useful for inspecting the exact payload that was (or would be) delivered to webhooks.
Authorizations
Administrative API key with full system access. Also accepted as an alternative to ApiKeyAuth on an explicit per-operation allowlist — the authoritative list is the union of operations whose security: block declares AdminKeyAuth (consult per-operation security blocks rather than this prose, which has historically drifted as the dual-auth surface expanded). When using AdminKeyAuth on list or fund endpoints, a tenant scoping parameter (typically tenant or tenant_id) is required for scoping (400 if missing) — the per-operation description specifies which. Lookup-style endpoints that uniquely identify a resource by non-tenant key (e.g. GET /v1/admin/budgets/lookup, where the (scope, unit) pair is unique) do NOT require a tenant parameter. Allowlisting is per-operation (exact method:path matching — no prefix matching, no wildcards) so new endpoints do not accidentally inherit admin-accessible status.
Parameters
Path Parameters
Responses
Event details
Query events for the authenticated tenant
Returns events scoped to the authenticated tenant only. Only tenant-accessible event types are returned (budget., reservation., tenant.*).
PERMISSIONS: - Requires events:read permission on the API key.
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Parameters
Query Parameters
"budget.created""budget.updated""budget.funded""budget.debited""budget.reset""budget.reset_spent""budget.debt_repaid""budget.frozen""budget.unfrozen""budget.closed""budget.threshold_crossed""budget.exhausted""budget.over_limit_entered""budget.over_limit_exited""budget.debt_incurred""budget.burn_rate_anomaly""reservation.denied""reservation.denial_rate_spike""reservation.expired""reservation.expiry_rate_spike""reservation.commit_overage""tenant.created""tenant.updated""tenant.suspended""tenant.reactivated""tenant.closed""tenant.settings_changed""webhook.created""webhook.updated""webhook.paused""webhook.resumed""webhook.disabled""webhook.deleted""api_key.created""api_key.revoked""api_key.expired""api_key.permissions_changed""api_key.auth_failed""api_key.auth_failure_rate_spike""policy.created""policy.updated""policy.deleted""system.store_connection_lost""system.store_connection_restored""system.high_latency""system.webhook_delivery_failed""system.webhook_test""budget""tenant""api_key""policy""reservation""system""webhook""date-time""date-time"110050Responses
Event list (tenant-scoped)
Query budget balances (admin-plane view)
Returns budget ledger balances for the authenticated tenant, with optional filtering by scope prefix and unit. This is the admin-plane balance query — the runtime-plane equivalent with subject-based filtering is defined in cycles-protocol-v0.yaml.
ADMIN-PLANE SEMANTICS: - Returns full ledger state including debt, overdraft_limit, is_over_limit - Scoped to effective tenant (derived from API key) - Supports scope_prefix filtering (prefix match on canonical scope) - Supports unit filtering
Authorizations
Tenant-scoped API key for runtime operations (consistent with Cycles Protocol)
Parameters
Query Parameters
Filter by scope prefix
"USD_MICROCENTS""TOKENS""CREDITS""RISK_POINTS"501100Responses
Budget ledgers matching the query filters