Reservations

Release an unused reservation

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 reason body field with a structured tag (e.g. "[INCIDENT_FORCE_RELEASE]") for grep-ability in the audit log.
post/v1/reservations/{reservation_id}/release

Request

  • Base URL: https://api.cycles.local
  • URL: https://api.cycles.local/v1/reservations/{reservation_id}/release
  • Auth: one of:
    • API key in header X-Cycles-API-Key
    • API key in header X-Admin-API-Key

Path parameters

reservation_idstring required

Headers

X-Idempotency-Keystring

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 outcome and payload (including any server-generated identifiers such as reservation_id), except that remaining_ttl_ms on a replayed createReservation or extendReservation success is a volatile response observation and is not part of the attested CyclesEvidence payload. When emitted, it MUST be recomputed from the original expires_at_ms and the current authoritative server time, never copied from the stored response; it MUST be 0 if the reservation is no longer ACTIVE. All other fields replay verbatim.

Request body

idempotency_keystring required
reasonstring

Response

Release succeeded

status'RELEASED' required

Example response

{
  "released": {
    "unit": "USD_MICROCENTS",
    "amount": 500000
  },
  "balances": [
    {
      "scope": "tenant:acme-corp/workspace:prod",
      "scope_path": "tenant:acme-corp/workspace:prod",
      "remaining": {
        "unit": "USD_MICROCENTS",
        "amount": 4577000
      },
      "reserved": {
        "unit": "USD_MICROCENTS",
        "amount": 500000
      },
      "spent": {
        "unit": "USD_MICROCENTS",
        "amount": 423000
      },
      "allocated": {
        "unit": "USD_MICROCENTS",
        "amount": 5500000
      }
    }
  ]
}

Changes

No recorded changes to this operation across all 1 revision of this API.