Ir al contenido

Según su conexión, puede haber un sitio de Overturo más adecuado para usted: sus datos se almacenarían en Estados Unidos.

Autorización de agentes

Autorice acciones de agentes de IA: concesiones, recibos, supervisión y los SDKs que hablan el protocolo.

El cuerpo de la documentación está en inglés.

Overview

The Overturo Authorization Protocol (OAP) is a wire-level authorization protocol for AI agents. It sits one layer above OAuth 2.0 / OIDC: identity tokens answer who is the agent; OAP answers which actions is this agent authorized to take, under which bounds, on whose behalf, and how is each decision recorded.

OAP ships in two adoption depths. Pick one per application; per-agent-class promotion is a configuration change, not a re-integration.

Human approval surface: when an authorize call needs a human in the loop, the Conductor or Oversight escalation rides the Trust Surface delivery layer — same iframe / popup / SDK as consent flows, with a third outcome (counter) added. The Conductor Mode tab covers approvals originating from origin: authorize; the Oversight Mode tab covers approvals originating from origin: attestation. The embed/SDK story is identical — what differs is who originates and who is asked. The full authorize cascade is on the Conductor Mode tab.

Quickstart — three short paths

Pick the role you're integrating from. Each path links into the tab with the field shapes, error codes, and code samples you'll need.

Agent builder (Conductor)
  1. Generate an API token at Developer → Credentials.
  2. Install @overturo/sdk (TypeScript) or overturo (Python). See the SDKs tab.
  3. POST /api/v1/grants with a DPoP-bound credential. See the Conductor Mode tab for the request body.
  4. Use the returned agent token to call authorize() per action.
Policy-engine operator (Oversight)
  1. Provision a Trusted Attester at /trusted_attesters and copy the one-time bearer token.
  2. Set the application's mode to oversight or hybrid. See the Oversight Mode tab.
  3. Install @overturo/sdk (TypeScript) or overturo (Python), or deploy the OPA adapter sidecar.
  4. POST /api/v1/oap/attestations per decision; heartbeat between bursts.
Counterparty (Verifier)
  1. Install @overturo/verify — zero runtime deps.
  2. Call verifyReceipt(jwt, { jwksUrl }).
  3. Branch on iss_role — authorizer vs witness carry different trust weights. See the Receipts & Verification tab.
Evidence holder (Records)
  1. Fetch the durable record: GET /api/v1/authorization_receipts/:id (audit:verify scope).
  2. Pick a flavor — signed verifies offline against published keys, years later.
  3. Resolve a held runtime receipt by jti through the dispute kit's join slice. See Receipts & Verification → Durable authorization records.

OAP has two layers. Runtime receipts authorize — short-lived, verified before honoring an action. Durable authorization records prove — one frozen, standards-structured document per delegated authority (ISO/IEC TS 27560-aligned), with the agent's public accountability record, its content-hashed capability manifest, and Article 50 disclosure receipts around it. The wire is closed; the record is published and independently verifiable.

Two adoption modes

Conductor Mode

The platform is in the decision path. Agents call POST /api/v1/grants; the platform runs a 15-step evaluation cascade and either issues a signed receipt, escalates to the principal, or denies with a category-tagged reason.

Trust posture: receipts carry iss_role: "authorizer". Counterparties may rely on the receipt as the authorizing artefact.

Oversight Mode

Your existing policy engine (Open Policy Agent, AWS Cedar, in-house rules) decides. You submit attestations of those decisions to POST /api/v1/oap/attestations; the platform witnesses, signs, anchors to the audit chain, and surfaces escalations.

Trust posture: receipts carry iss_role: "witness". Counterparties weight them lower than authorizer receipts — the distinction is wire-level.

Which mode should I pick?

  • Already have a policy engine you trust? Start in Oversight. You keep your decision authority and gain a tamper-proof audit substrate, a branded human-approval surface, regulator-grade evidence packages, and sub-30-second global revocation.
  • Building net-new agent surfaces? Start in Conductor. The 15-step cascade replaces most of what you'd otherwise build (rate limits, scope checks, value bounds, time windows, escalation routing) and gives counterparties a stronger artefact to rely on.
  • Mixed estate? Hybrid is a first-class mode — different agent classes on the same application can run in different depths.

Where OAP sits next to OAuth and OIDC

  • OAuth 2.0 / OIDC still issues the agent's identity tokens. See OAuth Authorization.
  • OIDC-A 1.0 identity overlays plug into OAP as a third agent_credential path alongside SD-JWT and W3C VC. See the OIDC-A Interop tab.
  • MCP integrations use OAP receipts as the wire-level proof that an action is authorized; the @overturo/mcp-authorize middleware verifies them in-process.

Closed wire, open SDKs

OAP's wire format is proprietary; this surface documents the shapes integrators call and consume. The first-party SDKs that issue, accept, and verify OAP receipts are open-source (Apache 2.0). See the SDKs tab for what's published today, in which languages, and what each library covers.

Conductor Mode

The platform decides. Every action an agent takes flows through a 15-step evaluation cascade and emits a signed receipt or a category-tagged denial. Counterparties verify the receipt; the tamper-evident audit chain records every step.

Human-approval flow (Trust Surface integration)

When the cascade returns escalate, the platform mints a Trust Surface decision session (kind: approval) and returns {decision_url, session_token, deadline} in the response envelope. Your application either redirects the principal or embeds the decision client-side:

<overturo-decision token="dts_..."></overturo-decision>
<script type="module" src="https://cdn.overturo.com/js/v1/overturo.js"></script>

Three outcomes (origin: authorize):

  • approve — principal authorizes the action as-is; agent receives approval.granted webhook
  • deny — principal rejects; agent receives approval.denied
  • counter — principal proposes alternative terms; agent receives approval.countered with counter_proposal in payload

Quorum support: escalations with quorum_type: "all" | "majority" | "threshold" are already shipped. Each approver renders the same <overturo-decision> element; the webhook fires once with the aggregated outcome.

Python and JavaScript code samples are on the SDKs tab. Embed reference: the Embedding tab in Developer Docs.

Grant lifecycle

  1. POST /api/v1/grants — agent submits credential + scope + actions + valid_until + (optionally) agent_attestation.
  2. The cascade evaluates; outcome is allow, escalate, or deny.
  3. On allow: an Ed25519-signed receipt is issued (iss_role: "authorizer") and persisted to the audit chain.
  4. On escalate: an approval request is opened, the principal is notified, and a signed approval URL is delivered through the configured channel.
  5. On deny: the response carries a denial_category + cascade_step so the agent (and your dashboard) know exactly which check failed.

Worked example

Authentication is a personal API token, generated at Developer → Credentials. Every grant must carry an idempotency key so retries are safe. The agent_dpop_jkt is the SHA-256 thumbprint of the DPoP public key the agent will use when authorizing actions — see the SDKs tab for the helper that computes it.

curl -X POST https://overturo.com/api/v1/grants \
  -H "Authorization: Bearer $OVERTURO_API_TOKEN" \
  -H "Idempotency-Key: 7f3c1d2e-…" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id":       "agent-checkout-v3",
    "agent_dpop_jkt": "<base64url SHA-256 of the agent DPoP public key>",
    "scope":          ["payments:write"],
    "actions":        ["payment.send"],
    "valid_until":    "2026-12-31T23:59:59Z",
    "value_bounds":   { "amount_per_action": "100.00", "currency": "USD" },
    "human_register": { "displayed_to_principal": "..." }
  }'
Response (allow)
{
  "grant_id":         "ath_us_xxxxxxxx",
  "agent_token":      "eyJhbGciOi…",
  "grant_attestation": "eyJhbGciOi…",
  "iss":              "https://overturo.com",
  "oap_ver":          "1.0"
}

The 15-step evaluation cascade

Positions 1–2 reject malformed or unauthenticated requests at the API edge. Positions 3–15 are evaluated by the authorization engine. Two positions are reserved for future use; the rest are active in v1.0.

# Check Denial category on failure
1Request shape (controller)authorization_denied
2Authentication (controller)authorization_denied
3Grant exists & is activeauthorization_denied
4Scope allowed by grantauthorization_denied
5Action allowed by grantauthorization_denied
6Reserved (action_not_prohibited)—
7Within value boundsintent_denied
8Within time windowintent_denied
9Reputation threshold metintent_denied
10Escalation bounds (escalate if needed)intent_denied
11Purpose-of-use compatibleintent_denied
12Reserved (max_actions)—
13Sequence boundstrajectory_denied
14Continuation chain depthtrajectory_denied
15Drift detectiontrajectory_denied

Denial categories

Every deny response carries one of three categories. They map to the cascade phase that rejected the request, so a counterparty (or your operator dashboard) can route the response to the right reviewer.

Category Phase Meaning
authorization_deniedSteps 1–5The agent is not entitled to take this action at all — grant missing, expired, or doesn't cover this scope/action.
intent_deniedSteps 7–11The action is in scope but this particular invocation violates a bound (amount, time, reputation, purpose).
trajectory_deniedSteps 13–15Each call individually would pass but the sequence — rate, ordering, drift from declared trajectory — fails.

Authority bounds — six constraint primitives

A grant's authority_bounds declare what the agent may do, with which limits. The six bound types are independent; a grant may set any subset. A seventh family — sequence bounds — lives on a sibling column and gates step 13 of the cascade.

Bound JSONB key What it limits
Scopescope_boundsWhich OAuth scopes the agent may exercise on this grant.
Actionaction_boundsWhich action classes (e.g. pay, refund) the agent may invoke.
Valuevalue_boundsPer-invocation and aggregate ceilings (e.g. amount in USD).
Timetime_boundsValidity window and per-time-bucket counts.
Escalationescalation_boundsWhen to interrupt the agent and ask the principal; quorum requirements.
Reputationreputation_boundsMinimum trust score / vouch count required.
Sequence (sibling)oap_sequence_boundsTrajectory shape: ordering, rate, repetition (cascade step 13).

Escalation

When the cascade hits an escalation bound, the platform opens an approval request, renders the action context using a template specific to the action class, and signs an approval URL the principal can click from any channel — email, SMS, in-app notification, or an MCP elicitation prompt.

Approval URLs carry a third iss_role value — approval_url_signer — distinct from the receipt-issuer roles. See the Receipts & Verification tab for the full iss_role taxonomy.

Unified approval URL. The authorize response on the escalate branch returns three TrustSurface fields alongside the existing escalation payload:

  • decision_url — https://<region>/decisions/<session_token>, suitable for embed / popup / redirect via @overturo/js.
  • session_token — 43-char URL-safe Base64 handle for the TrustSurface session.
  • approval_ttl_at — ISO-8601 deadline; the postMessage v2 protocol emits countdown ticks against this.

The branded /checkout/<jwt> URL form (platform-managed notification dispatch) continues unchanged for opaque-link integrations.

Version + conformance

GET /api/v1/oap/version advertises the supported OAP versions, regional issuers, conformance levels, and audit-chain genesis hashes. The Conformance tab walks the payload field by field.

Oversight Mode

Your existing policy engine — Open Policy Agent, AWS Cedar / Verified Permissions, in-house rules — keeps making the allow/deny decision. The platform witnesses each decision: tamper-proof audit chain, signed witness receipts, regulator-grade evidence packages, branded human-approval surface (Overturo Checkout), and sub-30-second global revocation.

Receipts issued under Oversight carry iss_role: "witness". Counterparty verification libraries weight them lower than authorizer receipts — the distinction is wire-level and the @overturo/verify libraries throw (not warn) on missing or unexpected iss_role.

Human-approval flow (Trust Surface integration)

When an Oversight attestation determines a human is needed (your policy returned escalate, or your attestation included requires_human_approval: true), the platform mints a Trust Surface decision session with origin: attestation. The same <overturo-decision> element renders it — identical chrome to the Conductor-Mode flow, identical postMessage protocol, identical webhook contract.

What differs is who originated the ask and who is asked. Approvers see "policy XYZ flagged this action for review" instead of "agent ABC requested authorization." Both pages cross-reference each other — see the Conductor Mode human-approval flow for the origin: authorize equivalent.

Three outcomes (origin: attestation):

  • approve — reviewer authorizes; attestation completes as approved with witnessed receipt
  • deny — reviewer rejects; attestation completes as denied
  • counter — reviewer proposes alternative terms (different scope, different bounds); your policy engine receives the counter-proposal on the next attestation

Python and JavaScript examples are on the SDKs tab. Trust Surface embed reference: the Embedding tab in Developer Docs.

Application mode

Each application carries a mode attribute. The three valid values:

  • conductor (default) — every agent action passes through the cascade.
  • oversight — the platform never authorizes; it only witnesses attestations submitted by your policy engine.
  • hybrid — per-agent-class routing within one application. Promotion or demotion is a configuration change, not a re-integration.

Setting the mode on an application

A new application is created in conductor mode by default. Two paths exist to change it:

  • Self-service promotion (Oversight → Conductor): after attestations are flowing, use the What-if-Conductor dashboard to promote individual agent classes or the whole application. Each promotion is one click and is reversible.
  • Initial mode (Conductor → Oversight or Hybrid): not yet self-service. Contact your account manager (hosted) or use the operator console (self-hosted) to set the mode flag before your first integration.

Provisioning a Trusted Attester

Self-service UI: /trusted_attesters. An account admin creates the attester identity, the platform mints a bearer token, and the token is shown exactly once on the create / rotate screen — it is stored only as a SHA-256 digest server-side. Copy it into your secret store before navigating away; there is no "show again" affordance.

Lifecycle actions
Action When to use it
CreateFirst integration, or one identity per environment (staging / prod) so a leaked dev token never touches production data.
RotateOn a routine cadence or on suspected compromise. Rotation mints a new token in a second slot; the old token keeps working for the overlap window (default 24h, configurable) so you can roll your fleet without downtime.
Suspend / UnsuspendTemporary stop without revoking. Suspended attesters return a distinct denial response so your client can distinguish "rotate me" from "stop calling".
DestroyPermanent. Both token slots are cleared. Use when retiring a service.
Request elevationTo add the operator-gated revocations:trigger permission. Posts a rationale to the operator queue for review.
Scoping

Each Trusted Attester belongs to one account. Optionally, you can scope an attester to a single application — the same policy engine identity then can't attest for any application it isn't bound to. Leave the application unset to attest for all of the account's applications with one identity.

Trusted Attester authentication

Oversight uses a fifth platform auth mechanism alongside the four documented under Authentication: the Trusted Attester bearer token. Your policy engine identifies as a peer service, not as a user or an agent.

Authorization: Bearer tat_<region>_<base64url(32)>

Tokens are issued per trusted-attester identity and carry a permission set drawn from this vocabulary:

  • attestations:submit — create attestations
  • attestations:heartbeat — gap-detection liveness
  • escalations:create — request human approval
  • revocations:trigger — operator-gated; customer needs scope-elevation approval

Tokens support two-slot rotation (overlap rotation without downtime). Suspension is a distinct denial response so your client can distinguish "rotate me" from "stop calling".

Attestation ingest

POST /api/v1/oap/attestations records one decision your policy engine made. The platform signs a witness receipt, anchors it to the tamper-evident audit chain, and returns the artefact.

Required body fields
Field Type Purpose
attestation_idstring ≤ 64Your idempotency key; replays return the original receipt.
application_idprefix idThe application the decision was made for. The legacy alias touchpoint_id is still accepted for backward compatibility.
agent_classstring ≤ 128Identifier for the agent role (e.g. checkout_assistant).
action_classstring ≤ 64Action taxonomy entry (e.g. pay).
decisionenumOne of allow, deny, escalate.
decided_atRFC 3339When your engine made the decision.
sequence_numberpositive intMonotonic per agent_class. Gaps are flagged by the platform.
legal_basisenumLawful basis for the decision. Wire enum derives from GDPR Article 6: consent, contract, legal_obligation, vital_interests, public_task, legitimate_interests. US deployments map their CCPA purpose-limitation or HIPAA permitted-use rationale to the closest of these values. Mandatory — evidence packages depend on it.
evidence_digest64-hex SHA-256Hash of the decision inputs (the policy engine's decision log entry, canonicalised). Anchors the witness without leaking the inputs themselves.
contextobjectOptional structured context (≤ 4 KiB). Surfaced in escalations and the operator dashboard.
Worked example
curl -X POST https://overturo.com/api/v1/oap/attestations \
  -H "Authorization: Bearer $OVERTURO_ATTESTER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "attestation_id": "att-2026-06-03-0042",
    "application_id": "app_us_xxxxxxxx",
    "agent_class": "data_export_agent",
    "action_class": "mcp_tool_call",
    "decision": "allow",
    "decided_at": "2026-06-03T09:14:22Z",
    "sequence_number": 42,
    "legal_basis": "legitimate_interests",
    "evidence_digest": "a1b2c3...",
    "context": { "policy_ref": "policy-export-v1", "policy_version": "1.2.0" }
  }'
Response shape
{
  "attestation": {
    "id": "<prefix id>",
    "received_at": "2026-06-03T09:14:23Z",
    "sequence_number": 42,
    "decision": "allow",
    "idempotent_replay": false
  },
  "receipt": "<Ed25519-signed JWS with iss_role: witness>"
}

Heartbeat & gap detection

POST /api/v1/oap/attestations/heartbeat tells the platform your policy engine is alive even when it hasn't made any decisions to report. Combined with the monotonic sequence_number on attestations, the platform detects gaps and surfaces them on the operator dashboard and in evidence packages.

The heartbeat + sequence-number contract is non-negotiable: without it, an Oversight customer could quietly fail to attest some decisions and still have the platform's brand applied to the resulting audit trail.

Client-triggered revocation

POST /api/v1/oap/revocations (requires revocations:trigger permission). Propagates through the same webhook + security-event-stream pipeline as Conductor revocations, under the inherited < 30-second SLA. Supports an Idempotency-Key header so retries are safe.

Revocations are surfaced in the operator dashboard at /surfaces/oversight/revocations alongside their triggering attestation (if any).

Operator surfaces

  • /surfaces/oversight/attestation_stream — live stream + export.
  • /surfaces/oversight/escalations — Oversight-side escalation inbox.
  • /surfaces/oversight/revocations — client-triggered revocation history.
  • /surfaces/oversight/hybrid_routing — per-agent-class mode resolution.
  • /surfaces/oversight/what_if_conductor — counterfactual comparison: which decisions would the platform have made differently?

Approval URL

Oversight escalations expose the same unified /decisions/<session_token> URL as Conductor escalations. The escalation-creation response surfaces decision_url, session_token, and approval_ttl_at alongside the existing fields. Principals can embed, pop up, or redirect to this URL via @overturo/js.

The branded /checkout/<jwt> URL form (platform-managed notification dispatch) is unchanged for opaque-link integrations. The legacy /oap/escalations/<prefix_id>?token=<jwt> form 301-redirects to the unified URL during the migration window.

Receipts & Verification

An OAP runtime receipt is an Ed25519-signed JWS that captures one decision the platform made or witnessed — the short-lived artifact a counterparty verifies before honoring an action. Counterparties verify the signature, inspect the iss_role claim, apply the appropriate trust weight, and proceed. Verification works offline; online verification adds replay protection. Behind every runtime receipt stands the durable authorization record — the frozen, independently verifiable document of the delegation itself (below).

The iss_role claim

Every receipt carries a required iss_role claim. The platform issues three role values; counterparty libraries weight them differently and refuse receipts where the claim is absent or unrecognised.

Value Issued by What it asserts
authorizerConductor ModeThe platform ran the 15-step cascade and authorized the action. Strongest trust weight.
witnessOversight ModeA trusted attester (your policy engine) reported its decision; the platform signed the witness record. Lower trust weight — the platform did not authorize.
approval_url_signerEscalation flowAn approval URL that, when clicked by the principal, resolves an escalation. Not an authorization artefact — a delivery vehicle.

The @overturo/verify library exposes the role-to-trust-weight mapping at ISS_ROLE_TO_TRUST_WEIGHT; integrations that mix authorizer and witness receipts in the same pipeline should branch on it explicitly.

Receipt examples

Both receipts are Ed25519-signed JWS with a header carrying { alg: "EdDSA", typ: "oap+jwt", kid: "oap-<region>-v<N>" }. The payload differs:

iss_role: "authorizer" (Conductor)
{
  "iss":             "https://overturo.com",
  "iss_role":        "authorizer",
  "aud":             "did:web:vendor.example",
  "jti":             "<nonce-from-authorize>",
  "oap_ver":         "1.0",
  "oap_conformance": "federated",
  "grant_id":        "ath_us_xxxxxxxx",
  "action":          "payment.send",
  "scope":           "payments:write",
  "value":           "75.00",
  "currency":        "USD",
  "chronicle_id":    "audit_rec_xxx",
  "single_use":      true,
  "context_hash":    "<64-hex SHA-256>",
  "iat":             1748951662,
  "exp":             1748951962
}
iss_role: "witness" (Oversight)
{
  "iss":                 "https://overturo.com",
  "iss_role":            "witness",
  "sub":                 "att_us_xxxxxxxx",
  "oap_ver":             "1.0",
  "oap_conformance":     "oversight_basic",
  "decision":            "allow",
  "legal_basis":         "legitimate_interests",
  "policy_ref":          "policy-export-v1",
  "policy_version":      "1.2.0",
  "attestation_digest":  "sha256:<64-hex>",
  "jti":                 "wrec_xxxxxxxx",
  "iat":                 1748951662,
  "exp":                 1748955262
}

The authorizer receipt names the action being authorized; the witness receipt names the decision your policy engine made. chronicle_id and grant_id are the join keys: hold onto them — they resolve a runtime receipt into the durable authorization record's trail and the dispute kit's runtime_join slice, months after the receipt expired.

Verifying a receipt — TypeScript

import { verifyReceipt } from "@overturo/verify"

const verified = await verifyReceipt(receiptJwt, {
  jwksUrl: "https://overturo.com/.well-known/jwks.json",
})

if (verified.iss_role === "authorizer") {
  // strong: platform ran the cascade and authorized this action
  acceptPayment(verified)
} else if (verified.iss_role === "witness") {
  // witness_only: client's policy engine decided; platform recorded
  recordForAudit(verified)
} else {
  // approval_url_signer — not a decision artefact, do not honor
  throw new Error("not an authorization receipt")
}

verifyReceipt throws ReceiptInvalid on missing or unknown iss_role, expired exp, future iat, signature failure, or unknown kid. The Python equivalent is verify_receipt_offline in overturo.

Offline verification

Fetch the platform JWKS once (GET /.well-known/jwks.json), cache it, and verify receipts locally with any Ed25519-aware JWS library. The first-party verifiers are @overturo/verify (TypeScript) and overturo (Python). The same two packages also verify the durable signed record export offline — verifyRecord and verify_record respectively, resolving the record's stamped key version against the published key set. See the SDKs tab.

Offline verification does not catch revocation. For replay-sensitive flows (payments, irrevocable actions), follow up with an online check.

One boundary worth writing down: the runtime receipt's TTL bounds honoring, not evidence. An expired receipt still verifies cryptographically forever — which is exactly what a dispute months later needs.

Online verification

POST /.well-known/overturo-verify. Authenticated as a counterparty (bearer token). Body:

{
  "receipt": "<JWS compact serialization>",
  "action_completed": true
}

Response carries signature validity, current revocation status, and (when action_completed: true) a one-shot consumption acknowledgement that prevents the same receipt being used twice on different counterparties.

Decode helper

POST /.well-known/overturo-decode. Anonymous. Returns the receipt payload without signature verification — useful for debugging integrations and dashboard rendering. Don't use it as a verification step.

Revocation list

GET /.well-known/oap-revocation-list returns the current revocation set, supports cursor pagination, and is cached for 60 seconds. Bulk verifiers fetch this once and check membership locally.

Durable authorization records

Every delegated-authority commitment freezes exactly one authorization record — the durable, standards-structured document of who authorized which agent under which enforced bounds. Fetch it with GET /api/v1/authorization_receipts/:id (requires the audit:verify token scope) in three flavors via ?flavor=: canonical (the rendered document), signed (the frozen snapshot + a detached signature that verifies offline against published keys), and dpv (standards-vocabulary JSON-LD — served only when the record carries personal-data processing; pure authority semantics refuse with dpv_unavailable rather than inventing pseudo-vocabulary). Unknown flavors and unsignable reconstructions refuse with typed errors (unknown_flavor, not_signable).

Out-of-band agent disclosures mint durable, anonymous-capable disclosure receipts via POST /api/v1/disclosure_receipts (requires disclosures:write; the payload is closed — flow_id, agent_id, disclosed_at, locale — and delivery provenance is always recorded as operator-declared; no payload field can claim platform delivery).

Record holders download the dispute kit from the record page: the signed record, the lifecycle timeline, the runtime_join slice that resolves held runtime receipts by jti, and oversight evidence where a human decided. Full field semantics, flavors, and worked verification examples live in Docs → Receipts and the Receipt Interop & Verification guide published with the developer documentation.

Discovery

Three discovery surfaces tell integrators what this OAP deployment supports: the OIDC discovery document (extended with OAP fields), /api/v1/oap/version, and the OAP-specific well-known endpoints.

OIDC discovery extensions

/.well-known/openid-configuration carries the standard OAuth 2.0 / OIDC fields plus an OAP block. Notable extensions:

  • oap_jwks_uri — Ed25519 receipt-signing keys (distinct from jwks_uri which serves the OAuth/OIDC RSA/ES256 keys).
  • oap_protocol_versions_supported — array of OAP versions the issuer currently serves.
  • agent_claims_supported / agent_types_supported / delegation_methods_supported — OIDC-A 1.0 capability advertisement.
  • agent_attestation_endpoint / agent_attestation_formats_supported / agent_attestation_signing_alg_values_supported — attestation discovery triad.

The OIDC-A Interop tab covers the agent-side discovery fields in full.

/api/v1/oap/version

The single source of truth for what this deployment implements. The Conformance tab walks the payload field by field; the high-level shape:

{
  "oap_ver": "1.0",
  "supported": ["1.0"],
  "current": "1.0",
  "deprecated": [],
  "regional_issuers": { ... },
  "chronicle_genesis_hashes": { ... },
  "oap_conformance": "conductor_full",
  "conformance_capabilities": { ... },
  "oversight_conformance": "oversight_basic",
  "oversight_conformance_levels": ["oversight_basic", "oversight_full"],
  "spec_url": "https://overturo.com/specs/oap-v1.0"
}

OAP-specific well-known endpoints

Endpoint Purpose
/.well-known/jwks.json JSON Web Key Set for authorization server token verification
/.well-known/oap-attestation OAP agent attestation provider discovery
/.well-known/oap-credentials/:id OAP agent credential metadata (by credential id)
/.well-known/oap-revocation-list OAP token revocation list
/.well-known/witness-configuration External witness anchoring configuration and receipt signing-key discovery (current + historical region keys)
/.well-known/transparency/:application_id Controller identification record for an application's receipts: declared parties, export flavors, and the schema, interpretation, and key-discovery pointers
/.well-known/transparency/agents/:agent_id Agent accountability record: the operator's declared identity, the agent's platform-attested status, current credential attestations, and the receipt machine pointers
/.well-known/transparency/agents/:agent_id/manifests/:version A published capability-manifest version: the agent's declared capability set frozen at pin time, with its content hash for independent verification
POST /.well-known/overturo-verifyOnline receipt verification + revocation check.
POST /.well-known/overturo-decodeAnonymous receipt decoder (debugging — not a verification step).

The full developer-discoverable /.well-known/* catalogue lives under Docs → API Reference.

SDKs

First-party libraries for issuing, accepting, and verifying OAP receipts. All OAP SDKs ship under Apache 2.0. The wire format itself is proprietary; the SDKs are the supported way to interop with it.

Trust Surface integration (v1): the JavaScript SDK ships overturo.decisions.* as the kind-agnostic primitive plus overturo.consent.* and overturo.approvals.* facades, alongside the <overturo-decision> custom element. The Python SDK adds a decisions module for server-side session minting and Conductor's OapApprovalRequired exception handling. See the Embedding tab in Developer Docs for the integration reference.

For agent builders (Conductor Mode)

Submit grant requests, refresh credentials, sign DPoP proofs, verify receipts you received from counterparties.

@overturo/sdk
TypeScript · v1.5.0 · Apache 2.0 · Source
npm install @overturo/sdk
import { OverturoAuthorize, jwkThumbprint } from "@overturo/sdk"

// 1. Generate a DPoP keypair, then bind its thumbprint at grant creation.
const jkt = await jwkThumbprint(dpopKey.publicJwk)
// ... POST /api/v1/grants with `agent_dpop_jkt: jkt` ...

// 2. After cooling-off, wrap the returned credentials.
const client = new OverturoAuthorize({
  grantId:    "ath_us_xxxxxxxx",
  agentToken: process.env.OVERTURO_AGENT_TOKEN,
  dpopKey,
  iss:        "https://overturo.com",
})

// 3. Authorize a specific action. Throws OapError on deny.
const result = await client.authorize({
  nonce:    crypto.randomUUID(),
  action:   "payment.send",
  scope:    "payments:write",
  value:    "75.00",
  currency: "USD",
})
overturo
Python 3.10+ · v1.2.0 · Apache 2.0 · Source
pip install overturo
import uuid, os
from overturo import DpopKeyPair, OverturoAuthorize, jwk_thumbprint

dpop_key = DpopKeyPair.generate()
jkt      = jwk_thumbprint(dpop_key.public_jwk)
# ... POST /api/v1/grants with `agent_dpop_jkt: jkt` ...

with OverturoAuthorize(
    grant_id    = "ath_us_xxxxxxxx",
    agent_token = os.environ["OVERTURO_AGENT_TOKEN"],
    dpop_key    = dpop_key,
    iss         = "https://overturo.com",
) as client:
    result = client.authorize(
        nonce    = str(uuid.uuid4()),
        action   = "payment.send",
        scope    = "payments:write",
        value    = "75.00",
        currency = "USD",
    )

For counterparties (receipt verification)

You're on the receiving end — an agent presented you a receipt and you need to verify it before honoring the action. Both libraries enforce the iss_role contract and reject malformed receipts.

@overturo/verify
TypeScript · v0.4.3 · Apache 2.0 · Source
npm install @overturo/verify
import { verifyReceipt } from "@overturo/verify"

const verified = await verifyReceipt(receiptJwt, {
  jwksUrl: "https://overturo.com/.well-known/jwks.json",
})

console.log(verified.iss_role)     // "authorizer" | "witness" | "approval_url_signer"
console.log(verified.trust_weight) // "strong" | "witness_only" | "approval_url"

The package also ships verifyRecord — offline verification of the durable signed record export (the ?flavor=signed download) against published keys, plus verifyManifestPin for capability-manifest pins. See the Receipts tab.

@overturo/mcp-authorize
TypeScript · v1.1.0 · Apache 2.0 · Source

Drop-in middleware for MCP servers — verifies _meta.oap_receipt on every tool call.

npm install @overturo/mcp-authorize @overturo/sdk
import { mcpAuthorize, isOapError } from "@overturo/mcp-authorize"
import { rawEd25519ToJwk } from "@overturo/sdk"

// Pre-fetch the regional JWKS at server boot.
const jwks = (await fetch("https://overturo.com/.well-known/jwks.json")
  .then(r => r.json())).keys.map(k => rawEd25519ToJwk(k.kid, k.x))

const verify = mcpAuthorize({
  acceptedIssuers: ["https://overturo.com", "https://eu.overturo.com"],
  ownIdentifier:   "did:web:my-mcp-server.com",
  jwks,
  required:        true,
})

// Then wire `verify(req)` into your MCP server's request pipeline.

For Oversight Mode integrators

Submit attestations from your policy engine. The OPA adapter is a deployable sidecar that bridges Open Policy Agent's decision log into OAP attestations without any code changes to your policies. Each SDK reads the attester token from an environment variable so it never lands in source.

@overturo/sdk
TypeScript · v1.5.0 · Apache 2.0 · Source
npm install @overturo/sdk
import { OverturoOversight } from "@overturo/sdk"
import { evidenceDigest } from "@overturo/sdk/utils"

const client = await OverturoOversight.create({
  baseUrl:          process.env.OVERTURO_BASE_URL,
  token:            process.env.OVERTURO_ATTESTER_TOKEN,
  applicationId:    process.env.OVERTURO_APPLICATION_ID,
  heartbeatEnabled: true,
  startSequence:    await loadFromRedis("oversight:seq"),
  onSequenceUpdate: async (seq) => saveToRedis("oversight:seq", seq),
})

await client.attest({
  agentClass:     "data_export_agent",
  actionClass:    "mcp_tool_call",
  decision:       "allow",
  legalBasis:     "legitimate_interests",
  evidenceDigest: evidenceDigest(opaInput, opaOutput),
})
overturo
Python 3.10+ · v1.2.0 · Apache 2.0 · Source
pip install overturo
import asyncio, os
from overturo_oversight import OverturoOversight, evidence_digest

async def main():
    client = await OverturoOversight.create(
        base_url         = "https://overturo.com",
        token            = os.environ["OVERTURO_ATTESTER_TOKEN"],
        application_id   = os.environ["OVERTURO_APPLICATION_ID"],
        heartbeat_enabled= True,
    )
    await client.attest(
        agent_class     = "data_export_agent",
        action_class    = "mcp_tool_call",
        decision        = "allow",
        legal_basis     = "legitimate_interests",
        evidence_digest = evidence_digest(opa_input, opa_output),
    )
    await client.close()

asyncio.run(main())

Synchronous wrappers (e.g. client.attest_sync(...)) are available for non-async callers.

overturo/opa-adapter
Go sidecar binary · v1 · Apache 2.0 · Source

Bridge between Open Policy Agent's decision log and OAP attestations. No application code change — point OPA's decision log at the adapter.

docker pull overturo/opa-adapter:v1
# In your OPA config:
decision_logs:
  console: false
  service: overturo
services:
  - name: overturo
    url: http://opa-adapter:8181/v1/logs
# Then run the adapter with the attester token:
docker run -d \
  -e OVERTURO_BASE_URL=https://overturo.com \
  -e OVERTURO_ATTESTER_TOKEN=$OVERTURO_ATTESTER_TOKEN \
  -e OVERTURO_APPLICATION_ID=$OVERTURO_APPLICATION_ID \
  -p 8181:8181 overturo/opa-adapter:v1

Coverage gaps to be aware of

  • No first-party Ruby OAP SDK. The overturo Ruby gem is a generic REST client for the Overturo HTTP API, not an OAP library. For Ruby OAP, verify receipts directly using any Ed25519 JWS library against the published JWKS — the wire shape is documented in the Receipts tab.
  • No Java or Go OAP library SDK. The Go binary above is a sidecar for OPA, not an embeddable library. Counterparties on those runtimes verify receipts using their language's standard Ed25519 + JWS libraries.
  • Don't confuse @overturo/js with the OAP SDKs. That package is the consent-flow embed SDK for the Connect / Consent surfaces. The OAP TypeScript SDKs are the four authorize / verify / mcp-authorize / oversight-sdk packages above.

REST API client (not OAP-specific)

The overturo Ruby gem (Apache-2.0) is a generic client for the Overturo HTTP API. Useful for application-management tasks (creating applications, configuring webhooks, etc.) but does not implement OAP grant issuance, attestation submission, or receipt verification. Source: github.com/overturo/sdk-ruby.

OAP for Agents (OIDC-A 1.0)

Overturo Authorize (OAP) accepts OIDC-A 1.0–compatible ID Tokens as an agent credential. This page covers the acceptance pipeline, the receipt overlay claims, the discovery extensions, and the error reference.

Overview — authorization above identity

OAP and OIDC-A cover different layers of the agent-trust stack. OIDC-A is an OpenID Connect extension that standardises agent identity claims. OAP is the bounded-authorization-and-commerce layer that sits above any agent identity substrate.

  • OAP consumes OIDC-A identity proofs. When an agent vendor publishes OIDC-A 1.0–compatible ID Tokens, principals pass them as agent_credential at grant creation. OAP extracts the standardised identity claims and binds them to the grant.
  • OIDC-A-compatible agents integrate one step shorter. No bespoke agent registration: if your IdP already issues OIDC-A ID Tokens, the same token authorizes grant creation in OAP.
  • OAP is the bounded-authority layer above any standard agent identity layer. OIDC-A tells you who the agent is. OAP enforces what the agent is allowed to do — with per-action receipts, escalation, audit, revocation, and commerce primitives the identity layer doesn't cover.

Overturo claims compatibility at identity boundaries, not OIDC-A conformance. OAP is not an OIDC-A extension; it adopts OIDC-A claim names where the two specs overlap.

Grant creation — the OIDC-A ID Token path

agent_credential accepts an OIDC-A 1.0–compatible ID Token issued by a trusted Authorization Server (e.g. the agent vendor's identity service), alongside the existing SD-JWT and W3C VC paths. The token MUST:

  • Be a compact-serialised JWT (<header>.<payload>.<signature>)
  • Carry the OIDC-A §2.1 required claims: iss, sub, aud, iat, exp, agent_type, agent_model, agent_provider, agent_instance_id
  • Have aud including the regional OAP issuer (https://us.overturo.com, https://eu.overturo.com, or https://ap.overturo.com) for the region where the grant is being created
  • Be signed under a key in the issuer's published JWKS, with an algorithm in the issuer's trust list entry (defaults: EdDSA, ES256, RS256)
  • Not have been consumed before (cross-platform single-use per (iss, jti); tokens without jti synthesize one from the canonical hash)

When this path is used, the platform extracts agent_type, agent_model, agent_provider, agent_version, and agent_instance_id from the token's claims and stores them on the grant. The token bytes are discarded after grant creation; only the SHA-256 canonical hash and the extracted claims persist.

Maximum token size: 16 KB.

agent_metadata block (optional integrator self-report)

When agent_credential is an SD-JWT, W3C VC, or absent, the grant creation request MAY carry an agent_metadata block declaring the agent's identity. Unknown fields are rejected with agent_credential_malformed.

Field Type Notes
agent_typestringClosed taxonomy: assistant, retrieval, coding, domain_specific, autonomous, supervised
agent_modelstring ≤ 200 charsVendor model identifier
agent_providerstring ≤ 200 charsVendor name
agent_versionstring ≤ 100 charsVendor version string
agent_instance_idstring ≤ 200 charsUnique-per-running-instance identifier

Provenance: the block is stored with provenance: "integrator_self_report". The dashboard surfaces a neutral badge — the platform makes no claim that self-reported values are true. When both an OIDC-A ID Token and an agent_metadata block are supplied, every field present in BOTH MUST match exactly (agent_metadata_mismatch on conflict; detail.disagreeing_fields lists them).

Receipts — OIDC-A overlay claims

When the underlying grant carries agent_metadata, receipts emit additional informational claims alongside the OAP-native fields. Counterparties unaware of OIDC-A treat unknown claims as informational pass-through — receipts with overlay claims still verify against pre-spec-96 verifiers.

Claim Source Notes
agent_typegrant.agent_metadata.agent_typeClosed taxonomy
agent_modelgrant.agent_metadata.agent_model–
agent_providergrant.agent_metadata.agent_provider–
agent_versiongrant.agent_metadata.agent_version–
agent_instance_idgrant.agent_metadata.agent_instance_id–
delegator_subgrant.agent_metadata.delegator_subSubject who delegated to the agent (optional)
delegation_purposegrant.agent_metadata.delegation_purposeFree-text purpose of the delegation (optional)
delegation_chaingrant.delegation_chainMulti-hop delegation only; array shape below
delegation_chain shape (multi-hop)
Per-hop object (OIDC-A section 2.4.2)
{
  "iss": "https://us.overturo.com",
  "sub": "user_alice",
  "aud": "agent_xyz",
  "delegated_at": "2026-01-01T00:00:00Z",
  "scope": "wallet:usdc:spend",
  "purpose": "Pay vendors",
  "jti": "hop-1"
}

Validation rules per OIDC-A §2.4.2 — implemented by the reference verification libraries (Node + Python SDKs):

  1. Chronological ordering — delegated_at increases across the array.
  2. Audience chaining — aud of hop N MUST equal sub of hop N+1.
  3. Scope reduction — each hop's scope is a subset of the prior hop's.

Validation failures surface as delegation_chain_invalid.

Attestation — runtime configuration proof

OAP v1.1 accepts an optional agent_attestation block alongside the grant-creation body (and via the refresh endpoint). The attestation is a vendor-signed JWT asserting the agent runtime's configuration — build hash, model version, optionally hardware-attested provenance — distinct from the identity claims covered above. Identity says who the agent is; attestation says what configuration it's running in.

Signature verified, not content. When the platform accepts an attestation it has verified the provider's SIGNATURE against a trusted JWKS. The platform makes no representation that the provider's content claims (build hash, model version, agent_version, etc.) are true. Counterparties whose policy gates on attestation content take their own audit position on the provider's claims; the platform is a pass-through.

v1.1 scope: vendor-signed JWTs only. Hardware-attested formats (EAT, RATS, TPM, SEV-SNP, TDX) are v1.2+ per spec §1.1.

agent_attestation block (creation + refresh)

Closed shape, two fields. Submitted on POST /api/v1/grants (alongside the grant body) or POST /api/v1/grants/<grant_id>/attestation (refresh). Extra fields are rejected with agent_attestation_malformed.

Field Type Notes
formatstringURI from agent_attestation_formats_supported (discovery). v1.1: urn:overturo:agent_attestation:vendor-jwt-v1
tokenstring ≤ 16 KBCompact JWT, signed by a trusted provider

Example body submitted at grant creation:

POST /api/v1/grants — agent_attestation alongside the grant body
{
  "agent_id": "tp_app_abc123",
  "agent_dpop_jkt": "<base64url SHA-256 of the agent's DPoP key>",
  "scope": ["wallet:usdc:spend"],
  "actions": ["pay"],
  "valid_until": "2026-12-31T23:59:59Z",
  "agent_attestation": {
    "format": "urn:overturo:agent_attestation:vendor-jwt-v1",
    "token": "eyJhbGciOiJFZERTQSIsImtpZCI6ImsxIn0.eyJpc3MiOi..."
  }
}
Refresh endpoint

Agents refresh their own attestation BEFORE exp without re-prompting the principal:

  • POST /api/v1/grants/<grant_id>/attestation
  • Authenticate with the DPoP-bound agent token (same auth as /authorize)
  • Required Idempotency-Key header (UUIDv4)
  • Region-pinned: the request MUST land on the grant's home region (the SDK auto-routes on a 421 grant_region_mismatch)
  • Single-use per (iss, jti) — cross-platform replay defence, 409 agent_attestation_replayed on re-use
Receipt overlay claim

When a grant has a current, unexpired attestation, receipts emit an agent_attestation sibling overlay alongside the OIDC-A identity overlay. Six fields total:

Claim Notes
formatAttestation format URI (matches discovery)
issAttestation provider issuer URI
jtiAttestation token jti — retrieval handle for the endpoint below
iatInteger seconds. Attestation token's issued-at time
expInteger seconds. Past this point the overlay claim is omitted from new receipts (§2.1.4) — the agent provider's chosen exp is the authoritative freshness signal
claims_digestSHA-256 hex of the JWT compact serialization — retrieval-key handle

The receipt deliberately does NOT carry the JWT bytes inline (size budget — receipts stay under 2 KB). Counterparties needing the bytes for content inspection fetch them via the attestation endpoint below.

agent_attestation_endpoint (token retrieval)

GET /.well-known/oap-attestation?jti=<receipt_jti>&digest=<claims_digest> (advertised in the discovery doc). Anonymous, cacheable for 5 minutes (private). Four documented status codes:

Status Meaning
200Body: {format, token} — exactly two fields, no extras
404Unknown receipt OR receipt has no attestation overlay (uniform — privacy)
409digest does not match the attestation associated with the receipt (anti-probe)
410Past 90-day retention (bytes cleared) or refresh-history-pruned

Discovery extensions

GET /.well-known/openid-configuration advertises spec-96 OIDC-A compatibility alongside the standard OpenID Connect fields:

Field Type Description
agent_claims_supportedarray of stringsOIDC-A claim names the platform understands at input and emits at output
agent_types_supportedarray of stringsClosed taxonomy intersected with platform-recognised values
delegation_methods_supportedarray of URIsMechanisms the platform accepts as agent_credential
oap_jwks_uriURIOAP receipt-signing JWKS endpoint. Distinct from jwks_uri
oap_protocol_versions_supportedarray of stringsOAP wire-format versions the issuer currently serves (e.g. ["1.0"])
agent_attestation_endpointURIAnonymous endpoint for fetching attestation JWT bytes by (jti, claims_digest)
agent_attestation_formats_supportedarray of URIsAttestation formats the pipeline accepts. v1.1: vendor-jwt-v1
agent_attestation_signing_alg_values_supportedarray of stringsSignature algorithms the verifier honors per-provider. v1.1: EdDSA, ES256, RS256
agent_capabilities_endpointURI templateURL for the public capability discovery endpoint with the literal {agent_id} placeholder (OIDC-A §4.5 convention)
agent_capabilities_projection_versions_supportedarray of stringsProjection versions the endpoint may emit on oidc_a.projection_version. v1.1 ships ["1"]

jwks_uri vs oap_jwks_uri: the discovery document advertises two JWKS endpoints. jwks_uri serves the platform authorization server's RSA / ES256 keys for OAuth 2.0 / OIDC ID Token verification. oap_jwks_uri serves OAP-platform Ed25519 receipt-signing keys. Use oap_jwks_uri for OAP receipt verification; mixing the two will fail signature checks.

Capability discovery

OAP v1.1 ships a public, unauthenticated endpoint that lets counterparties discover what an agent is configured to do — its declared scopes, action verbs, bound annotations, and OIDC-A capability projection — before initiating a grant. Counterparties read this once at the start of a relationship and again whenever the agent's version_id rotates.

Not to be confused with the capability manifest at /.well-known/transparency/agents/:agent_id/manifests/:version — that surface serves the content-hashed declaration a durable authorization record pinned at grant time (post-grant frozen-pin verification); this endpoint serves the live configuration for pre-grant discovery. Both exist on purpose; they answer different questions.

Endpoint
GET https://<region-domain>/api/v1/agents/{agent_id}/capabilities

The full URL template is advertised in the discovery document under agent_capabilities_endpoint. The {agent_id} placeholder follows the OIDC-A §4.5 convention — substitute the actual id at fetch time. The path shape is agent_<region>_<base32> where the region segment is part of the id and routes the request to that agent's home region.

Response shape
{
  "agent_id":      "agent_us_AbCdEf...",
  "region":        "us",
  "version_id":    "tpcv_us_...",          // immutable snapshot id
  "published_at":  "2026-05-21T12:34:56Z",
  "scopes":        [{ "id": "...", "label": "...", "parent": "...",
                      "custom": false, "status": "stable" }, ...],
  "actions":       ["read", "write", ...],
  "bounds_supported": {
    "scope": {}, "action": {}, "value": {},
    "time":  {}, "escalation": {}, "reputation": {}
  },
  "oidc_a": {
    "agent_capabilities":    ["oap:openid", "oap:profile", ...],
    "projection_version":    "1",
    "agent_type":            "assistant",
    "agent_provider":        "anthropic",
    "agent_model":           "claude-opus-4-7",
    "agent_version":         "2.0.1"
  },
  "cache": { "max_age_seconds": 300, "version_id": "tpcv_us_..." }
}
Freshness model
  • ETag: strong validator (no W/ prefix), SHA-256 of the canonical-form response body. If-None-Match returns 304 when nothing changed.
  • Cache-Control: public, max-age=300 on 200 + 304 responses. no-store on 4xx so intermediaries never cache rejections.
  • Cross-region: 307 redirect with Cache-Control: public, max-age=86400 when the agent's home region differs from the request host. The redirect fires before any DB lookup — privacy-preserving.
OIDC-A capability projection

The oidc_a.agent_capabilities array is a sorted, deduplicated, top-most-per-root list of "oap:<scope_id>" strings. v1 algorithm: drop custom + preview-status scopes, group by root segment, keep the most-general ancestor per group, prefix with oap:, sort lex. The version is pinned via projection_version so cached projections survive when new versions ship additively.

projection_version Description
1v1.1 ships v1 only — 4-step projection over the scope list. Future projections (v2+) extend the discovery list additively.
Privacy invariant — uniform 404

The endpoint returns a byte-identical 404 envelope (reason_code agent_not_discoverable) for FIVE sub-cases: unknown agent_id, application not of agent type, operator-suppressed (capabilities_published = false), no snapshot yet, and operator-managed suppression-list entry. An external observer cannot distinguish them — capability discovery never leaks whether a given agent_id exists in the system.

Rate limit: 60 req/min per IP for the GET path. OPTIONS preflight is intentionally unrate-limited so browser CORS handshakes never trip the throttle. Counterparties that need elevated quotas authenticate with their counterparty token.

Error reference

These errors fire during the OIDC-A ID Token acceptance pipeline at POST /api/v1/grants. All carry the standard OAP error envelope; HTTP status is 400 unless noted.

reason_code HTTP Cause
agent_credential_malformed400Not a parseable JWT, missing required claims, or > 16 KB
untrusted_agent_credential_issuer400iss not in trust list for this region, or kid not in per-issuer allowlist
agent_credential_signature_invalid400Signature verification failed; detail.reason distinguishes jwks_fetch_failed, jwks_unreachable, jwks_malformed
agent_credential_expired400iat ≤ now < exp window failed (±60s clock skew)
agent_credential_audience_mismatch400aud didn't include the regional OAP issuer URI
agent_credential_replayed409Same (iss, jti) already consumed cross-platform
agent_metadata_mismatch400agent_metadata block and OIDC-A ID Token disagree on a field; detail.disagreeing_fields lists them
agent_type_outside_taxonomy400agent_type value not in the closed taxonomy
Attestation acceptance errors (OAP v1.1)

Fire during the attestation pipeline at POST /api/v1/grants (creation) and POST /api/v1/grants/<id>/attestation (refresh). All carry the same OAP error envelope.

reason_code HTTP Cause
agent_attestation_malformed400Not a parseable JWT, missing required claims (iss/aud/iat/exp/jti), unknown fields, or > 16 KB
agent_attestation_untrusted_provider400iss not in the regional trust list, OR kid not in the per-provider kid_allowlist
agent_attestation_signature_invalid400JWKS unreachable / malformed / wrong key / unsupported alg; detail.reason distinguishes
agent_attestation_expired400iat ≤ now < exp window failed (±60s clock skew)
agent_attestation_audience_mismatch400aud did not include the regional OAP issuer URI
agent_attestation_kid_revoked400Signature kid is in the operator's kid_revocations list for the provider
agent_attestation_replayed409Same (iss, jti) already consumed cross-platform
agent_attestation_identity_mismatch400Attestation's identity claims disagree with the grant's stored identity OR the prior attestation; detail.disagreeing_fields lists them
agent_token_grant_mismatch401Refresh path. Fires when EITHER (a) the URL :id does not match the grant the agent token was minted for, OR (b) the verified DPoP jkt does not match the grant's registered oap_agent_dpop_jkt. Both checks defend against agent tokens being reused across grants
grant_region_mismatch421Refresh request landed on the wrong-region endpoint — SDK auto-routes to the grant's home region (Misdirected Request)
Capability discovery errors (OAP v1.1)

Fire on the public endpoint GET /api/v1/agents/{agent_id}/capabilities. The 404 envelope is byte-identical across all five sub-cases per the §2.1.2 privacy invariant — an observer cannot tell why a request failed.

reason_code HTTP Cause
agent_id_malformed400agent_id failed format validation. The only 4xx that doesn't fold into the uniform 404 — format errors don't leak existence
agent_not_discoverable404Uniform across: unknown agent_id, application not of agent type, capabilities_published = false, no snapshot, operator suppression-list entry

Platform operators

Trust-list management is deploy-managed, not runtime-mutable. Adding a new OIDC-A issuer requires a coordinated deploy by the platform operator.

  • Hosted Overturo customers: contact your account manager to add a trusted issuer to your region.
  • Self-hosted operators (OIDC-A identity trust list): trust-list shape, JWKS configuration, boot-time validation, rollout stages, and backout are covered in the platform operations runbook shipped with your deployment.
  • Self-hosted operators (capability discovery suppression list): the deploy-managed deny-list shape, when to use it (legal hold, regulator demand), and the per-application capabilities_published toggle that's the everyday alternative are documented in your operations runbook.
  • Self-hosted operators (attestation provider trust list): the parallel trust list governing the OAP v1.1 attestation pathway — including per-kid revocation, the on-demand revocation sweep job, and the 90-day token-byte retention SLA — is covered alongside the identity trust list in the operations runbook.

Conformance

Conductor and Oversight conformance are orthogonal. A deployment may serve one, both, or neither at a given level. The live values for this deployment are advertised at /api/v1/oap/version.

Trust Surface conformance suite

In addition to the Conductor and Oversight conformance levels above, the Trust Surface delivery layer that hosts OAP human-approval flows has its own conformance suite. It validates:

  • Decidable instance contract — every kind honors the 7-method interface, idempotent submit_decision, correct cancel transitions
  • postMessage v2 envelope shape and per-kind, per-type schemas
  • Surface invariants — CSP nonce, allowed-origin, sandbox attrs, deadline enforcement
  • API shape vs. /api/v1/openapi.json declarations
  • Telemetry emissions match the published telemetry manifest
  • Documentation linkcheck — every URL resolves, every code example parses

The public conformance corpus (signed-record fixtures, discovery fixtures, and the round-trip test) is at github.com/overturo/conformance.

Current deployment

OAP version: 1.0

Conductor conformance: federated

Oversight conformance: oversight_basic

Conductor conformance levels

Three nested levels. Each level inherits the required capabilities of the level below and adds its own. A deployment advertises the highest level whose required set it satisfies.

core

Required (10)

  • cascade_denial_categories
  • felicity_conditions
  • hitl_timeout_invariant
  • six_bound_bounded_authority
  • sequence_bounds
  • two_register_redaction
  • denial_log_alerts
  • receipt_verification_offline
  • receipt_verification_online
  • revocation_propagation_30s

Recommended (3)

  • purpose_of_use_level_1
  • drift_detection
  • continuation_chains
delegated

Required (14)

  • cascade_denial_categories
  • felicity_conditions
  • hitl_timeout_invariant
  • six_bound_bounded_authority
  • sequence_bounds
  • two_register_redaction
  • denial_log_alerts
  • receipt_verification_offline
  • receipt_verification_online
  • revocation_propagation_30s
  • delegation_attenuation
  • cascading_revocation_chain
  • bounded_delegation_depth
  • re_consent_rules_table

Recommended (3)

  • continuation_chains
  • purpose_of_use_level_1
  • drift_detection
federated

Required (19)

  • cascade_denial_categories
  • felicity_conditions
  • hitl_timeout_invariant
  • six_bound_bounded_authority
  • sequence_bounds
  • two_register_redaction
  • denial_log_alerts
  • receipt_verification_offline
  • receipt_verification_online
  • revocation_propagation_30s
  • delegation_attenuation
  • cascading_revocation_chain
  • bounded_delegation_depth
  • re_consent_rules_table
  • multi_region_cross_region_sso
  • witness_network_integration
  • merkle_anchoring
  • cross_region_revocation
  • drift_detection

Recommended (3)

  • c2pa_attribution
  • purpose_of_use_level_1
  • continuation_chains

Oversight conformance levels

  • oversight_basic
  • oversight_full

oversight_basic covers attestation ingest, witness receipts, and the heartbeat / sequence-number contract. oversight_full adds the SDK + OPA reference adapter, evidence-package adapter, "what if Conductor" comparison surface, and hybrid mode coordinator. A Conductor-conformant deployment may serve no Oversight requests; an Oversight-conformant deployment may not implement the Conductor cascade at all.

Discovering conformance programmatically

GET /api/v1/oap/version returns the full conformance descriptor. See the Discovery tab for the response shape. Counterparties and partner systems should call this endpoint, not hard-code level names — the inventory of capabilities grows as new sub-specs ship.

Record conformance

The durable records this protocol produces carry their own conformance story: every record kind is live-shape-validated against the published receipt schema, and the claims line is deliberate — consent and notice records carry a self-declared conformance to ISO/IEC TS 27560:2023; pure authority records follow the standard's structure and claim 27560-aligned, never more. Details and field semantics: Docs → Receipts.

¿Listo para empezar?

Obtener un token de API