Operator Guide — Running a Verification Service¶
This guide is for third parties who want to run an "agent verified" service: an HTTP API that verifies DCP Signed Bundles (and optionally anchors hashes to a blockchain). The protocol does not require any central server; verification can always be done locally with dcp verify-bundle. This service is optional and is run at the operator's choice.
What is an "agent verified" service?¶
An agent verification service is an HTTP API that:
- Verifies a Signed Bundle: runs the same normative checklist as spec/VERIFICATION.md (schema validation, signature, intent_hash, audit chain, optional merkle_root).
- Optionally checks an
anchor_receiptagainst a public blockchain or transparency log (using public data only). - Optionally anchors a
bundle_hashto an existing chain and returns ananchor_receiptto the client.
The service is stateless: each request receives a bundle (and optionally a public key), verifies it, and returns a result. No central registry of agents; the protocol does not define a canonical URL (e.g. no mandatory "dcp.ai" endpoint).
verified: true means the bundle is intact and signed by the keys it names. It does not say who the principal is, or whether you should act on the bundle: accepting bundles only from principals you trust is admission, a separate step (POST /v2/admit in the reference server, see ADMISSION.md, unreleased).
Who runs it?¶
Third parties. Anyone can deploy this service using this repo (schemas + spec + CLI or programmatic API). The protocol author does not operate a central verification server.
Requirements¶
- A checkout of this repository: schemas in
schemas/v1/andschemas/v2/, spec inspec/, and the reference CLI and verification library of the root package, which is not published to npm. - Ability to run verification: either the CLI (
dcp verify-bundle [--policy <mode>] <signed.json> [public_key.txt]) or the programmatic API from the repo:verifySignedBundle(async) andvalidateBundleinlib/verify.js. V2 bundles are schema-validated there and then verified by@dcp-ai/sdk. - Optional, for anchoring: RPC or block explorer access to an existing chain (Bitcoin, Ethereum, or a transparency log). See STORAGE_AND_ANCHORING.md.
Suggested API contract¶
So that clients and operators can interoperate, this section suggests a minimal contract. Implementations may extend it.
POST /verify¶
Verifies a Signed Bundle against the normative checklist (schema, signature, intent_hash, audit chain, optional merkle).
- Request (JSON):
signed_bundle(object): the Signed Bundle to verify.-
public_key_b64(string, optional): for V1, the signer's public key when the bundle does not include it; otherwise the bundle'ssignature.signer.public_key_b64is used. For V2, it pins the classical signer (refused inpq_onlymode). -
Response (JSON):
verified(boolean):trueif all checks pass.errors(array of strings, optional): ifverifiedisfalse, human-readable error messages.
Example:
// Request
{ "signed_bundle": { "bundle": { ... }, "signature": { ... } } }
// Response (success)
{ "verified": true }
// Response (failure)
{ "verified": false, "errors": ["SIGNATURE INVALID", "Hint: Check that the public key ..."] }
The reference server (server/) implements this as POST /verify. Its response always carries dcp_version and errors; for V2 it adds warnings, verifier_policy_hash and resolved_tier. Request bodies are JSON.
POST /anchor (optional)¶
Anchors a bundle_hash to a chain and returns an anchor_receipt. The operator configures chain and credentials (e.g. wallet, RPC URL). See STORAGE_AND_ANCHORING.md for receipt format.
- Request (JSON):
bundle_hash(string): e.g.sha256:<hex>.-
chain(string): e.g."bitcoin","ethereum". -
Response (JSON):
anchor_receipt(object): e.g.{ "chain": "bitcoin", "tx_id": "...", "block_height": N }or Ethereum-style fields.
Implementation of /anchor depends on the operator's chain and tooling (Bitcoin OP_RETURN, Ethereum contract event, etc.). The reference anchor service (services/anchor) does not implement it yet: it records hashes locally, in memory, with tx_hash: null and onchain: false, and returns no anchor_receipt. The reference verification server answers POST /anchor with 501.
Deployment¶
The reference verification server, anchor service, transparency log, and revocation registry are all published as Docker images on GitHub Container Registry. In most cases you don't need to clone the repo at all — docker run is enough.
Option 1 — pull the reference image (fastest)¶
docker run -d -p 3000:3000 ghcr.io/dcp-ai-protocol/dcp-ai/verification:latest
curl http://localhost:3000/health
Multi-arch (linux/amd64 + linux/arm64). Tags: :latest, the release semver tags (:<major>.<minor>.<patch>, :<major>.<minor>, :<major>) and :sha-<short>. The full stack (verification + anchor + two transparency logs + revocation, five containers) can be brought up with one docker compose up -d run in docker/, or with docker compose -f docker/docker-compose.yml up -d from the repo root.
Option 2 — managed PaaS¶
Pre-wired configs for Fly.io are in deploy/fly/; the deployment guide also covers Google Cloud Run and Railway patterns.
Option 3 — embed the verifier in your own service¶
If you want verification inside your existing application (no separate HTTP service), install the SDK for your language and call its verifier directly (verifySignedBundleV2 in TypeScript, verify_signed_bundle_v2 in Python and Rust, v2.VerifySignedBundleV2 in Go). These commands install the published versions:
npm install @dcp-ai/sdk # TypeScript / Node.js
pip install dcp-ai # Python
cargo add dcp-ai@2.14.0
go get github.com/dcp-ai-protocol/dcp-ai/sdks/go/v2@v2.14.0
See each SDK's README for the exact import path and API surface, and its Release status for what the published version lacks. On main, the TypeScript, Python, Go and Rust SDKs verify V1 and V2 bundles natively, and @dcp-ai/wasm exposes the Rust V2 verifier. Their V2 verifiers follow the checklist in VERIFICATION.md, including each artifact's signature (Step V2-8) and the PQ checkpoints (Step V2-12), and, from @dcp-ai/sdk 2.2.1, @dcp-ai/wasm 2.1.1, dcp-ai 2.10.1 (PyPI), Go v2.11.1 and Rust dcp-ai 2.11.1, the secondary fields of Step V2-11 that are present: earlier versions check the primary audit chain and Merkle root but not the optional secondary chain or audit_merkle_root_secondary (see STORAGE_AND_ANCHORING.md).
Stateless by design¶
- No database required for verification: each request is self-contained.
- Persistence is needed for everything else: the gateway's passport and key registries, the anchor queue, the transparency log and the revocation registry.
Reference services keep state in memory only¶
The reference gateway (server/) and services (services/) have no persistent store, except that the revocation service can keep its state in a file (REVOCATION_STATE_PATH: off by default in the service, on in the compose file in docker/, which puts it on a volume). A restart, a deploy or a crash wipes their state, including a crash from running out of memory. That state is:
- registered passports, keys and emergency tokens;
- revocations;
- the transparency log;
- pending anchors and local anchor records.
The one exception is the revocation service with REVOCATION_STATE_PATH on persistent storage (a volume): its registrations and revocations survive a restart.
After a wipe, what was recorded is gone, but the gates stay:
- Registration. Registering an
agent_idstill needs the operator token, also for anagent_idthat was registered before the wipe, since every one is new again. - Revocation lookups. The revocation service no longer knows the revocations it recorded:
GET /check/<agent_id>answersrevoked: falsefor an agent revoked before the wipe;/.well-known/dcp-revocations.jsonno longer lists it, so a deny-list revocation source reads it as not revoked;GET /v2/check/kid/<kid>answers 404 (status unknown) for its keys.- The gateway forgets its passports, keys (revoked and retired ones included) and emergency tokens.
- No trust is gained. A wipe alone does not make a principal trusted or a bundle admitted: admission still needs the operator's trust set and, under strict-v1, a revocation snapshot.
Add persistent storage before relying on these services in production.
To keep memory bounded, the identity, key and revocation registries refuse work instead of evicting state:
| Service | Limit | Setting |
|---|---|---|
| Gateway | Registering a new agent_id needs the operator token (401) |
OPERATOR_TOKEN |
| Gateway | 20 passport registrations per client per hour (429) | REGISTRATIONS_PER_HOUR |
| Gateway | 10,000 registered keys; new agents then get 507 (a rotation drops a retired key first, so it still fits) | MAX_REGISTERED_KEYS |
| Gateway | 4 rotated-out keys kept per agent; older ones stay revoked as tombstones | — |
| Gateway | 64 keys per agent over its lifetime; further rotations get 409 (raise it for agents that rotate often) | MAX_KEYS_PER_AGENT |
| Gateway | 100 POST requests per client per minute, 5 emergency revocations per minute | — |
| Revocation | Registering a new agent_id needs the operator token (401) |
OPERATOR_TOKEN |
| Revocation | 20 registrations per client per hour (429) | REGISTRATIONS_PER_HOUR |
| Revocation | 10,000 registered agents; new ones then get 507 | MAX_AGENTS |
| Revocation | Text fields of at most 256 characters; 5 emergency revocations per client per minute | — |
| Transparency log | Gossip exchanges need a tree head signed by a pinned peer (GOSSIP_PEERS=<url>#<key>); 16 KB bodies; the last 100 distinct alerts; polls read 16 KB at most, time out after one interval and never overlap; per pinned key, at most 8 witnessed logs of 256 tree sizes each, in memory |
GOSSIP_PEERS |
| Endpoints that read a body | 1 MB request bodies (413); POST /v2/disputes/:id/escalate and POST /v2/delegation/mandate/:id/revoke do not read theirs |
— |
Two parts of the gateway behave differently:
- DCP-05–09 record stores evict. These are the stores for lifecycle, vitality, testaments, succession, disputes, jurisprudence, objections, rights, obligations, violations, mandates, advisory declarations, mirrors, interactions and awareness thresholds. Each keeps at most 10,000 entries, and 10,000 per agent in its per-agent lists, and evicts the oldest (FIFO): an evicted record is gone, without an error.
- Audit chains have no limit of their own (
POST /v2/audit/append). Only the request limits apply to them.
The limits count per client IP. Behind a proxy that appends the client IP to X-Forwarded-For, set TRUST_PROXY=true; otherwise every client shares the proxy's address.
Environment variables (verification service)¶
PORT— HTTP port (default3000)OPERATOR_TOKEN— bearer token for the admin endpoints (policy, advisories, governance) and for registering newagent_ids; unset keeps them lockedVERIFIER_MODE—classical_only|hybrid_preferred|hybrid_required|pq_onlyALLOW_V1_BUNDLES—falserejects V1 bundlesDCP_DEMO_ENDPOINTS—off(the default) ordcp-05-09, which enables the DCP-05–09 demo endpoints and needs anOPERATOR_TOKENof at least 32 RFC 6750 b64token characters; any other value stops the serverTRUST_PROXY,REGISTRATIONS_PER_HOUR,MAX_REGISTERED_KEYS,MAX_KEYS_PER_AGENT— see aboveDCP_TRUSTED_PRINCIPALS_FILE,DCP_ADMISSION_PROFILE_FILE,DCP_REVOCATION_LIST_URL,DCP_REVOCATION_LIST_AUTHORIZATION,DCP_REVOCATION_TIMEOUT_MS— admission forPOST /v2/admit, see ADMISSION.mdREQUIRE_SESSION_BINDING,REQUIRE_COMPOSITE_BINDING,MAX_KEY_AGE_DAYSandPQ_CHECKPOINT_INTERVALappear in the deploy configs but are not read yet
For anchor, transparency-log, and revocation env variables see their respective README files under services/ or the per-service fly.toml in deploy/fly/.
Blockchain and verification¶
- Verification only: The service can limit itself to POST
/verify, applying the VERIFICATION.md checklist (schema, signature, intent_hash, audit chain, merkle; the SDK verifiers from@dcp-ai/sdk2.2.1,@dcp-ai/wasm2.1.1,dcp-ai2.10.1 (PyPI), Go v2.11.1 and Rustdcp-ai2.11.1 also check the optional secondary chain fields that are present; earlier versions do not). No blockchain needed. - Verify anchor_receipt: If the client sends an
anchor_receiptwith the bundle, the service can optionally check thatbundle_hashappears at the given chain/log index using public data only (e.g. fetch tx from block explorer). No central server of the protocol is involved. - Anchor (write): The operator runs a node or uses RPC and writes hashes to an existing chain; the service returns
anchor_receiptto the client. This is optional and operator-specific, and the reference anchor service does not do it yet (seeservices/anchor/README.md).
V2.0 Verification Service¶
DCP v2.0 introduces post-quantum hybrid cryptography, adaptive security tiers, and composite signatures. Operators running verification services must update their configuration to support V2.
Verifier Policy Configuration¶
The verifiers take a VerifierPolicy (schemas/v2/verifier_policy.schema.json). The reference server starts with this one:
{
"default_mode": "hybrid_required",
"risk_overrides": { "high": "hybrid_required", "medium": "hybrid_required", "low": "hybrid_required" },
"min_classical": 1,
"min_pq": 1,
"accepted_classical_algs": ["ed25519"],
"accepted_pq_algs": ["ml-dsa-65", "slh-dsa-192f"],
"accepted_hash_algs": ["sha256", "sha384"],
"require_session_binding": true,
"require_composite_binding": true,
"max_key_age_days": 365,
"allow_v1_bundles": true,
"allow_classical_fallback_disable": false,
"warn_classical_only_deprecated": false,
"advisory_rejected_algs": []
}
risk_overrides is keyed by the passport's risk_tier. The server has no policy file: VERIFIER_MODE and ALLOW_V1_BUNDLES set it at startup, POST /v2/policy/mode with { "mode": "<mode>" } (operator token) switches the mode at runtime, accepted advisories add to advisory_rejected_algs, and GET /v2/policy returns the current policy and its hash. A switch of mode sets default_mode and every risk_overrides entry to that mode. To embed a verifier with your own policy, pass a full policy to the SDK: a partial one is accepted, but the fields you leave out are not filled with defaults (see MIGRATION_V1_V2.md, Step 8).
Verification modes:
- classical_only — Only Ed25519 signatures required (V1 compatibility)
- hybrid_preferred — Ed25519 required, ML-DSA-65 checked if present
- hybrid_required — Both Ed25519 and ML-DSA-65 composite signature required
- pq_only — Only the post-quantum signature is required and checked; a bundle signed classical_only is rejected, and a pinned classical key (public_key_b64) is refused. In the reference server this mode also turns V1 bundles off.
In every mode, a PQ signature (ML-DSA-65 or SLH-DSA-192f) that is present must verify; an invalid one is rejected.
POST /verify (V2)¶
V2 bundles include composite_sig with both classical and post-quantum components:
{
"signed_bundle": {
"bundle": {
"dcp_bundle_version": "2.0",
"manifest": {
"session_nonce": "a1b2c3...",
"rpr_hash": "sha256:...",
"passport_hash": "sha256:...",
"intent_hash": "sha256:...",
"policy_hash": "sha256:...",
"audit_merkle_root": "sha256:...",
"audit_merkle_root_secondary": "sha3-256:...",
"audit_count": 1
},
"responsible_principal_record": { "payload": {...}, "payload_hash": "sha256:...", "composite_sig": {...} },
"agent_passport": { "payload": {...}, "payload_hash": "sha256:...", "composite_sig": {...} },
"intent": { "payload": {...}, "payload_hash": "sha256:...", "composite_sig": {...} },
"policy_decision": { "payload": {...}, "payload_hash": "sha256:...", "composite_sig": {...} },
"audit_entries": [ {...} ]
},
"signature": {
"composite_sig": {
"classical": { "alg": "ed25519", "kid": "...", "sig_b64": "..." },
"pq": { "alg": "ml-dsa-65", "kid": "...", "sig_b64": "..." },
"binding": "pq_over_classical"
}
}
}
}
The reference server's V2 response includes the resolved security tier. POST /v2/bundle/verify (V2 only; it also accepts the signed bundle as the whole body) answers:
{
"verified": true,
"dcp_version": "2.0",
"errors": [],
"warnings": [],
"verifier_policy_hash": "sha256:...",
"resolved_tier": "elevated",
"verification_mode": "hybrid_required",
"session_binding_valid": true,
"manifest_valid": true
}
POST /verify gives the same fields up to resolved_tier. session_binding_valid and manifest_valid are read from the error messages, so use verified and errors to decide.
Security Tiers in Verification¶
Each security tier maps to a verification mode and a PQ checkpoint interval (spec §14.1):
| Tier | Verification Mode | PQ Checkpoint |
|---|---|---|
| Routine | classical_only |
Every 50 events |
| Standard | hybrid_preferred |
Every 10 events |
| Elevated | hybrid_required |
Every event |
| Maximum | hybrid_required |
Every event |
There is no size budget per tier. A bundle's size depends on its algorithms, its audit entries and PQ checkpoints
and its JSON encoding: measure your largest bundles. For example, the synthetic hybrid bundle
signed_bundles.base in tests/interop/v2/admission_vectors.json is 32,996 bytes as compact JSON; that is an
observation, not a limit. Send bundles in a JSON request body with an explicit size budget, not in a header (see
QUICKSTART_EXPRESS.md).
The verifier can upgrade a tier (e.g., force elevated for financial operations) but MUST NOT downgrade it. On main, the SDK verifiers (TypeScript, Go, Rust, WASM and Python) check the bundle signature and every artifact signature against the stricter of the policy mode (the risk_overrides entry for the passport's risk_tier, or default_mode) and the tier's mode (spec §14.3), so a passport that declares risk_tier: "low" still needs a hybrid signature for a payment intent. They also check the PQ checkpoints the bundle carries (spec/VERIFICATION.md V2-12). Published versions may lag: see each SDK's Release status.
The reference server verifies V2 bundles through lib/verify.js, which hands them to the TypeScript SDK of the same checkout with the server's policy; the Docker images build that SDK from the source (see docker/Dockerfile). Its verification_mode field is the tier's mode, not the effective mode.
Capabilities Endpoint (V2)¶
V2 services expose GET /.well-known/dcp-capabilities.json. The reference server answers:
{
"supported_versions": ["1.0", "2.0"],
"supported_algs": {
"signing": ["ed25519", "ml-dsa-65", "slh-dsa-192f"],
"kem": ["x25519", "ml-kem-768", "x25519-ml-kem-768"],
"hash": ["sha256", "sha3-256", "sha384"]
},
"supported_wire_formats": ["application/json", "application/cbor"],
"features": {
"composite_signatures": true,
"session_binding": true,
"blinded_rpr": true,
"dual_hash_chains": true,
"pq_checkpoints": true,
"emergency_revocation": true,
"multi_party_auth": true,
"pq_only_mode": true,
"advisory_auto_response": true,
"governance_keys": true,
"hsm_provider": false,
"agent_lifecycle": false,
"succession": false,
"dispute_resolution": false,
"rights_obligations": false,
"delegation": false,
"dcp05_09_demo_endpoints": false
},
"demo_endpoints": {
"dcp-05-09": { "enabled": false, "normative": false, "verifies_signatures": false, "access": "operator_token" }
},
"verifier_policy_hash": "sha256:...",
"min_accepted_version": "1.0"
}
This is what the server advertises, not a list of checked guarantees. Its endpoints read JSON bodies only, although application/cbor is listed. Since 06/11/2026 it advertises hsm_provider: false: the repository has no HSM provider (SECURITY_MODEL.md). Since 07/11/2026 the DCP-05 to DCP-09 features are false: the server implements none of them normatively. dcp05_09_demo_endpoints and demo_endpoints say whether the demo endpoints are enabled; they are not normative, verify no signature and need the operator token.
Observability¶
V2 services should expose metrics for monitoring:
- Latency: p50/p95/p99 verification latency by security tier
- Throughput: Bundles verified per second
- Cache: Verification cache hit/miss ratio
- PQ Checkpoints: Number of PQ checkpoints verified
- Errors: Error counts by DCP error code (DCP-E001 through DCP-E902)
- Tiers: Distribution of verification requests by security tier
Recommended: Use the SDK's built-in dcpTelemetry module with OpenTelemetry-compatible exporters (OBSERVABILITY.md). The reference server does not emit these metrics itself.
Migration for Existing V1 Operators¶
Existing V1 operators can upgrade incrementally:
- Update to DCP v2.0 SDK
- Set
default_mode: 'classical_only'(VERIFIER_MODE=classical_onlyin the reference server); the security tier still raises the mode tohybrid_requiredfor elevated and maximum actions - Gradually enable
hybrid_preferredfor new agents - Move to
hybrid_requiredwhen PQ adoption is sufficient
See MIGRATION_V1_V2.md for detailed migration steps.
DCP-05–09 Service Endpoints¶
The verification server has 31 demo endpoints for lifecycle management, digital succession, dispute resolution, rights framework, and personal representation, off by default.
Off by default, operator-only, unverified. Every request under the twelve path families of these endpoints gets 404 unless the server starts with
DCP_DEMO_ENDPOINTS=dcp-05-09, which needs anOPERATOR_TOKENof at least 32 RFC 6750 b64token characters (the server does not start otherwise). Enabled, each request, GET included, needs exactlyAuthorization: Bearer <OPERATOR_TOKEN>: 401 otherwise, answered before the body is read, withConnection: close. The token only lets the operator in: the endpoints check each record against its schema and the format of its IDs, verify nocomposite_sigand establish no principal authority, so treat what they store as unverified records. Their stores live in the same process as the identity registries; since 07/11/2026 decommissioning no longer changes a registered passport. The global limit of 100 POST requests per minute per client applies first (429).Migration (07/11/2026). Before this change these endpoints were on and needed no token. To keep using them, start the server with
DCP_DEMO_ENDPOINTS=dcp-05-09and a longOPERATOR_TOKEN(openssl rand -hex 32), and sendAuthorization: Bearer <OPERATOR_TOKEN>with every request, GET included.
Each POST takes the record under the key named in the table (for example { "commissioning_certificate": { ... } }). :agent_id and :id are URL-encoded.
DCP-05: Agent Lifecycle Management¶
| Method | Endpoint | Body key | Description |
|---|---|---|---|
| POST | /v2/lifecycle/commission |
commissioning_certificate |
Puts the agent in state commissioned; for an agent already known, this resets its state and history |
| POST | /v2/lifecycle/vitality |
vitality_report |
Stores a vitality report; a different state in the report is a lifecycle transition |
| POST | /v2/lifecycle/decommission |
decommissioning_record |
Moves the agent to decommissioned |
| GET | /v2/lifecycle/:agent_id |
— | Current state, history and number of vitality reports |
Lifecycle transitions the server accepts: commissioned → active, active → declining, active → decommissioned, declining → decommissioned. The SDK's state machine also allows commissioned → decommissioned and declining → active.
DCP-06: Digital Succession & Inheritance¶
| Method | Endpoint | Body key | Description |
|---|---|---|---|
| POST | /v2/succession/testament |
digital_testament |
Stores the agent's testament (one per agent) |
| GET | /v2/succession/testament/:agent_id |
— | The agent's testament |
| POST | /v2/succession/execute |
succession_record |
Records a succession; the predecessor must be declining or decommissioned when the server knows its state |
| POST | /v2/succession/memory-transfer |
memory_transfer_manifest |
Validates the manifest and answers with counts; it is not stored |
| GET | /v2/succession/:agent_id |
— | Successions recorded for a predecessor |
DCP-07: Conflict Resolution & Dispute Arbitration¶
| Method | Endpoint | Body key | Description |
|---|---|---|---|
| POST | /v2/disputes/create |
dispute_record |
Stores a dispute |
| POST | /v2/disputes/:id/escalate |
— | Moves the dispute to the next escalation level |
| POST | /v2/disputes/:id/resolve |
arbitration_resolution (optional) |
Marks the dispute resolved; the resolution, when given, is stored as is |
| GET | /v2/disputes/:id |
— | The dispute |
| POST | /v2/objections/create |
objection_record |
Stores an objection |
| POST | /v2/jurisprudence |
jurisprudence_bundle |
Stores a jurisprudence bundle |
| GET | /v2/jurisprudence |
— | All stored jurisprudence bundles |
DCP-08: Rights & Obligations Framework¶
| Method | Endpoint | Body key | Description |
|---|---|---|---|
| POST | /v2/rights/declare |
rights_declaration |
Stores the agent's rights declaration (one per agent) |
| GET | /v2/rights/:agent_id |
— | The agent's rights declaration |
| POST | /v2/obligations/record |
obligation_record |
Adds an obligation record |
| GET | /v2/obligations/:agent_id |
— | The agent's obligation records |
| POST | /v2/rights/violation |
violation_report |
Stores a rights violation report |
DCP-09: Personal Representation & Delegation¶
| Method | Endpoint | Body key | Description |
|---|---|---|---|
| POST | /v2/delegation/mandate |
delegation_mandate |
Stores a mandate |
| GET | /v2/delegation/mandate/:id |
— | The mandate, with revoked |
| POST | /v2/delegation/mandate/:id/revoke |
— | Revokes a mandate whose revocable is true |
| POST | /v2/agent-advisory/declare |
advisory_declaration |
Stores an advisory declaration |
| GET | /v2/agent-advisory/:id |
— | The advisory declaration |
| POST | /v2/mirror/generate |
principal_mirror |
Adds a principal mirror |
| GET | /v2/mirror/:agent_id |
— | The agent's principal mirrors |
| POST | /v2/interactions/record |
interaction_record |
Stores an interaction record |
| POST | /v2/awareness/threshold |
awareness_threshold |
Stores the agent's awareness threshold (one per agent) |
| GET | /v2/awareness/threshold/:agent_id |
— | The agent's awareness threshold |
A record stored by ID, or one per agent, is replaced by a later POST for the same ID or agent. Objections, violation reports and interaction records have no GET endpoint.
Production Hardening¶
The DCP-05–09 endpoints have:
- JSON Schema validation — Every POST that submits a record is validated against its schema before storage.
escalateandrevoketake no record;resolvetakes an optionalarbitration_resolution, which it stores without validating it - Rate limiting — 100 requests/minute/IP on all POST endpoints
- Body size limits — 1 MB maximum request body (returns 413) where the body is read;
escalateandrevokedo not read it - Input ID validation — The IDs the server keys on must match
^[\w:.\-]{1,256}$; other characters are rejected - Bounded storage — each in-memory store keeps at most 10,000 entries and evicts the oldest (FIFO): an evicted record is gone. The identity registries refuse instead (507); see Reference services keep state in memory only
- Security headers — X-Content-Type-Options, X-Frame-Options, Strict-Transport-Security, Cache-Control
They do not include signature verification of the records or any principal authority; when enabled, the operator token is their only access control (see the note at the top of this section).
Reference¶
- Verification checklist: spec/VERIFICATION.md
- Storage and anchoring: STORAGE_AND_ANCHORING.md
- Bundle format: spec/BUNDLE.md