The person who gives an agent its authority stays in charge of it. They decide what it may do, one revoke takes it back everywhere, and every decision comes with a signed receipt.
@delegus/sdk , alongside @delegus/core (the protocol engine) and @delegus/conformance (the vectors and CLI); all are Apache-2.0. This reference is generated from the source on the main branch, which can be ahead of the version on the registry; the version at the top of this page is the source version. The Delegus service is not open source. The integration surface is the one the integrate page shows.Client#
The one object a relying party or a Principal talks to Delegus through.
Delegusclass#
packages/sdk/src/client.ts
class Delegus {
new (opts?: DelegusOptions): Delegus
transport: Transport
// The RP's own public base URL (for Proof binding and the MCP tool URI); not a secret.
publicBaseUrl: string | null
// GET /me: what this client's API key resolves to (subject, role, settings).
me(): Promise<JsonObject>
// GET /healthz: true when Delegus reports every backing service reachable.
health(): Promise<{ ok: boolean; env?: string; did?: string; }>
apiKeys: { list: (subject?: string) => Promise<JsonObject>; create: (label?: string, subject?: string) => Promise<JsonObject>; revoke: (keyId: string, subject?: string) => Promise<JsonObject>; }
// Express-style middleware for an ordinary HTTP API (http.ts): every request is checked against the caller's
// Grant and Proof, bound to the exact method and URL, with the Action built from the body, path and query
// through a route map. Mount before the routes it protects.
http(opts?: HttpMiddlewareOptions): ReturnType<typeof createHttpMiddleware>
mcp(opts?: McpOptions): McpMiddleware
// POST /verify. Returns the signed Receipt for ALLOW and DENY alike.
//
// The API answers with the receipt of the relying party's own profile, so by
// default (`protocol: "auto"`) the SDK reads `receipt_version` from inside the
// signed receipt payload (never from an unsigned member) and checks the
// response accordingly:
// - delegus-receipt-v1: the v0.2 path, after checking the receipt
// signature under the service's published keys (the same key source and
// rules as v2: EdDSA, the receipt's kid, a `#receipt-<n>` key of the
// service DID; did:web:delegus.ai in production) and that the response
// body is exactly the signed payload;
// - delegus-receipt-v2: the v0.3-rc1 checks in full (parseVerifyResponseV3):
// the signature under the service's published keys, the body equal to
// the payload, `authority_commitment` opened to `authority` (and, when
// pinned, `capability_key_commitment` with `capability_key_opening`),
// `relies_on`, `requires` and `opening`;
// - anything else, or no readable receipt: ResponseIntegrityError.
// Either way, after the signature check the receipt must be about this
// request: its signed grant_hash and proof_hash must be sha256 over the
// Grant and Proof sent (and, on v2, request_hash over the Action when present).
// `requires` is sent as given; a v1 receipt in answer to it fails closed.
//
// `protocol: "v0.2"` and `protocol: "v0.3"` pin one profile; a receipt of the
// other one throws ResponseIntegrityError naming the pin and what came back.
// Every failure is fail closed: do not act on the request.
verify(req: VerifyRequestV3): Promise<VerifyResponseV3>
// POST /verify. Returns the signed Receipt for ALLOW and DENY alike.
//
// The API answers with the receipt of the relying party's own profile, so by
// default (`protocol: "auto"`) the SDK reads `receipt_version` from inside the
// signed receipt payload (never from an unsigned member) and checks the
// response accordingly:
// - delegus-receipt-v1: the v0.2 path, after checking the receipt
// signature under the service's published keys (the same key source and
// rules as v2: EdDSA, the receipt's kid, a `#receipt-<n>` key of the
// service DID; did:web:delegus.ai in production) and that the response
// body is exactly the signed payload;
// - delegus-receipt-v2: the v0.3-rc1 checks in full (parseVerifyResponseV3):
// the signature under the service's published keys, the body equal to
// the payload, `authority_commitment` opened to `authority` (and, when
// pinned, `capability_key_commitment` with `capability_key_opening`),
// `relies_on`, `requires` and `opening`;
// - anything else, or no readable receipt: ResponseIntegrityError.
// Either way, after the signature check the receipt must be about this
// request: its signed grant_hash and proof_hash must be sha256 over the
// Grant and Proof sent (and, on v2, request_hash over the Action when present).
// `requires` is sent as given; a v1 receipt in answer to it fails closed.
//
// `protocol: "v0.2"` and `protocol: "v0.3"` pin one profile; a receipt of the
// other one throws ResponseIntegrityError naming the pin and what came back.
// Every failure is fail closed: do not act on the request.
verify(req: VerifyRequestV2): Promise<Receipt>
// POST /verify. Returns the signed Receipt for ALLOW and DENY alike.
//
// The API answers with the receipt of the relying party's own profile, so by
// default (`protocol: "auto"`) the SDK reads `receipt_version` from inside the
// signed receipt payload (never from an unsigned member) and checks the
// response accordingly:
// - delegus-receipt-v1: the v0.2 path, after checking the receipt
// signature under the service's published keys (the same key source and
// rules as v2: EdDSA, the receipt's kid, a `#receipt-<n>` key of the
// service DID; did:web:delegus.ai in production) and that the response
// body is exactly the signed payload;
// - delegus-receipt-v2: the v0.3-rc1 checks in full (parseVerifyResponseV3):
// the signature under the service's published keys, the body equal to
// the payload, `authority_commitment` opened to `authority` (and, when
// pinned, `capability_key_commitment` with `capability_key_opening`),
// `relies_on`, `requires` and `opening`;
// - anything else, or no readable receipt: ResponseIntegrityError.
// Either way, after the signature check the receipt must be about this
// request: its signed grant_hash and proof_hash must be sha256 over the
// Grant and Proof sent (and, on v2, request_hash over the Action when present).
// `requires` is sent as given; a v1 receipt in answer to it fails closed.
//
// `protocol: "v0.2"` and `protocol: "v0.3"` pin one profile; a receipt of the
// other one throws ResponseIntegrityError naming the pin and what came back.
// Every failure is fail closed: do not act on the request.
verify(req: VerifyRequestAuto): Promise<VerifyResult>
// POST /verify. Returns the signed Receipt for ALLOW and DENY alike.
//
// The API answers with the receipt of the relying party's own profile, so by
// default (`protocol: "auto"`) the SDK reads `receipt_version` from inside the
// signed receipt payload (never from an unsigned member) and checks the
// response accordingly:
// - delegus-receipt-v1: the v0.2 path, after checking the receipt
// signature under the service's published keys (the same key source and
// rules as v2: EdDSA, the receipt's kid, a `#receipt-<n>` key of the
// service DID; did:web:delegus.ai in production) and that the response
// body is exactly the signed payload;
// - delegus-receipt-v2: the v0.3-rc1 checks in full (parseVerifyResponseV3):
// the signature under the service's published keys, the body equal to
// the payload, `authority_commitment` opened to `authority` (and, when
// pinned, `capability_key_commitment` with `capability_key_opening`),
// `relies_on`, `requires` and `opening`;
// - anything else, or no readable receipt: ResponseIntegrityError.
// Either way, after the signature check the receipt must be about this
// request: its signed grant_hash and proof_hash must be sha256 over the
// Grant and Proof sent (and, on v2, request_hash over the Action when present).
// `requires` is sent as given; a v1 receipt in answer to it fails closed.
//
// `protocol: "v0.2"` and `protocol: "v0.3"` pin one profile; a receipt of the
// other one throws ResponseIntegrityError naming the pin and what came back.
// Every failure is fail closed: do not act on the request.
verify(req: AnyVerifyRequest): Promise<VerifyResult>
// OpenID AuthZEN Access Evaluation over /verify (for PEPs such as MCP servers):
// subject {type:"agent", id, properties:{grant, proof}}, action {name, properties}, resource {type, id}.
// `decision` is true only for ALLOW; `context.reason` is the Delegus reason, `context.receipt` the signed receipt.
evaluate(req: { subject: { type: string; id: string; properties?: JsonObject; }; action: { name: string; properties?: JsonObject; }; resource: { type: string; id: string; properties?: JsonObject; }; context?: JsonObject; }): Promise<{ decision: boolean; context: JsonObject; }>
outcomes: { report: (receiptId: string, event: OutcomeEvent) => Promise<JsonObject>; }
decisions: { get: (receiptId: string) => Promise<DecisionRecord>; chain: (receiptId: string) => Promise<ChainInput>; list: (opts?: ListOptions & { rp?: string; keyId?: string; decision?: "ALLOW" | "DENY"; reason?: string; principal?: string; grantId?: string; }) => Promise<Page<JsonObject>>; }
// GET /decisions/export as NDJSON rows (decision summary + full receipt + outcome ledger); one page, cursor in `next_cursor`.
decisionsExport(opts?: ListOptions & { rp?: string; keyId?: string; decision?: "ALLOW" | "DENY"; reason?: string; principal?: string; grantId?: string; }): Promise<Page<JsonObject>>
// GET /decisions/{receipt_id}/disclosure (v0.3-rc1 §R.5): the disclosure
// package for a v2 receipt, for its relying party or principal only (404 for
// anyone else, and for a receipt with nothing to disclose). It carries the
// openings of the receipt's commitments, the consumption snapshot when the
// receipt pins one, and per dependency entry what reproduces it (the prior
// receipt and its opening only for a caller entitled to that receipt). Pass it
// as `disclosure` to receipts.verifyV2Entitled; nothing is verified here.
disclosure(receiptId: string): Promise<DisclosurePackage>
// GET /decisions/stats: decisions and outcomes rolled up per Principal.
decisionsStats(opts?: { since?: string; until?: string; rp?: string; principal?: string; }): Promise<JsonObject>
// The Principal directory (§2.1 trust network): who is registered and verified, since when, with which keys. Any live key.
principals: { list: (opts?: { kind?: "managed" | "hosted"; state?: "verified" | "unverified"; orgId?: string; limit?: number; cursor?: string; }) => Promise<Page<JsonObject>>; get: (did: string) => Promise<JsonObject>; }
grants: { list: (opts?: ListOptions & { principal?: string; agent?: string; state?: "active" | "revoked"; }) => Promise<Page<JsonObject>>; }
// GET /usage: verifies per UTC day (`byKey` adds a per-API-key breakdown).
usage(opts?: { since?: string; until?: string; rp?: string; principal?: string; keyId?: string; byKey?: boolean; }): Promise<JsonObject>
// GET /audit: newest first; own actions for a subject key, the org and its members for an org key, everything for admin.
audit(opts?: ListOptions & { actor?: string; action?: string; target?: string; }): Promise<Page<JsonObject>>
orgs: { create: (opts: { slug: string; name: string; }) => Promise<Org>; selfServe: (opts: { slug: string; name: string; adminEmail: string; clientIp?: string; }) => Promise<SelfServeBundle>; selfServeStarter: (rpDid: string) => Promise<SelfServeStarter>; selfServeFirstReceipt: (rpDid: string) => Promise<Receipt>; entitlement: (orgId: string) => Promise<Entitlement>; setEntitlement: (orgId: string, e: EntitlementRequest) => Promise<Entitlement>; get: (orgId: string) => Promise<Org & { members: JsonObject[]; }>; addMember: (orgId: string, did: string) => Promise<JsonObject>; apiKeys: { list: (orgId: string) => Promise<JsonObject>; create: (orgId: string, role: "read" | "admin", label?: string) => Promise<JsonObject>; revoke: (orgId: string, keyId: string) => Promise<JsonObject>; }; principal: (did: string) => Principal; }
// Principal onboarding (admin token, or an org:admin key, which onboards into its own org). `org` here is the managed-Principal DID path `did:web:<domain>:org:<slug>`; the customer account is `orgs`.
org: { create: (opts: { slug: string; signer?: Signer; keyId?: string; orgId?: string; }) => Promise<CreatedOrg>; register: (opts: { did: string; kid?: string; signer?: Signer; orgId?: string; }) => Promise<{ principal: Principal; apiKey: string; verification: JsonObject; didDocumentResolved: boolean; }>; }
relyingParties: { create: (opts: { slug?: string; did?: string; name?: string; proofWindowSeconds?: number; orgId?: string; profile?: "delegus-base-v1" | "delegus-base-v3" | "delegus-base-v4-draft"; }) => Promise<{ did: string; apiKey: string; client: Delegus; }>; get: (did: string) => Promise<JsonObject>; update: (did: string, patch: { name?: string; proofWindowSeconds?: number; verifyRateLimitPerMinute?: number; }) => Promise<JsonObject>; }
checkpoints: { get: (day?: string | "latest") => Promise<JsonObject>; leaves: (day: string) => Promise<string[]>; verify: (day?: string | "latest", keys?: Readonly<Record<string, Uint8Array<ArrayBufferLike>>> | undefined) => Promise<{ ok: boolean; day: string; root: string; treeSize: number; detail?: string; checkpoint?: Checkpoint; }>; contains: (day: string, receiptIds: readonly string[]) => Promise<{ present: string[]; missing: string[]; }>; }
evidence: { get: (hash: string) => Promise<Uint8Array | null>; }
// The service DID document's keys by kid (receipt and status-list keys). Only
// methods of the document's own DID count (`<doc.id>#…`, controller absent or
// `doc.id`), so a receipt's kid is bound to that DID; which fragment may sign
// what (`#receipt-<n>`, `#status-<n>`) is checked at verification. Against the
// production API the document must be `did:web:delegus.ai`.
serviceKeys(): Promise<TrustedKeys>
receipts: { verify: (receiptJws: string, keys: Readonly<Record<string, Uint8Array<ArrayBufferLike>>>, did?: string) => ReceiptVerification; verifyV2Public: (receiptJws: string, opts?: { body?: Record<string, unknown>; keys?: Readonly<Record<string, Uint8Array<ArrayBufferLike>>>; did?: string; }) => Promise<PublicVerificationV2>; verifyV2Entitled: (receiptJws: string, opts?: Omit<Parameters<typeof verifyReceiptV2Entitled>[0], "receipt" | "keys"> & { keys?: Readonly<Record<string, Uint8Array<ArrayBufferLike>>>; }) => Promise<EntitledVerificationV2>; inclusion: (receiptId: string, keys?: Readonly<Record<string, Uint8Array<ArrayBufferLike>>> | undefined) => Promise<{ ok: boolean; pending?: boolean; day: string; root?: string; detail?: string; }>; reverify: (input: { receipt: Receipt | string | Record<string, unknown>; grant: string; proof: string; action: unknown; keys?: Readonly<Record<string, Uint8Array<ArrayBufferLike>>>; proofWindowSeconds?: number; requires?: DependencyDeclaration[]; evidence?: ReadonlyMap<string, Uint8Array>; consumptionSnapshot?: ConsumptionSnapshot; }) => Promise<ReverifyResult>; }
}isVerifyResponseV3function#
packages/sdk/src/client.ts
Is this verify() result a checked v0.3 response (delegus-receipt-v2)?
function isVerifyResponseV3(r: VerifyResult): r is VerifyResponseV3PRODUCTION_SERVICE_DIDconst#
packages/sdk/src/client.ts
The production service DID (spec §2.0); its document is served at PRODUCTION_API/.well-known/did.json.
const PRODUCTION_SERVICE_DID: "did:web:delegus.ai"VERIFY_DEFAULT_PROTOCOLconst#
packages/sdk/src/client.ts
const VERIFY_DEFAULT_PROTOCOL: VerifyProtocolCreatedOrginterface#
packages/sdk/src/client.ts
interface CreatedOrg {
principal: Principal
did: string
kid: string
apiKey: string
signer: Signer
}DecisionRecordinterface#
packages/sdk/src/client.ts
GET /decisions/{receipt_id}: the receipt, its outcomes and, for a v2 receipt's own parties, its openings.
interface DecisionRecord {
receipt: Receipt
outcomes: JsonObject[]
// The matched Capability in plaintext; opens `authority_commitment` under `authority_opening`.
authority?: Capability | undefined
// Opens `authority_commitment` (43-char base64url).
authority_opening?: string | undefined
// Opens `evidence.consumption.capability_key_commitment` (43-char base64url).
capability_key_opening?: string | undefined
}DelegusOptionsinterface#
packages/sdk/src/client.ts
interface DelegusOptions {
// RP or Principal API key (`dk_rp_…` / `dk_principal_…`).
apiKey?: string | undefined
// Delegus admin token, for onboarding calls.
adminToken?: string | undefined
// Self-serve provision key (console only): POST /orgs/self-serve, the starter calls, and org entitlements.
provisionKey?: string | undefined
// API origin; default production.
baseUrl?: string | undefined
// The origin Agents address this RP at (§4.3). RPs behind proxies MUST set
// it so htu binding checks see the URL the Agent targeted.
publicBaseUrl?: string | undefined
fetch?: FetchLike | undefined
timeoutMs?: number | undefined
}DisclosurePackageinterface#
packages/sdk/src/client.ts
GET /decisions/{receipt_id}/disclosure (v0.3-rc1 §R.5).
interface DisclosurePackage {
receipt_id: string
// The consumption snapshot the receipt pins by hash (budgeted Capabilities).
consumption_snapshot?: JsonObject | undefined
// Per dependency entry: the pinned results plus what reproduces them (receipt and opening only when the caller is entitled to the prior receipt).
relies_on?: DisclosureEntry[] | undefined
// The matched Capability in plaintext; opens `authority_commitment` under `authority_opening`.
authority?: Capability | undefined
// Opens `authority_commitment` (43-char base64url).
authority_opening?: string | undefined
// Opens `evidence.consumption.capability_key_commitment` (43-char base64url).
capability_key_opening?: string | undefined
}Entitlementinterface#
packages/sdk/src/client.ts
The engine's view of an org's plan: the stored row (null fields when none is stored) and what the gate would decide now.
interface Entitlement {
org_id: string
// Whether a row exists. With enforcement on, no row means no plan.
stored: boolean
production: "allowed" | "blocked" | null
production_until: string | null
check_cap: number | null
cap_since: string | null
reason: "trial" | "paid" | "past_due_grace" | "canceled" | "comp" | "none" | null
as_of: string | null
updated_at: string | null
// Production checks counted since cap_since (at most check_cap); null without a cap.
production_checks_since_cap: number | null
// A staff, self-test or canary tenant that never needs a plan.
comp: boolean
// What the gate would decide for the next production check now.
effective: "allowed" | "blocked"
// Why it would be refused; null when allowed.
effective_detail: string | null
// Whether this deployment refuses (true) or only logs (false) a blocked production check.
enforced: boolean
// PUT only: whether this push was stored.
applied?: boolean | undefined
}EntitlementRequestinterface#
packages/sdk/src/client.ts
An org's production entitlement, as the console pushes it (PUT /orgs/{org_id}/entitlement).
interface EntitlementRequest {
production: "allowed" | "blocked"
// Production checks stop at this instant; null for no end.
production_until: string | null
// At most this many production checks since cap_since; null for no cap.
check_cap: number | null
cap_since: string | null
reason: "trial" | "paid" | "past_due_grace" | "canceled" | "comp" | "none"
// The console's change time: an older push never overwrites a newer one.
as_of: string
}ListOptionsinterface#
packages/sdk/src/client.ts
interface ListOptions {
limit?: number | undefined
cursor?: string | undefined
since?: string | undefined
until?: string | undefined
}Orginterface#
packages/sdk/src/client.ts
An organization: a customer account owning Principals and relying parties.
interface Org {
org_id: string
slug: string
name: string
created_at: string
}OutcomeEventinterface#
packages/sdk/src/client.ts
interface OutcomeEvent {
type: "fulfilled" | "cancelled" | "dispute_opened" | "dispute_resolved" | "chargeback_received" | "chargeback_reversed" | "loss_reported"
occurred_at: string
evidence_ref?: string | undefined
note?: string | undefined
correction_of?: string | undefined
resolution?: "agent_at_fault" | "agent_not_at_fault" | "indeterminate" | undefined
loss_amount?: number | undefined
currency?: string | undefined
reporter_signature?: string | undefined
}Pageinterface#
packages/sdk/src/client.ts
interface Page {
items: T[]
// Pass back as `cursor` for the next page; null on the last page.
next_cursor: string | null
}ReceiptOpeningsinterface#
packages/sdk/src/client.ts
What opens a v2 receipt's commitments, as GET /decisions/{id} and its disclosure package return them (review H2).
interface ReceiptOpenings {
// The matched Capability in plaintext; opens `authority_commitment` under `authority_opening`.
authority?: Capability | undefined
// Opens `authority_commitment` (43-char base64url).
authority_opening?: string | undefined
// Opens `evidence.consumption.capability_key_commitment` (43-char base64url).
capability_key_opening?: string | undefined
}SelfServeBundleinterface#
packages/sdk/src/client.ts
POST /orgs/self-serve: a whole new tenant plus its first-ALLOW material.
interface SelfServeBundle {
org: Org
// org:admin key — keep server-side; never show the customer.
org_admin_key: string
relying_party: { did: string; name: string; profile: string; proof_window_seconds: number; }
// The customer's first verify key (dk_rp_…), shown once.
rp_verify_key: string
starter: SelfServeStarter
}SelfServeStarterinterface#
packages/sdk/src/client.ts
A ready-to-verify sample from the shared sandbox Principal, bound to one relying party. POST grant/proof/action to /verify with the RP's key.
interface SelfServeStarter {
grant: string
proof: string
action: JsonObject
grant_id: string
// When the Proof leaves the RP's proof window; ask for a fresh starter after this.
expires_at: string
verify_url: string
verify_curl: string
}VerifyRequestinterface#
packages/sdk/src/client.ts
interface VerifyRequest {
grant: string
proof: string
action: unknown
// The request the RP received. When given, the SDK checks the Proof's
// htm/htu against it before calling Delegus (§4.3) and throws
// ProofBindingError on mismatch. `path` is joined to `publicBaseUrl`.
request?: { method: string; url?: string; path?: string; chain?: string[]; } | undefined
}VerifyRequestAutointerface#
packages/sdk/src/client.ts
A /verify request that accepts either profile (the default). requires goes to a v0.3 relying party; a v1 receipt in answer to it fails closed.
interface VerifyRequestAuto {
protocol?: "auto" | undefined
requires?: DependencyDeclaration[] | undefined
grant: string
proof: string
action: unknown
// The request the RP received. When given, the SDK checks the Proof's
// htm/htu against it before calling Delegus (§4.3) and throws
// ProofBindingError on mismatch. `path` is joined to `publicBaseUrl`.
request?: { method: string; url?: string; path?: string; chain?: string[]; } | undefined
}VerifyRequestV2interface#
packages/sdk/src/client.ts
A /verify request pinned to v0.2 (delegus-receipt-v1 only).
interface VerifyRequestV2 {
protocol: "v0.2"
grant: string
proof: string
action: unknown
// The request the RP received. When given, the SDK checks the Proof's
// htm/htu against it before calling Delegus (§4.3) and throws
// ProofBindingError on mismatch. `path` is joined to `publicBaseUrl`.
request?: { method: string; url?: string; path?: string; chain?: string[]; } | undefined
}VerifyRequestV3interface#
packages/sdk/src/client.ts
A v0.3-rc1 /verify request pinned to v0.3 (delegus-receipt-v2 only).
interface VerifyRequestV3 {
protocol: "v0.3"
// The prior decisions this action must rest on (§5.1): 1–8 distinct { fingerprint, mode }; the actor's `relies_on` must cover each (D1).
requires?: DependencyDeclaration[] | undefined
grant: string
proof: string
action: unknown
// The request the RP received. When given, the SDK checks the Proof's
// htm/htu against it before calling Delegus (§4.3) and throws
// ProofBindingError on mismatch. `path` is joined to `publicBaseUrl`.
request?: { method: string; url?: string; path?: string; chain?: string[]; } | undefined
}AnyVerifyRequesttype#
packages/sdk/src/client.ts
Any /verify request.
type AnyVerifyRequest = VerifyRequestV3 | VerifyRequestV2 | VerifyRequestAutoVerifyProtocoltype#
packages/sdk/src/client.ts
Which receipt profile verify() accepts. - "auto" (the default): whatever the relying party's profile answers with, read from the signed receipt payload. delegus-receipt-v1 takes the v0.2 path; delegus-receipt-v2 takes the full v0.3 checks; anything else fails closed. - "v0.2": a pin; only delegus-receipt-v1 is accepted. - "v0.3": a pin; only delegus-receipt-v2 is accepted.
type VerifyProtocol = "v0.3" | "v0.2" | "auto"VerifyResulttype#
packages/sdk/src/client.ts
What verify() returns under "auto": a v1 receipt or a checked v0.3 response. Tell them apart with isVerifyResponseV3.
type VerifyResult = Receipt | VerifyResponseV3Principal#
A company that issues Grants to its agents.
Principalclass#
packages/sdk/src/principal.ts
class Principal {
new (opts: PrincipalOptions): Principal
did: string
kid: string | null
signer: Signer | null
grant: { create: (req: GrantRequest) => Promise<IssuedGrant>; revoke: (grantId: string) => Promise<{ grant_id: string; revoked_at: string; }>; }
keys: { retire: (kid: string) => Promise<{ kid: string; state: "retired" | "compromised"; }>; compromise: (kid: string) => Promise<void>; }
// Run domain verification now and return the state and instructions.
verifyDomain(): Promise<JsonObject>
status(): Promise<JsonObject>
}V3_CAPABILITY_ACTIONSconst#
packages/sdk/src/principal.ts
v0.2 action types, plus the v0.3-rc1 seller-side commitments (usable only with relying parties on delegus-base-v3).
const V3_CAPABILITY_ACTIONS = {
// Returns a string representation of an array.
toString(): string
// Returns a string representation of an array. The elements are converted to string using their toLocaleString methods.
toLocaleString(): string
// Combines two or more arrays.
concat(...items: ConcatArray<"commerce:quote" | "commerce:accept" | "commerce:fulfil">[]): ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]
// Adds all the elements of an array separated by the specified separator string.
join(separator?: string): string
// Returns a section of an array.
slice(start?: number, end?: number): ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]
// Returns the index of the first occurrence of a value in an array.
indexOf(searchElement: "commerce:quote" | "commerce:accept" | "commerce:fulfil", fromIndex?: number): number
// Returns the index of the last occurrence of a specified value in an array.
lastIndexOf(searchElement: "commerce:quote" | "commerce:accept" | "commerce:fulfil", fromIndex?: number): number
// Determines whether all the members of an array satisfy the specified test.
every<S extends "commerce:quote" | "commerce:accept" | "commerce:fulfil">(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => value is S, thisArg?: any): this is readonly S[]
// Determines whether the specified callback function returns true for any element of an array.
some(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => unknown, thisArg?: any): boolean
// Performs the specified action for each element in an array.
forEach(callbackfn: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => void, thisArg?: any): void
// Calls a defined callback function on each element of an array, and returns an array that contains the results.
map<U>(callbackfn: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => U, thisArg?: any): U[]
// Returns the elements of an array that meet the condition specified in a callback function.
filter<S extends "commerce:quote" | "commerce:accept" | "commerce:fulfil">(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => value is S, thisArg?: any): S[]
// Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
reduce(callbackfn: (previousValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil", currentValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil", currentIndex: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => "commerce:quote" | "commerce:accept" | "commerce:fulfil"): "commerce:quote" | "commerce:accept" | "commerce:fulfil"
// Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
reduceRight(callbackfn: (previousValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil", currentValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil", currentIndex: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => "commerce:quote" | "commerce:accept" | "commerce:fulfil"): "commerce:quote" | "commerce:accept" | "commerce:fulfil"
// Returns the value of the first element in the array where predicate is true, and undefined
// otherwise.
find<S extends "commerce:quote" | "commerce:accept" | "commerce:fulfil">(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, obj: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => value is S, thisArg?: any): S | undefined
// Returns the index of the first element in the array where predicate is true, and -1
// otherwise.
findIndex(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, obj: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => unknown, thisArg?: any): number
// Returns an iterable of key, value pairs for every entry in the array
entries(): ArrayIterator<[number, "commerce:quote" | "commerce:accept" | "commerce:fulfil"]>
// Returns an iterable of keys in the array
keys(): ArrayIterator<number>
// Returns an iterable of values in the array
values(): ArrayIterator<"commerce:quote" | "commerce:accept" | "commerce:fulfil">
// Determines whether an array includes a certain element, returning true or false as appropriate.
includes(searchElement: "commerce:quote" | "commerce:accept" | "commerce:fulfil", fromIndex?: number): boolean
// Calls a defined callback function on each element of an array. Then, flattens the result into
// a new array.
// This is identical to a map followed by flat with depth 1.
flatMap<U, This = undefined>(callback: (this: This, value: "commerce:quote" | "commerce:accept" | "commerce:fulfil", index: number, array: ("commerce:quote" | "commerce:accept" | "commerce:fulfil")[]) => U | readonly U[], thisArg?: This | undefined): U[]
// Returns a new array with all sub-array elements concatenated into it recursively up to the
// specified depth.
flat<A, D extends number = 1>(this: A, depth?: D | undefined): FlatArray<A, D>[]
// Returns the item located at the specified index.
at(index: number): "commerce:quote" | "commerce:accept" | "commerce:fulfil" | undefined
// Iterator of values in the array.
__@iterator@208(): ArrayIterator<"commerce:quote" | "commerce:accept" | "commerce:fulfil">
// Is an object whose properties have the value 'true'
// when they will be absent when used in a 'with' statement.
__@unscopables@592: { readonly [x: number]: boolean | undefined; readonly length?: boolean | undefined; toString?: boolean | undefined; toLocaleString?: boolean | undefined; concat?: boolean | undefined; join?: boolean | undefined; slice?: boolean | undefined; indexOf?: boolean | undefined; lastIndexOf?: boolean | undefined; every?: boolean | undefined; some?: boolean | undefined; forEach?: boolean | undefined; map?: boolean | undefined; filter?: boolean | undefined; reduce?: boolean | undefined; reduceRight?: boolean | undefined; find?: boolean | undefined; findIndex?: boolean | undefined; entries?: boolean | undefined; keys?: boolean | undefined; values?: boolean | undefined; includes?: boolean | undefined; flatMap?: boolean | undefined; flat?: boolean | undefined; at?: boolean | undefined; [Symbol.iterator]?: boolean | undefined; readonly [Symbol.unscopables]?: boolean | undefined; }
}AgentInventoryEntryinterface#
From the next SDK release. AgentInventoryEntry isn't in the published @delegus/sdk 0.3.3 on npm yet.
packages/sdk/src/principal.ts
interface AgentInventoryEntry {
did: string
principal: string
created_at: string
disabled_at: string | null
}Capabilityinterface#
packages/sdk/src/principal.ts
interface Capability {
action: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"
constraints: JsonObject
resources?: string[] | undefined
}GrantRequestinterface#
packages/sdk/src/principal.ts
interface GrantRequest {
// Agent DID (did:key).
agent: string
// 1–16 Capabilities (§3.3).
authority: Capability[]
// RFC 3339 UTC; default now (whole seconds).
validFrom?: string | undefined
// RFC 3339 UTC; default validFrom + 30 days; at most 90 days after validFrom.
validUntil?: string | undefined
// RP DIDs; absent = any registered RP.
audience?: string[] | undefined
// Refuse (PersonalDataError, before any request) when lintAuthority() finds
// an email address, a phone number or a card number in the authority's
// strings. Default false: the Grant is issued and the findings come back in
// `warnings`. Resources should be opaque ids; receipts may keep them for years.
refusePersonalData?: boolean | undefined
// Default true: declare the authority, audience and validity at allocation and record the Grant's hash after signing (never the bytes). false: allocate only.
declare?: boolean | undefined
}IssuedGrantinterface#
packages/sdk/src/principal.ts
interface IssuedGrant {
id: string
// The Grant compact JWS to hand to the Agent.
jws: string
credentialStatus: JsonObject
validFrom: string
validUntil: string
// Present only when lintAuthority() found something that looks like personal data in the authority.
warnings?: LintFinding[] | undefined
}PrincipalOptionsinterface#
packages/sdk/src/principal.ts
interface PrincipalOptions {
did: string
// `did:web:…#key-n` of `signer`; required to create Grants.
kid?: string | undefined
signer?: Signer | undefined
apiKey: string
transport: Transport
now?: (() => number) | undefined
// `apiKey` is an org:admin key of the Principal's org: name the Principal on every call (`?principal=<did>`). Grants cannot be created this way.
viaOrgKey?: boolean | undefined
}Agent#
The key that signs a Proof for each request.
Agentclass#
packages/sdk/src/agent.ts
class Agent {
new (signer: Signer): Agent
did: string
kid: string
signer: Signer
sign(req: ProofRequest): Promise<string>
// The two request headers the RP forwards to /verify (§4.4).
headers(req: ProofRequest): Promise<{ "Delegus-Grant": string; "Delegus-Proof": string; "Delegus-Grant-Chain"?: string; }>
// Add this agent to a company's agent list with an enrolment token the company gave its builder (named-agents.md).
// The request is also signed with this agent's key, so a token can only ever list the key that signs. The agent
// arrives pending: it can be named in sentences, and given authority, only after an admin approves it.
register(req: { delegus: DelegusEndpoint; token: string; name: string; description?: string; }): Promise<JsonObject>
// A vendor's agent joins a customer's agent list with the one-time connect code the customer created and shared. It
// arrives pending, labelled with the vendor, until the customer approves it; the vendor gets no power to issue grants.
connect(req: { delegus: DelegusEndpoint; code: string; name: string; vendor: string; description?: string; }): Promise<JsonObject>
createChild(req: { parent: string; parentChain?: string[]; agent: string; authority: unknown[]; audience: string[]; validFrom?: string; validUntil?: string; depth?: number; delegus: DelegusEndpoint; }): Promise<{ jws: string; id: string; chain: string[]; }>
// The Delegus-Grant / Delegus-Proof headers for one HTTP request to a Delegus-guarded API (http.ts): the Proof
// binds the method and the canonical URL; the Action is built exactly as the server builds it, through the
// server's route map when given (`routes` = the compiled map from compileRouteMap, or the JSON it serves at
// /delegus-routes.json), else `api:call` on the URL.
httpHeaders(req: { grant: string; method: string; url: string; rpDid: string; body?: unknown; routes?: CompiledRoutes | unknown; iat?: number; jti?: string; chain?: string[]; op?: string; }): Promise<{ "Delegus-Grant": string; "Delegus-Proof": string; "Delegus-Grant-Chain"?: string; }>
mcpHeaders(req: { grant: string; endpoint: string; tool: string; rpDid: string; iat?: number; jti?: string; chain?: string[]; op?: string; args?: unknown; map?: ToolMap; }): Promise<{ "Delegus-Grant": string; "Delegus-Proof": string; }>
// New Agent with an in-memory Ed25519 key (dev default).
static create(): Agent
}DelegusEndpointinterface#
packages/sdk/src/agent.ts
What createChild() needs to reach Delegus: its base URL and the service DID agent-signed requests are addressed to.
interface DelegusEndpoint {
baseUrl: string
serviceDid: string
fetch?: { (input: RequestInfo | URL, init?: RequestInit): Promise<Response>; (input: string | URL | Request, init?: RequestInit): Promise<Response>; } | undefined
}ProofRequestinterface#
packages/sdk/src/agent.ts
interface ProofRequest {
// The Grant compact JWS (its `id` is taken from it) or a bare Grant id.
grant: string
// The RP DID the Proof is for (`aud`).
audience: string
// The HTTP request the Agent is about to make.
method: string
url: string
// The Action, built with `actions.*` from the same wire fields the RP will use.
action: unknown
// Override the clock (seconds since epoch); default now.
iat?: number | undefined
// Override the nonce (22–64 base64url chars); default 16 random bytes.
jti?: string | undefined
}Actions#
Helpers that build the action object the relying party describes.
actionsconst#
packages/sdk/src/actions.ts
const actions = {
// `commerce:purchase`: amount in minor units (integer), ISO 4217 currency.
purchase(fields: { resource: string; amount: number; currency: string; }): Action
// `api:call`: uppercase HTTP method, absolute http(s) resource URI.
apiCall(fields: { method: string; resource: string; }): Action
}actionsV3const#
packages/sdk/src/actions.ts
const actionsV3 = {
// `commerce:purchase`: the actor commits its Principal to buy.
purchase(fields: Amounted): ActionV3
// `commerce:quote`: the actor offers, for its Principal, to sell at this price.
quote(fields: Amounted): ActionV3
// `commerce:accept`: the actor accepts an order for its Principal at this price.
accept(fields: Amounted): ActionV3
// `commerce:fulfil`: the actor commits its Principal to deliver the named resource.
fulfil(fields: { resource: string; } & DependencyFields): ActionV3
// `api:call`: uppercase HTTP method, absolute http(s) resource URI.
apiCall(fields: { method: string; resource: string; } & DependencyFields): ActionV3
// Add `relies_on` to an Action built elsewhere (it must not already declare one, and must carry no transaction handle).
withDependencies(action: Action | ActionV3, deps: DependencyFields): ActionV3
}DependencyFieldsinterface#
packages/sdk/src/actions.ts
The optional v0.3 declaration every v3 Action may carry.
interface DependencyFields {
// 1–8 distinct { fingerprint, mode } entries; there is no default mode.
relies_on?: DependencyDeclaration[] | undefined
}Keys and signers#
Where private keys live. The signer interface is pluggable: memory for development, KMS or an HSM in production.
MemorySignerclass#
packages/sdk/src/keys.ts
class MemorySigner {
new (seed: Uint8Array): MemorySigner
// Raw 32-byte Ed25519 public key.
publicKey: Uint8Array<ArrayBufferLike>
// PureEdDSA over exactly `data`; 64 bytes.
sign(data: Uint8Array): Uint8Array
toJwk(): Ed25519Jwk
static generate(): MemorySigner
static fromSeed(seed: Uint8Array): MemorySigner
static fromJwk(jwk: unknown): MemorySigner
}Ed25519Jwkinterface#
packages/sdk/src/keys.ts
Ed25519 private key as a JWK (RFC 8037): the portable at-rest form.
interface Ed25519Jwk {
kty: "OKP"
crv: "Ed25519"
x: string
d: string
}Signerinterface#
packages/sdk/src/keys.ts
interface Signer {
// Raw 32-byte Ed25519 public key.
publicKey: Uint8Array<ArrayBufferLike>
// PureEdDSA over exactly `data`; 64 bytes.
sign(data: Uint8Array): Uint8Array | Promise<Uint8Array>
}Errors#
Everything the SDK throws.
DelegusApiErrorclass#
packages/sdk/src/errors.ts
A non-2xx answer from the Delegus API: { error, message } plus the HTTP status.
class DelegusApiError {
new (status: number, code: string, message: string): DelegusApiError
name: string
status: number
code: string
message: string
stack?: string | undefined
cause?: unknown
}DelegusErrorclass#
packages/sdk/src/errors.ts
class DelegusError {
new (message?: string): DelegusError
new (message?: string, options?: ErrorOptions): DelegusError
name: string
message: string
stack?: string | undefined
cause?: unknown
}PersonalDataErrorclass#
packages/sdk/src/errors.ts
grant.create refused: the authority's strings look like they contain personal data (lintAuthority) and refusePersonalData was set. Use opaque ids.
class PersonalDataError {
new (findings: ReadonlyArray<{ path: string; kind: string; }>): PersonalDataError
name: "PersonalDataError"
findings: readonly { path: string; kind: string; }[]
message: string
stack?: string | undefined
cause?: unknown
}PlanRequiredErrorclass#
packages/sdk/src/errors.ts
HTTP 402 PLAN_REQUIRED: production checks need a plan for this account. Not a DENY: the check was refused before evaluation, no receipt was issued, and the Proof was not spent. Sandbox checks keep working.
class PlanRequiredError {
new (status: number, code: string, message: string): PlanRequiredError
name: string
status: number
code: string
message: string
stack?: string | undefined
cause?: unknown
}ProofBindingErrorclass#
packages/sdk/src/errors.ts
class ProofBindingError {
new (expected: { method: string; url: string; }, proof: { htm: string; htu: string; }): ProofBindingError
name: "ProofBindingError"
expected: { method: string; url: string; }
proof: { htm: string; htu: string; }
message: string
stack?: string | undefined
cause?: unknown
}Transport#
HTTP plumbing, replaceable for tests.
Transportclass#
packages/sdk/src/transport.ts
class Transport {
new (opts: TransportOptions): Transport
baseUrl: string
json(method: string, path: string, opts?: { token?: string | null; body?: unknown; headers?: Record<string, string>; }): Promise<JsonValue>
// A request whose body is text (NDJSON, CSV, plain); errors are the API's JSON errors.
raw(method: string, path: string, opts?: { token?: string | null; }): Promise<{ status: number; text: string; headers: Headers; }>
bytes(path: string): Promise<Uint8Array | null>
}FetchLiketype#
packages/sdk/src/transport.ts
type FetchLike = (input: string, init: RequestInit) => Promise<Response>v0.3#
Verifying under the v0.3 rules: opening checks, dependency helpers and receipt v2 verification.
ResponseIntegrityErrorclass#
packages/sdk/src/v3.ts
A v0.3 /verify response failed an integrity check. Fail closed: do not act on it.
class ResponseIntegrityError {
new (message?: string): ResponseIntegrityError
new (message?: string, options?: ErrorOptions): ResponseIntegrityError
name: string
message: string
stack?: string | undefined
cause?: unknown
}checkAuthorityOpeningfunction#
packages/sdk/src/v3.ts
Does opening open commitment (a receipt's authority_) to this Capability? Core's verifyAuthorityOpening, after the SDK's integers-only rule. Throws TypeError when authority is not a JSON object with integers only; otherwise true or false, never a fallback.
function checkAuthorityOpening(commitment: string, opening: string, authority: unknown): booleancheckCapabilityKeyOpeningfunction#
packages/sdk/src/v3.ts
Does opening open commitment (a receipt's evidence.) to the key of this Capability? The key is core's capabilityKey: sha256(JCS(authority)). Throws TypeError when authority is not a JSON object with integers only.
function checkCapabilityKeyOpening(commitment: string, opening: string, authority: unknown): booleandecisionDisagreementfunction#
packages/sdk/src/v3.ts
Do the decision, the reason and the check results agree (spec §5.4)? ALLOW: reason null, every protocol and trust check true. DENY: some check is false, and the reason is one the first false check in the v3 order can report. Either way each layer's result is PASS exactly when all its checks are true. Returns null when they agree, else what disagrees.
function decisionDisagreement(body: Pick<ReceiptV2Body, "decision" | "reason" | "protocol" | "trust">): string | nulldependencyOnfunction#
packages/sdk/src/v3.ts
The relies_on entry a downstream action declares for a prior response: its fingerprint (never the nonce) and a mode.
function dependencyOn(response: Pick<VerifyResponseV3, typeof F_OPENING>, mode: DependencyMode): DependencyDeclarationisReliesOnEntriesfunction#
packages/sdk/src/v3.ts
Well-formed recorded dependency entries (the engine's rule) with distinct fingerprints.
function isReliesOnEntries(v: unknown): v is ReliesOnEntry[]parseReceiptV2Bodyfunction#
packages/sdk/src/v3.ts
Parse a signed payload as a delegus-receipt-v2 body (profile delegus-base-v3); null unless well formed.
function parseReceiptV2Body(payload: unknown): ReceiptV2Body | nullparseVerifyResponseV3function#
packages/sdk/src/v3.ts
Validate a /verify response as v0.3-rc1 and return it typed. Throws ResponseIntegrityError (fail closed) unless: - it carries a receipt JWS whose signature verifies under trust (the service's published keys; a #receipt- key of its DID), whose payload is a delegus-receipt-v2 body (profile delegus-base-v3) and equals the response body after JCS, with authority, authority_, capability_, relies_on and opening set aside; - when sent.grant / sent.proof are given, the signed grant_hash and proof_hash are their sha256 (the receipt is about this request); - the decision, reason and check results agree (decisionDisagreement): an ALLOW has every protocol and trust check true, D1–D7 included; a DENY's reason is one its first false check in the v3 order can report; - on ALLOW: authority_, authority, authority_, transaction and opening are all present; - authority and authority_ are present exactly when authority_ is (ALLOW or DENY), and the opening opens the commitment to authority (core verifyAuthorityOpening; integers only); - capability_ is present exactly when evidence. is, and opens it to sha256(JCS(authority)) (core verifyCapabilityKeyOpening); a v2 receipt carrying a plaintext capability_ is refused; - relies_on is present exactly when relies_ is, well formed, and hashes to it; its entries are the action's declaration, in order; an ALLOW for an action that declared relies_on must pin them; - requires_ is present exactly when requires was sent, and is its hash; - opening is exactly { fingerprint, nonce } and opens the fingerprint for this receipt's JWS; - transaction is a canonical 22-character handle; - request_, when present and the action is given, is sha256(JCS(action)).
function parseVerifyResponseV3(response: unknown, sent: SentV3, trust: ReceiptTrust): VerifyResponseV3receiptBindingMismatchfunction#
packages/sdk/src/v3.ts
Is this signed receipt payload about the request that was sent? grant_hash and proof_hash are sha256 over the UTF-8 of the Grant and Proof exactly as sent (core computes them the same way). Null when they match (or were not given), else what differs. Call it on the verified payload, after the signature.
function receiptBindingMismatch(payload: Record<string, unknown>, sent: { grant?: string; proof?: string; }): string | nullreliesOnHashfunction#
packages/sdk/src/v3.ts
relies_on_hash: sha256 over the UTF-8 of JCS(the full entries array). Throws unless the entries are well formed.
function reliesOnHash(entries: unknown): Sha256RefrequiresHashfunction#
packages/sdk/src/v3.ts
requires_hash: sha256 over the UTF-8 of JCS(requires). Throws unless requires is well formed.
function requiresHash(requires: unknown): Sha256RefsplitV2Responsefunction#
packages/sdk/src/v3.ts
Split a v3 /verify response into the receipt body and the members returned beside it (authority, authority_, capability_, relies_on, opening).
function splitV2Response(response: unknown): SplitResponseV2 | stringvalidateRequiresfunction#
packages/sdk/src/v3.ts
Parse and validate requires (§5.1): the same shape and rules as relies_on (1–8 entries, distinct, a mode each).
function validateRequires(requires: unknown): DependencyDeclaration[]verifyReceiptV2Entitledfunction#
packages/sdk/src/v3.ts
Entitled reproduction (§6.4) as far as material allows: public verification, then open authority_ (and capability_) with their openings, reproduce relies_ and requires_ from their plaintext, and each dependency entry from a disclosure package entry and/or a prior receipt with its opening. ok is true only when everything was reproduced: any part that was not reproducible (or not supplied) makes it false, and D5 is reported as Delegus's attestation.
function verifyReceiptV2Entitled(input: { receipt: string; body?: Record<string, unknown>; keys: TrustedKeys; did?: string; authority?: unknown; reliesOn?: unknown; requires?: unknown; authorityOpening?: unknown; capabilityKeyOpening?: unknown; disclosure?: unknown; priors?: readonly PriorReceipt[]; }): EntitledVerificationV2verifyReceiptV2Publicfunction#
packages/sdk/src/v3.ts
Public verification of a v2 receipt (§6.4): anyone holding it can check it is authentic and unmodified. Signature, body equals payload (when a JSON body is given), and the v2 fields are well formed and consistent. It does not say why the decision was made.
function verifyReceiptV2Public(input: { receipt: string; body?: Record<string, unknown>; keys: TrustedKeys; did?: string; }): PublicVerificationV2verifyReceiptV2Signaturefunction#
packages/sdk/src/v3.ts
The engine's receipt signature check, narrowed to delegus-receipt-v2.
function verifyReceiptV2Signature(receiptJws: unknown, keys: TrustedKeys, did?: string): ReceiptV2SignatureDependencyOpeninginterface#
packages/sdk/src/v3.ts
The commitment to a receipt a later action may declare (fingerprint) and its opening (nonce, 43-char base64url).
interface DependencyOpening {
fingerprint: `sha256:${string}`
nonce: string
}DependencyVerificationinterface#
packages/sdk/src/v3.ts
interface DependencyVerification {
index: number
fingerprint: string
mode: string
// reproduced: every applicable part reproduced (D5 attested);
// partial: nothing failed but something was not reproducible;
// failed: something failed; not_supplied: no material at all for this entry.
result: "not_supplied" | "reproduced" | "partial" | "failed"
checks: Record<DependencyPart, { status: PartStatus; detail: string; }>
// The prior receipt's id, when its receipt was supplied and verifies.
receipt_id?: string | undefined
}DisclosureEntryinterface#
packages/sdk/src/v3.ts
One entry of a dependency disclosure package (GET /decisions/{id}/disclosure, relies_on). Always: fingerprint, mode, checks (D2–D7), transaction_equal and receipt_hash. For CURRENT_AUTHORITY: status_credential, status_list_index and evidence_nonce. The prior receipt and its opening only for a caller entitled to that receipt itself.
interface DisclosureEntry {
fingerprint: string
mode: string
checks: Record<string, unknown>
transaction_equal: boolean | null
receipt_hash?: string | undefined
status_credential?: string | undefined
status_list_index?: string | undefined
evidence_nonce?: string | undefined
receipt?: string | undefined
opening?: string | undefined
}EntitledVerificationV2interface#
packages/sdk/src/v3.ts
interface EntitledVerificationV2 {
level: "entitled"
// `authority_commitment` opened with `authority_opening` to the plaintext Capability.
authority: PlaintextComparison
// `evidence.consumption.capability_key_commitment` opened with `capability_key_opening` to sha256(JCS(authority)).
capability_key: PlaintextComparison
relies_on: PlaintextComparison
requires: PlaintextComparison
dependencies: DependencyVerification[]
// Supplied priors or disclosure entries that name no relies_on entry of this receipt, or contradict themselves.
unmatched: { source: "priors" | "disclosure"; index: number; detail: string; }[]
receipt_id: string | null
decision: string | null
reason: string | null
ok: boolean
checks: V2Check[]
}PlaintextComparisoninterface#
packages/sdk/src/v3.ts
interface PlaintextComparison {
result: PlaintextResult
pinned: string | null
computed: string | null
detail?: string | undefined
}PriorReceiptinterface#
packages/sdk/src/v3.ts
A prior receipt and its opening, as an entitled party holds them (e.g. the prior /verify response it stored).
interface PriorReceipt {
// The prior receipt's compact JWS, exactly as issued.
receipt: string
// Its opening nonce (43-char base64url).
nonce: string
// The fingerprint the opening came with, if known; checked too.
fingerprint?: string | undefined
}PublicVerificationV2interface#
packages/sdk/src/v3.ts
interface PublicVerificationV2 {
ok: boolean
level: "public"
receipt_id: string | null
decision: string | null
reason: string | null
checks: V2Check[]
}ReceiptTrustinterface#
packages/sdk/src/v3.ts
The keys a v2 receipt must verify under: the service's published keys (its DID document), and that DID.
interface ReceiptTrust {
keys: Readonly<Record<string, Uint8Array<ArrayBufferLike>>>
// The service DID; the receipt's kid must be a `#receipt-<n>` key of it.
did?: string | undefined
}SentV3interface#
packages/sdk/src/v3.ts
What the relying party sent, for the response checks.
interface SentV3 {
action?: unknown
requires?: readonly DependencyDeclaration[] | undefined
// The Grant compact JWS sent; when given, the receipt's grant_hash must be sha256 over its UTF-8.
grant?: string | undefined
// The Proof compact JWS sent; when given, the receipt's proof_hash must be sha256 over its UTF-8.
proof?: string | undefined
}SplitResponseV2interface#
packages/sdk/src/v3.ts
A response (or stored response JSON) split into the signed body and what came beside it.
interface SplitResponseV2 {
jws: string
parsed: ParsedJws
// The members that must equal the signed payload.
body: Record<string, unknown>
authority?: unknown
authorityOpening?: unknown
capabilityKeyOpening?: unknown
reliesOn?: unknown
opening?: unknown
}V2Checkinterface#
packages/sdk/src/v3.ts
interface V2Check {
check: string
ok: boolean
detail: string
}DependencyParttype#
packages/sdk/src/v3.ts
type DependencyPart = "D2" | "D3" | "D4" | "D5" | "D6" | "D7" | "receipt_hash" | "evidence_commitment"PartStatustype#
packages/sdk/src/v3.ts
How one part of a dependency was established: reproduced recomputed from supplied material; equals what the receipt pins failed recomputed; differs from what the receipt pins (or the material contradicts itself) attested Delegus's statement, which no one outside Delegus can recompute by design (D5) not_reproducible the material to recompute it was not supplied skipped does not apply to this entry (D6, D7 and evidence_commitment for PRIOR_DECISION)
type PartStatus = "reproduced" | "failed" | "attested" | "not_reproducible" | "skipped"PlaintextResulttype#
packages/sdk/src/v3.ts
type PlaintextResult = "match" | "mismatch" | "not_supplied" | "not_in_receipt" | "invalid"ReceiptV2type#
packages/sdk/src/v3.ts
A delegus-receipt-v2 receipt: the body plus its receipt JWS.
type ReceiptV2 = Omit<Receipt, V2Omit> & V2FieldsReceiptV2Bodytype#
packages/sdk/src/v3.ts
A delegus-receipt-v2 body (no plaintext authority, no plaintext dependencies).
type ReceiptV2Body = Omit<ReceiptBody, V2Omit> & V2FieldsReceiptV2Signaturetype#
packages/sdk/src/v3.ts
type ReceiptV2Signature = { ok: true; body: ReceiptV2Body; kid: string; } | { ok: false; detail: string; }ReliesOnEntrytype#
packages/sdk/src/v3.ts
One relies_on entry as Delegus records it: the declaration plus per-entry results D2–D7 and, for CURRENT_AUTHORITY, an evidence commitment.
type ReliesOnEntry = DependencyEntryResultVerifyResponseV3type#
packages/sdk/src/v3.ts
A /verify response under v0.3-rc1: the v2 receipt plus, beside it, the plaintext authority with authority_ (and capability_ when the receipt pins that commitment), the plaintext relies_on entries and, on ALLOW, the opening. Every one of them has been checked against the receipt.
type VerifyResponseV3 = Omit<Receipt, V2Omit> & V2Fields & { authority?: Capability; authority_opening?: string; capability_key_opening?: string; relies_on?: ReliesOnEntry[]; opening?: DependencyOpening; }v0.3 fields#
The v0.3 Action and response fields.
RECEIPT_VERSION_V2const#
packages/sdk/src/v3-fields.ts
const RECEIPT_VERSION_V2: "delegus-receipt-v2"MCP servers#
The middleware that checks every MCP tools/call before the tool runs, and the agent-side helpers. See /docs/mcp.
createMcpMiddlewarefunction#
packages/sdk/src/mcp.ts
function createMcpMiddleware(client: Delegus, opts?: McpOptions): McpMiddlewareencodeToolNamefunction#
packages/sdk/src/mcp.ts
Percent-encode any character outside the SHOULD-limited [A-Za-z0-9_.-] tool-name set (both sides use this).
function encodeToolName(name: string): stringfetchToolMapfunction#
packages/sdk/src/mcp.ts
Agent side: fetch and validate the tool map an MCP endpoint publishes at <endpoint>/. Cached per URL by hash; expectHash (from a Delegus- header, sha256=<hex> or sha256:) makes a stale cache entry refetch and a mismatching file an error, so the agent learns of a changed map before signing rather than at P14. null = the endpoint publishes no map (404): build the bare tool-URI Action.
function fetchToolMap(endpoint: string, opts?: { fetch?: typeof fetch; expectHash?: string; }): Promise<FetchedToolMap | null>toolUrifunction#
packages/sdk/src/mcp.ts
The tool URI an api:call Action addresses: <normalizeHtu(.
function toolUri(publicBaseUrl: string, path: string, toolName: string): string | nullARGUMENTS_UNMAPPABLEconst#
packages/sdk/src/mcp.ts
The middleware's own refusal when a mapped tool's arguments cannot be turned into an Action: an integration error, before /verify, never a receipt reason.
const ARGUMENTS_UNMAPPABLE: "ARGUMENTS_UNMAPPABLE"MCP_DELEGUS_ERROR_CODEconst#
packages/sdk/src/mcp.ts
JSON-RPC server-error range (-32000..-32099); avoids MCP's own -32020.
const MCP_DELEGUS_ERROR_CODE: -32040TOOL_MAP_FILEconst#
packages/sdk/src/mcp.ts
The file name, beside the MCP endpoint, at which the middleware serves its tool map.
const TOOL_MAP_FILE: "delegus-tools.json"FetchedToolMapinterface#
packages/sdk/src/mcp.ts
What fetchToolMap returns: the validated map, its hash and where it came from.
interface FetchedToolMap {
map: ToolMap
hash: string
url: string
}McpCallSeeninterface#
From the next SDK release. McpCallSeen isn't in the published @delegus/sdk 0.3.3 on npm yet.
packages/sdk/src/mcp.ts
What the middleware saw of one tools/call, set on the request for the code around it (the gateway's record).
interface McpCallSeen {
tool: string
// The JSON-RPC id of the call (null for a notification).
id: string | number | null
// The Action sent to Delegus, once built.
action?: unknown
decision?: "ALLOW" | "DENY" | undefined
reason?: string | null | undefined
receipt?: McpReceipt | undefined
// Whether the tool is enforced (false: unlisted under `tools`, passed unchecked).
enforced: boolean
}McpDecisioninterface#
packages/sdk/src/mcp.ts
interface McpDecision {
decision: "ALLOW" | "DENY"
reason: string | null
tool: string
receipt?: McpReceipt | undefined
receiptId?: string | undefined
// On a DENY decided in the middleware because /verify failed or its response did not check: what went wrong (for operators, never sent to the caller).
error?: string | undefined
}McpOptionsinterface#
packages/sdk/src/mcp.ts
interface McpOptions {
// Which tools to enforce: an allow-list or a predicate. Absent = enforce every tool. Unlisted tools pass through UNVERIFIED.
tools?: string[] | ((name: string) => boolean) | undefined
// Called with the outcome of every enforced tools/call (for logging / metrics).
onDecision?: ((d: McpDecision) => void) | undefined
// The relying-party DID to advertise in the discovery header on missing credentials. Absent = resolved once via GET /me.
relyingParty?: string | undefined
// "auto" (default, MCP_DEFAULT_PROTOCOL), or a pin: "v0.2" or "v0.3". Passed through to verify().
protocol?: VerifyProtocol | undefined
// With "auto" or "v0.3": the prior decisions every enforced tools/call must rest on (§5.1); checked when the middleware is created. A v0.2 relying party refuses them (fail closed).
requires?: DependencyDeclaration[] | undefined
// The MCP tool map (tool-map.ts): how a tool's arguments become the Action's resource and amount. The
// parsed JSON object; validated when the middleware is created (a ToolMapError names the tool and field).
// Tools without an entry keep the bare tool-URI Action. The map is served at `<path>/delegus-tools.json`
// and named in the `Delegus-Tools` header, so agents build the same Action.
map?: unknown
}McpRequestinterface#
packages/sdk/src/mcp.ts
Minimal Express-style shapes so the middleware needs no web-framework dependency.
interface McpRequest {
method?: string | undefined
url?: string | undefined
path?: string | undefined
headers: Record<string, string | string[] | undefined>
body?: unknown
// Set on ALLOW: the Delegus receipt (v0.3: the checked response) and the Action that authorized this tools/call.
delegus?: { receipt: McpReceipt; action: unknown; } | undefined
// Set for every single tools/call with a string tool name: what the middleware saw and decided.
delegusCall?: McpCallSeen | undefined
}McpResponseinterface#
packages/sdk/src/mcp.ts
interface McpResponse {
statusCode?: number | undefined
setHeader(name: string, value: string): void
end(body?: string): void
}McpMiddlewaretype#
packages/sdk/src/mcp.ts
type McpMiddleware = (req: McpRequest, res: McpResponse, next: McpNext) => Promise<void>McpProtocoltype#
packages/sdk/src/mcp.ts
The protocol the middleware speaks to Delegus: "auto" (the default) accepts the relying party's own profile; "v0.2" and "v0.3" pin one.
type McpProtocol = "v0.3" | "v0.2" | "auto"McpReceipttype#
packages/sdk/src/mcp.ts
The receipt the middleware attaches: a v0.2 receipt, or the checked v0.3 response (receipt v2 plus authority and its opening).
type McpReceipt = Receipt | VerifyResponseV3Tool maps#
How a tool call’s arguments become the action Delegus Check verifies, on the server and the agent alike.
ToolMapErrorclass#
packages/sdk/src/tool-map.ts
A map that cannot be loaded; tool and field name the entry at fault when there is one.
class ToolMapError {
new (message: string, tool?: string | null, field?: string | null): ToolMapError
tool: string | null
field: string | null
name: string
message: string
stack?: string | undefined
cause?: unknown
}encodeSegmentfunction#
packages/sdk/src/tool-map.ts
Percent-encode one path segment: RFC 3986 unreserved characters kept, everything else (incl. * ? % # /) encoded as UTF-8.
function encodeSegment(s: string): stringisDotSegmentfunction#
packages/sdk/src/tool-map.ts
"." or ".." in disguise. Percent-decode repeatedly (stop when unchanged or malformed), NFKC-normalize each round; true when any round is a dot segment, when the text still carries "%2e" (any case) once decoding stops, or when it is still changing after DECODE_ROUNDS rounds. A malformed sequence is literal.
function isDotSegment(segment: string): booleanmcpActionfunction#
packages/sdk/src/tool-map.ts
Build the Action for one tools/call. null = the tool has no entry (keep the bare tool-URI Action). toolUri is the URI the caller derives for the tool (<base>/); an api:call resource is <toolUri>/. A refusal names the field so the caller can deny with the reason spelled out.
function mcpAction(map: ToolMap, tool: string, toolUri: string, args: unknown): ToolMapResult | nullresolvePointerfunction#
packages/sdk/src/tool-map.ts
RFC 6901 resolution over the call's arguments. undefined = no such path. "" = the whole document.
function resolvePointer(doc: unknown, pointer: string): unknowntoMinorUnitsfunction#
packages/sdk/src/tool-map.ts
Exact conversion to integer minor units; a string explains a refusal. Never floating-point arithmetic.
function toMinorUnits(value: unknown, unit: "minor" | "major", decimals?: number): number | stringtoolMapHashfunction#
packages/sdk/src/tool-map.ts
sha256 over the JCS form of the map: the identifier both sides compare.
function toolMapHash(map: ToolMap): Sha256ReftoolMapWarningsfunction#
packages/sdk/src/tool-map.ts
Non-fatal findings for an operator: two tools mapping to the same commerce type with the same template shape share one authority (a Grant for one authorizes the other).
function toolMapWarnings(map: ToolMap): string[]TOOL_MAP_ACTIONSconst#
packages/sdk/src/tool-map.ts
const TOOL_MAP_ACTIONS = {
// Returns a string representation of an array.
toString(): string
// Returns a string representation of an array. The elements are converted to string using their toLocaleString methods.
toLocaleString(): string
// Combines two or more arrays.
concat(...items: ConcatArray<"commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call">[]): ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]
// Adds all the elements of an array separated by the specified separator string.
join(separator?: string): string
// Returns a section of an array.
slice(start?: number, end?: number): ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]
// Returns the index of the first occurrence of a value in an array.
indexOf(searchElement: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", fromIndex?: number): number
// Returns the index of the last occurrence of a specified value in an array.
lastIndexOf(searchElement: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", fromIndex?: number): number
// Determines whether all the members of an array satisfy the specified test.
every<S extends "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call">(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => value is S, thisArg?: any): this is readonly S[]
// Determines whether the specified callback function returns true for any element of an array.
some(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => unknown, thisArg?: any): boolean
// Performs the specified action for each element in an array.
forEach(callbackfn: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => void, thisArg?: any): void
// Calls a defined callback function on each element of an array, and returns an array that contains the results.
map<U>(callbackfn: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => U, thisArg?: any): U[]
// Returns the elements of an array that meet the condition specified in a callback function.
filter<S extends "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call">(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => value is S, thisArg?: any): S[]
// Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
reduce(callbackfn: (previousValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", currentValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", currentIndex: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"): "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"
// Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
reduceRight(callbackfn: (previousValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", currentValue: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", currentIndex: number, array: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"): "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"
// Returns the value of the first element in the array where predicate is true, and undefined
// otherwise.
find<S extends "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call">(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, obj: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => value is S, thisArg?: any): S | undefined
// Returns the index of the first element in the array where predicate is true, and -1
// otherwise.
findIndex(predicate: (value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, obj: readonly ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => unknown, thisArg?: any): number
// Returns an iterable of key, value pairs for every entry in the array
entries(): ArrayIterator<[number, "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"]>
// Returns an iterable of keys in the array
keys(): ArrayIterator<number>
// Returns an iterable of values in the array
values(): ArrayIterator<"commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call">
// Determines whether an array includes a certain element, returning true or false as appropriate.
includes(searchElement: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", fromIndex?: number): boolean
// Calls a defined callback function on each element of an array. Then, flattens the result into
// a new array.
// This is identical to a map followed by flat with depth 1.
flatMap<U, This = undefined>(callback: (this: This, value: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call", index: number, array: ("commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call")[]) => U | readonly U[], thisArg?: This | undefined): U[]
// Returns a new array with all sub-array elements concatenated into it recursively up to the
// specified depth.
flat<A, D extends number = 1>(this: A, depth?: D | undefined): FlatArray<A, D>[]
// Returns the item located at the specified index.
at(index: number): "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call" | undefined
// Iterator of values in the array.
__@iterator@208(): ArrayIterator<"commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call">
// Is an object whose properties have the value 'true'
// when they will be absent when used in a 'with' statement.
__@unscopables@592: { readonly [x: number]: boolean | undefined; readonly length?: boolean | undefined; toString?: boolean | undefined; toLocaleString?: boolean | undefined; concat?: boolean | undefined; join?: boolean | undefined; slice?: boolean | undefined; indexOf?: boolean | undefined; lastIndexOf?: boolean | undefined; every?: boolean | undefined; some?: boolean | undefined; forEach?: boolean | undefined; map?: boolean | undefined; filter?: boolean | undefined; reduce?: boolean | undefined; reduceRight?: boolean | undefined; find?: boolean | undefined; findIndex?: boolean | undefined; entries?: boolean | undefined; keys?: boolean | undefined; values?: boolean | undefined; includes?: boolean | undefined; flatMap?: boolean | undefined; flat?: boolean | undefined; at?: boolean | undefined; [Symbol.iterator]?: boolean | undefined; readonly [Symbol.unscopables]?: boolean | undefined; }
}ToolMapinterface#
packages/sdk/src/tool-map.ts
interface ToolMap {
version: 1
tools: Record<string, ToolMapEntry>
}ToolMapAmountinterface#
packages/sdk/src/tool-map.ts
interface ToolMapAmount {
// JSON pointer to the amount.
value: string
// JSON pointer to the currency, or a literal ISO 4217 code (three upper-case letters).
currency: string
// "minor": the value is a non-negative safe integer in minor units. "major": a number or decimal string with at most `decimals` fractional digits, converted by string arithmetic.
unit: "minor" | "major"
// Required with "major": the currency's fractional digits (0–6).
decimals?: number | undefined
}ToolMapEntryinterface#
packages/sdk/src/tool-map.ts
interface ToolMapEntry {
action: "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"
// Literal text plus `{<json-pointer>}` placeholders. For api:call the result is appended to the tool URI; for the commerce types it is the resource itself.
resource: string
amount?: ToolMapAmount | undefined
}ToolMapActiontype#
packages/sdk/src/tool-map.ts
type ToolMapAction = "commerce:quote" | "commerce:accept" | "commerce:fulfil" | "commerce:purchase" | "api:call"ToolMapResulttype#
packages/sdk/src/tool-map.ts
type ToolMapResult = { ok: true; action: Record<string, JsonValue>; resource: string; method: string; } | { ok: false; error: string; field: string; }Ordinary HTTP APIs#
The same check in front of a REST API: Express and Fastify middleware and the route map. See /docs/http.
RouteMapErrorclass#
packages/sdk/src/http.ts
class RouteMapError {
new (message: string, route?: string | null): RouteMapError
route: string | null
name: string
message: string
stack?: string | undefined
cause?: unknown
}checkHttpRequestfunction#
packages/sdk/src/http.ts
The check itself. url is the canonical public URL of the request (the server knows its publicBaseUrl; the path and query come from the request). Pure apart from the one call to Delegus.
function checkHttpRequest(client: Delegus, opts: HttpCheckOptions, req: HttpRequestLike & { url: string; }): Promise<HttpCheckOutcome>createHttpMiddlewarefunction#
packages/sdk/src/http.ts
Express-style middleware: app. before the routes it protects (mount express. first so req.body is the parsed JSON). Serves the route map at /. OPTIONS passes; everything else is checked. On ALLOW req.delegus holds the receipt and the Action, and Delegus- is on the response; on DENY, 403 (401 without credentials) with the reason.
function createHttpMiddleware(client: Delegus, opts?: HttpMiddlewareOptions): (req: MinimalReq, res: MinimalRes, next: (err?: unknown) => void) => Promise<void>fastifyDelegusHttpfunction#
packages/sdk/src/http.ts
Fastify: app.. Uses request. as Fastify parsed it, request. and request.; on ALLOW request. is set and the receipt header added to the reply; on DENY the reply is sent and the handler never runs.
function fastifyDelegusHttp(client: Delegus, opts?: HttpMiddlewareOptions): (request: { method: string; url: string; headers: Record<string, string | string[] | undefined>; body?: unknown; delegus?: unknown; }, reply: { code(c: number): unknown; header(n: string, v: string): unknown; send(b: unknown): unknown; }) => Promise<void>httpActionfunction#
packages/sdk/src/http.ts
The Action a request is checked as. url must be the canonical public URL (publicBaseUrl + path, query kept as received).
function httpAction(compiled: CompiledRoutes | null, req: { method: string; url: string; body?: unknown; }): HttpActionResultmatchRoutefunction#
packages/sdk/src/http.ts
The first route whose method and path pattern match, with the path parameters it bound.
function matchRoute(compiled: CompiledRoutes, method: string, path: string): { route: CompiledRoutes["routes"][number]; params: Record<string, string>; } | nullCompiledRoutesinterface#
packages/sdk/src/http.ts
A compiled route map: the path matcher per route and the tool-map-shaped templates the Action is built from.
interface CompiledRoutes {
map: RouteMap
hash: string
json: string
routes: (RouteDef & { segments: Array<{ literal: string; } | { param: string; }>; })[]
// The templates, as a tool map keyed by route id (so mcpAction renders them).
templates: ToolMap
// The same templates under the tool map's own member name, so mcpAction can read a CompiledRoutes directly.
tools: Record<string, ToolMapEntry>
}HttpCheckOptionsinterface#
packages/sdk/src/http.ts
interface HttpCheckOptions {
// The route map, already compiled with compileRouteMap; null = every request is `api:call` on its URL.
routes?: CompiledRoutes | null | undefined
protocol?: VerifyProtocol | undefined
// The relying-party DID to advertise on missing credentials. Absent = resolved once via GET /me.
relyingParty?: string | undefined
onDecision?: ((d: { decision: "ALLOW" | "DENY"; reason: string | null; route: string | null; method: string; url: string; receiptId?: string; error?: string; }) => void) | undefined
}HttpCheckOutcomeinterface#
packages/sdk/src/http.ts
interface HttpCheckOutcome {
status: 200 | 401 | 403
headers: Record<string, string>
// Present when the request may proceed.
receipt?: VerifyResult | undefined
// Present on a refusal: the JSON body to send.
body?: JsonObject | undefined
decision: "ALLOW" | "DENY"
reason: string | null
action: JsonObject | null
route: string | null
}HttpMiddlewareOptionsinterface#
packages/sdk/src/http.ts
interface HttpMiddlewareOptions {
// The route map JSON (validated here) or an already compiled one.
routeMap?: unknown
// The route map, already compiled with compileRouteMap; null = every request is `api:call` on its URL.
routes?: CompiledRoutes | null | undefined
protocol?: VerifyProtocol | undefined
// The relying-party DID to advertise on missing credentials. Absent = resolved once via GET /me.
relyingParty?: string | undefined
onDecision?: ((d: { decision: "ALLOW" | "DENY"; reason: string | null; route: string | null; method: string; url: string; receiptId?: string; error?: string; }) => void) | undefined
}HttpActionResulttype#
packages/sdk/src/http.ts
type HttpActionResult = { ok: true; action: JsonObject; route: string | null; } | { ok: false; reason: string; detail: string; route: string | null; }Receipt chains#
From the next SDK release. This section isn't in the published @delegus/sdk 0.3.3 on npm yet.
Verify a chain of linked receipts offline.
comparePolicyfunction#
packages/sdk/src/chain.ts
Compare a verified chain to the confirmed policy. report comes from verifyChain with the company's Grants supplied.
function comparePolicy(report: ChainReport, policy: PolicyMapping): PolicyReportverifyChainfunction#
packages/sdk/src/chain.ts
Verify a chain offline. grants: the Grants the company holds, any order; matched to links by sha256 of the JWS.
function verifyChain(chain: ChainInput, keys: Record<string, Uint8Array>, grants?: readonly string[], serviceDid?: string): ChainReportChainInputinterface#
packages/sdk/src/chain.ts
interface ChainInput {
root: string
links: { receipt_id: string; depth: number; receipt: string; decision: "ALLOW" | "DENY"; reason: string | null; evaluated_at: string; relying_party: string; principal: string | null; agent: string | null; grant_id: string | null; grant_hash: string | null; action: JsonValue | null; relies_on: Array<{ fingerprint: string; mode: string; checks: JsonValue; transaction_equal: boolean | null; receipt_hash?: string; receipt_id?: string; opening?: string; withheld?: boolean; }>; }[]
withheld?: number | undefined
truncated?: boolean | undefined
}ChainReportinterface#
packages/sdk/src/chain.ts
interface ChainReport {
root: string
ok: boolean
links: LinkReport[]
link_count: number
withheld: number
truncated: boolean
not_confirmed_here: string[]
// Each link's action as the chain carried it, by receipt id (for the policy comparison).
actions?: Record<string, JsonValue> | undefined
}LinkReportinterface#
packages/sdk/src/chain.ts
interface LinkReport {
receipt_id: string
depth: number
agent: string | null
decision: "ALLOW" | "DENY"
reason: string | null
signature: "invalid" | "valid"
body_matches_payload: boolean
relies_on: { fingerprint: string; mode: string; prior_receipt_id: string | null; prior_agent: string | null; opening_reproduces: boolean | "withheld"; prior_is_allow: boolean | "withheld"; prior_signature: "valid" | "invalid" | "withheld"; }[]
grant: { grant_id: string | null; grant_hash: string | null; supplied: boolean; hash_matches: boolean | null; parses: boolean | null; subject_is_agent: boolean | null; authority: Capability[] | null; audience: string[] | null; valid_from: string | null; valid_until: string | null; }
ok: boolean
failures: string[]
}PolicyLinkinterface#
packages/sdk/src/chain.ts
interface PolicyLink {
receipt_id: string
agent: string | null
holder: { id: string; kind: string; } | null
// matches: same authority; narrower: inside the policy's; wider: something the policy does not give; not_supplied: no Grant to compare; no_holder: the agent is not a holder at as_of.
grant: "not_supplied" | "matches" | "narrower" | "wider" | "no_holder"
detail: string | null
// Per Grant Capability: the policy rule ids it traces to (empty when it fits no policy Capability).
provenance: { capability: number; rules: string[]; }[]
// The step this link performed, read from the action's resource; null when it cannot be told, with the candidates.
step: string | null
candidates: string[]
}PolicyMappinginterface#
packages/sdk/src/chain.ts
interface PolicyMapping {
format: "delegus-pack-authority-map-v1"
matrix_hash: string
as_of: string
relying_party: string
grants: { did: string; id: string; kind: string; authority: Capability[]; audience: string[]; provenance: Array<{ capability: number; rules: Array<{ rule: string; role: string; unit: string; }>; }>; }[]
steps: { action: string; operation: string; doc: string; creates: boolean; approval: boolean; distinct_from: string[]; requires_prior: string[]; quorum: { actions: string[]; min: number; } | null; }[]
}PolicyReportinterface#
packages/sdk/src/chain.ts
interface PolicyReport {
matrix_hash: string
as_of: string
ok: boolean
links: PolicyLink[]
segregation: SegregationCheck[]
quorum: QuorumCheck[]
not_confirmed_here: string[]
}QuorumCheckinterface#
packages/sdk/src/chain.ts
interface QuorumCheck {
receipt_id: string
step: string
required: number
distinct_voters: number
verdict: "not_determinable" | "met" | "not_met"
why: string
}SegregationCheckinterface#
packages/sdk/src/chain.ts
interface SegregationCheck {
receipt_id: string
prior_receipt_id: string | null
agent: string | null
prior_agent: string | null
step: string | null
prior_step: string | null
// distinct: different agents; same_agent_violation: the policy requires different people here; same_agent_allowed: the same person, and the policy does not forbid it; not_determinable: a step or an agent is unknown (withheld, or ambiguous).
verdict: "distinct" | "same_agent_violation" | "same_agent_allowed" | "not_determinable"
why: string
}Issuance lint#
Warnings for personal data in a grant before it is issued.
lintAuthorityfunction#
packages/sdk/src/lint.ts
Lint a Grant's authority (an array of Capabilities, or one Capability) for personal data in its strings. Returns one finding per kind per string; empty when nothing looks personal.
function lintAuthority(authority: unknown): LintFinding[]luhnValidfunction#
packages/sdk/src/lint.ts
Luhn (mod 10) over a digit string.
function luhnValid(d: string): booleanpersonalDataInfunction#
packages/sdk/src/lint.ts
The kinds of personal data a single string looks like it contains.
function personalDataIn(s: string): PersonalDataKind[]LintFindinginterface#
packages/sdk/src/lint.ts
interface LintFinding {
// Where, e.g. `authority[0].resources[1]`. The matched value is not echoed.
path: string
kind: PersonalDataKind
}Types from @delegus/core#
Re-exported so an integrator never needs to import core directly.
EVALUATION_ORDER_V3const#
packages/core/src/types.ts
delegus-base-v3 order (v0.3-rc1 §5.4): … P20 → P21 → D1 … D7 → [consume] → T7. The atomic spend is the very last step: it runs only when every other check passed, so no request consumes budget and is then refused.
const EVALUATION_ORDER_V3 = {
// Gets the length of the array. This is a number one higher than the highest element defined in an array.
length: number
// Returns a string representation of an array.
toString(): string
// Returns a string representation of an array. The elements are converted to string using their toLocaleString methods.
toLocaleString(): string
// Combines two or more arrays.
concat(...items: ConcatArray<CheckId>[]): CheckId[]
// Adds all the elements of an array separated by the specified separator string.
join(separator?: string): string
// Returns a section of an array.
slice(start?: number, end?: number): CheckId[]
// Returns the index of the first occurrence of a value in an array.
indexOf(searchElement: CheckId, fromIndex?: number): number
// Returns the index of the last occurrence of a specified value in an array.
lastIndexOf(searchElement: CheckId, fromIndex?: number): number
// Determines whether all the members of an array satisfy the specified test.
every<S extends CheckId>(predicate: (value: CheckId, index: number, array: readonly CheckId[]) => value is S, thisArg?: any): this is readonly S[]
// Determines whether the specified callback function returns true for any element of an array.
some(predicate: (value: CheckId, index: number, array: readonly CheckId[]) => unknown, thisArg?: any): boolean
// Performs the specified action for each element in an array.
forEach(callbackfn: (value: CheckId, index: number, array: readonly CheckId[]) => void, thisArg?: any): void
// Calls a defined callback function on each element of an array, and returns an array that contains the results.
map<U>(callbackfn: (value: CheckId, index: number, array: readonly CheckId[]) => U, thisArg?: any): U[]
// Returns the elements of an array that meet the condition specified in a callback function.
filter<S extends CheckId>(predicate: (value: CheckId, index: number, array: readonly CheckId[]) => value is S, thisArg?: any): S[]
// Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
reduce(callbackfn: (previousValue: CheckId, currentValue: CheckId, currentIndex: number, array: readonly CheckId[]) => CheckId): CheckId
// Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
reduceRight(callbackfn: (previousValue: CheckId, currentValue: CheckId, currentIndex: number, array: readonly CheckId[]) => CheckId): CheckId
// Returns the value of the first element in the array where predicate is true, and undefined
// otherwise.
find<S extends CheckId>(predicate: (value: CheckId, index: number, obj: readonly CheckId[]) => value is S, thisArg?: any): S | undefined
// Returns the index of the first element in the array where predicate is true, and -1
// otherwise.
findIndex(predicate: (value: CheckId, index: number, obj: readonly CheckId[]) => unknown, thisArg?: any): number
// Returns an iterable of key, value pairs for every entry in the array
entries(): ArrayIterator<[number, CheckId]>
// Returns an iterable of keys in the array
keys(): ArrayIterator<number>
// Returns an iterable of values in the array
values(): ArrayIterator<CheckId>
// Determines whether an array includes a certain element, returning true or false as appropriate.
includes(searchElement: CheckId, fromIndex?: number): boolean
// Calls a defined callback function on each element of an array. Then, flattens the result into
// a new array.
// This is identical to a map followed by flat with depth 1.
flatMap<U, This = undefined>(callback: (this: This, value: CheckId, index: number, array: CheckId[]) => U | readonly U[], thisArg?: This | undefined): U[]
// Returns a new array with all sub-array elements concatenated into it recursively up to the
// specified depth.
flat<A, D extends number = 1>(this: A, depth?: D | undefined): FlatArray<A, D>[]
// Returns the item located at the specified index.
at(index: number): CheckId | undefined
// Iterator of values in the array.
__@iterator@208(): ArrayIterator<CheckId>
// Is an object whose properties have the value 'true'
// when they will be absent when used in a 'with' statement.
__@unscopables@592: { readonly [x: number]: boolean | undefined; readonly length?: boolean | undefined; toString?: boolean | undefined; toLocaleString?: boolean | undefined; concat?: boolean | undefined; join?: boolean | undefined; slice?: boolean | undefined; indexOf?: boolean | undefined; lastIndexOf?: boolean | undefined; every?: boolean | undefined; some?: boolean | undefined; forEach?: boolean | undefined; map?: boolean | undefined; filter?: boolean | undefined; reduce?: boolean | undefined; reduceRight?: boolean | undefined; find?: boolean | undefined; findIndex?: boolean | undefined; entries?: boolean | undefined; keys?: boolean | undefined; values?: boolean | undefined; includes?: boolean | undefined; flatMap?: boolean | undefined; flat?: boolean | undefined; at?: boolean | undefined; [Symbol.iterator]?: boolean | undefined; readonly [Symbol.unscopables]?: boolean | undefined; }
}DependencyDeclarationinterface#
packages/core/src/action-v3.ts
interface DependencyDeclaration {
fingerprint: `sha256:${string}`
mode: "PRIOR_DECISION" | "CURRENT_AUTHORITY"
}Receiptinterface#
packages/core/src/receipt.ts
A signed receipt: the body as signed (§6.4: equal to the JWS payload) and the JWS.
interface Receipt {
// Non-detached compact JWS over JCS(body as signed).
receipt: string
receipt_version: "delegus-receipt-v2" | "delegus-receipt-v1" | "delegus-receipt-v3"
// delegus-receipt-v1 only: the matched Capability, or null on DENY.
authority?: Capability | null | undefined
// delegus-receipt-v2: the matched Capability under a commitment (§R.6); the plaintext and its opening go to the RP beside the receipt.
authority_commitment?: `sha256:${string}` | undefined
// delegus-receipt-v2: sha256 over JCS(the declared dependencies with their per-entry results).
// Constant size whatever the number of dependencies (KMS signs ≤ 4,096 bytes); the entries
// themselves go to the relying party beside the receipt, like `authority`.
relies_on_hash?: `sha256:${string}` | undefined
// delegus-receipt-v2: sha256 over JCS(the relying party's `requires`), when it sent one, so D1 is reproducible.
requires_hash?: `sha256:${string}` | undefined
// delegus-receipt-v2: this receipt's pairwise transaction handle (22 chars base64url).
transaction?: string | undefined
receipt_id: string
decision: Decision
reason: ReasonCode | null
evaluated_at: string
relying_party: string
principal?: { id: string; verification: "domain" | "unverified" | "managed"; } | undefined
agent?: string | undefined
grant_id?: string | undefined
grant_hash: `sha256:${string}`
proof_hash: `sha256:${string}`
request_hash?: `sha256:${string}` | undefined
expires_at?: string | undefined
evidence: ReceiptEvidence
trust: { result: LayerResult; policy_version: ProfileSpec["policy"]; checks: Record<string, CheckOutcome>; }
protocol: Omit<{ result: LayerResult; profile: ProfileId; profile_hash: Sha256Ref; checks: Record<string, CheckOutcome>; }, "checks"> & { checks: ReceiptBody["protocol"]["checks"] | string; }
}ReverifyResultinterface#
packages/core/src/receipt.ts
interface ReverifyResult {
// Signature valid, every supplied artifact matches its pinned hash, and everything that could be reproduced was.
ok: boolean
signature: "invalid" | "valid"
detail?: string | undefined
hashes?: Record<"profile" | "grant" | "proof" | "request" | "did_document" | "status_credential" | "trust_config", HashComparison> | undefined
// Whether `protocol`, `decision` and `reason` were reproduced, and what differed.
reproduced?: { protocol: boolean; decision: boolean; differences: string[]; } | undefined
// What this run could not reproduce and why: the trust attestations (always), and for a v0.3 receipt
// the commitments without their openings, P21 without the consumption snapshot, D1–D7 without the
// dependency material, and the decision when it rests on one of those. Not a failure; a boundary.
notReproduced?: { what: string; why: string; }[] | undefined
receipt?: ReceiptBody | undefined
recomputed?: ReceiptBody | undefined
}DependencyModetype#
packages/core/src/action-v3.ts
type DependencyMode = "PRIOR_DECISION" | "CURRENT_AUTHORITY"TrustedKeystype#
packages/core/src/status.ts
Raw Ed25519 public keys by kid.
type TrustedKeys = { readonly [x: string]: Uint8Array<ArrayBufferLike>; }The delegus CLI#
The same operations from a shell, for onboarding and for scripts. The text below is the binary's own help output, captured at build time.
Usage: delegus <command> [options]
Delegus verifies an AI agent's delegated authority to act (spec v0.3-rc1; v0.2 receipts supported).
Every command prints one JSON object on stdout. Exit 0 on success
(ALLOW), 1 on error, 2 when a decision is DENY or a receipt does not
reverify.
Commands:
conformance Run the Delegus conformance vectors (v0.2; --v3 for v0.3) (needs @delegus/conformance installed)
doctor Check the API, your key and its subject; the first thing to run on day one
key list List the API keys of your subject (ids and labels only)
key create Issue an additional API key for your subject (rotation step 1); the key is printed once
key revoke Revoke one of your subject's API keys by its id (rotation step 2, or a leaked key)
keygen Generate an Ed25519 key and write it as a private JWK (mode 0600)
org init Create an organization account (owns Principals and relying parties; holds dashboard keys) (admin token)
org show Show an organization and its members (org key or admin token)
org add-member Attach an existing Principal or relying party to an organization (admin token)
org key-create Issue an org key with role read or admin, printed once (org:admin key or admin token)
org key-list List an organization's keys (ids and labels only)
org key-revoke Revoke an organization key by its id (org:admin key or admin token)
org create Create a managed Principal at Delegus whose signing key is --key (admin token, or an org:admin key)
org register Register a customer-hosted Principal (did:web) and get its domain-verification instructions (admin token, or an org:admin key)
org verify Run domain verification for a Principal now and print its state (Principal key)
rp create Create a Relying Party, managed (--slug) or hosted (--did), and print its API key once (admin token, or an org:admin key)
agent create Generate an Agent key (did:key) and write it as a private JWK (mode 0600)
agent register Add an Agent to the Principal's inventory (Principal key)
agent disable Kill switch: revoke every Grant naming the Agent (Principal key)
grant create Issue a Grant: allocate its status entry at Delegus, sign it locally with --key (Principal key)
grant compile Compile authority written in plain words into the exact capabilities a Grant will carry, with its read-back (offline)
grant explain Read a Grant back in words from its JSON, and name anything it carries that the read-back does not explain (offline)
approval verify Re-check a passkey approval record with nothing from Delegus: the person's assertion over the Grant's exact bytes (offline)
grant revoke Revoke a Grant; returns once every later /verify anywhere will deny it (Principal key)
key retire Retire a Principal signing key (rotation): existing Grants stay valid, new Grants must use an active key (Principal key)
key compromise Mark a Principal key compromised: every Grant it signed denies immediately (Principal key)
proof sign Sign a proof of grant with an Agent key, binding one Grant, one RP and one request
verify POST /verify as a Relying Party; prints the signed Receipt, exit 0 for ALLOW and 2 for DENY (RP key)
outcome report Append an Outcome Attestation to a decision (RP key, the RP in the receipt)
decision get Fetch a decision: its receipt and outcome ledger (RP key, the RP in the receipt)
principal list Principal directory: who is registered and verified, since when, with which keys (any key)
principal show One Principal from the directory (full record for its own key, its org or admin)
decision list List decisions newest first (RP key: own; org key: the org's relying parties; admin: any)
decision export Export decisions with full receipts and outcome ledgers (NDJSON to stdout, or --csv); follows cursors until done or --limit rows
decision stats Decisions and outcomes rolled up per Principal over a range (default last 30 days)
receipt verify Verify a receipt (no API key needed). Alone: signature under the published DID document and the public check. With --grant --proof --action: re-run the open checks with the artifacts fetched by hash and say exactly what was and was not reproduced (v0.2 and v0.3). --entitled (v0.3): open the commitments without a re-run
chain verify The auditor's chain: fetch (or read) a receipt's chain and re-verify every link offline: each receipt's signature, each relies_on opening against the prior receipt (D2), each prior decision ALLOW (D4), and each Grant you hold against its link's grant_hash and agent; with --policy, each Grant against the confirmed policy and the people across links. Exit 0 only when every link (and the policy) passes
receipt inclusion Prove a receipt is in its day's signed Merkle checkpoint (audit path to the root, root signature from the DID document; no key needed)
checkpoint verify Third-party check of a day's checkpoint: recompute the Merkle root from the published leaves and verify the signature (no key needed)
checkpoint contains Check that receipt ids (from `delegus decision list` or your logs) are leaves of a day's checkpoint
action purchase Print the canonical commerce:purchase Action for these wire fields
action api-call Print the canonical api:call Action for these wire fields
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show help
Environment: DELEGUS_API_URL, DELEGUS_API_KEY, DELEGUS_ADMIN_TOKEN; the flags above override them.
Key files are Ed25519 private JWKs (kty OKP, crv Ed25519, x, d) written with mode 0600.
Arguments shown as <jws|file> or <json|file> take the value itself or the path of a file holding it.
Run 'delegus <command> --help' for the options of one command.delegus conformance#
Usage: delegus conformance [--impl <module>] [--only <id,id>] [--dir <path>]
Run the Delegus conformance vectors (v0.2; --v3 for v0.3) (needs @delegus/conformance installed).
Options:
--impl <module> Module exporting an Implementation to test instead of @delegus/core
--only <id,id> Run only these vector ids
--dir <path> A cases/ + sets/ directory other than the shipped vectors
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus doctor#
Usage: delegus doctor
Check the API, your key and its subject; the first thing to run on day one.
Options:
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus key list#
Usage: delegus key list
List the API keys of your subject (ids and labels only).
Options:
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus key create#
Usage: delegus key create [--label <label>]
Issue an additional API key for your subject (rotation step 1); the key is printed once.
Options:
--label <label> A label for the new key
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus key revoke#
Usage: delegus key revoke --id <key_id>
Revoke one of your subject's API keys by its id (rotation step 2, or a leaked key).
Options:
--id <key_id> The key id from `delegus key list`
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus keygen#
Usage: delegus keygen --out <file> [--force]
Generate an Ed25519 key and write it as a private JWK (mode 0600).
Options:
--out <file> File to write the JWK to
--force Overwrite an existing file
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org init#
Usage: delegus org init --slug <slug> --name <name>
Create an organization account (owns Principals and relying parties; holds dashboard keys) (admin token).
Options:
--slug <slug> Account slug (lowercase DNS label)
--name <name> Display name
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org show#
Usage: delegus org show --id <org_id>
Show an organization and its members (org key or admin token).
Options:
--id <org_id> The org id from `delegus org init`
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org add-member #
Usage: delegus org add-member --id <org_id> --did <did:web>
Attach an existing Principal or relying party to an organization (admin token).
Options:
--id <org_id> The org id
--did <did:web> The Principal's or relying party's DID
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org key-create #
Usage: delegus org key-create --id <org_id> --role <read|admin> [--label <label>]
Issue an org key with role read or admin, printed once (org:admin key or admin token).
Options:
--id <org_id> The org id
--role <read|admin> read: every GET about the org; admin: also onboarding, keys, revocation
--label <label> A label for the key
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org key-list #
Usage: delegus org key-list --id <org_id>
List an organization's keys (ids and labels only).
Options:
--id <org_id> The org id
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org key-revoke #
Usage: delegus org key-revoke --id <org_id> --key-id <key_id>
Revoke an organization key by its id (org:admin key or admin token).
Options:
--id <org_id> The org id
--key-id <key_id> The key id from `delegus org key-list`
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org create#
Usage: delegus org create --slug <slug> --key <file> [--key-id <id>] [--org <org_id>]
Create a managed Principal at Delegus whose signing key is --key (admin token, or an org:admin key).
Options:
--slug <slug> Principal slug (DID did:web:<domain>:org:<slug>)
--key <file> Principal key file from `delegus keygen`
--key-id <id> Key id fragment (default key-1)
--org <org_id> Attach to this organization (admin token; an org:admin key always uses its own)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org register#
Usage: delegus org register --did <did:web> [--org <org_id>]
Register a customer-hosted Principal (did:web) and get its domain-verification instructions (admin token, or an org:admin key).
Options:
--did <did:web> The Principal's DID
--org <org_id> Attach to this organization (admin token)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus org verify#
Usage: delegus org verify --did <did:web>
Run domain verification for a Principal now and print its state (Principal key).
Options:
--did <did:web> The Principal's DID
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus rp create#
Usage: delegus rp create [--slug <slug>] [--did <did:web>] [--name <name>] [--proof-window <seconds>] [--org <org_id>]
Create a Relying Party, managed (--slug) or hosted (--did), and print its API key once (admin token, or an org:admin key).
Options:
--slug <slug> Managed RP slug (exactly one of --slug, --did)
--did <did:web> Hosted RP DID (exactly one of --slug, --did)
--name <name> Display name
--proof-window <seconds> How long a proof of grant stays fresh
--org <org_id> Attach to this organization (admin token; an org:admin key always uses its own)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus agent create#
Usage: delegus agent create --out <file> [--force]
Generate an Agent key (did:key) and write it as a private JWK (mode 0600).
Options:
--out <file> File to write the JWK to
--force Overwrite an existing file
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus agent register#
Usage: delegus agent register --principal <did:web> --did <did:key>
Add an Agent to the Principal's inventory (Principal key).
Options:
--principal <did:web> The Principal's DID (did:web)
--did <did:key> The Agent's DID
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus agent disable#
Usage: delegus agent disable --principal <did:web> --did <did:key>
Kill switch: revoke every Grant naming the Agent (Principal key).
Options:
--principal <did:web> The Principal's DID (did:web)
--did <did:key> The Agent's DID
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus grant create#
Usage: delegus grant create --principal <did:web> --key <file> --kid <kid> --agent <did:key> --authority <json|file> [--valid-from <iso>] [--valid-until <iso>] [--audience <did,did>] [--refuse-personal-data]
Issue a Grant: allocate its status entry at Delegus, sign it locally with --key (Principal key).
Options:
--principal <did:web> The Principal's DID (did:web)
--key <file> Principal key file
--kid <kid> Verification method of --key in the Principal's DID document (did:web:…#key-n)
--agent <did:key> The Agent the Grant is for
--authority <json|file> JSON array of capabilities: [{action, constraints, resources?}]
--valid-from <iso> RFC 3339 UTC, whole seconds (default now)
--valid-until <iso> RFC 3339 UTC, whole seconds (default validFrom + 30 days; at most 90)
--audience <did,did> Comma-separated RP DIDs (default any registered RP)
--refuse-personal-data Refuse (exit 1) when the authority looks like it holds an email, phone or card number; by default the Grant is issued with `warnings`
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus grant compile#
Usage: delegus grant compile --sentence <text> [--agents <json|file>] [--relying-parties <json|file>] [--now <iso>]
Compile authority written in plain words into the exact capabilities a Grant will carry, with its read-back (offline).
Options:
--sentence <text> e.g. "Let ordering-agent pay acme-* up to $250 per day until 2026-12-31, at Northfield only"
--agents <json|file> Agent names to did:key, e.g. {"ordering-agent": "did:key:z6Mk…"} (a did:key in the sentence needs none)
--relying-parties <json|file> Relying party names to DIDs, for "at <name> only"
--now <iso> The clock (default now); the Grant starts at this second
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus grant explain#
Usage: delegus grant explain --grant <jws|json|file>
Read a Grant back in words from its JSON, and name anything it carries that the read-back does not explain (offline).
Options:
--grant <jws|json|file> A Grant JWS, its decoded payload, or a compiled draft
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus approval verify#
Usage: delegus approval verify --record <json|file> [--grant <jws|file>] [--rp-id <id>] [--origin <url>]
Re-check a passkey approval record with nothing from Delegus: the person's assertion over the Grant's exact bytes (offline).
Options:
--record <json|file> The delegus-approval-v1 record (as retrieved by its approval_record_hash)
--grant <jws|file> The Grant JWS: also check the record is about exactly these bytes
--rp-id <id> Require this WebAuthn relying party id (e.g. app.delegus.ai)
--origin <url> Require this ceremony origin (e.g. https://app.delegus.ai)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus grant revoke#
Usage: delegus grant revoke --principal <did:web> --id <urn:delegus:grant:…>
Revoke a Grant; returns once every later /verify anywhere will deny it (Principal key).
Options:
--principal <did:web> The Principal's DID (did:web)
--id <urn:delegus:grant:…> The Grant id
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus key retire#
Usage: delegus key retire --principal <did:web> --kid <kid>
Retire a Principal signing key (rotation): existing Grants stay valid, new Grants must use an active key (Principal key).
Options:
--principal <did:web> Your Principal DID
--kid <kid> The key's DID URL
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus key compromise#
Usage: delegus key compromise --principal <did:web> --kid <kid>
Mark a Principal key compromised: every Grant it signed denies immediately (Principal key).
Options:
--principal <did:web> The Principal's DID (did:web)
--kid <kid> The compromised key (did:web:…#key-n)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus proof sign#
Usage: delegus proof sign --key <file> --grant <jws|file|id> --rp <did:web> --method <M> --url <url> --action <json|file> [--iat <seconds>] [--jti <nonce>]
Sign a proof of grant with an Agent key, binding one Grant, one RP and one request.
Options:
--key <file> Agent key file
--grant <jws|file|id> The Grant JWS, a file holding it, or a bare Grant id
--rp <did:web> The Relying Party the proof of grant is for (aud)
--method <M> HTTP method of the request
--url <url> Absolute http(s) URL of the request
--action <json|file> The Action (see `delegus action …`)
--iat <seconds> Issued-at override, seconds since the epoch (default now)
--jti <nonce> Nonce override, 22–64 base64url chars (default 16 random bytes)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus verify#
Usage: delegus verify --grant <jws|file> --proof <jws|file> --action <json|file> [--method <M>] [--url <url>] [--v3] [--requires <json|file>]
POST /verify as a Relying Party; prints the signed Receipt, exit 0 for ALLOW and 2 for DENY (RP key).
Options:
--grant <jws|file> The Grant the Agent presented
--proof <jws|file> The proof of grant the Agent presented
--action <json|file> The Action built from the request
--method <M> With --url: check the proof of grant binds to this request before calling Delegus
--url <url> With --method: the URL the request arrived at
--v3 v0.3-rc1: expect a delegus-receipt-v2 and check authority (opened against authority_commitment), relies_on, requires and opening against it (fails closed)
--requires <json|file> With --v3: the prior decisions this action must rest on, [{ fingerprint, mode }]
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus outcome report#
Usage: delegus outcome report --receipt <drc_…> --type <type> [--occurred-at <iso>] [--note <text>] [--evidence-ref <ref>] [--resolution <r>] [--loss-amount <int>] [--currency <CCY>] [--correction-of <id>]
Append an Outcome Attestation to a decision (RP key, the RP in the receipt).
Options:
--receipt <drc_…> The receipt id
--type <type> One of fulfilled, cancelled, dispute_opened, dispute_resolved, chargeback_received, chargeback_reversed, loss_reported
--occurred-at <iso> RFC 3339 UTC (default now)
--note <text> Free-text note
--evidence-ref <ref> Reference to the reporter's evidence
--resolution <r> One of agent_at_fault, agent_not_at_fault, indeterminate
--loss-amount <int> Loss in minor units
--currency <CCY> ISO 4217 currency of --loss-amount
--correction-of <id> The attestation this one corrects
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus decision get#
Usage: delegus decision get --receipt <drc_…>
Fetch a decision: its receipt and outcome ledger (RP key, the RP in the receipt).
Options:
--receipt <drc_…> The receipt id
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus principal list#
Usage: delegus principal list [--kind <managed|hosted>] [--state <verified|unverified>] [--limit <n>] [--cursor <did>]
Principal directory: who is registered and verified, since when, with which keys (any key).
Options:
--kind <managed|hosted> Filter
--state <verified|unverified> Filter
--limit <n> Page size (≤ 200)
--cursor <did> next_cursor from the previous page
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus principal show#
Usage: delegus principal show --did <did:web>
One Principal from the directory (full record for its own key, its org or admin).
Options:
--did <did:web> The Principal's DID (did:web)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus decision list#
Usage: delegus decision list [--rp <did:web>] [--decision <ALLOW|DENY>] [--reason <code>] [--since <iso>] [--until <iso>] [--limit <n>] [--cursor <receipt_id>]
List decisions newest first (RP key: own; org key: the org's relying parties; admin: any).
Options:
--rp <did:web> One relying party
--decision <ALLOW|DENY> Filter
--reason <code> DENY reason filter
--since <iso> evaluated_at ≥
--until <iso> evaluated_at <
--limit <n> Page size (≤ 200)
--cursor <receipt_id> next_cursor from the previous page
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus decision export#
Usage: delegus decision export [--rp <did:web>] [--since <iso>] [--until <iso>] [--decision <ALLOW|DENY>] [--csv] [--limit <n>]
Export decisions with full receipts and outcome ledgers (NDJSON to stdout, or --csv); follows cursors until done or --limit rows.
Options:
--rp <did:web> One relying party
--since <iso> evaluated_at ≥
--until <iso> evaluated_at <
--decision <ALLOW|DENY> Filter
--csv CSV instead of NDJSON (one API page of up to 5000 rows)
--limit <n> Stop after this many rows (NDJSON)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus decision stats#
Usage: delegus decision stats [--rp <did:web>] [--principal <did:web>] [--since <iso>] [--until <iso>]
Decisions and outcomes rolled up per Principal over a range (default last 30 days).
Options:
--rp <did:web> One relying party
--principal <did:web> One Principal
--since <iso> inclusive
--until <iso> exclusive
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus receipt verify#
Usage: delegus receipt verify --receipt <json|jws|file> [--grant <jws|file>] [--proof <jws|file>] [--action <json|file>] [--proof-window <seconds>] [--evidence <dir>] [--consumption-snapshot <json|file>] [--entitled] [--authority <json|file>] [--authority-opening <base64url>] [--capability-key-opening <base64url>] [--relies-on <json|file>] [--requires <json|file>] [--priors <json|file>] [--disclosure <json|file>] [--did-document <json|file>]
Verify a receipt (no API key needed). Alone: signature under the published DID document and the public check. With --grant --proof --action: re-run the open checks with the artifacts fetched by hash and say exactly what was and was not reproduced (v0.2 and v0.3). --entitled (v0.3): open the commitments without a re-run.
Options:
--receipt <json|jws|file> The receipt JSON as printed by `delegus verify`, or its JWS
--grant <jws|file> Re-run: the Grant the RP presented (v1 receipts: required)
--proof <jws|file> Re-run: the proof of grant the RP presented (v1 receipts: required)
--action <json|file> Re-run: the Action the RP presented (v1 receipts: required)
--proof-window <seconds> Re-run: the RP's proof-of-grant window at the time (default 60)
--evidence <dir> Re-run: a directory of artifacts already held, one file per sha256 (named <hex> or sha256-<hex>); anything missing is fetched by hash. With --did-document this is fully offline
--consumption-snapshot <json|file> Re-run, v0.3 with a budget: the consumption snapshot the receipt pins (entitled material); without it P21 and the decision are reported as not reproduced
--entitled v2 receipts: also open authority_commitment (and capability_key_commitment), reproduce relies_on_hash and requires_hash, and each dependency (from --disclosure and/or --priors); exit 0 only when everything was reproduced
--authority <json|file> With --entitled: the plaintext Capability, or a stored response carrying it and its openings (default: `authority` in the --receipt JSON)
--authority-opening <base64url> With --entitled: the opening of authority_commitment (default: `authority_opening` in the --receipt JSON, --authority response or --disclosure package)
--capability-key-opening <base64url> With --entitled: the opening of evidence.consumption.capability_key_commitment (default: `capability_key_opening`, as for --authority-opening)
--relies-on <json|file> With --entitled: the plaintext relies_on entries (default: `relies_on` in the --receipt JSON)
--requires <json|file> With --entitled: the requires the relying party sent
--priors <json|file> With --entitled: a JSON array of prior /verify responses (receipt + opening) or { receipt, nonce }
--disclosure <json|file> With --entitled: the dependency disclosure package (GET /decisions/{id}/disclosure) or its relies_on entries
--did-document <json|file> The service DID document to take the receipt keys from (default: fetched from the API)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus chain verify#
From the next SDK release. It isn't in the published @delegus/sdk on npm yet.
Usage: delegus chain verify [--id <drc_…>] [--chain <json|file>] [--grants <dir|file,...>] [--did-document <json|file>] [--policy <json|file>]
The auditor's chain: fetch (or read) a receipt's chain and re-verify every link offline: each receipt's signature, each relies_on opening against the prior receipt (D2), each prior decision ALLOW (D4), and each Grant you hold against its link's grant_hash and agent; with --policy, each Grant against the confirmed policy and the people across links. Exit 0 only when every link (and the policy) passes.
Options:
--id <drc_…> The root receipt id (fetched with the API key; its relying party, principal or org)
--chain <json|file> A chain as returned by GET /decisions/{id}/chain, for a fully offline run (then --did-document is needed too)
--grants <dir|file,...> The company's Grant JWS files (one JWS per file, or a directory of them); matched to links by sha256
--did-document <json|file> The service DID document to take the receipt keys from (default: fetched from the API)
--policy <json|file> The confirmed policy as @delegus/authority-map maps it (delegus-pack-authority-map-v1): each link's Grant is compared to the holder's authority (matches, narrower, wider) with the rule ids it traces to, and the agents across links are checked where the policy wants different people (dual control, no self-approval, a quorum)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus receipt inclusion#
Usage: delegus receipt inclusion --id <drc_…>
Prove a receipt is in its day's signed Merkle checkpoint (audit path to the root, root signature from the DID document; no key needed).
Options:
--id <drc_…> The receipt id
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus checkpoint verify#
Usage: delegus checkpoint verify [--day <YYYY-MM-DD>]
Third-party check of a day's checkpoint: recompute the Merkle root from the published leaves and verify the signature (no key needed).
Options:
--day <YYYY-MM-DD> UTC day (default: the latest closed day)
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus checkpoint contains#
Usage: delegus checkpoint contains --day <YYYY-MM-DD> --ids <id,id|file>
Check that receipt ids (from `delegus decision list` or your logs) are leaves of a day's checkpoint.
Options:
--day <YYYY-MM-DD> UTC day
--ids <id,id|file> Comma-separated receipt ids, or a file with one per line
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus action purchase#
Usage: delegus action purchase --resource <r> --amount <int> --currency <CCY>
Print the canonical commerce:purchase Action for these wire fields.
Options:
--resource <r> What is bought
--amount <int> Amount in minor units
--currency <CCY> ISO 4217 currency
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpdelegus action api-call #
Usage: delegus action api-call --method <M> --resource <url>
Print the canonical api:call Action for these wire fields.
Options:
--method <M> HTTP method (uppercased)
--resource <url> Absolute http(s) resource URI
Global options:
--api-url <url> API origin (env DELEGUS_API_URL; default https://api.delegus.ai)
--api-key <key> RP or Principal API key (env DELEGUS_API_KEY)
--admin-token <token> Delegus admin token for onboarding (env DELEGUS_ADMIN_TOKEN)
--json-compact Print the result on one line
--help, -h Show helpSDK and CLI: v0.3 additions#
Additions to SDK and CLI for the v0.3 release candidate, as published in @delegus/ 0.2.0 (packages/, v3-, client.ts, actions.ts, cli.ts). Names, inputs and results below are copied from that code.
Release candidate. These additions follow v0.3-rc1 and ship in
@delegus/0.2.0, the first release that carries v0.3; 0.1.4 has none of it. Nothing here changes a v0.2 call: a relying party onsdk delegus-keeps getting v1 receipts.base- v1
Most of the /docs/sdk page is generated at build time from the TypeScript source and the CLI's own help output. The text below is the explanation that goes above them: what each v0.3 piece is for and how the pieces fit.
SDK 0.2.0 also adds: decisions. returning the fields that come back beside the receipt (the authority and its openings); a disclosure( method for GET /; signature checking of v1 receipts; and request binding, where proof_hash and grant_hash must match what was sent.
Choosing the protocol#
delegus- is the default profile for relying parties (PATCH / with { "profile": . sets it; only an org:admin key of the organization that owns the relying party, or Delegus staff, may change it, and moving a relying party back to an older profile is staff-only). verify takes a protocol option:
"auto"(the default): accepts whatever the relying party's profile answers with, read from the signed receipt. Adelegus-takes the v0.2 path, areceipt- v1 delegus-takes the full v0.3 checks, and anything else fails closed.receipt- v2 "v0.: a pin; only3" delegus-is accepted.receipt- v2 "v0.: a pin; only2" delegus-is accepted.receipt- v1
import { Delegus } from "@delegus/sdk";
const delegus = new Delegus({ apiKey: process.env.DELEGUS_API_KEY });
const d = await delegus.verify({ grant, proof, action, protocol: "v0.3" });Verifying under v0.3#
delegus.verify(req: VerifyRequestV3): Promise<VerifyResponseV3> #
VerifyRequestV3 is the v0.2 VerifyRequest (grant, proof, action, optional request) plus:
| Member | Type | Meaning |
|---|---|---|
protocol | "v0.3" | Required to opt in |
requires | DependencyDeclaration[], optional | The earlier decisions this action must rest on: 1–8 distinct { fingerprint, mode }. Validated before sending (TypeError if malformed). |
VerifyResponseV3 is the v2 receipt (ReceiptV2) plus the members returned beside it:
| Member | Type | Present |
|---|---|---|
authority | Capability | Exactly when the receipt pins authority_commitment |
authority_opening | string (43 characters) | Same |
capability_key_opening | string | Exactly when the receipt pins evidence.consumption.capability_key_commitment |
relies_on | ReliesOnEntry[] | Exactly when the receipt pins relies_on_hash |
opening | DependencyOpening ({ fingerprint, nonce }) | ALLOW only |
Before returning, the SDK checks the response against the receipt and throws ResponseIntegrityError (fail closed) unless all of these hold:
- the receipt's signature verifies under the service's published keys, and it is a
delegus-receipt onreceipt- v2 delegus-;base- v3 - the response body equals the signed payload;
- the decision, the reason and the check results agree (an ALLOW has every check true, D1–D7 included; a DENY's reason is one its first false check can report);
- on ALLOW,
authority_,commitment authority,authority_,opening transactionandopeningare all present; authority_opensopening authority_tocommitment authority;capability_openskey_ opening capability_to the key ofkey_ commitment authority, and a v2 receipt carrying a plaintextcapability_is refused;key relies_onhashes torelies_, and its entries are the Action's declaration, in order;on_ hash requires_is present exactly when you senthash requires, and is its hash;opening.opensnonce opening.for this receipt;fingerprint transactionis a well-formed 22-character handle;request_is the hash of the Action you sent.hash
A pinned commitment is never trusted without its opening.
Building v0.3 Actions: actionsV3#
| Function | Builds |
|---|---|
actionsV3.purchase({ resource, amount, currency, relies_on? }) | commerce:purchase |
actionsV3.quote({ resource, amount, currency, relies_on? }) | commerce:quote |
actionsV3.accept({ resource, amount, currency, relies_on? }) | commerce:accept |
actionsV3.fulfil({ resource, relies_on? }) | commerce:fulfil |
actionsV3.apiCall({ method, resource, relies_on? }) | api:call |
actionsV3.withDependencies(action, { relies_on }) | Adds relies_on to an Action built elsewhere |
Each validates the result with the engine's v0.3 Action rules (check P15) and throws if it is malformed. withDependencies throws if the Action already declares relies_on or carries a transaction handle. None of them can add a transaction handle: under v0.3 an Action never carries one.
dependencyOn(response, mode): DependencyDeclaration #
Returns the relies_on entry a later action declares for an earlier decision: { fingerprint, mode }, taken from the earlier response's opening. It never includes the nonce. Throws TypeError when mode is not PRIOR_ or CURRENT_, or when the response has no opening (every DENY).
import { dependencyOn, actionsV3 } from "@delegus/sdk";
const entry = dependencyOn(r1, "CURRENT_AUTHORITY");
const action = actionsV3.accept({ resource: "compute/gpu-hours/order-7731", amount: 1840000, currency: "USD", relies_on: [entry] });Opening checks#
v0.3 receipts pin the matched capability, and for a budgeted capability its internal key, by commitment: a hash over the value together with a 32-byte random opening. These two functions answer one question each: does this opening open this commitment to this value?
checkAuthorityOpening(commitment: string, opening: string, authority: unknown): boolean #
| Input | What to pass |
|---|---|
commitment | The receipt's authority_commitment |
opening | authority_opening: 43 characters of unpadded base64url (32 bytes) |
authority | The plaintext capability: authority from the response, GET /decisions/{receipt_id} or the disclosure package |
Result: true when the opening opens the commitment to exactly that capability (canonicalized with JCS), otherwise false. A malformed opening or commitment gives false, never a fallback. Throws TypeError when authority is not a JSON object or contains a number that is not a safe integer (the protocol has no floats).
checkCapabilityKeyOpening(commitment: string, opening: string, authority: unknown): boolean #
| Input | What to pass |
|---|---|
commitment | The receipt's evidence.consumption.capability_key_commitment |
opening | capability_key_opening |
authority | The plaintext capability. The function derives the key itself as sha256(JCS(authority)); you never handle the key. |
Result and errors: as for checkAuthorityOpening.
Both call the engine's own checks (verifyAuthorityOpening, verifyCapabilityKeyOpening in @delegus/) after the SDK's integers-only rule. They replace the pre-H2 authorityHash, which no longer exists.
import { checkAuthorityOpening } from "@delegus/sdk";
const ok = checkAuthorityOpening(stored.authority_commitment, stored.authority_opening, stored.authority);
if (!ok) throw new Error("stored authority does not match the receipt");Verifying a v2 receipt later#
verifyReceiptV2Public({ receipt, body?, keys, did? }): PublicVerificationV2 #
What anyone holding the receipt can check: signature, body equals payload (when body is given), v2 shape and profile, decision/reason/results agreement, and each v2 field well formed. Returns { ok, level: "public", receipt_, where each V2Check is { check, ok, detail }. It says nothing about why the decision was made.
Also on the client, with the published keys fetched for you: delegus..
verifyReceiptV2Entitled(input): EntitledVerificationV2 #
For the receipt's relying party or principal. Runs the public checks, then reproduces what the receipt pins from the material you supply.
| Input | Meaning |
|---|---|
receipt, body?, keys, did? | As for the public check |
authority? | The plaintext capability. Default: authority in disclosure |
authorityOpening? | Opens authority_commitment. Default: authority_opening in disclosure |
capabilityKeyOpening? | Opens capability_key_commitment. Default: capability_key_opening in disclosure |
reliesOn? | The relies_on entries returned beside the receipt |
requires? | The requires you sent |
disclosure? | The disclosure package from GET /decisions/{receipt_id}/disclosure, or its relies_on array |
priors? | PriorReceipt[]: earlier receipts you hold, each { receipt, nonce, fingerprint? } |
Result (EntitledVerificationV2):
| Member | Meaning |
|---|---|
ok | true only when every applicable part was reproduced (D5 counts as Delegus's attestation). Anything not supplied or only partly reproducible makes it false. |
authority, capability_key, relies_on, requires | Each a PlaintextComparison: { result, pinned, computed, detail? }, where result is match, mismatch, not_supplied, not_in_receipt or invalid |
dependencies[] | One DependencyVerification per entry: { index, fingerprint, mode, result, checks, receipt_id? }. result is reproduced, partial, failed or not_supplied. checks covers D2–D7, receipt_hash and evidence_commitment, each with a status of reproduced, failed, attested (D5), not_reproducible (material missing) or skipped (D6, D7 and evidence_commitment for PRIOR_DECISION) |
unmatched[] | Supplied priors or disclosure entries that name no entry of this receipt, or contradict themselves |
Also on the client: delegus..
Neither function re-runs the checks P1 to P21 from the Grant, Proof and Action: they check the commitments, the hashes and the per-dependency results. Re-evaluating a v2 receipt offline is not available yet.
Other v0.3 exports#
| Export | What it does |
|---|---|
parseVerifyResponseV3(response, sent, trust) | The response check verify runs, for a response you obtained another way. Throws ResponseIntegrityError. |
splitV2Response(response) | Separates the signed body from the members beside it. Returns an error string if it is not a receipt. |
parseReceiptV2Body(payload) | A ReceiptV2Body, or null unless well formed on delegus-base-v3 |
verifyReceiptV2Signature(receiptJws, keys, did?) | The engine's signature check, narrowed to v2 |
reliesOnHash(entries), requiresHash(requires) | Recompute relies_on_hash and requires_hash. Throw TypeError on malformed input. |
validateRequires(requires), isReliesOnEntries(v) | Shape checks for requires and recorded entries |
decisionDisagreement(body) | null when decision, reason and results agree; otherwise what disagrees |
EVALUATION_ORDER_V3 | The v0.3 check order, P1 through T7 |
PROFILE_V3, RECEIPT_VERSION_V2, v3Fields | The v0.3 wire names in one place |
CLI#
delegus verify --v3 [--requires <json|file>] #
--v3 expects a delegus- and runs the same response checks as verify(, failing closed. --requires takes the [{ fingerprint, mode }] list and needs --v3. Exit 0 for ALLOW, 2 for DENY.
delegus receipt verify with a v2 receipt#
--receipt accepts the JSON printed by delegus verify -, a stored /verify response, a GET / response body, or the bare JWS. A v2 receipt is checked publicly by default; --entitled adds reproduction. No API key is needed.
| Flag | Meaning |
|---|---|
--entitled | Also open authority_commitment (and capability_key_commitment), reproduce relies_on_hash and requires_hash, and each dependency (from --disclosure and/or --priors); exit 0 only when everything was reproduced |
--authority <json\|file> | With --entitled: the plaintext capability, or a stored response carrying it and its openings (default: authority in the --receipt JSON) |
--authority-opening <base64url> | With --entitled: the opening of authority_commitment (default: authority_opening in the --receipt JSON, --authority response or --disclosure package) |
--capability-key-opening <base64url> | With --entitled: the opening of evidence.consumption.capability_key_commitment (default: capability_key_opening, found the same way) |
--relies-on <json\|file> | With --entitled: the plaintext relies_on entries (default: relies_on in the --receipt JSON) |
--requires <json\|file> | With --entitled: the requires the relying party sent |
--priors <json\|file> | With --entitled: a JSON array of earlier /verify responses (receipt and opening) or { receipt, nonce } objects |
--disclosure <json\|file> | With --entitled: the disclosure package (GET /decisions/{receipt_id}/disclosure) or its relies_on entries |
--did-document <json\|file> | The service DID document to take receipt keys from (default: fetched from the API) |
Rules the CLI enforces: every plaintext flag needs --entitled; --grant, --proof, --action and - are refused for a v2 receipt; every v2 flag is refused for a v1 receipt. Exit codes: 0 when ok, 2 when not, 1 for a usage error.
Opening flags are needed only when the receipt JSON you pass does not already carry the openings, for example when you kept the receipt and its openings in separate places:
# The receipt alone (bare JWS), with the plaintext capability and both openings kept separately
delegus receipt verify \
--receipt receipt.jws \
--entitled \
--authority capability.json \
--authority-opening "$AUTHORITY_OPENING" \
--capability-key-opening "$CAPABILITY_KEY_OPENING" \
--did-document did.jsonThe output is the EntitledVerificationV2 object as JSON. With the right capability and openings, authority. and capability_ are match. A wrong opening gives mismatch and exit 2. A receipt that pins a commitment you supplied no opening for gives not_ and exit 2. A capability-key opening for a receipt that pins no such commitment is reported, not ignored.
If you stored the full /verify response, the openings come with it and the flags can be left out:
delegus receipt verify --receipt response.json --entitled --requires requires.json --disclosure disclosure.jsondecisions. (and so the CLI's delegus decision get) returns the authority and openings the API returns beside the receipt, so its output can go straight to receipt verify. delegus. fetches GET / with an entitled key.
No CLI command builds a v0.3 Action with relies_on (there is action purchase and action api- only); write the Action JSON by hand and sign it with delegus proof sign -.