---
title: "Get delegation"
method: GET
path: "/api/v1/delegations/{id}"
tags: ["Delegations"]
---

# Get delegation

`GET /api/v1/delegations/{id}`

## Request

- Base URL: `https://api.proof.holdings`
- URL: `https://api.proof.holdings/api/v1/delegations/{id}`
- Auth: one of:
  - HTTP bearer
  - API key in cookie `auth_token`

Fetch one of YOUR delegations by Mongo id or `ph_dlg_*` handle. Returns the stored publishable token (re-minting is billed, re-reading is not) and `effective_status` — the DERIVED liveness over both clocks: a delegation whose control proof was revoked or suspended reports it immediately, and one past the earlier of its own and the control proof's expiry reports `expired`.

## Path parameters

- `id` string, required: Delegation Mongo id or public handle (`ph_dlg_<32 hex>`)

## Response `200`

The delegation with its derived effective status

- DelegationDetail: A delegation with its derived effective status
  - `id` string, required: MongoDB ObjectId
  - `delegation_id` string, nullable, required: Stable public handle (`ph_dlg_<32 hex>`) — also the token's `sub`, and accepted by the proof status endpoint
  - `principal` string, required: The proven domain that authorized the delegate — derived from the control proof, never client input
  - `delegate` DelegateIdentifier, required: Typed delegate identifier
    - `type` 'url' | 'purl', required: Delegate identifier type: `purl` for a package (`pkg:npm/postmark-mcp`), `url` for an https endpoint
    - `value` string, required: The identifier. Canonicalized per type at creation: purl version/qualifiers/subpath are rejected (delegate the artifact, not a version); urls must be https with no credentials, query or fragment
  - `scope` string[], required
  - `control_proof` string, required: The control proof handle this delegation points down to
  - `status` 'active' | 'revoked', required: The owner's OWN record — whether they revoked this delegation themselves. Nothing else writes it: neither the control proof dying nor this delegation's own lifetime running out. Liveness is DERIVED and reported separately as `effective_status`. This stored field is also what `?status=` filters on
  - `revoked_at` string, date-time, nullable, required
  - `revoked_reason` string, nullable, required
  - `environment` 'production' | 'test', required
  - `issued_at` string, date-time, required
  - `expires_at` string, date-time, required: Never later than the control proof's own expiry at issuance (effective expiry is min of the two)
  - `created_at` string, date-time, required
  - `token` string, nullable, required: The signed delegation JWT — the PUBLISHABLE artifact (publish it in your MCP server card under `_meta` → `holdings.proof/delegation`). Same key, algorithm and JWKS as proof tokens
  - `effective_status` 'active' | 'revoked' | 'expired' | 'suspended', required: DERIVED liveness, computed at read time from BOTH clocks that govern a delegation: the control proof it stands on (cascade rule a — revoked, suspended or expired flows through) and its own `expires_at` (rule b — effective expiry is the earlier of the two). Either one running out reports `expired` here while the delegation's own `status` stays untouched. This is the field to render — `status` alone would show a live badge on a delegation every verifier already rejects
  - `is_valid` boolean, required: True only when `effective_status` is `active`. It is a restatement of that field, not a second opinion: expiry is decided once, inside the derivation above

## Other responses

- `404`: Delegation not found (uniform for foreign or missing)
- `503`: Delegation status could not be resolved (registry unreachable). Fails closed rather than reporting the stored status as if it were derived — retry

---

[API](https://skmtc.dev/proof/apis/proof-holdings-api.md) · [All operations](https://skmtc.dev/proof/apis/proof-holdings-api/llms.txt) · [OpenAPI document](https://skmtc.dev/proof/apis/proof-holdings-api/revisions/b15f506de696?raw)
