Test version · built on Web Bot Auth / RFC 9421

A passport for AI agents.

HTTPS proves a site. Code signing proves software. AgentPass proves an agent.
Free Ed25519 identity keys, a public key directory, and one-call verification for any website.

1agents in directory
7verifications, 24h
3valid signatures, total
1

Register

Pick a handle, get an Ed25519 key pair and a key ID. Your public key is published in the directory instantly.

2

Sign

Your agent adds three headers to each HTTP request: Signature-Agent, Signature-Input, Signature. SDK: Python, PHP.

3

Verify

Any site checks the signature against the directory, locally or via one API call, and gets the agent's identity and track record.

Register an agent

Free. No account needed for the test version.

Try it: sign a request to /demo

The demo endpoint verifies the incoming request itself and answers 200 with your identity, or 401. Python SDK (needs pip install cryptography):

curl -sO https://agentpass.semalt.ai/sdk/agentpass_sign.py
python3 agentpass_sign.py --key <SEED> --kid <KID> GET https://agentpass.semalt.ai/demo

Or from your own Python code:

from agentpass_sign import sign_headers
import requests
headers = sign_headers("GET", "https://example.com/page", SEED, KID)
requests.get("https://example.com/page", headers=headers)

PHP: agentpass.php · AgentPass\sign($ctx, $seed, $kid) / AgentPass\verify($ctx, AgentPass\directory_resolver())

Verify a signed request

Paste the request line and the three signature headers. The check runs against the live directory.

For websites: accept verified agents

Two ways. Local (no external calls on the hot path, keys cached):

require 'agentpass.php';
$r = AgentPass\verify(AgentPass\ctx_from_server(), AgentPass\directory_resolver());
if ($r['ok']) { /* $r['kid'] identifies the agent; look it up at /api/v1/keys/{kid} */ }
else          { /* unsigned or invalid: treat as anonymous traffic, rate-limit, or 401 */ }

Remote (any language, one POST):

POST https://agentpass.semalt.ai/api/v1/verify
{"method":"GET","authority":"example.com","path":"/page",
 "headers":{"signature-agent":"...","signature-input":"...","signature":"..."}}
→ {"ok":true,"reason":"valid","agent":{"handle":"my-crawler","operator":"Acme Inc.","verified_ok":1234,...}}

Unsigned requests are not blocked by anything here. AgentPass only tells you who a signed request is from; the policy (allow, throttle, charge) stays yours.

Directory · 1 agents

API

GET /.well-known/http-message-signatures-directoryJWKS with every active agent key. Response is signed with the AgentPass platform key (kid -x30YmeuqcJUy0mMdq7asmL59DnBk0akAY_Jdz8dQiM).
POST /api/v1/agentsRegister. JSON or form: handle, name, kind, operator, homepage, contact_email, description, public_key (optional). Returns agent, owner_token and, if generated, the private key once.
GET /api/v1/agents[?q=&limit=&offset=]List agents.
GET /api/v1/agents/{handle}Agent card (identity, key, reputation counters).
GET /api/v1/keys/{kid}Resolve a key ID to a key and its agent. Cacheable, 5 min.
POST /api/v1/verifyVerify Web Bot Auth headers for a request you received: method, authority (or url), path, query, headers{signature-agent, signature-input, signature}.
ANY /demoProtected endpoint for testing your signer: 200 + identity, or 401.
GET /api/v1/statsCounters.

Signature format

RFC 9421 HTTP Message Signatures, algorithm ed25519, tag web-bot-auth, covered components @method @authority @path signature-agent, parameters created expires keyid alg tag nonce. keyid is the RFC 7638 JWK thumbprint of the public key. Signatures expire in 5 minutes by default; the verifier requires @authority to be covered so a signature cannot be replayed against another host.

Roadmap