---
title: "Get reservation details (optional, for debugging)"
method: GET
path: "/v1/reservations/{reservation_id}"
tags: ["Reservations"]
---

# Get reservation details (optional, for debugging)

`GET /v1/reservations/{reservation_id}`

## Request

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

Retrieve current status and details of a reservation by ID. Useful for debugging and monitoring long-running operations.
EXPIRY (NORMATIVE, revision 2026-07-03):
  - If the reservation exists but its status is EXPIRED, the server MUST
    return 410 with error=RESERVATION_EXPIRED (this operation's declared
    410 response). A reservation that never existed returns 404 NOT_FOUND.
  - EXPIRED reservations remain discoverable via listReservations, which
    returns them as normal 200 rows with status=EXPIRED — the 410 applies
    only to this single-resource GET. This codifies the reference
    implementation's settled behavior; the pre-revision text enumerated
    only commit/release/extend in the 410 rule, leaving GET ambiguous.

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
    read any reservation regardless of owning tenant; reservation_id
    already pins the owner so no extra parameter is needed.

## Path parameters

- `reservation_id` string, required

## Response `200`

Reservation details

- object: Reservation details returned by GET /v1/reservations/{reservation_id}. Useful for debugging.
  - `reservation_id` string, required
  - `status` 'ACTIVE' | 'COMMITTED' | 'RELEASED' | 'EXPIRED', required: Reservation lifecycle state (v1+ may add additional terminal states).
  - `idempotency_key` string
  - `subject` union, required: Dimension bag for hierarchical budgets. At least one standard field (tenant, workspace, app, workflow, agent, or toolset) MUST be provided. A subject containing only `dimensions` is invalid; server MUST return 400 INVALID_REQUEST. Hierarchy: tenant → workspace → app → workflow → agent → toolset. CHARSET (NORMATIVE, revision 2026-07-03): - Standard-field values (tenant/workspace/app/workflow/agent/toolset) SHOULD match ^[a-zA-Z0-9_.-]+$. Canonical scope identifiers and scope paths use ":" and "/" as structural delimiters, so delimiter, whitespace, and control characters have no stable canonical encoding. - Servers MAY reject standard-field values outside this pattern with 400 INVALID_REQUEST (the reference implementation does). Clients MUST NOT rely on out-of-pattern values being accepted, and portable clients SHOULD restrict themselves to the pattern above. EXTENSIBILITY (v0): - dimensions is an optional, user-defined map for alternative taxonomies (e.g., cost_center/department/project) and policy/reporting. - v0 servers MAY ignore dimensions for budgeting decisions; if they do, they still MUST accept and round-trip it. - Keys SHOULD be lowercase and match ^[a-z0-9_.-]+$ for stable canonicalization; values are opaque strings.
    - object
      - `tenant` string, required
      - `workspace` string
      - `app` string
      - `workflow` string
      - `agent` string
      - `toolset` string
      - `dimensions` object: Optional custom dimensions for enterprise taxonomies and policy/reporting.
    - object
      - `tenant` string
      - `workspace` string, required
      - `app` string
      - `workflow` string
      - `agent` string
      - `toolset` string
      - `dimensions` object: Optional custom dimensions for enterprise taxonomies and policy/reporting.
    - object
      - `tenant` string
      - `workspace` string
      - `app` string, required
      - `workflow` string
      - `agent` string
      - `toolset` string
      - `dimensions` object: Optional custom dimensions for enterprise taxonomies and policy/reporting.
    - object
      - `tenant` string
      - `workspace` string
      - `app` string
      - `workflow` string, required
      - `agent` string
      - `toolset` string
      - `dimensions` object: Optional custom dimensions for enterprise taxonomies and policy/reporting.
    - object
      - `tenant` string
      - `workspace` string
      - `app` string
      - `workflow` string
      - `agent` string, required
      - `toolset` string
      - `dimensions` object: Optional custom dimensions for enterprise taxonomies and policy/reporting.
    - object
      - `tenant` string
      - `workspace` string
      - `app` string
      - `workflow` string
      - `agent` string
      - `toolset` string, required
      - `dimensions` object: Optional custom dimensions for enterprise taxonomies and policy/reporting.
  - `action` object, required
    - `kind` string, required: Action type identifier. Recommended format: <category>.<operation> Examples: llm.completion, llm.embedding, tool.search, tool.calculator, db.query, db.write, http.get, http.post, file.upload, message.email, webhook.outbound
    - `name` string, required: Provider/model/tool identifier (e.g., "openai:gpt-4o-mini", "web.search")
    - `tags` string[]: Optional policy tags (e.g., ["prod","customer-facing"])
  - `reserved` object, required
    - `unit` 'USD_MICROCENTS' | 'TOKENS' | 'CREDITS' | 'RISK_POINTS', required: Standard units. USD_MICROCENTS preserves precision for per-call and batched accounting (int64). - 1 USD_MICROCENTS = 10^-6 cents = 10^-8 dollars - 1 USD = 100 cents = 10^8 USD_MICROCENTS - Max int64 ≈ 9.22e18 USD_MICROCENTS ≈ $92.2B TOKENS are integer token counts. CREDITS/RISK_POINTS are generic integer units (optional in v0 implementations).
    - `amount` integer, required
  - `committed` object
    - `unit` 'USD_MICROCENTS' | 'TOKENS' | 'CREDITS' | 'RISK_POINTS', required: Standard units. USD_MICROCENTS preserves precision for per-call and batched accounting (int64). - 1 USD_MICROCENTS = 10^-6 cents = 10^-8 dollars - 1 USD = 100 cents = 10^8 USD_MICROCENTS - Max int64 ≈ 9.22e18 USD_MICROCENTS ≈ $92.2B TOKENS are integer token counts. CREDITS/RISK_POINTS are generic integer units (optional in v0 implementations).
    - `amount` integer, required
  - `created_at_ms` integer, required
  - `expires_at_ms` integer, required
  - `finalized_at_ms` integer: Wall-clock time at which the reservation reached a terminal state. Populated on COMMITTED and RELEASED rows only; absent on ACTIVE and EXPIRED rows. The `finalized_from` / `finalized_to` window filter on `listReservations` (revision 2026-05-22) operates against this same field with the same population semantics.
  - `scope_path` string, required: Canonical scope path (server-derived)
  - `affected_scopes` string[], required: Canonical scope identifiers impacted by this reservation, in canonical order.
  - `metadata` object: Metadata supplied at RESERVE time (on the create-reservation request), if any. For metadata attached at COMMIT time see `committed_metadata`.
  - `committed_metadata` object: Metadata supplied on the COMMIT request (`CommitRequest.metadata`), preserved on the reservation record. Present on COMMITTED rows whose commit carried metadata; absent otherwise. Distinct from `metadata`, which is captured at reserve time.
  - `evidence` object: Map of artifact type to the CyclesEvidence reference emitted for that operation on a reservation. Lets a consumer jump from a reservation straight to its signed envelope(s) via `getEvidence` without having captured the `evidence_id` off the original reserve / commit / release response. Keys are the reservation-applicable artifact types: a reservation has at most a `reserve` entry plus one terminal entry (`commit` XOR `release`). TRANSPORT METADATA, NOT ATTESTED (see `CyclesEvidenceRef`) — each entry is recorded after its artifact's `evidence_id` was computed and is not part of any attested payload.
    - `reserve` object: Reference to the CyclesEvidence envelope emitted for an operation. The `evidence_id` is the sha256 content hash of the JCS-canonical envelope and is computed SYNCHRONOUSLY at decision time, so it is returned on the operation response even though the envelope is Ed25519-signed and stored ASYNCHRONOUSLY. A caller (e.g. an APS gateway) binds its own signed receipt to this evidence by recording `evidence_id`, then fetches the envelope at `cycles_evidence_url` (see `getEvidence`) to verify it offline. Because signing/storage is async, the envelope MAY be served shortly after this response — consumers SHOULD treat a transient `404` from `getEvidence` as not-yet-available and retry. TRANSPORT METADATA, NOT ATTESTED: `cycles_evidence` is added to the response for the caller's convenience and is NOT part of the evidence the envelope attests. `remaining_ttl_ms` on ReservationCreateResponse is likewise a volatile transport observation rather than attested decision data, so a same-key replay can safely recompute it. The `evidence_id` is computed over the operation response WITHOUT either transport-only field — the envelope's `payload.<artifact>.response` mirror (`cycles-evidence-v0.2.yaml`) keeps `additionalProperties: false` and omits them. Implementations MUST compute `evidence_id` before stamping transport-only fields onto the response, and MUST NOT include either field in the attested payload.
      - `evidence_id` string, required: sha256 content id of the emitted envelope; resolve via getEvidence.
      - `cycles_evidence_url` string, uri, required: Absolute URL of the signed envelope, formed as `{server_id}/evidence/{evidence_id}`. Note `server_id` is already the canonical deployment base INCLUDING the `/v1` prefix (e.g. `https://cycles.example.com/v1`), so the join adds only `/evidence/{evidence_id}` — it MUST NOT re-add `/v1`.
    - `commit` object: Reference to the CyclesEvidence envelope emitted for an operation. The `evidence_id` is the sha256 content hash of the JCS-canonical envelope and is computed SYNCHRONOUSLY at decision time, so it is returned on the operation response even though the envelope is Ed25519-signed and stored ASYNCHRONOUSLY. A caller (e.g. an APS gateway) binds its own signed receipt to this evidence by recording `evidence_id`, then fetches the envelope at `cycles_evidence_url` (see `getEvidence`) to verify it offline. Because signing/storage is async, the envelope MAY be served shortly after this response — consumers SHOULD treat a transient `404` from `getEvidence` as not-yet-available and retry. TRANSPORT METADATA, NOT ATTESTED: `cycles_evidence` is added to the response for the caller's convenience and is NOT part of the evidence the envelope attests. `remaining_ttl_ms` on ReservationCreateResponse is likewise a volatile transport observation rather than attested decision data, so a same-key replay can safely recompute it. The `evidence_id` is computed over the operation response WITHOUT either transport-only field — the envelope's `payload.<artifact>.response` mirror (`cycles-evidence-v0.2.yaml`) keeps `additionalProperties: false` and omits them. Implementations MUST compute `evidence_id` before stamping transport-only fields onto the response, and MUST NOT include either field in the attested payload.
      - `evidence_id` string, required: sha256 content id of the emitted envelope; resolve via getEvidence.
      - `cycles_evidence_url` string, uri, required: Absolute URL of the signed envelope, formed as `{server_id}/evidence/{evidence_id}`. Note `server_id` is already the canonical deployment base INCLUDING the `/v1` prefix (e.g. `https://cycles.example.com/v1`), so the join adds only `/evidence/{evidence_id}` — it MUST NOT re-add `/v1`.
    - `release` object: Reference to the CyclesEvidence envelope emitted for an operation. The `evidence_id` is the sha256 content hash of the JCS-canonical envelope and is computed SYNCHRONOUSLY at decision time, so it is returned on the operation response even though the envelope is Ed25519-signed and stored ASYNCHRONOUSLY. A caller (e.g. an APS gateway) binds its own signed receipt to this evidence by recording `evidence_id`, then fetches the envelope at `cycles_evidence_url` (see `getEvidence`) to verify it offline. Because signing/storage is async, the envelope MAY be served shortly after this response — consumers SHOULD treat a transient `404` from `getEvidence` as not-yet-available and retry. TRANSPORT METADATA, NOT ATTESTED: `cycles_evidence` is added to the response for the caller's convenience and is NOT part of the evidence the envelope attests. `remaining_ttl_ms` on ReservationCreateResponse is likewise a volatile transport observation rather than attested decision data, so a same-key replay can safely recompute it. The `evidence_id` is computed over the operation response WITHOUT either transport-only field — the envelope's `payload.<artifact>.response` mirror (`cycles-evidence-v0.2.yaml`) keeps `additionalProperties: false` and omits them. Implementations MUST compute `evidence_id` before stamping transport-only fields onto the response, and MUST NOT include either field in the attested payload.
      - `evidence_id` string, required: sha256 content id of the emitted envelope; resolve via getEvidence.
      - `cycles_evidence_url` string, uri, required: Absolute URL of the signed envelope, formed as `{server_id}/evidence/{evidence_id}`. Note `server_id` is already the canonical deployment base INCLUDING the `/v1` prefix (e.g. `https://cycles.example.com/v1`), so the join adds only `/evidence/{evidence_id}` — it MUST NOT re-add `/v1`.

## Other responses

- `400`: Error response
- `401`: Error response
- `403`: Error response
- `404`: Error response
- `410`: RESERVATION_EXPIRED — the reservation exists but its status is EXPIRED. See the EXPIRY note in this operation's description (revision 2026-07-03); EXPIRED rows remain visible via listReservations.
- `500`: Error response

---

[API](https://skmtc.dev/runcycles/apis/cycles-budget-authority-api.md) · [All operations](https://skmtc.dev/runcycles/apis/cycles-budget-authority-api/llms.txt) · [OpenAPI document](https://skmtc.dev/runcycles/apis/cycles-budget-authority-api/revisions/7d42267c1ea0?raw)
