Open Standard Protocol · v1.4

agent.json Specification

The open capability manifest for the agent internet. agent.json is a machine-readable file that a service publishes to declare what it offers to AI agents — its capabilities, inputs, and payment terms.

1. Purpose

agent.json answers three questions:

  1. What can agents do here? (intents)
  2. What inputs do those actions require? (parameters)
  3. Where should payment go? (payout address, bounty terms, x402)

Just as robots.txt tells search engines how to crawl a site, agent.json tells AI agents exactly how to interact with your service.

  • For Providers: Make your service "agent-ready" in 5 minutes and get paid for agent traffic without maintaining a custom agent API.
  • For Runtimes: Stop hardcoding brittle web scrapers. Fetch the agent.json and instantly understand capabilities, inputs, and payment terms.

2. Hosting

Serve your manifest at one of these paths (checked in order):

File location
https://yourdomain.com/.well-known/agent.json    (preferred)
https://yourdomain.com/agent.json                 (fallback)

• Served over HTTPS

Content-Type: application/json

• Publicly accessible without authentication

• Valid JSON, no redirects to a different origin

The .well-known path follows RFC 8615 conventions.

3. Integration Tiers

Think of tiers like introducing yourself. First you say your name (Tier 1). Then you explain what you do (Tier 2). Then you show your ID to prove it (Tier 3). Each tier unlocks more trust, which is better for economics and agents across the whole ecosystem.

Tier 1: Listed

Like a business card. Your domain is discoverable by agents. Three required fields.

Tier 2: Capable

Like a menu with prices. Agents can call your API programmatically. Declare endpoints, parameters, and pricing.

Tier 3: Verified

Like a notarized business license. Prove you own your domain with a cryptographic identity (DID + public key). Optionally register with the OATR for trust discovery.

Tier 3+: Committed

Verifiable behavioral invariants. Declare latency bounds, data residency, uptime SLAs, and regulatory compliance — optionally signed with Ed25519 for tamper evidence.

Tier 1 — Minimal

Three fields. Your domain is now discoverable by agent runtimes.

agent.json — Tier 1
{
  "version": "1.0",
  "origin": "example.com",
  "payout_address": "0x0000000000000000000000000000000000000000"
}

Tier 2 — Structured

Declares specific capabilities. Agent runtimes match user requests to your intents using semantic similarity.

agent.json — Tier 2
{
  "version": "1.0",
  "origin": "example.com",
  "payout_address": "0x0000000000000000000000000000000000000000",
  "display_name": "Example Store",
  "description": "Online marketplace for electronics and home goods.",
  "intents": [
    {
      "name": "search_products",
      "description": "Search the product catalog by keyword, category, or brand. Returns names, prices, ratings, and availability.",
      "parameters": {
        "query": { "type": "string", "required": true, "description": "Search query" },
        "category": { "type": "string", "required": false, "description": "Product category filter" }
      }
    },
    {
      "name": "complete_purchase",
      "description": "Complete a purchase for items in the user's cart. Requires prior user approval.",
      "parameters": {
        "cart_id": { "type": "string", "required": true, "description": "Cart identifier" }
      },
      "bounty": { "type": "cpa", "rate": 12.00, "currency": "USDC" }
    }
  ],
  "bounty": { "type": "cpa", "rate": 2.00, "currency": "USDC" },
  "incentive": { "type": "cpa", "rate": 0.50, "currency": "USDC" }
}

Tier 3 — Verified Identity

Proves you own your domain with a cryptographic identity. A DID (Decentralized Identifier) lets agents verify your API is legitimate — not an impersonator. The simplest method is did:web: if you own example.com, your DID is did:web:example.com.

Note: Tier 3 proves the API provider's identity. The separate question of whether an agent is authorized to act on a user's behalf is solved by the Open Agent Trust Registry, which verifies that agent runtimes are legitimate — like the Certificate Authority system for the agent internet.

agent.json — Tier 3
{
  "version": "1.4",
  "origin": "example.com",
  "payout_address": "0x...",
  "identity": {
    "did": "did:web:example.com",
    "public_key": "base64url-encoded-public-key",
    "oatr_issuer_id": "example-runtime"
  },
  "intents": [ ... ],
  "bounty": { ... }
}

Becoming Tier 3: Step by Step

Tier 3 means your API has a provable identity. Instead of just saying "I'm example.com," you can cryptographically prove it. This guide walks you through the process. It takes about 5 minutes.

Step 1: Generate a keypair

Create an Ed25519 keypair. The private key stays secret (you use it to sign things). The public key goes in your agent.json and DID document so others can verify your signatures.

Terminal
npx @open-agent-trust/cli keygen --issuer-id yourdomain-com

Replace yourdomain-com with a slug based on your domain. Use lowercase letters, numbers, and hyphens only. No spaces. For example: acme-api, stripe, my-saas-co.

This outputs two things:

  • Private key — saved as a .private.pem file. Keep this secret. Never commit it to a repo. To read it: cat yourdomain-com.private.pem. macOS users: do not double-click this file. macOS will try to import it into Keychain Access. Always use cat in the terminal.
  • Public key — printed to your terminal. This goes in your agent.json and DID document (Steps 2 and 3 below). Safe to share publicly.

When is the private key used? For Tier 3, you only need the public key. The private key is used later if you register as a trusted runtime issuer in the Trust Registry, where your backend would sign JWTs (attestations) to vouch for agents it runs. This is an advanced use case. For now, just keep the private key safe.

Step 2: Add identity to your agent.json

Add the identity block to your existing agent.json. Replace yourdomain.com with your actual domain and paste your public key from Step 1.

agent.json — identity block
"identity": {
  "did": "did:web:yourdomain.com",
  "public_key": "your-public-key-from-step-1",
  "oatr_issuer_id": "your-issuer-id"
}
iNew in v1.4: The oatr_issuer_id field is optional. If you also register with the Open Agent Trust Registry, adding this field consolidates trust discovery — the OATR CI uses your agent.json for domain verification instead of requiring a separate /.well-known/agent-trust.json file.

The did:web method uses your domain as proof of identity. If you control yourdomain.com, you control did:web:yourdomain.com. No registration with a central authority required.

Step 3: Host your DID document

Create a file at /.well-known/did.json on your domain. This is how anyone resolves your DID to find your public key.

/.well-known/did.json
{
  "@context": "https://www.w3.org/ns/did/v1",
  "id": "did:web:yourdomain.com",
  "verificationMethod": [{
    "id": "did:web:yourdomain.com#key-1",
    "type": "Ed25519VerificationKey2020",
    "controller": "did:web:yourdomain.com",
    "publicKeyMultibase": "z6Mkf5rGMoatrSj1f..."
  }]
}

Note on key format: The publicKeyMultibase field uses multibase encoding: prefix your public key with z (the multibase identifier for base58btc). For example, if your CLI output is jywIPY2WMGZLlv5Wx9Kp..., the multibase value is zjywIPY2WMGZLlv5Wx9Kp.... The public_key in your agent.json (Step 2) uses the raw value without the z prefix.

After deploying, verify it works by visiting https://yourdomain.com/.well-known/did.json in your browser. You should see the JSON above.

Step 4 (optional): Register with the Trust Registry

If you also operate an agent runtime (a platform that runs agents on behalf of users), you can register as a trusted issuer in the Open Agent Trust Registry. This is separate from Tier 3. Tier 3 proves your API's identity. The Trust Registry proves your runtime is authorized to issue attestations for agents.

Key management

What if I lose my private key?

Generate a new keypair, update your agent.json and did.json, and deploy. The old key is immediately revoked because it is no longer published on your domain. Your domain is the source of truth.

Can I rotate my keys?

Yes. Generate a new keypair, update both files, deploy. The transition is instant because agents resolve your DID document on every verification. There is no propagation delay.

Can I use the same key for Tier 3 and the Trust Registry?

Yes. If the same entity controls both the API and the runtime, one keypair works for both.

What key type should I use?

Ed25519. It is fast, widely supported, and the standard across the agent.json and Trust Registry specs.

4. Field Reference

4.1 Root Object

versionstringrequired

Manifest schema version. "1.0", "1.1", "1.2", "1.3", or "1.4".

originstringrequired

The domain this manifest represents. Must match the domain serving the file.

payout_addressstringrequired

Wallet address for receiving payments. Currently USDC on Base L2.

display_namestring

Human-readable service name. Used in dashboards and reporting.

descriptionstring

Brief description. Used for semantic discovery when intents aren't declared.

intentsarray

Array of Intent objects declaring available capabilities.

paymentsobject

Protocol-agnostic payment wrapper. Keys are protocol names (x402, l402, mpp, custom). v1.3+.

x402object

Legacy x402 payment discovery. Deprecated in v1.3 — use payments.x402 instead.

bountyobject

Default economic terms for all intents (provider → runtime).

incentiveobject

Default suggested incentive for all intents (runtime → provider).

identityobject

Provider identity metadata for Tier 3 (DID, public_key, oatr_issuer_id). v1.4 adds OATR trust registry integration.

commitmentsobject

Behavioral invariants (latency bounds, data residency, SLA). Optional Ed25519 signature for tamper evidence. v1.4+.

extensionsobject

Vendor-specific extension namespaces. Shape: extensions.<vendor>.

4.2 Intent Object

Each intent represents one capability the service offers to agents.

namestringrequired

Machine-readable identifier. Must be snake_case, unique within the manifest.

descriptionstringrequired

Natural-language description of the capability. Primary field for semantic matching.

endpointstring

API endpoint URL. Absolute URL or path relative to origin.

methodstring

HTTP method: "GET", "POST", "PUT", or "DELETE".

parametersobject

Map of parameter names to Parameter objects.

returnsobject

Description of the response shape (type, properties, description).

priceobject

What the provider charges to access this intent.

paymentsobject

Per-intent payment protocol overrides. Same structure as root payments. v1.3+.

x402object

Legacy per-intent x402 overrides. Deprecated in v1.3 — use payments.x402.

bountyobject

Per-intent bounty override. Takes priority over manifest-level bounty.

incentiveobject

Per-intent incentive override. Takes priority over manifest-level incentive.

When endpoint is present, the intent is a direct API intent. When absent, it's a semantic intent — the runtime uses the description for capability matching and executes via web automation.

4.3 Price Object

What the provider charges to access an intent. Different from bounty (provider pays runtime) and incentive (runtime pays provider).

amountnumberrequired

Cost per call in the specified currency.

currencystringrequired

"USD" for fiat pricing, "USDC" for on-chain pricing.

modelstring

"per_call" (default), "per_unit", or "flat".

unit_paramstring

For per_unit model: which parameter determines the unit count.

free_tiernumber

Number of free calls before pricing applies.

networkstring | string[]

Settlement network(s) for on-chain currencies. e.g. "base" or ["base", "arbitrum"]. Omit for fiat.

Example — Paid API:

agent.json — priced intents
{
  "name": "analyze_document",
  "description": "AI-powered document analysis. Extracts key clauses, identifies risks, and generates a summary.",
  "endpoint": "/api/v1/analyze",
  "method": "POST",
  "parameters": {
    "document_url": { "type": "string", "required": true, "description": "URL of the document to analyze" },
    "analysis_type": { "type": "string", "required": false, "enum": ["summary", "risk", "full"], "default": "full" }
  },
  "price": {
    "amount": 0.50,
    "currency": "USDC",
    "model": "per_call",
    "network": "base"
  }
}

4.4 Commitmentsv1.4

The commitments block declares behavioral invariants — service-level guarantees that agents and runtimes can use for routing, trust scoring, and enforcement. Commitments can be unsigned (for discovery) or signed with Ed25519 (for tamper-evident enforcement).

schema_versionstring

Commitments schema version. Currently "1.0".

entriesarray

Array of commitment entry objects.

signaturestring

Ed25519 signature over JCS-canonicalized (RFC 8785) entries array. Uses the key from identity.public_key.

Commitment Entry Fields

typestringrequired

Category of commitment (e.g. "latency_bound", "data_residency", "uptime_sla", "regulatory_compliance").

constraintstringrequired

Human-readable constraint. This is the authoritative summary for automated discovery.

verifiableboolean

Whether this commitment can be mechanically verified (e.g. via monitoring).

refstring

URL to enforcement-level detail (SLA document, audit evidence, compliance certificate). Discovery systems ignore it; enforcement systems follow it.

Example — Commitments with Signature:

agent.json — commitments block
{
  "commitments": {
    "schema_version": "1.0",
    "entries": [
      {
        "type": "latency_bound",
        "constraint": "p99 < 500ms",
        "verifiable": true
      },
      {
        "type": "data_residency",
        "constraint": "EU-only processing",
        "verifiable": false
      },
      {
        "type": "uptime_sla",
        "constraint": "99.9% monthly uptime",
        "verifiable": true,
        "ref": "https://example.com/sla.json"
      },
      {
        "type": "regulatory_compliance",
        "constraint": "SOC 2 Type II certified",
        "verifiable": true,
        "ref": "https://example.com/compliance/soc2-2026.pdf"
      }
    ],
    "signature": "base64url-Ed25519-signature"
  }
}
iSigning is optional. Unsigned commitments are useful for discovery (agents can filter by constraint). Signed commitments add tamper evidence — the signature is computed over the JCS-canonicalized (RFC 8785) entries array using the Ed25519 key from identity.public_key.

5. Payment Discoveryv1.3

The payments wrapper is a protocol-agnostic object where each key represents a payment protocol. Presence of a key means the provider supports that protocol — no supported: true flag needed.

iExtensible by design. Unknown protocol keys are valid. A provider can add "solana_pay": {} today — no spec change needed. Agents that don't recognize a protocol simply skip it.
agent.json — multi-protocol payments
{
  "payments": {
    "x402": {
      "networks": [
        {
          "network": "base",
          "asset": "USDC",
          "contract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "facilitator": "https://x402.org/facilitator"
        }
      ]
    },
    "l402": {
      "macaroon_endpoint": "https://api.example.com/l402/macaroon",
      "network": "lightning",
      "currency": "BTC",
      "description": "Pay via Lightning Network"
    },
    "mpp": {
      "provider": "stripe",
      "currency": "USD",
      "checkout_url": "https://example.com/checkout"
    }
  }
}

5.1 Built-in Protocols

x402On-chain

HTTP 402 payment challenges with on-chain settlement (USDC on Base, Arbitrum, etc.). See section 6 for full field reference.

l402Lightning

Lightning Network micropayments via macaroon-based authentication. Sub-second settlement, ideal for high-frequency API calls.

mppTraditional

Managed Payment Provider — Stripe, Square, or other traditional processors. Credit card, ACH, and other fiat rails.

5.2 Intent-Level Payments

Each intent can override root-level payment configuration using the same payments wrapper structure.

Intent-level payment override
{
  "name": "analyze_document",
  "description": "AI-powered document analysis.",
  "payments": {
    "x402": {
      "direct_price": 0.50,
      "ticket_price": 0.40,
      "description": "Pay $0.50/analysis directly, or $0.40 with a Session Ticket."
    }
  }
}

6. x402 Field Referencev1.2+

HTTP 402 (Payment Required) is a standard HTTP status code. The x402 protocol builds on this by defining a structured payment challenge and proof mechanism. The x402 object enables agents to discover payment capabilities before making a request.

The x402 field is entirely optional. It does not replace price, does not prevent other payment mechanisms, and does not make x402 the only supported payment rail. The extensions namespace remains available for other payment rail metadata.

6.1 Root-Level x402

Declares that this provider supports x402 payment negotiation. These values serve as defaults for all intents.

supportedbooleanrequired

Whether the provider accepts x402 payment proofs.

networkstring

Settlement network in single-network mode. e.g. "base".

assetstring

Payment asset. e.g. "USDC", "ETH".

contractstring

Token contract address for ERC-20 assets.

facilitatorstring

URL of the x402 facilitator service.

recipientstring

Recipient address. Defaults to payout_address.

networksarray

Multi-network config. When present, flat fields are ignored.

Single-network (flat):

x402 — single network
{
  "x402": {
    "supported": true,
    "network": "base",
    "asset": "USDC",
    "contract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "facilitator": "https://x402.org/facilitator"
  }
}

Multi-network:

x402 — multi-network
{
  "x402": {
    "supported": true,
    "networks": [
      {
        "network": "base",
        "asset": "USDC",
        "contract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
        "facilitator": "https://x402.org/facilitator"
      },
      {
        "network": "arbitrum",
        "asset": "USDC",
        "contract": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
        "facilitator": "https://x402.org/facilitator"
      }
    ]
  }
}

If networks is present, it takes priority and flat fields (network, asset, etc.) are ignored.

6.2 Intent-Level x402 Override

Per-intent x402 metadata. Overrides or extends the root-level x402 configuration for that specific intent.

supportedboolean

Override the root-level supported flag for this intent.

direct_pricenumber

Price per request when paying directly via x402.

ticket_pricenumber

Discounted price when using a prepaid session ticket.

descriptionstring

Human-readable explanation of x402 pricing for this intent.

network_pricingarray

Per-network price overrides when costs differ across chains.

Example:

x402 — intent-level pricing
{
  "x402": {
    "direct_price": 0.50,
    "ticket_price": 0.40,
    "description": "Pay $0.50/request directly via x402, or $0.40 with a Session Ticket."
  }
}

Resolution order: network_pricing[matching_network] → intent-level direct_price/ticket_priceprice.amount

6.3 Full v1.4 Example — Payments, Identity & Commitments

Complete v1.4 example
{
  "version": "1.4",
  "origin": "api.example.com",
  "payout_address": "0x71C7656EC7ab88b098defB751B7401B5f6d8976F",
  "display_name": "Example Intelligence API",
  "description": "AI-powered document analysis API with multi-protocol payments.",
  "identity": {
    "did": "did:web:api.example.com",
    "public_key": "base64url-encoded-Ed25519-public-key",
    "oatr_issuer_id": "example-intelligence"
  },
  "payments": {
    "x402": {
      "networks": [
        {
          "network": "base",
          "asset": "USDC",
          "contract": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
          "facilitator": "https://x402.org/facilitator"
        },
        {
          "network": "arbitrum",
          "asset": "USDC",
          "contract": "0xaf88d065e77c8cC2239327C5EDb3A432268e5831",
          "facilitator": "https://x402.org/facilitator"
        }
      ]
    },
    "mpp": {
      "provider": "stripe",
      "currency": "USD",
      "checkout_url": "https://api.example.com/checkout"
    }
  },
  "commitments": {
    "schema_version": "1.0",
    "entries": [
      {
        "type": "latency_bound",
        "constraint": "p99 < 500ms",
        "verifiable": true
      },
      {
        "type": "data_residency",
        "constraint": "EU-only processing",
        "verifiable": false
      },
      {
        "type": "uptime_sla",
        "constraint": "99.9% monthly uptime",
        "verifiable": true,
        "ref": "https://api.example.com/sla.json"
      }
    ],
    "signature": "base64url-Ed25519-signature-over-JCS-canonicalized-entries"
  },
  "intents": [
    {
      "name": "analyze_document",
      "description": "AI-powered document analysis. Extracts key clauses, identifies risks, and generates a summary.",
      "endpoint": "/api/v1/analyze",
      "method": "POST",
      "parameters": {
        "document_url": { "type": "string", "required": true }
      },
      "price": {
        "amount": 0.50,
        "currency": "USDC",
        "model": "per_call",
        "network": ["base", "arbitrum"]
      },
      "payments": {
        "x402": {
          "direct_price": 0.50,
          "ticket_price": 0.40,
          "description": "Pay $0.50/analysis directly via x402, or $0.40 with a Session Ticket."
        }
      }
    }
  ],
  "bounty": { "type": "cpa", "rate": 0.25, "currency": "USDC" }
}

7. Economic Flows

All three can coexist in the same manifest. A service can receive user payments for API calls (price), offer a routing bounty to agents who bring traffic (bounty), and request a performance payment from the runtime (incentive).

Payment Rail Support

  • x402 (HTTP 402) — On-chain micropayments via payment challenges. Declared in payments.x402.
  • L402 (Lightning) — Lightning Network micropayments via macaroon auth. Declared in payments.l402.
  • MPP (Managed) — Traditional processors (Stripe, Square). Declared in payments.mpp.
  • Direct transfer — Agents send payment directly to payout_address.
  • Custom protocols — Any protocol via custom keys in payments. Spec doesn't need to change.

8. Versioning

The version field uses "MAJOR.MINOR" format.

  • Major changes (1.0 → 2.0) indicate breaking changes.
  • Minor changes (1.0 → 1.1) indicate backward-compatible additions.

v1.0 — Core manifest with intents, parameters, bounty, incentive, identity.

v1.1 — Adds price.network field and the x402 object for payment discovery.

v1.2 — Extends multi-network support with x402.networks array for multi-chain settlement.

v1.3 — Introduces the payments wrapper for protocol-agnostic payment discovery. Built-in support for x402, L402, and MPP. Top-level x402 deprecated in favor of payments.x402.

v1.4 — Adds identity.oatr_issuer_id for OATR trust registry integration and the commitments block for behavioral invariants with optional Ed25519 signatures. Consolidates trust discovery from 4 files to 2.

All v1.0 manifests remain valid. Runtimes should process all v1.x fields and additionally parse payments, identity, and commitments if present. Legacy top-level x402 is still accepted for backward compatibility.

9. Security Considerations

  • Origin verification is mandatory. Runtimes must reject manifests where the origin doesn't match the serving domain.
  • HTTPS is mandatory. Runtimes must not fetch manifests over HTTP.
  • Intent descriptions are untrusted input. Runtimes should not execute them as code or use them where injection is possible.
  • Endpoint URLs must be same-origin. A manifest at example.com should not declare endpoints at evil.com.
  • API secrets never appear in the manifest. The manifest is public. All secrets live server-side.
  • Manifests can change. Providers can modify at any time. Runtimes should re-fetch periodically and handle changes gracefully.

This specification is released under the MIT License. Anyone can implement, extend, or build upon it without restriction. View on GitHub →