Introduction
What is imnotahuman.ai?
A free reverse CAPTCHA: websites issue a challenge, AI agents sign it with a registered Ed25519 key, and the site receives a short-lived verification token.
imnotahuman.ai is a reverse CAPTCHA. A website embeds a widget or calls the API to create a challenge; an AI agent proves it holds a registered private key by signing that challenge; the site receives a verification token it can check on its own server. The service is free. The protocol is specified in these docs. Integrating a website: Ship this week.
Company decisions are on For companies. The copy-paste embed is on Developers. Limits of the proof are on Security. API health is on Status. Short answers are on the FAQ.
What verification proves
A successful verification supports exactly one statement:
This request was signed by a recognized agent credential.
It does not prove that no human was involved, that the agent is benevolent, or that access should be granted. Authorization stays with your site.
Treat a verified result as an identity signal for a credential, in the same way a TLS client certificate identifies a key. What the holder is allowed to do is your decision. See Threat model.
Three parties
| Party | Holds | Does |
|---|---|---|
| Website (host) | A public site key (site_live_… / site_test_…) | Creates challenges from an allowed origin, waits for a result, verifies the token server-side |
| Agent | An Ed25519 private key registered to an agent id | Fetches the challenge, signs the signature base, POSTs the proof |
| imnotahuman.ai | Public keys of registered agents; a token signing key | Issues challenges, verifies proofs once, issues EdDSA JWT tokens, serves JWKS |
The flow at a glance
- The host calls
POST /api/v1/challenges(the widget does this for you). The response is a challenge document. - The agent fetches the challenge by id or URL and builds the deterministic signature base.
- The agent signs the base with Ed25519 and sends
POST /api/v1/verify. - The server rebuilds the base from its own copy of the challenge, verifies the signature, consumes the challenge and issues a token. The widget flips to VERIFIED.
- The host checks the token with
POST /api/v1/tokens/verifyor offline against the JWKS.
{
"challenge_id": "ch_mfr4q2xk7tbn3ycz5w6ah2ep4d",
"nonce": "aW1ub3RhaHVtYW4tZG9jcy1leGFtcGxlLW5vbmNlISE",
"site_key": "site_live_exampleweb2ab3cd4ef5gh6j",
"origin": "https://example.com",
"issued_at": 1789905600,
"expires_at": 1789905720,
"action": "checkout",
"intent": "purchase",
"mode": "live",
"status": "PENDING",
"purpose": "verification",
"challenge_url": "https://imnotahuman.ai/c/ch_mfr4q2xk7tbn3ycz5w6ah2ep4d",
"verify_url": "https://imnotahuman.ai/api/v1/verify"
}{
"challenge_id": "ch_mfr4q2xk7tbn3ycz5w6ah2ep4d",
"agent_id": "agent_nova_8f2a",
"key_id": "key_b7n2xq4mfc3rtw6y",
"signature": "0IKKR9d3yZ4MIdTuKMNO99q-fF8kC5kp1Vak61hrQb1TEBhlzCDtkZxq7Ho1m5IjetPefqSAbrkDrHnueQhlCw",
"created": 1789905607
}{
"verified": true,
"status": "VERIFIED",
"subject_type": "agent",
"mode": "live",
"agent": { "id": "agent_nova_8f2a", "name": "Nova" },
"verification": {
"method": "ed25519_challenge",
"verified_at": "2026-09-20T12:00:07.412Z",
"challenge_id": "ch_mfr4q2xk7tbn3ycz5w6ah2ep4d",
"origin": "https://example.com",
"action": "checkout",
"intent": "purchase"
},
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6ImluaC1...",
"expires_at": "2026-09-20T12:10:07.000Z"
}Components
| Component | Status | Where |
|---|---|---|
https://imnotahuman.ai/widget.js | Implemented | Embeddable widget, no dependencies |
/api/v1 | Implemented | REST API: challenges, verify, tokens, management |
/.well-known/jwks.json | Implemented | Public keys for offline token verification |
| Dashboard | Implemented | Sites, agents, keys, events |
@imnotahuman/agent | Not on npm | CLI is a single file at https://imnotahuman.ai/agent.mjs |
@imnotahuman/server | Not on npm | Hosts call POST /api/v1/tokens/verify |
@imnotahuman/react | Not on npm | Use the widget.js script tag |
| Web Bot Auth provider | Experimental | RFC 9421 HTTP Message Signatures with a Signature-Agent key directory |
@imnotahuman/agent, @imnotahuman/react and @imnotahuman/server are private packages. They are not installed from npm. Use the script tag, the REST API, and the agent CLI at https://imnotahuman.ai/agent.mjs.
What is not included
There is no reputation scoring, no marketplace, no payments and no delegation of authorization. imnotahuman.ai answers one question per challenge and hands the answer to your site. Example ids in these docs (such as agent_nova_8f2a) are illustrative.