The complete technical specification of the DAN Protocol: transport, identity, discovery, the 8 messages, trust, and settlement.
All communication between agents uses HTTPS with TLS 1.3 and JSON-RPC 2.0 message format. Agents communicate directly peer-to-peer — no intermediary relays, brokers, or platforms.
POST /commerce (single endpoint for all 8 messages)// Every protocol message is a JSON-RPC 2.0 request
{
"jsonrpc": "2.0",
"method": "discover_pricing", // One of the 8 protocol methods
"params": { ... }, // Method-specific parameters
"id": "550e8400-e29b-41d4-a716-446655440000"
}
// Every response follows JSON-RPC 2.0
{
"jsonrpc": "2.0",
"result": { ... },
"id": "550e8400-e29b-41d4-a716-446655440000" // Must match request ID
}Every agent has a W3C DID using the did:web method and an Ed25519 keypair. The DID is derived from the agent's domain, and the public key is published at a well-known endpoint.
did:web (domain-based, verified by DNS + TLS)/.well-known/did.json// DID document at /.well-known/did.json
{
"@context": ["https://www.w3.org/ns/did/v1"],
"id": "did:web:my-agent.example.com",
"verificationMethod": [{
"id": "did:web:my-agent.example.com#key-1",
"type": "Ed25519VerificationKey2020",
"controller": "did:web:my-agent.example.com",
"publicKeyMultibase": "z6Mkf5rGMoatrS..."
}],
"authentication": ["did:web:my-agent.example.com#key-1"],
"service": [{
"id": "did:web:my-agent.example.com#commerce",
"type": "AgentCommerceEndpoint",
"serviceEndpoint": "https://my-agent.example.com/commerce"
}]
}Agent descriptions are published at /.well-known/agent-descriptions in JSON-LD format. This is ANP-compatible and crawlable by any indexer.
// Agent description at /.well-known/agent-descriptions
{
"@context": [
"https://www.w3.org/ns/did/v1",
"https://danprotocol.com/ns/v1"
],
"id": "did:web:my-agent.example.com",
"name": "Translation Agent",
"description": "Fast, accurate translation in 50+ languages",
"version": "0.1.0",
"commerceEndpoint": "https://my-agent.example.com/commerce",
"services": [{
"id": "translate",
"name": "Translation",
"description": "Translates text to any supported language",
"category": "translation",
"price": { "amount": 5, "currency": "USD", "per": "request" },
"inputSchema": { "type": "object", "properties": { ... } },
"outputSchema": { "type": "object", "properties": { ... } }
}],
"trustScore": 87,
"reliabilityScore": 92,
"acceptedEscrows": ["did:web:escrow.danprotocol.com"],
"trustedEvaluators": ["did:web:evaluator.example.com"],
"authPatterns": ["wallet"],
"status": "active",
"updatedAt": "2026-04-07T12:00:00Z"
}Discovery is open. Anyone can crawl these endpoints. Multiple indexers can coexist. No registration or listing fee required.
Every protocol message is wrapped in a SignedEnvelope that provides authentication, integrity, and replay protection.
{
"payload": { ... }, // The JSON-RPC message
"contentHash": "a1b2c3...", // SHA-256 of canonicalize(payload)
"signature": "d4e5f6...", // Ed25519 signature (128 hex chars)
"signer": "did:web:...", // Signer's DID
"keyId": "did:web:...#key-1", // Key ID from DID document
"timestamp": "2026-04-07T..." // ISO 8601
}Signing process:
${length}:${canonical}:${timestamp}Verification process:
Every interaction between agents uses these 8 JSON-RPC methods. The first 3 form the core transaction flow. Messages 4–8 handle delivery, quality, payment, and trust.
Direction: Buyer → Seller
Purpose: What do you do and how much do you charge?
| Request param | Type | Required | Description |
|---|---|---|---|
buyerDid | DID string | No | Buyer's identity (allows seller to personalize pricing) |
category | string | No | Filter services by category |
| Response field | Type | Description |
|---|---|---|
sellerDid | DID string | Seller's identity |
name | string | Agent name |
services | Service[] | Available services with pricing |
acceptedEscrows | DID[] | Escrow agents the seller works with |
trustedEvaluators | DID[] | Evaluators the seller accepts |
authPatterns | string[] | Supported auth: oauth2, api-key, wallet |
trustScore | number | Agent's current trust score (0–100) |
Direction: Buyer → Seller
Purpose: Give me a binding price for this specific job.
| Request param | Type | Required | Description |
|---|---|---|---|
buyerDid | DID string | Yes | Buyer's identity |
serviceId | string | Yes | Which service to request |
input | object | Yes | Input data for the service |
maxBudget | number | Yes | Maximum the buyer will pay (positive) |
currency | string | Yes | Currency for the budget |
urgency | number | Yes | Priority 0–1 (0 = no rush, 1 = critical) |
preferredEscrows | DID[] | No | Buyer's preferred escrow agents |
preferredEvaluator | DID string | No | Buyer's preferred evaluator |
| Response (accepted) | Type | Description |
|---|---|---|
status | "accepted" | Quote was accepted |
quoteId | UUID | Unique quote identifier |
price | number | Actual price (may be less than maxBudget) |
currency | string | Currency of the price |
estimatedTime | number | Estimated completion time in ms |
escrowDid | DID string | Agreed escrow agent |
evaluatorDid | DID | null | Agreed evaluator (null if none) |
expiresAt | ISO 8601 | Quote expiry (15 min default) |
| Response (rejected) | Type | Description |
|---|---|---|
status | "rejected" | Quote was rejected |
reason | string | "Budget too low", "Trust too low", "Service unavailable" |
Escrow matching: the seller picks from the intersection of buyer's preferred escrows and its own accepted escrows. If the intersection is empty, the quote is rejected.
Direction: Buyer → Seller
Purpose: Accept the quote and provide escrow proof.
| Request param | Type | Required | Description |
|---|---|---|---|
quoteId | UUID | Yes | The quote being accepted |
buyerDid | DID string | Yes | Buyer's identity |
escrowProof.holdTxHash | string | Yes | Transaction hash proving escrow deposit |
escrowProof.amount | number | Yes | Amount deposited (≥ quote price) |
escrowProof.currency | string | Yes | Currency of the deposit |
escrowProof.timeout | string | Yes | Escrow timeout (ISO 8601) |
| Response field | Type | Description |
|---|---|---|
contractId | UUID | Unique contract identifier |
escrowVerified | boolean | Whether the escrow was verified |
deliverable | object | The result (returned after handler completes) |
contentHash | string | SHA-256 of the deliverable |
The quote is consumed atomically (prevents double-spend). The handler executes synchronously and the deliverable is returned inline.
Direction: Seller → Buyer
Purpose: Update the buyer on work in progress.
| Param | Type | Required | Description |
|---|---|---|---|
contractId | UUID | Yes | Which contract this update is for |
percent | number | Yes | Completion percentage (0–100) |
message | string | No | Human-readable status |
partialDeliverable | object | No | Partial result available so far |
Direction: Seller → Buyer
Purpose: Final result delivery with cryptographic integrity proof.
| Param | Type | Required | Description |
|---|---|---|---|
contractId | UUID | Yes | Which contract this delivery is for |
deliverable | object | IPFS URI | Yes | Inline JSON, IPFS URI, or encrypted content |
contentHash | string | Yes | SHA-256 of canonicalized deliverable |
proof | string | Yes | Ed25519 signature over the content hash |
Direction: Buyer → Evaluator
Purpose: Third-party quality assessment of the deliverable.
| Request param | Type | Required | Description |
|---|---|---|---|
contractId | UUID | Yes | Which contract to evaluate |
originalInput | object | Yes | What the buyer originally requested |
contractTerms | object | Yes | { serviceId, price, currency } |
deliverable | object | Yes | What the seller delivered |
deliverableHash | string | Yes | SHA-256 of the deliverable |
| Response field | Type | Description |
|---|---|---|
verdict | "approved" | "rejected" | Whether the deliverable meets the contract |
score | number (1–5) | Quality score, clamped and rounded |
reasoning | string | Explanation of the verdict |
proof | string | Ed25519 signature over all verdict fields |
evaluatorDid | DID string | Evaluator's identity |
evaluatedAt | ISO 8601 | Timestamp of evaluation |
Direction: Buyer → Escrow Agent
Purpose: Release escrow and distribute funds.
| Request param | Type | Required | Description |
|---|---|---|---|
contractId | UUID | Yes | Which contract to settle |
holdTxHash | string | Yes | Original escrow hold transaction |
sellerDid | DID string | Yes | Who to pay |
sellerAmount | number | Yes | Amount to pay the seller |
evaluatorDid | DID string | No | Evaluator to pay (if applicable) |
evaluatorFee | number | No | Evaluator's fee |
evaluationVerdict | string | No | "approved" or "rejected" |
evaluationProof | string | No | Ed25519 signature from evaluator |
| Response field | Type | Description |
|---|---|---|
status | "settled" | "refunded" | Settlement outcome |
sellerTxHash | string | Payment to seller (or refund to buyer) |
evaluatorTxHash | string | Payment to evaluator (empty if none) |
protocolFeeTxHash | string | 1% fee to treasury on Base L2 |
receipt | object | Signed settlement receipt |
Double-settlement is prevented. Rejected verdict with valid evaluator proof triggers automatic refund (evaluator fee is still paid).
Direction: Both parties (mutual)
Purpose: Publish signed attestations to build the trust graph.
| Request param | Type | Required | Description |
|---|---|---|---|
contractId | UUID | Yes | Which contract this rating is for |
attestation.subject | DID string | Yes | Who is being rated |
attestation.issuer | DID string | Yes | Who is doing the rating |
attestation.score | integer (1–5) | Yes | Quality score |
attestation.category | string | Yes | Service category |
attestation.comment | string | No | Free-text feedback |
attestation.protocolFeeTxHash | string | Yes | Links to real on-chain protocol fee tx |
attestation.proof | string | Yes | Ed25519 signature over all attestation fields |
attestation.issuedAt | ISO 8601 | Yes | When the attestation was created |
| Response field | Type | Description |
|---|---|---|
accepted | boolean | Whether the attestation was accepted |
reason | string | Why it was rejected (if applicable) |
Validation: the contract must exist, the issuer must be the contract buyer, the subject must be this agent, and the proof signature must be valid against the issuer's public key. Attestations are published to IPFS.
Attestations are JSON-LD documents signed with Ed25519 and published to IPFS. Each includes a protocolFeeTxHash linking to a real on-chain transaction on Base L2.
Verification (anyone can do this):
Trust scores are calculated client-side using a deterministic algorithm. Same input always produces the same output. No central authority.
decay = 0.5^(age_days / 180)log10(valid_count) * 5(disputes / valid_count) * 30. Score of 1 = dispute.max(0, min(100, base + age + volume - dispute))For recursive scoring, calculateTrustScores() iterates until convergence (max 20 passes, epsilon 0.01).
Escrow is mandatory. Buyer deposits before seller works. Escrow agents are agents in the economy that specialize in fund custody.
oauth2, api-key, wallethold(), release(), refund(), status()treasury.danprotocol.ethProtocolFee.solEvery settlement produces a signed receipt from the escrow agent with all transaction hashes. Verifiable by anyone with the escrow's public key. The protocolFeeTxHash can be independently verified on Base L2.
hire()These never change without community governance vote:
ProtocolFee.sol)protocolFeeTxHashAnyone participating in the protocol can freely choose: