VDA Witness
Verified Digital Agents (VDA) · https://getvda.ai
https://witness.getvda.ai/.well-known/agent-card.json
● healthy
Seals governed AI-agent decisions into tamper-evident, Ed25519-signed, independently-verifiable records, and produces EU AI Act Article 12 evidence from the sealed trail. Part of the VDA platform.
Transport
HTTP+JSON
Protocol
0.2.5
Price
—
Skills
-
Seal a human-in-the-loop decisionSeals a governance record for a HUMAN decision. Content-based and auditor-reconstructable: it captures the deciding human's identity and role, the disposition and rationale, the policies/SOPs cited AS THE BASIS (by reference, and where possible captured text or hash — policies drift, so an auditor needs the version in force), and content-addressable references (with sha256 hashes) to the system-of-record artifacts the decider SAW at decision time — reservation records, folios, inventory state — NOT the action produced. From the sealed record alone an auditor can verify exactly what state the decider was looking at. Witness seals the ASSERTED actor identity; it does not authenticate the person. Use evidence[].inline to embed a snapshot (≤100KB; bytes are verified against the hash at seal time) when upstream availability isn't guaranteed. If a decision genuinely has no evidentiary basis, state it in evidence_omitted_reason rather than omitting silently. See the MCP `seal_hitl_decision` inputSchema for required fields.evidencehitlgovernanceaudit
-
Seal an autonomous agent actionSeals a record for an action an agent took AUTONOMOUSLY under a governing rule. Records what the agent consumed as two fields split by provenance: `evidence` is EXTERNAL material it saw (content-addressed + hashed — e.g. a whoami response from another service), `parameters` is the COMPUTED arguments it was passed (self-contained, no hash — e.g. requested scopes, jurisdictions). One-question test: exists outside this record? → evidence (hash it); computed/passed as an argument? → parameters. At least one is required (or evidence_omitted_reason). Optionally include agent_context — free-form execution-substrate hints (cloud_run_revision, model_name, region) so an auditor can ask 'was this at a known-buggy revision?'; asserted by you, not verified by Witness. For a human decision use seal_hitl_decision.evidenceagentgovernanceaudit
-
Seal an attestationSeals an assertion that a fact or state held AS OF a point in time — a model passed an evaluation, a card was issued, a key was rotated, a config was live. Not for decisions (use the decision skills). Captures the asserting party, the claim, and the as-of time; supporting external references (evidence) are optional but strengthen it. Cite the framework via governing_basis, or it is sealed as attested-by-the-signing-party, not independently verified by Witness.attestationed25519audit
-
Issue an admission credentialIssue an agent admission credential — a sealed attestation admitting an agent (subject_did) to a customer environment with a scope, valid until expiry. The Witness record IS the credential (no separate document): enforcers hold only the credential id and check it via check_valid (Contract B); it is revocable via revoke_admission_credential. Sealed by the issuer's Witness account — only that account can revoke. subject_did / environment_id / scope / compliance_mappings are ASSERTED, not authenticated by Witness (the admission workflow establishes them; Witness records the claim). Records are immutable — validity is computed at verify time, never mutated. HOLDER-BINDING: the credential id is a bearer handle — issuing it does not bind the holder; the ENFORCER must separately prove the presenter controls subject_did (see check_valid). PROVISIONAL is representable honestly: sandbox_result.pass may be false and score null ('not run'), and evidence_seal_ref may point at an honest stub — a credential can truthfully record a conditional / not-yet-passed admission rather than forcing a passing claim.credentialadmissionattestationed25519
-
Check a credential's validityCONTRACT B — the public credential-verification endpoint. Is this admission credential currently valid? PUBLIC, no key: input is a credential_id; anyone holding one can verify it, which is what makes issuer-issued credentials verifiable-by-anyone (their whole value). Witness returns the single canonical verdict — issued ∧ signature verifies ∧ not revoked by the issuer ∧ not expired — so every enforcer is identically correct and the meaning of 'valid' evolves in ONE place, never drifting across independent implementations (the reason this is a skill and not a two-call recipe). Response {valid, code, subject, issuer, environment, scope, expires_at, revoked, revoked_at?, reason_code?, issuer_verified, issuer_verification}; code is 'valid' | 'revoked' | 'expired' | 'not_found' | 'not_credential'. PUBLIC — no key (a credential id is not a secret; CRL/OCSP posture). Cache-Control: private, max-age=60. issuer_verified is a DISTINCT signal from the lifecycle verdict — issuer-authenticity: 'verified' (customer-managed record signed by a key published in issuer_did's DID document — provable even against Witness), 'key_not_in_did_doc' (LOUD: claims an issuer but signed by a key not in its DID — suspicious), 'custodial' (Witness-signed; issuer-authenticity not established, only integrity/anchoring), or 'did_unresolvable' (the check did not complete; not verified AND not forged). Set your own bar: a high-stakes environment may require issuer_verified:true; a low-stakes one may accept custodial. TWO enforcer disciplines the schema teaches: (1) a credential id is a BEARER handle — a valid credential is necessary, NOT sufficient; you MUST separately challenge the presenter to prove control of `subject` (a DID challenge), because validity is not proof the presenter is the subject. (2) Record each check_valid response in YOUR OWN audit log (timestamp, credential_id, response) — Witness's cache and logs tell you what was returned, but only your local record proves what YOU acted on and when, when a regulator later asks how you knew the credential was valid at time T.credentialverificationrevocationenforcement
-
Verify a record's issuer-authenticity (verdict only)Is a record's signature by the issuer it claims? PUBLIC, no key. Input is a record_id; the answer is a VERDICT plus the issuer DID and the public key it resolved against — NEVER the record body, decision.inputs, or evidence. General records (attestations, agent_actions) are account-private; this is the ONLY thing about them that is publicly checkable, and the surface is exactly as wide as the question. This is how an enforcer of a privilege-widening event — e.g. a service sealing a genesis authority registration or a baseline promotion ABOUT ITSELF, customer-managed — confirms the issuer signed it, not merely that Witness recorded it, without holding the account's key or seeing the record. Response {record_id, signature_valid, issuer_verified, issuer_verification, issuer_did, signer_key}. Same four states as check_valid's issuer_verified: 'verified' (signing key IS published in the claimed issuer's did:web) | 'key_not_in_did_doc' (LOUD — signed by a key NOT in that DID; suspicious) | 'custodial' (Witness's own key signed it — issuer-authenticity is not the applicable question, a different custody model, not a failure) | 'did_unresolvable' (issuer DID unreachable — the check did NOT complete; treat as neither verified nor forged). The issuer DID is taken from the credential's issuer_did or, for a general record, from the signer's did:web keyId. Cache-Control: public, max-age=60 (no-store while did_unresolvable). ids are unguessable UUIDs; unknown → not_found.verificationissuer-authenticityenforcementcustody
-
Revoke an admission credentialRevoke an admission credential your account issued. Only the issuing account may revoke (enforced structurally by comparing sealing accounts, not a DID string). Terminal — re-admission is a NEW credential. Produces a new immutable revocation attestation that supersedes the credential; verify_admission_credential reflects it within the ~60s cache window. Customers who want a credential revoked call the issuing service (onboard.getvda.ai), which owns revocation policy and executes here — customers do not call Witness directly.credentialrevocationattestation
-
Revoke an account API key (sealed as an event)Revoke one of your account's API keys — the key stops authenticating at once, and the revocation is itself sealed as a key_revocation attestation on your chain. TWO authorities: (1) CONTROLLER-AUTHORIZED, owner self-service, no operator — prepare a key_revocation via /prepare {skill:'revoke_api_key', params:{key_id, revoked_by:{type:'controller'}, reason_code}}, sign the canonical bytes with your BOUND CONTROLLER key, and POST { record } here. Witness verifies the signer IS your bound controller and that the key is yours; the record is customer-managed (owner-signed) so the revocation is provable AGAINST Witness, not merely asserted by it. (2) ADMIN break-glass (operator, x-witness-admin, { key_id }) — sealed custodially, revoked_by.type='operator'; the record honestly shows Witness asserted it. revoked_by.type is the trust distinction, not a code path. Revocation is TOTAL: a revoked key 401s at auth AND its account's records become unfetchable with it — there is NO operator backdoor to read a revoked account's records. Reflected in whoami: a revoked key 401s immediately (no-store); a sibling's ≤60s cached 200 is the only propagation lag.revocationkey-managementcustodysecurity
-
Resolve a Witness key — cross-service auth (Contract A)The SANCTIONED cross-service authorization endpoint. A sibling getvda.ai service that accepts `Authorization: Bearer wtn.<id>.<secret>` from ITS caller validates that key by calling whoami — Witness is the sole source of truth for its own keys, so no sibling replicates the key store. Returns everything a sibling needs to authorize on IDENTITY, not just presence: account_id (WHO), tier (SEALED|ANCHORED), scopes (WHAT it may do), compliance, key_id, revoked (always false on 200), and expires_at (validity window; null = non-expiring — a revoked or expired key 401s before reaching here). A key can only ever resolve ITSELF — it cannot enumerate other accounts. Any missing/invalid key returns a uniform 401 'unknown or invalid API key' (no existence leak). Available as REST (GET) and as the MCP `whoami` tool; permissively rate-limited per IP and per account.authcross-servicecompositionsuite
-
Seal (general-purpose / compatibility)General-purpose seal, retained for backward compatibility and for records that fit none of the shaped skills. PREFER a shaped skill so your record is auditor-reconstructable: seal_hitl_decision (a human decided), seal_agent_action (an agent acted), seal_attestation (you assert a fact/state). Records sealed here carry no record_type and report as unstructured. API key required; no key? see `provisioning.selfServeKey` or the MCP `get_test_key` tool.evidenceed25519auditcompatibility
-
Read your own recordsRead back what you've sealed (operational query, account-scoped by your key — never an accountId param). `list_records` returns paginated summaries + the set of chainKeys in your account (discover your own chains); `get_record` returns the FULL signed body of one record. For OFFLINE verification of chain continuity with ZERO calls back to Witness, fetch a self-contained proof bundle: `GET /records/{recordId}?proof=chain` (record + full chain + anchor attestation + did.json) or `GET /chains/{chainKey}/proof` (whole trail). Feed it to `offlineVerify({record, chain, anchor, didDocument})` — verdicts: ANCHORED_VALID / SIGNED_PENDING / BROKEN / INSUFFICIENT_PROOF (the last means proof material was missing, NOT tampering). Distinct from `report` (Article-12 artefact). Foreign/unknown id → not-found (no leak).readqueryaudit-trail
-
Self-provision an account (no human)Self-issue a SEALED-tier API key in-band with no human. Pass an Ed25519 controller PUBLIC key (`controllerPublicKeyJwk`) to claim a DURABLE, self-renewable account bound to a key you hold — otherwise the account auto-expires ~7 days. Sealed tier = signed + hash-chained + independently verifiable OFFLINE, but NOT externally anchored (terminal — it stays sealed). The Anchored tier (externally committed, "provable even against us") is concierge-provisioned separately. Then `renew` re-keys the same account forever. See also `provisioning.selfServeKey`.provisioningself-serveed25519
-
Renew a key (agent-provable, no human)Get a fresh short-TTL API key for an account you ALREADY control — indefinitely, with no human and no permanent secret. Two steps: POST /renew/challenge {accountId} → nonce; Ed25519-sign `vda.witness.renew/1|<accountId>|<nonce>` with your controller key; POST /renew {accountId, nonce, signature} → fresh key bound to the SAME account (chains continue, prev-hash unbroken). Bind the controller key at creation via `provisioning.selfServeKey.controllerPublicKeyJwk`.credentialrenewaled25519self-serve
-
Verify a recordIndependently verify a record or chain (Ed25519 signature + hash-chain). No auth.verificationtamper-evidence
-
Article 12 Evidence ReportGenerate an EU AI Act Article 12 evidence report from the sealed trail (API key required).eu-ai-actart-12evidence
How to call
A2A endpoint (HTTP+JSON)
https://witness.getvda.ai
Documentation
https://witness.getvda.ai/docs
Homepage
https://getvda.ai
Listed in
Directories this entry was found in.
agenstry