Delegations

Create delegation

Issue a delegation: your proven domain (the control_proof) authorizes an artifact — a package (purl) or an https endpoint (url) — for a set of capability scopes. Mints a signed delegation token (ES256 — same key and JWKS as proof tokens) carrying principal, delegate, scope, control_proof and its own revocation handle. The token is what you publish; the record is what you revoke. A requested lifetime longer than the control proof's remaining one is rejected, never truncated. Each mint consumes 1 proof from your plan quota (re-issuance included).

post/api/v1/delegations

Request

  • Base URL: https://api.proof.holdings
  • URL: https://api.proof.holdings/api/v1/delegations
  • Auth: one of:
    • HTTP bearer
    • API key in cookie auth_token

Request body

control_proofstring required

Public handle (ph_ctl_<32 hex>) of YOUR active domain proof — the authority the delegation chains down to

scopestring[] required

Capability tokens: lowercase kebab-case, 1-32 entries, at most 64 characters each (e.g. send-email). These are NOT API scopes — an API-style resource:action such as payments:read is rejected with 400 invalid_scope; an over-long or over-count list is rejected by the request schema as validation_error. Deduplicated and sorted at creation; verifiers compare by exact string match

expires_ininteger

Lifetime in seconds. Defaults to the shorter of one year and the control proof remainder. A request LONGER than the control proof remainder is rejected (400), never silently truncated

Example request

{
  "control_proof": "ph_ctl_0123456789abcdef0123456789abcdef",
  "delegate": {
    "value": "pkg:npm/postmark-mcp"
  },
  "scope": [
    "send-email"
  ]
}

Response

Delegation created — the response carries the publishable signed token AND the same derived effective_status/is_valid the reads carry, so the shape of a delegation does not depend on which verb produced it (m-fix-proof-api-consistency)

idstring required

MongoDB ObjectId

delegation_idstring nullable required

Stable public handle (ph_dlg_<32 hex>) — also the token's sub, and accepted by the proof status endpoint

principalstring required

The proven domain that authorized the delegate — derived from the control proof, never client input

scopestring[] required
control_proofstring 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_atstring date-time nullable required
revoked_reasonstring nullable required
environment'production' | 'test' required
issued_atstring date-time required
expires_atstring date-time required

Never later than the control proof's own expiry at issuance (effective expiry is min of the two)

created_atstring date-time required
tokenstring 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_validboolean 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

Example response

{
  "id": "507f1f77bcf86cd799439011",
  "delegation_id": "ph_dlg_0123456789abcdef0123456789abcdef",
  "principal": "postmark.com",
  "delegate": {
    "value": "pkg:npm/postmark-mcp"
  },
  "scope": [
    "send-email"
  ],
  "control_proof": "ph_ctl_0123456789abcdef0123456789abcdef"
}

Changes

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