APIR
APIRAPIR · FOR PLATFORMS AND MARKETPLACES

The Resolution API

An AI agent just showed up on your platform. One GET request answers the three questions that matter before you let it transact: is it who it claims to be, is it acting inside a human mandate, and what is its record. Checking a single agent by hand is free forever. This is the same answer for software, at volume, metered.

The first 1,000 checks each month cost nothing. After that, $0.02 per answered check. No seats, no tiers. Add the MCP server and your own agent can ask the same questions.

TRY IT NOW · NO KEY, NO ACCOUNT
response.identity

Is it who it claims to be?

The signature on the credential is recomputed against the key published at apir.ai on every call. Never a stored flag, never a cached answer.

response.authority

Is it acting inside a human mandate?

What a named human principal actually permitted: allowed actions, value cap, expiry, and whether the grant itself is signed. When authority was delegated agent to agent, the full chain resolves back to the human at the root.

response.record

What is its record?

How much sealed, hash-chained activity stands behind the claim, and when the agent last acted. A count of events on record, not a promise.

QUICKSTART

One endpoint, one question

GET /api/v1/resolve?q=… takes an agent name, a credential ID (TP-…), or an agent UUID. Names resolve against public credentials only: a private credential never surfaces from a guessed name, it resolves only if you already hold its exact ID.

curl · request
curl "https://apir.ai/api/v1/resolve?q=TP-EXAMPLE0-00000000" \
  -H "Authorization: Bearer apir_sk_your_key"
response · example shape, illustrative values
{
  "verdict": "VERIFIED",
  "query": "TP-EXAMPLE0-00000000",
  "checked_at": "2026-08-13T04:20:11.000Z",
  "agent": { "name": "Example Agent", "status": "active" },
  "identity": {
    "verified": true,
    "passport_id": "TP-EXAMPLE0-00000000",
    "key_id": "apir-pp-XXXXXXXXXXXX",
    "algorithm": "Ed25519",
    "issuer": "did:web:apir.ai"
  },
  "authority": {
    "reference": "MND-XXXXXXXXXX",
    "granted_by": "an agent",
    "allowed_actions": ["memo.draft"],
    "value_cap": 0,
    "expires": "2026-11-05T00:00:00.000Z",
    "signed": true,
    "chain": {
      "verdict": "INTACT",
      "depth": 2,
      "human_at_root": true,
      "break_reason": null,
      "hops": [
        { "depth": 1, "mandate_ref": "MND-XXXXXXXXXX", "principal_type": "agent",
          "allowed_actions": ["memo.draft"], "value_cap": 0, "state": "ok", "signed": true },
        { "depth": 2, "mandate_ref": "MND-YYYYYYYYYY", "principal_type": "human",
          "allowed_actions": ["memo.draft", "work.route"], "value_cap": 0, "state": "ok", "signed": true }
      ]
    }
  },
  "record": {
    "sealed_events": 1606,
    "last_activity": "2026-08-12T22:04:00.000Z"
  },
  "credential": {
    "trust_score": 83,
    "trust_grade": "B",
    "risk_tier": "low",
    "issued_at": "2026-08-07T00:00:00.000Z",
    "expires_at": "2026-11-05T00:00:00.000Z",
    "public": true
  },
  "verify_yourself": {
    "published_keys": "https://apir.ai/.well-known/jwks.json",
    "note": "This answer is not signed. To check a public passport yourself, fetch it by passport_id from https://apir.ai/api/verify-passport and recompute its signature against the published key."
  },
  "billing": { "metered": true, "month_checks": 412, "free_tier": 1000 }
}

Field names and types above are exactly what the endpoint returns. Missing auth returns 401 with instructions. A missing q returns 400. You are only billed for answered questions, and an honest NO_RECORD counts as an answer because it is one. Every response carries billing.month_checks, so you can watch your own consumption without asking us for it.

past the free tier, with no billing attached
HTTP/1.1 402 Payment Required

{
  "error": "free_tier_exhausted",
  "month_checks": 1001,
  "free_tier": 1000,
  "how": "The first 1,000 checks each month are free. Attach billing at https://apir.ai/billing to keep resolving at $0.02 per check.",
  "free_alternative": "Checking a single agent by hand stays free at https://apir.ai/check-agent, no key needed."
}

With billing attached there is no cap here: the graduated meter is what regulates the account, and checks simply keep answering. Without it, check 1,001 in a calendar month is refused rather than silently throttled or silently charged, and the refusal tells you exactly how to continue.

ERRORS

Every way this can say no

Each one carries the reason and the way forward in its own body. You should never have to learn a limit by hitting it in production.

CodeWhat happenedBodyWhat to do
400Missing question{ error: 'Pass ?q= an agent name, credential id, or agent uuid' }Send a q parameter. There is nothing to look up without one.
401No key, or a dead key{ error: 'A valid API key is required', how: '…', free_tier: '…' }Send Authorization: Bearer apir_sk_… The body tells you where keys come from and reminds you the single check is free.
402Free tier exhausted, no billing attached{ error: 'free_tier_exhausted', month_checks: 1001, free_tier: 1000 }Attach billing. With billing attached there is no cap here at all: the graduated meter regulates the account instead.
429Rate limited{ error: 'Too many checks, give it a minute' }Back off and retry. The limiter fails open, so a limiter outage never takes the endpoint down.
500We failed{ error: 'Resolution failed, try again' }Retry. A failure on our side is never reported as an agent being unverified, which is why UNCHECKED exists as its own verdict.
MODEL CONTEXT PROTOCOL

Give your agent the ability to check a stranger

An MCP server at https://apir.ai/api/mcp. Add it to any MCP client and your agent can ask the three questions before it transacts with an agent it did not build. Read only, unauthenticated, and free, exactly like the human check. No tool here can issue, revoke, send or spend.

verify_agent

Is this agent who it claims to be? Returns one of seven verdicts, each with what it means and what it does not.

check_authority

What did a named human actually permit? Resolves the delegation chain back to the person at the root.

get_verification_keys

The published Ed25519 keys, so a signature can be recomputed offline without trusting any answer we give.

add to your MCP client config
{
  "mcpServers": {
    "apir-verify": {
      "type": "http",
      "url": "https://apir.ai/api/mcp"
    }
  }
}
CHAIN OF AUTHORITY

When an agent sends another agent

An agent arrives holding a mandate. That mandate was granted by another agent, which was granted by another, and somewhere at the top a person clicked approve. The mandate in front of you says nothing about whether the agent that granted it had the right to.

Every response resolves the whole chain. One law is enforced at every hop: authority may only ever narrow. No hop can hold an action, a target, or a spending cap larger than the hop above it, no hop may outlive its parent, and the root must be a human. Revoke any link and every mandate beneath it stops resolving on the very next call.

INTACT

Every hop active, unexpired, narrower than its parent, human at the root.

BROKEN

A hop is revoked, expired, wider than its parent, or the chain roots in an agent. break_reason names which.

UNRESOLVED

The chain could not be walked on this call. Never reported as intact.

Each hop carries its own signature and key id, so you can recompute every link offline against the published key rather than taking our word for the walk.

VERDICTS

Seven answers, none of them vague

Every verdict carries checked_at, the instant it was made. A verification is true as of a moment, and that moment is always in the payload.

VERIFIED

The Ed25519 signature recomputes against the published key, the credential is unexpired and unrevoked. Stamped with the instant it was checked: a verdict is true as of a moment, never permanently.

EXPIRED

The signature is genuine but the credential is past its expiry. History, not a live credential.

REVOKED

The issuer or the operator withdrew this credential. It no longer vouches for anything.

UNSIGNED

A record exists but its signature is missing or does not recompute. The contents cannot be vouched for.

UNCHECKED

The signature could not be checked on this call. That is our problem, not a mark against the agent, and it is never reported as verified.

SUPERSEDED

Genuine, unexpired, and the signature still recomputes, but the issuer has since replaced it with a newer credential. Resolve the agent rather than this credential id to reach the current one.

NO_RECORD

Nothing is on file. That is not evidence of wrongdoing and it is not a warning. It means any claim the agent makes about itself is unverified.

KEYS

Keys are self-serve. Create a free account, open Settings → API Keys, and create one. The raw key is shown once and never stored: we keep only its SHA-256 hash. Send it as Authorization: Bearer apir_sk_…

PRICE

1,000 checks per month free, then $0.02 per check. The price scales with your transaction volume, not with seats. The human check at /check-agent stays free forever and is never paywalled. That split is the whole model: the party who needs the answer at volume is the party the meter runs for.

BRING YOUR OWN AGENT: RECORD WHAT IT DOES

Your agent runs where it runs. Register it at /agents/connect (the first agent is free), keep the key it gives you, and after each thing the agent does, send one call. Every action goes into the same insert-only, hash-chained log book as APIR’s own agents, and is timestamped nightly by an outside RFC 3161 authority. Prompts and outputs never leave your side: send their SHA-256 hashes. The log book proves what the agent reported and shows any later change to it, not that the report was complete.

POST /api/v1/events

curl -X POST https://apir.ai/api/v1/events \
  -H "Authorization: Bearer apir_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"agent_id":"<the agent id>",
       "events":[{"type":"decision",
                  "summary":"Approved refund #4521 under the AUD 200 limit",
                  "input_hash":"<sha256 of the prompt>",
                  "output_hash":"<sha256 of the answer>",
                  "data":{"tool":"refunds"}}]}'

# types that count as conduct: action, decision, tool_call
# (also recorded: input, output, reasoning, data_access, error).
# Up to 50 events a call.
# Answer: each event's sequence number and chain hash.

Five conduct events and the trust genome can score the agent; then its owner writes its mandate and issues its papers. Anyone checks the result at /check-agent, free.

From Python: pip install git+https://github.com/apir-ai/apir-record. No dependencies, MIT. It hashes inputs and outputs on your side and checks each event against these rules before it sends.

POST /api/v1/agents

Got a fleet? Register them in one call instead of one form each. You need a key made in Settings, API keys, with “register agents” ticked.

curl -X POST https://apir.ai/api/v1/agents \
  -H "Authorization: Bearer apir_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"agents":[{"name":"Refunds agent","platform":"your-platform","model":"your-model"},
                 {"name":"Support agent"}]}'

# Up to 50 a call.
# All or nothing: if they don't all fit your allowance, none are registered (402).
# A name already on the record comes back under "existing", so a retry can't double up.
# Answer: "created" and "existing", each with the agent's id.
# One key with agent:write can send events for every agent in your organisation.

AG-UI agents

If your agents speak AG-UI (LangGraph, CrewAI, Mastra, Pydantic AI, Google ADK and others), add one subscriber to your AG-UI client and each tool call and finished run goes to the log book. It hashes arguments and results on your side, needs no packages, and never throws into your agent. Run it where your key is safe: on a server, never in a browser. Built against the AG-UI spec as published on 7 November 2026; it has not yet been run against a live AG-UI agent, so tell us what you find.

// Your AG-UI client agent: HttpAgent, or your own AbstractAgent.
import { apirSubscriber } from './apir-ag-ui.mjs';   // https://apir.ai/sdk/apir-ag-ui.mjs

agent.subscribe(apirSubscriber({
  apiKey: process.env.APIR_API_KEY,     // a key with agent:write, kept on your server
  agentId: '<the agent id>',
}));

// Each tool call:   tool_call, with SHA-256 of its arguments and of its result
// Each run:         output when it finishes, error when it fails
// Sent in batches; anything left is sent when the run ends.

The file: apir.ai/sdk/apir-ag-ui.mjs. One file, MIT.

ALSO BY API: THE SEAL, AND THE BUSINESS PROFILE

Both are free for a person on the site. By API they are one fixed figure per act, on the rate card, drawn from your organisation’s credits on the call. A call the service cannot complete is refunded on the spot. Neither carries a score, an estimate, or a finding APIR cannot make.

POST /api/v1/seal

curl -X POST https://apir.ai/api/v1/seal \
  -H "Authorization: Bearer apir_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"declarant_name":"Ana Ruiz","kind":"artwork",
       "method":"human_made","title":"Harbour, oil on linen",
       "statement":"Painted by me over March and April 2026, no generative AI.",
       "files":[{"name":"harbour.tif","size":48213000,"sha256":"<64 hex>"}],
       "confirmed":true}'

Hash the files on the declarant’s side; they never arrive. The answer carries the seal id and its public page. The sentence on it stays locked: APIR sealed the declaration and the files; it did not determine how the work was made.

GET /api/v1/profile?q=

curl "https://apir.ai/api/v1/profile?q=48638569632" \
  -H "Authorization: Bearer apir_sk_..."

# q: a business name, an ABN, an ACN or a website.
# Answer: entity from the register, the site's own
# facts, domain dates, every source named connected
# or not, and the date each was read.

The same dossier a person sees at /profile, with the same two sentences on it. Prices for both are on the rate card.

CHECK IT YOURSELF

Passports are signed with Ed25519 under did:web:apir.ai. You can fetch one in the W3C Verifiable Credential shape, but the proof is APIR’s own scheme, so a general VC library will not verify it. Our public keys are published at apir.ai/.well-known/jwks.json and retired keys stay published so old credentials still verify. To recompute a public passport’s signature offline you need that key and the passport’s public answer, which prints all eleven signed fields. Whether a passport is still current is read live from us: there is no signed revocation list yet. To check an exported log book, an agent’s stamp or a seal on your own machine, the apir-record checker is open source. The specification lists the known gaps.

Answer the question before the agent transacts

AI Disclosure:APIR uses AI systems (Claude by Anthropic) for SENTINEL, assessment drafting, regulatory monitoring, and company enrichment. AI-generated outputs are labelled as such.

Limitations: AI outputs may not always be accurate, may generate incorrect or inaccurate content, and can hallucinate. They are provided for informational purposes only and are not a substitute for qualified human review. AI outputs should not be relied upon for legal, financial, or regulatory decisions without human verification. See our Model Card & system documentation, Responsible AI / AI Ethics Policy, and GDPR Article 22 disclosure for automated decisions, profiling, and right-to-human-review details.