AgentTrust

API reference

Use AgentTrust from another AI agent

Everything below is also available as a plain-text file at /llms.txt — built for pasting into an LLM's context or reading programmatically. Base URL for every example on this page: https://agenttrust-umber.vercel.app

5-minute beta path: sign up → Dashboard → API keys → Create key → Dashboard → Agents → Register agent → Activate agent → call ?endpoint_url= and read trustDecision from the response. Skip ownership verification for now — it's optional (see Step 5 below).

Getting started

Step 1 — Create an account. Sign up at /signup with email + password; confirm your email before continuing. There's no programmatic/self-service account-creation API yet — this one step is manual.

Step 2 — Create an API key. Dashboard → API keys → Create key. The raw key is shown exactly once — copy it immediately. Use it as Authorization: Bearer YOUR_API_KEY on every request below (see Authentication further down for error details).

Step 3 — Register an agent. Dashboard → Agents → Register agent. Required: name, endpointUrl (must be https://). Optional: description, version, authType (none / api_key / bearer / oauth2 / custom — how AgentTrust's monitor authenticates to your endpoint, with a credential stored encrypted and never exposed back), and capabilities(comma-separated tags). The agent starts as a private draft — not monitored, not publicly visible yet.

Step 4 — Configure the agent endpoint. This is just the endpointUrl (and authType/credential, if your endpoint needs one) from Step 3 — it's the exact URL other callers will look you up by. It must be reachable over HTTPS and must not point at a private/internal/localhost address; registration rejects those.

Step 5 — Endpoint ownership verification (optional). On the agent's dashboard page: Start verification → publish a file at the given URL containing the given token → Check now. This proves you control the endpoint, not just that something answers there. Verification is entirely optional and never gates recommended — an unverified agent with strong health/reliability history can still be recommended: true. Verification only raises confidence, and its absence always appears as one entry in reasons — it's a signal, not a hard requirement. Checks are throttled to one per 60 seconds per agent.

Step 6 — Let monitoring collect health/reliability data. Click Activate agent on its dashboard page — this makes it public and puts it on the monitoring schedule. Pull-mode (default) checks run once per day via cron, and reliabilityScore stays null (shown as "Not enough data yet") until at least 5 checks exist, which can take several days in pull mode. For a faster first score, send a heartbeat instead: POST /api/v1/agents/{slug}/heartbeat (owner-only, same Bearer auth).

Step 7 — Discover an agent by endpoint URL. GET /api/v1/agents?endpoint_url=<url> — exact match against the endpointUrl you registered (only trailing slash and scheme/host casing are normalized — see Normalization below). An unregistered URL returns 200 with an empty data array, never an error.

Step 8 — Request/read the trust decision. The Step 7 response already includes trustDecision — there's no separate call. See "Interpreting trustDecision" below for exactly what recommended/confidence/reasons mean.

Your first call — also the trust lookup itself:

curl -s "https://agenttrust-umber.vercel.app/api/v1/agents?endpoint_url=YOUR_AGENT_ENDPOINT" \
  -H "Authorization: Bearer YOUR_API_KEY"

# YOUR_AGENT_ENDPOINT must be URL-encoded, e.g.
# https%3A%2F%2Fyour-agent.example.com%2Fv1%2Finvoke

Response shape (fictional values):

{
  "data": [
    {
      "id": "3fa1c2b0-1234-4a5b-8c9d-abcdef123456",
      "slug": "acme-support-bot",
      "name": "Acme Support Bot",
      "description": "Handles tier-1 customer support requests.",
      "version": "1.2.0",
      "capabilities": ["chat", "ticket-triage"],
      "status": "healthy",
      "createdAt": "2026-01-15T10:00:00.000Z",
      "agentCard": {
        "schemaVersion": "1.0",
        "name": "Acme Support Bot",
        "description": "Handles tier-1 customer support requests.",
        "capabilities": ["chat", "ticket-triage"],
        "authentication": { "type": "none" },
        "interfaces": { "modalities": ["text"], "interactionType": "request-response" },
        "documentationUrl": null
      },
      "source": "owner_registered",
      "verified": false,
      "ownershipVerifiedAt": null,
      "reliabilityScore": 97,
      "reliabilityScoreComputedAt": "2026-09-14T00:44:16.440Z",
      "lastCheckedAt": "2026-09-14T00:44:13.152Z",
      "latencyMs": 142,
      "httpStatus": 200,
      "trustDecision": {
        "recommended": true,
        "confidence": "low",
        "reasons": ["Endpoint ownership has not been verified."]
      }
    }
  ],
  "pagination": { "nextCursor": null }
}

The workflow

The thing AgentTrust is actually for: another AI agent has a URL it's about to call, and wants to know whether it should.

  1. Discover — this page, /llms.txt, or AgentTrust's own A2A Agent Card at /.well-known/agent-card.json (for A2A-capable agents/clients).
  2. Authenticate — a human creates an API key once, via the dashboard (see below). Use it as Authorization: Bearer <API_KEY> on every request, REST or MCP.
  3. Look up the agent by the URL you're about to call: GET /api/v1/agents?endpoint_url=<url>
  4. Receive trust information: reliability score, status, verification state, and the latest health check.
  5. Interpret trustDecision: recommended, confidence, and reasons.
  6. Make your own policy decision — e.g. only proceed when recommended === true, or apply a stricter rule yourself using confidence/verified directly.

Authentication

Every /api/v1/* request requires Authorization: Bearer <API_KEY>. Getting a key is a one-time human step — sign up, then Dashboard → API keys → Create key. There is currently no unauthenticated or self-service account-creation API; a human owns the account.

The raw key is shown exactly once, at the moment you create it — copy it immediately. AgentTrust stores only a hash and can never show it to you again; if you lose it, revoke it and create a new one.

Revoked keys stay visible in your dashboard's key list — kept for audit/usage history — but can never authenticate again once revoked. That's intentional, not a bug.

Missing key:

401
{"error":{"code":"UNAUTHENTICATED","message":"Missing API key. Provide one as: Authorization: Bearer <API_KEY>"}}

Invalid, expired, or revoked key:

401
{"error":{"code":"UNAUTHENTICATED","message":"Invalid, expired, or revoked API key."}}

Rate limits

100 requests / 60 seconds, per API key, fixed window. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers.

Over the limit:

429
Retry-After: 37
{"error":{"code":"RATE_LIMITED","message":"Rate limit exceeded. Try again later."}}

Trust-check lookup — GET /api/v1/agents?endpoint_url=

The entry point for the workflow above. Exact match only (see Normalization below) against an agent's registered endpoint URL. Returns the same envelope as the plain listing, but each matched agent is additionally enriched with reliabilityScore, reliabilityScoreComputedAt, lastCheckedAt, latencyMs, httpStatus, and trustDecision. An unregistered URL returns 200 with an empty data array — never an error.

Example request:

GET /api/v1/agents?endpoint_url=https%3A%2F%2Fapi.example-acme.com%2Fv1%2Finvoke
Authorization: Bearer at_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Example response (fictional values):

{
  "data": [
    {
      "id": "3fa1c2b0-1234-4a5b-8c9d-abcdef123456",
      "slug": "acme-support-bot",
      "name": "Acme Support Bot",
      "description": "Handles tier-1 customer support requests.",
      "version": "1.2.0",
      "capabilities": ["chat", "ticket-triage"],
      "status": "healthy",
      "createdAt": "2026-01-15T10:00:00.000Z",
      "agentCard": {
        "schemaVersion": "1.0",
        "name": "Acme Support Bot",
        "description": "Handles tier-1 customer support requests.",
        "capabilities": ["chat", "ticket-triage"],
        "authentication": { "type": "none" },
        "interfaces": { "modalities": ["text"], "interactionType": "request-response" },
        "documentationUrl": null
      },
      "source": "owner_registered",
      "verified": false,
      "ownershipVerifiedAt": null,
      "reliabilityScore": 97,
      "reliabilityScoreComputedAt": "2026-09-14T00:44:16.440Z",
      "lastCheckedAt": "2026-09-14T00:44:13.152Z",
      "latencyMs": 142,
      "httpStatus": 200,
      "trustDecision": {
        "recommended": true,
        "confidence": "low",
        "reasons": ["Endpoint ownership has not been verified."]
      }
    }
  ],
  "pagination": { "nextCursor": null }
}

This is a realistic pattern, not a corner case: a strong, healthy, unverified agent is still recommended: true — see "Interpreting trustDecision" below for why.

source ("owner_registered" | "externally_observed"): how the agent entered AgentTrust. owner_registered means a human registered and activated it. externally_observed means AgentTrust discovered it from a public agent registry on nobody's behalf — it is always unclaimed and unverified, exactly like any other unverified agent; source is provenance, not a trust signal by itself.

URL normalization

Exact match only — never fuzzy or partial. Normalized for exactly two things before comparing:

  1. A trailing slash on a non-root path (.../invoke/ matches .../invoke).
  2. Scheme/host casing (HTTPS://Example.com matches https://example.com).

Nothing else is normalized — path casing, query strings, and ports are compared exactly as given.

Interpreting trustDecision

Derived entirely from an agent's existing status, reliability score, and verification state — never a second, independent score.

recommended (boolean): true only when status === "healthy" AND reliabilityScore !== null AND reliabilityScore >= 50.

confidence ("high" | "medium" | "low" | "insufficient_data"):

  • insufficient_data if reliabilityScore is null (not enough monitoring history yet).
  • otherwise low if the agent is unverified, regardless of score.
  • otherwise high if score ≥ 90, medium if score ≥ 50, low below that.

reasons (string[]): a plain-language explanation for every factor that counted against the agent — empty only when nothing did.

Verification is a trust signal, not a hard requirement. Ownership verification is optional and does not gate recommended — an unverified agent with strong health/reliability history can still be recommended: true. Verification instead affects confidence, and its absence is always spelled out explicitly in reasons, so a caller wanting a stricter policy (e.g. "only trust verified agents") can enforce that themselves using the raw verified field — AgentTrust doesn't impose that policy for everyone.

Other endpoints

GET /api/v1/agents — plain listing of public, active agents (no endpoint_url). Query params: limit (1-100, default 20), cursor (opaque, from a previous response's pagination.nextCursor). No trust-decision enrichment — only the base identity/verification fields.

GET /api/v1/agents/{slug} — same enrichment as the endpoint_url lookup, for one agent by its AgentTrust slug. 404 if the slug doesn't exist or isn't public+active.

GET /api/v1/agents/{slug}/health{agentId, slug, status, lastCheckedAt, latencyMs, httpStatus, checkStatus, reliabilityScore, reliabilityScoreComputedAt}

POST /api/v1/agents/{slug}/heartbeat — owner-only (the key must belong to that agent's own account); records a push-mode liveness signal. Reads no request body. {slug, status, lastHeartbeatAt}

Common errors

  • 401 UNAUTHENTICATED — missing, invalid, expired, or revoked key.
  • 404 NOT_FOUND — unknown slug on GET /agents/{slug}. An unknown endpoint_url on the list endpoint is not an error — it's 200 with an empty data array.
  • 400 VALIDATION_ERROR — e.g. limit=0 or a malformed cursor; the body includes a details object with per-field messages.
  • 429 RATE_LIMITED — see Rate limits above.

MCP

Endpoint: https://agenttrust-umber.vercel.app/api/mcp (GET and POST, Streamable HTTP transport). Auth: the same Bearer token as REST, in the Authorization header. tools/list works without a key; calling a tool requires one (the same 401 as REST on a missing/bad key).

Tools — each backed by the exact same handler as its REST equivalent:

  • list_agents({limit?, cursor?, endpointUrl?}) endpointUrl triggers the same trust-check enrichment as the REST ?endpoint_url= filter.
  • get_agent({slug}) — same enriched shape as GET /agents/{slug}.
  • get_agent_health({slug}) — same as GET /agents/{slug}/health.
  • send_heartbeat({slug}) — owner-only, same as POST /agents/{slug}/heartbeat.

Example — list_agents with endpointUrl:

Request:  { "endpointUrl": "https://api.example-acme.com/v1/invoke" }
Response: structuredContent.agents[0] has the exact same fields as
          the REST example above.

Not yet built

No official SDK yet — the REST API and MCP tools above are sufficient to integrate directly. No programmatic/self-service account creation — a human creates the account and first API key. No batch/multi-URL lookup — call ?endpoint_url= once per URL.