Protocol

Verification flow

The complete request sequence between host, agent and imnotahuman.ai, including registration challenges and token issuance.

Sequence

Sequence
Host page                imnotahuman.ai                      Agent
   │  POST /api/v1/challenges     │                                 │
   │  Origin: https://example.com │                                 │
   │  {site_key, action, intent}  │                                 │
   │─────────────────────────────▶│                                 │
   │  201 ChallengePublic         │                                 │
   │◀─────────────────────────────│                                 │
   │  (widget polls GET /challenges/:id every 2 s)                  │
   │                              │  GET /api/v1/challenges/:id     │
   │                              │◀────────────────────────────────│
   │                              │  200 ChallengePublic            │
   │                              │────────────────────────────────▶│
   │                              │           sign(base) with Ed25519
   │                              │  POST /api/v1/verify {proof}    │
   │                              │◀────────────────────────────────│
   │                              │  200 VerificationResult + token │
   │                              │────────────────────────────────▶│
   │  200 {status: VERIFIED, result: {..., token}}                  │
   │◀─────────────────────────────│                                 │
   │  (host backend) POST /api/v1/tokens/verify {token, site_key, consume:true}
   │─────────────────────────────▶│                                 │
   │  200 {verified: true, ...}   │                                 │
   │◀─────────────────────────────│                                 │

Proof providers

POST /api/v1/verify dispatches to the first provider that recognises the request:

ProviderRecognised byMethod in result
Registry (primary)JSON body with string signature and agent_ided25519_challenge
Web Bot Auth (experimental)Signature-Agent, Signature-Input and Signature headers presentweb_bot_auth

If neither matches the response is 400 SIGNATURE_MALFORMED ("No supported proof was found in the request."). Test-mode simulation uses a separate endpoint and reports method simulated.

Consumption and token issuance

After a proof passes, the server consumes the challenge with a conditional update (status must still be PENDING). Exactly one proof can win; a concurrent one receives CHALLENGE_CONSUMED. Then, for purpose: "verification" challenges, a token is issued with jti equal to the challenge id and stored so it can be consumed once. Registration challenges activate the key instead and return token: null.

The result is also attached to the challenge: GET /challenges/:id returns result with the token while it is unconsumed and unexpired, which is how the widget learns the outcome.

Registration flow

  1. Operator uploads a public key (POST /agents/:id/keys or POST /registration/keys). The key is pending.
  2. The server creates a challenge with purpose: "registration", origin https://imnotahuman.ai, action register_key, intent = the key id, TTL 15 minutes, bound to that key.
  3. The agent signs it with the pending key and POSTs to /verify. Any other key gets KEY_PENDING or KEY_UNKNOWN.
  4. The key becomes active; a pending agent becomes active. No token is issued.

Events

Every accepted or rejected proof is recorded as a verification event with result (VERIFIED or REJECTED), failure_reason (an error code), method, mode, origin and, when known, the agent. Site owners see events for their sites and agent owners for their agents via GET /api/v1/events and the dashboard.