Release an unused reservation
POST
/v1/reservations/{reservation_id}/release
Releases reserved amount back to remaining budget.
IDEMPOTENCY (NORMATIVE): - On replay with the same idempotency_key, the server MUST return the original successful response payload.
TENANCY (NORMATIVE):
- Under ApiKeyAuth: if the reservation exists but is owned by
a different effective tenant, the server MUST return 403 FORBIDDEN. - Under AdminKeyAuth (added 2026-04-13): admin operators can
release any reservation regardless of owning tenant — the
ops use case is "force-expire a hung reservation" during
incident response. reservation_id pins the owner so no
extra parameter is needed.
AUDIT (NORMATIVE, AdminKeyAuth path):
- The audit-log entry for an admin-driven release MUST record
actor_type=admin_on_behalf_of (existing audit field, value
already used on createBudget / createPolicy / updatePolicy
in the governance-admin spec). This lets security review
distinguish admin-driven releases from tenant self-service
without joining to the keys table. - The entry MUST be discoverable via the governance plane's
audit-query surface (GET /v1/admin/audit/logs in the
governance-admin spec). Writing the entry to a store the
governance audit-query endpoint cannot read from does not
satisfy this requirement — the operational intent is that
admin-driven release actions surface in the same admin-
facing audit view that shows governance-plane audit
entries. How servers achieve this is an implementation
concern and out of scope for the spec. - Callers SHOULD populate the optional
reasonbody field
with a structured tag (e.g. "[INCIDENT_FORCE_RELEASE]")
for grep-ability in the audit log.
Authorizations
ApiKeyAuth
Type
API Key (header: X-Cycles-API-Key)
or
AdminKeyAuth
Type
API Key (header: X-Admin-API-Key)
Parameters
Header Parameters
X-Idempotency-Key
Optional idempotency key header. If both header and body idempotency_key are provided, they MUST match. Server MUST enforce idempotency per endpoint by (effective tenant, endpoint, idempotency_key). On replay of an idempotent request that previously succeeded, server MUST return the original successful response payload (including any server-generated identifiers such as reservation_id).
Type
string
Min Length
1Max Length
256Path Parameters
reservation_id*
Type
Requiredstring
Min Length
1Max Length
128Request Body
application/json
JSON "idempotency_key": "string", "reason": "string"
{
}
Responses
Release succeeded
application/json
JSON "status": "string", "released": { "unit": "string", "amount": 0 }, "balances": [ { "scope": "string", "scope_path": "string", "remaining": { "unit": "string", "amount": 0 }, "reserved": { "unit": "string", "amount": 0 }, "spent": { "unit": "string", "amount": 0 }, "debt": { "unit": "string", "amount": 0 }, "allocated": { "unit": "string", "amount": 0 }, "overdraft_limit": { "unit": "string", "amount": 0 }, "is_over_limit": true } ]
{
}