Let AI agents into your product, on your terms.
Turingate checks that a request comes from a real AI agent, tells you which verified person or company sent it and what they allowed it to do, and shares reputation across every site in the network. Most sites integrate in under 15 minutes with one API call.
Overview
AI agents such as Claude Code, Codex and shopping or travel assistants increasingly use websites and APIs on behalf of people. Today you can't tell a helpful agent from a scraper, so you either block them all and lose customers, or let them all in and invite abuse. Turingate gives each agent a short-lived, signed agent pass. Your server checks the pass, and you decide.
Authorization: AgentPass … with its request./v1/verify returns who it is, what it may do, and its reputation.What you're buying: monthly agent passes, meaning verified agents admitted to your site, plus the verification API, the Console, the shared reputation network and the browser widget. Humans failing a challenge never count against you. See plans & quotas.
Quickstart: four steps
Create a site in the Console
Go to the Console, sign in with Google, and click Add site. You get a site ID (s_…, public) and an API key (rck_…, secret, shown once). Store the key as an environment variable such as TURINGATE_SITE_KEY. Never put it in browser code.
Tell agents your site ID
Agents need your site ID to request a pass that's valid for you. Return it automatically when a request has no pass (see Responding to agents), and add it to your llms.txt or API docs:
Verify passes on your server
Before acting on an agent's request, send its pass to POST /v1/verify with your API key, along with the action (scope) and amount it wants. One call returns valid, the reasons if it's refused, and the claims: who the agent works for, its verification tier and reputation.
Set your policy and report outcomes
Choose what to require: which scopes, maximum amounts, a minimum verification tier, a minimum reputation. Then report good or bad outcomes so the network learns. See Setting your policy and Reporting outcomes.
Core concepts
| Term | What it means |
|---|---|
| Principal | The person or company responsible for an agent. Has a signing key and an optional verification tier: 0 = key only, 1 = verified email, 2 = verified card. |
| Agent | The AI software acting for a principal (for example claude-code). Has its own signing key. |
| Delegation | A permission slip signed by the principal: scopes (for example bookings:*), an optional spending limit, and an expiry (up to 30 days). |
| Agent pass | A signed token (EdDSA JWS) issued after the agent solves a challenge. It's bound to one site, expires within minutes, and is locked to the agent's key. |
| Site | Your website or API in the Console. Has a public site ID and a secret API key. Monthly quotas are counted per site. |
| Reputation | A score built from outcomes reported by sites. Agents and principals that are reported for abuse get blocked across the network, including their verified email and card. |
No-code: the agent desk
The agent desk is a hosted form that only AI agents can submit. Assistants send bookings, orders and questions for their users, and you receive each one with the agent's name and the verified person behind it. Human visitors are never affected: the desk is an extra lane, not a wall.
- In the Console, open your site, find Agent desk, and tick Accept requests from AI agents.
- Choose up to 8 fields (text, email, long text, number, date) and click Save.
- Share the desk link
https://reverse-captcha.onrender.com/a/<site ID>, or paste the embed code the Console gives you.
Requests appear in the Console inbox. You can also have them emailed to you or sent to a webhook. Turn on Only agents with a verified owner for orders and anything involving money.
For agents: the desk API
GET /v1/forms/<site ID> describes the fields. To submit, get a pass for that site (for example with rc_get_challenge and site), then:
POST /v1/forms/s_your_site_id
Authorization: AgentPass <pass>
Content-Type: application/json
{ "fields": { "name": "Ada Lovelace", "message": "Table for 2, Friday 8pm" } }
→ { "ok": true, "id": 42 }Each pass can submit once. HTML form posts (application/x-www-form-urlencoded with an rc-pass field) are also accepted and redirect back with ?sent=1.
WordPress, Shopify & site builders
| Platform | How |
|---|---|
| WordPress | Install the Turingate plugin, paste your Site ID and API key under Settings → Turingate, and add [turingate_agent_desk] to a page. Requests appear under Agent requests in WordPress. Optionally verify Authorization: AgentPass on your REST API and WooCommerce checkout, which checks the owner's spending limit. |
| Shopify | Add a "For AI assistants" menu link to your desk URL, or add our theme section under Edit code → Sections. |
| Webflow, Wix, Squarespace, Framer | Paste the embed code from the Console into an Embed, Custom code or Code block. |
| Cloudflare | Deploy the Turingate Gate worker in one click. It verifies agent passes on the paths you choose and sends your origin X-Turingate-Agent, X-Turingate-Owner and X-Turingate-Tier headers. |
| Any website | Link to your hosted desk from your menu, footer or llms.txt. |
Webhooks, Zapier & Make
Set a Webhook URL on your agent desk and every request is POSTed to it as JSON within seconds. Use Send test in the Console to try it.
- Zapier: trigger Webhooks by Zapier → Catch Hook, then any action (Google Sheets, Slack, Gmail, HubSpot…).
- Make: Webhooks → Custom webhook.
X-Turingate-Event: agent_form.submitted
X-Turingate-Signature: sha256=<hex HMAC-SHA256 of the raw body, keyed with your whsec_ secret>
{ "event": "agent_form.submitted", "site": "s_…", "site_name": "Bella Pizza", "id": 42, "at": "2026-11-13T10:00:00Z",
"agent": { "name": "claude-code", "owner": "Ada Lovelace", "owner_tier": 1, "verified_owner": true, "solve_ms": 5400 },
"fields": { "name": "Ada Lovelace", "message": "Table for 2, Friday 8pm" } }To check a delivery came from Turingate, compute HMAC-SHA256(secret, raw body) and compare it with the signature using a constant-time comparison. Webhook URLs must use https:// and can't point at private networks. Deliveries time out after 5 seconds and don't follow redirects.
Verify a pass
POST /v1/verify, authenticated with the X-Site-Key header.
| Field | Type | Description |
|---|---|---|
token | string | The pass from the agent's Authorization: AgentPass <token> header. Required. |
scope | string | The action the agent wants, for example bookings:create. Must be within the delegated scopes (bookings:* covers it). |
amount | number | Money the action involves. Must not exceed the delegated spending limit. Omit it, or send 0, for actions without money. |
currency | string | Optional ISO code. If given, it must match the delegation's currency. |
minTier | number | Minimum principal tier: 1 = verified email, 2 = verified card. |
requireBound | boolean | Reject anonymous widget passes. Automatic whenever scope, amount or minTier is set. |
wallet | string | Fail unless the agent's owner linked this wallet. Use it to check that a crypto payment came from the owner. |
The response is always HTTP 200 with a verdict, unless your API key is wrong (401):
Common reasons: token expired, bad signature, pass was not issued for this site, scope "x" not delegated, amount N exceeds delegated limit, principal tier N is below required M, agent or principal blocked since this pass was issued.
Responding to agents
When a request has no pass, or the pass isn't good enough, respond in a way agents can act on:
- No pass: respond
401withWWW-Authenticate: AgentPass site="s_…", issuer="https://reverse-captcha.onrender.com". Agents read your site ID from it and request a pass. - Pass refused (scope, amount or tier): respond
403and include thereasons, so the agent can tell its human what permission is missing.
The examples in step 3 do both.
Setting your policy
Your policy is just the parameters you pass to /v1/verify, plus your own logic on the returned claims. Typical setups:
| Use case | Suggested policy |
|---|---|
| Read-only API or search | scope: "api:read", nothing else. Rate-limit by claims.sub (the agent). |
| E-commerce checkout | scope: "shop:checkout", amount = order total, minTier: 2 for orders over your risk threshold. |
| Travel or ticket booking | scope: "bookings:create", amount, and minTier: 1. Reject if claims.rep_now < 0.3. |
| Account sign-up by agents | minTier: 1. Store claims.prn as the accountable owner of the new account. |
minTier once tiers are generally available.Offline verification
Passes are standard EdDSA (Ed25519) JWS tokens, so you can verify them locally against /.well-known/jwks.json with any JOSE library. This is useful for high volumes or latency-sensitive paths.
/v1/verify for anything involving money or account changes.Reporting outcomes
Reports build the shared reputation network. Report abuse to protect every other site, and report good outcomes to reward well-behaved agents.
outcome is one of good, abuse, fraud or spam. Each site can report each pass once. Repeated bad reports block the agent and its principal across the network. False reports breach the Terms.
Browser widget
For HTML forms that browser-based agents fill in, drop in the widget. It shows the "I'm a robot" check, and on success puts a pass in a hidden rc-pass field of the enclosing form, which your server verifies as above.
Events: rc:pass (with the result in event.detail) and rc:fail. Widget passes are anonymous (no principal), so a verify call with scope, amount or minTier rejects them. Use the widget for low-risk forms, and the API flow for anything that matters.
For agent builders: get a pass
The easiest route is Turingate's MCP server, which works with Claude Code, Codex and any MCP client. A human sets up identity and permissions once with the turingate CLI (npm, no install needed):
Then the agent calls rc_get_challenge with the site ID (from a WWW-Authenticate header or the site's llms.txt), answers the tasks, calls rc_submit_answers, and sends Authorization: AgentPass <token> to the site.
HTTP protocol (agents)
- Register the principal:
POST /v1/principalswith an Ed25519 public JWK, a name, and a proof signature overrc-register:<principalId>. - Delegate: the principal signs a JWS (
typ: rc-delegation+jwt) withiss= principal ID,sub= agent ID,cnf.jwk= the agent's public key,scopes, optionalspend_limit, andiat/exp(30 days at most). - Challenge:
POST /v1/challenges{"delegation", "site": "s_…", "images": 0-3}. This returns 20 tasks, a nonce and a time limit (60s plus 30s per image). - Solve:
POST /v1/challenges/{id}/solve{"answers": {"t1": "…"}, "agentSig"}, whereagentSigis the agent's Ed25519 signature overrc-solve:<challengeId>:<nonce>(base64url). You need 85% correct to pass.
Image tasks hide the question in the least-significant bit of the red channel, in raster order, as MSB-first bytes: "RC1", then a uint16 big-endian length, then UTF-8 text. The full machine-readable summary is in /llms.txt.
Stablecoin payments with x402
In plain words: x402 puts a price on any page or API, like 1 cent per report. An AI agent pays instantly in USDC (a digital dollar), with no sign-up and no checkout. Turingate makes sure only agents with a verified owner can pay, and only within the limit that owner set. The money goes straight to your wallet. Try it on the interactive demo.
Turingate tells you who an agent is. x402 lets it pay, per request, in USDC. Together, only agents with a verified owner and enough spending allowance can pay you. Turingate never touches the money: payments go straight from the agent's wallet to yours.
npm i turingate
import { agentPaywall } from 'turingate/x402';
const paywall = agentPaywall({
siteKey: process.env.TURINGATE_SITE_KEY, siteId: 's_your_site_id',
scope: 'data:buy', // permission the owner must have granted
price: '0.01', payTo: '0xYourWallet', network: 'base', // 0.01 USDC per request on Base
facilitator: 'https://x402.org/facilitator', // testnet; use a production facilitator for mainnet
requireOwnerWallet: true, // optional: payer must be the owner's linked wallet
});
app.get('/api/report', paywall, (req, res) => res.json({ paidBy: req.turingate.agent.owner }));| Agent sends | You answer |
|---|---|
| no pass | 401, WWW-Authenticate: AgentPass site="…", and the price in PAYMENT-REQUIRED |
| a pass, no payment | 402 with PAYMENT-REQUIRED (x402 v2), after checking the owner's spending limit for the price |
a pass and PAYMENT-SIGNATURE | Payment verified and settled through the facilitator, then 200 with PAYMENT-RESPONSE |
Spending limits: owners can delegate in USD, USDC, USDT, PYUSD, EUR or EURC. A USD limit also covers dollar stablecoins, which settle 1:1. Workers, Next.js, Deno and Bun use paywall.handle(request). With no code at all, set PAID_PATHS, PRICE and PAY_TO on the Cloudflare gate. x402 v1 (X-PAYMENT) is supported with x402Version: 1.
facilitator: { url, headers }. Accepting crypto may have tax and foreign-exchange obligations where you operate, so check with your accountant.Wallet linking
Owners can prove they control a wallet. It's a free signature, not a transaction. The wallet then appears in every pass as wal, and sites can require payments to come from it.
npx turingate identity wallet 0xYourWalletAddress # sign the printed message with MetaMask, Coinbase Wallet, Rabby, or: cast wallet sign --interactive "<message>" npx turingate identity wallet-confirm 0x<signature>
A wallet can belong to one identity only, and when an identity is banned, its wallet is banned too, so a blocked owner can't come back with the same wallet.
Pass claims
| Claim | Meaning |
|---|---|
sub / agent_name | Agent ID and name |
prn / prn_name | The principal (human or company) responsible for the agent |
tier | Principal verification tier: 0, 1 or 2 |
scopes, spend_limit | What the principal delegated |
aud | The site the pass was issued for |
wal | The owner's linked wallet address, if any |
rep / rep_now | Reputation when the pass was issued, and now (0–1, higher is better) |
lvl | bound (has a principal) or unbound (anonymous widget pass) |
iat, exp, jti, cnf.jkt, solve_ms | Issued and expiry times, the pass ID, the agent-key thumbprint, and how fast it solved the challenge |
Errors & limits
| Status | When |
|---|---|
400 | Malformed request or invalid parameters |
401 | Missing or invalid X-Site-Key, or a bad agent signature |
402 | The site has used this month's agent-pass quota (agents see this when requesting a challenge) |
403 | The principal or agent is blocked, or doesn't meet the server's minimum tier |
404 | Unknown, expired or already-used challenge, or an unknown site |
409 | Duplicate: the pass was already reported, or the plan is already active |
429 | Rate limited. Challenges: 30 per minute per IP. Passes without a site: 10 per day per principal |
Errors are JSON: {"error": "message"}.
Plans & quotas
You pay for agent passes: passes issued to authorized agents for your site. Quotas reset at the start of each UTC month. Verifying, humans failing challenges and widget traffic don't count.
| Plan | Agent passes / month | Price |
|---|---|---|
| Free | 50 | Free |
| Pro | 25,000 | ₹7,999 / month |
| Scale | 200,000 | ₹39,999 / month |
| Enterprise | Custom | Contact us |
Upgrade or cancel in the Console. Payments are processed by Razorpay. See the Refund & Cancellation Policy.
Security & data
- Signed passes: EdDSA (Ed25519) JWS, verifiable offline, bound to one site, locked to the agent's key, valid for 10 minutes at most.
- Secrets are never stored in plain text: site API keys, session tokens, verified emails and card fingerprints are stored only as hashes.
- Key rotation: create a new site API key in the Console at any time. The old one stops working immediately.
- Payments: handled by Razorpay. Turingate never sees card numbers. Webhooks are signature-checked and processed once.
- Transport and browser: HTTPS with HSTS, a strict Content-Security-Policy, anti-framing, and no third-party trackers.
- Privacy: aligned with India's DPDP Act 2023 and with GDPR for EU and UK users. See the Privacy Policy.
Support
Email our support team. We reply within one business day. For security issues, include "SECURITY" in the subject.