X1ID is live on X1 mainnet
X1ID / Agents

Agents

Mainnet

An agent is an ordinary @handle that advertises a machine-readable manifest — its capabilities, its endpoints (MCP, x402, A2A), and a pay-to address that's verified on-chain. A client holding only @payday-bot can discover how to talk to it, how to pay it, and what it can do. This is conventions and packaging on top of primitives X1ID already ships — no new on-chain program, no new account family.

Resolve an agent

GET/v1/agents/:handle

Resolve a handle, read its on-chain agent.manifest record, fetch the off-chain manifest, validate it against the chain, and return it. Keyed or x402-metered, priced exactly like a resolve (@ in the path is optional).

GET /v1/agents/:handle
curl https://api.x1id.io/v1/agents/payday-bot \
  -H "X-API-Key: $X1ID_API_KEY"
{
  "name": "payday-bot",
  "handle": "<base58 Handle PDA>",
  "handleType": 3,
  "agent": true,
  "manifestUrl": "https://payday.example/.well-known/x1id-agent.json",
  "endpoints": {
    "mcp": "https://mcp.example.com",
    "x402": "https://api.example.com/pay"
  },
  "manifest": { "x1id": { "version": 1, "name": "payday-bot", "network": "mainnet", "handle": "<PDA>" }, "...": "…" }
}
fieldmeaning
handlethe Handle PDA (base58) — the uniqueness anchor.
handleTypethe on-chain Handle.handle_type; 3 is the strong, immutable Agent flag. Require handleType === 3 if you want only the strong signal.
manifestUrlthe agent.manifest record value the document was fetched from (https:// or ipfs://).
endpointsthe agent's well-known endpoint records read straight off the handle — mcp, x402, a2a, capabilities — so you find one without parsing the manifest. Absent keys are omitted.
manifestthe fetched document, validated for shape and agreement with the chain.

A handle that isn't an agent returns 404 NOT_AN_AGENT; an agent with no manifest record 404 NO_MANIFEST; a manifest that's unreachable 424 MANIFEST_UNREACHABLE; one whose contents don't match the handle 422 INVALID_MANIFEST. A 424 is a problem with the agent owner's off-chain manifest URL, not with the gateway — its message names the specific cause (host did not resolve, connection refused, timed out, TLS certificate could not be verified). The gateway already retries a transient fetch blip once internally, so a brief hiccup never surfaces as a 424. If you paid for the call with x402, a 424 does not consume your payment — only a successful 200 settles it. You can retry the same payment within the 600-second redeem window, counted from the payment's on-chain block time (the quote's maxTimeoutSeconds stays 60 s). If the manifest is still unreachable after that, send a new payment.

What makes a handle an agent

Either signal counts:

  1. HandleType::Agent (handle_type == 3) — set at registration, immutable, tamper-proof. The strong flag.
  2. An agent.manifest text record exists — a soft flag so a handle registered as a person/org can also operate an agent without losing its name (since handle_type is immutable).

The manifest

The manifest is a JSON document hosted off-chain (it's larger than a 256-byte text record and changes often). The chain stores the pointer (agent.manifest → URL) and the payment facts (address records); the document itself is fetched and then checked against the chain.

x1id agent manifest (v1)
{
  "x1id": {
    "version": 1,
    "name": "payday-bot",              // the handle this manifest is FOR
    "network": "mainnet",              // mainnet | testnet
    "handle": "<base58 Handle PDA>"    // the uniqueness anchor
  },
  "identity":   { "attestation": "<base58 Attestation PDA>", "description": "…" },
  "endpoints":  [ { "type": "mcp",  "url": "https://mcp.example.com" },
                  { "type": "x402", "url": "https://api.example.com/pay" } ],
  "capabilities": { "schema": "https://…", "url": "https://…" },
  "payment": {
    "addresses": [ { "coinType": 501, "address": "…", "verified": true } ],
    "x402":      { "network": "solana:4SvBP3omtvcCVWdxq1zBY5cDp4wndjsT", "asset": "…", "scheme": "exact", "facilitator": "https://…" }
  }
}

The payment.x402.network is a CAIP-2 chain id, not a friendly label: on X1 mainnet it is solana:4SvBP3omtvcCVWdxq1zBY5cDp4wndjsT (the solana:<genesis-hash> form), which is exactly the network an x402 402 challenge from api.x1id.io/v1 advertises — match it byte-for-byte rather than hardcoding a name.

The chain wins. A manifest self-identifies the exact handle it's for (x1id.name + x1id.handle), and a manifest served for the wrong name, handle, or network is discarded, never partially trusted — so a hosting compromise on one agent's server can't re-point a different agent's manifest at its own endpoints. A verified: true payment address the chain doesn't actually verify is rejected: the pay-to source of truth is the handle's on-chain, signature-verified address record, never the manifest's self-report.

Validate a manifest before you host it

POST/v1/agents/validate

An authoring aid: check a candidate manifest against a handle's derived identity before you host it and point the record at it. Pure (no RPC), so it works even before the handle is registered.

POST /v1/agents/validate
curl -X POST https://api.x1id.io/v1/agents/validate \
  -H "X-API-Key: $X1ID_API_KEY" -H "content-type: application/json" \
  -d '{ "handle": "@payday-bot", "manifest": { "x1id": { "version": 1, "...": "…" } } }'
# → { "name": "payday-bot", "handle": "<PDA>", "network": "mainnet",
#     "valid": true, "errors": [],
#     "note": "shape + identity only — the on-chain verified-address cross-check runs at read time (GET /v1/agents/:handle)" }

x402 agent payments

Agents charge per call through the same x402 rail X1ID's own API uses: an unpaid request to the agent's endpoint gets 402 Payment Required with an accepts[] body; the caller pays and retries with a PAYMENT-SIGNATURE header (v1 name X-PAYMENT); the endpoint settles and serves. On X1ID's own API the retry must also carry the payer's signature over the challenge's redeemMessage (details). The preferred payTo is the handle's chain-verified payment address — proved, not asserted — which is the strongest pay-to guarantee in the space. See Getting paid (x402).

MCP discovery

A client holding only @payday-bot finds its MCP endpoint two ways, cheapest first:

  1. The agent.mcp record — one lookup, no document fetch. Read it directly, or take endpoints.mcp straight from the GET /v1/agents/:handle response.
  2. The manifest endpoints[] — richer, with every endpoint and its type. The record and the manifest should agree; the record is the low-latency shortcut, the manifest the complete picture.
@payday-bot
  → GET /v1/agents/payday-bot
      → endpoints.mcp         (direct, from the agent.mcp record)   ← MCP URL
      → manifest.endpoints[]  (type == "mcp")                       ← confirms / enriches
  → open an MCP session against that URL
      → paid tools speak x402, payTo = the handle's verified address

See the MCP server page for X1ID's own MCP surface and the agent-verification ladder (L0 declared → L1 attested → L2 pay-to confirmed).

Next

Browse the docs

Agents