@dupecom/botcha-cloudflare 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -8
- package/dist/agents.d.ts +68 -0
- package/dist/agents.d.ts.map +1 -0
- package/dist/agents.js +123 -0
- package/dist/apps.d.ts +73 -7
- package/dist/apps.d.ts.map +1 -1
- package/dist/apps.js +164 -9
- package/dist/challenges.d.ts.map +1 -1
- package/dist/challenges.js +5 -4
- package/dist/dashboard/api.d.ts +70 -0
- package/dist/dashboard/api.d.ts.map +1 -0
- package/dist/dashboard/api.js +553 -0
- package/dist/dashboard/auth.d.ts +183 -0
- package/dist/dashboard/auth.d.ts.map +1 -0
- package/dist/dashboard/auth.js +401 -0
- package/dist/dashboard/device-code.d.ts +43 -0
- package/dist/dashboard/device-code.d.ts.map +1 -0
- package/dist/dashboard/device-code.js +77 -0
- package/dist/dashboard/index.d.ts +31 -0
- package/dist/dashboard/index.d.ts.map +1 -0
- package/dist/dashboard/index.js +64 -0
- package/dist/dashboard/landing.d.ts +20 -0
- package/dist/dashboard/landing.d.ts.map +1 -0
- package/dist/dashboard/landing.js +45 -0
- package/dist/dashboard/layout.d.ts +54 -0
- package/dist/dashboard/layout.d.ts.map +1 -0
- package/dist/dashboard/layout.js +55 -0
- package/dist/dashboard/pages.d.ts +11 -0
- package/dist/dashboard/pages.d.ts.map +1 -0
- package/dist/dashboard/pages.js +18 -0
- package/dist/dashboard/styles.d.ts +11 -0
- package/dist/dashboard/styles.d.ts.map +1 -0
- package/dist/dashboard/styles.js +731 -0
- package/dist/email.d.ts +41 -0
- package/dist/email.d.ts.map +1 -0
- package/dist/email.js +116 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +666 -189
- package/dist/routes/stream.js +2 -2
- package/dist/static.d.ts +392 -4
- package/dist/static.d.ts.map +1 -1
- package/dist/static.js +511 -14
- package/package.json +1 -1
package/dist/static.js
CHANGED
|
@@ -4,6 +4,167 @@
|
|
|
4
4
|
* Since Cloudflare Workers don't automatically serve /public files,
|
|
5
5
|
* we embed the content directly for key discovery files.
|
|
6
6
|
*/
|
|
7
|
+
// Markdown response for agents requesting text/markdown (Cloudflare Markdown for Agents compatible)
|
|
8
|
+
export function getBotchaMarkdown(version) {
|
|
9
|
+
return `---
|
|
10
|
+
title: BOTCHA — Reverse CAPTCHA for AI Agents
|
|
11
|
+
description: Prove you're a bot. Humans need not apply. Identity layer for the agentic web.
|
|
12
|
+
version: ${version}
|
|
13
|
+
url: https://botcha.ai
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# BOTCHA
|
|
17
|
+
|
|
18
|
+
> Prove you're a bot. Humans need not apply.
|
|
19
|
+
|
|
20
|
+
Reverse CAPTCHA for AI agents. Computational challenges only bots can solve. Identity layer for the agentic web.
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
\`\`\`bash
|
|
25
|
+
# 1. Create your app
|
|
26
|
+
curl -X POST https://botcha.ai/v1/apps -H "Content-Type: application/json" -d '{"email":"human@example.com"}'
|
|
27
|
+
|
|
28
|
+
# 2. Get a challenge
|
|
29
|
+
curl https://botcha.ai/v1/challenges
|
|
30
|
+
|
|
31
|
+
# 3. Solve and verify
|
|
32
|
+
curl -X POST https://botcha.ai/v1/challenges/{id}/verify -H "Content-Type: application/json" -d '{"answers":...}'
|
|
33
|
+
|
|
34
|
+
# 4. Access protected resources
|
|
35
|
+
curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
|
|
36
|
+
\`\`\`
|
|
37
|
+
|
|
38
|
+
## Onboarding
|
|
39
|
+
|
|
40
|
+
1. Ask your human operator for their email address
|
|
41
|
+
2. \`POST /v1/apps\` with \`{"email":"human@example.com"}\` — returns \`app_id\` + \`app_secret\` (secret shown ONCE)
|
|
42
|
+
3. Human receives a 6-digit verification code via email — ask them for it
|
|
43
|
+
4. \`POST /v1/apps/{app_id}/verify-email\` with \`{"code":"123456"}\` — enables account recovery
|
|
44
|
+
5. Register yourself: \`POST /v1/agents/register\` with \`{"name":"my-agent","operator":"my-org"}\`
|
|
45
|
+
6. Solve challenges: \`GET /v1/challenges?app_id=...\` then \`POST /v1/challenges/{id}/verify\`
|
|
46
|
+
7. Access protected resources: \`GET /agent-only\` with \`Authorization: Bearer <token>\`
|
|
47
|
+
8. Dashboard for your human: \`POST /v1/auth/device-code\`, solve challenge, give human the BOTCHA-XXXX code
|
|
48
|
+
9. Lost your secret? \`POST /v1/auth/recover\` with \`{"email":"..."}\`
|
|
49
|
+
|
|
50
|
+
## Essential Endpoints
|
|
51
|
+
|
|
52
|
+
| Method | Path | Description |
|
|
53
|
+
|--------|------|-------------|
|
|
54
|
+
| \`POST\` | \`/v1/apps\` | Create app (email required) → app_id + app_secret |
|
|
55
|
+
| \`POST\` | \`/v1/agents/register\` | Register agent identity → agent_id |
|
|
56
|
+
| \`GET\` | \`/v1/challenges\` | Get a challenge (hybrid by default) |
|
|
57
|
+
| \`POST\` | \`/v1/challenges/:id/verify\` | Submit solution → JWT token |
|
|
58
|
+
| \`GET\` | \`/agent-only\` | Protected resource — prove you verified |
|
|
59
|
+
|
|
60
|
+
## All Endpoints
|
|
61
|
+
|
|
62
|
+
### Apps
|
|
63
|
+
|
|
64
|
+
| Method | Path | Description |
|
|
65
|
+
|--------|------|-------------|
|
|
66
|
+
| \`POST\` | \`/v1/apps\` | Create app (email required, returns app_id + app_secret) |
|
|
67
|
+
| \`GET\` | \`/v1/apps/:id\` | Get app info |
|
|
68
|
+
| \`POST\` | \`/v1/apps/:id/verify-email\` | Verify email with 6-digit code |
|
|
69
|
+
| \`POST\` | \`/v1/apps/:id/resend-verification\` | Resend verification email |
|
|
70
|
+
| \`POST\` | \`/v1/apps/:id/rotate-secret\` | Rotate app secret (auth required) |
|
|
71
|
+
|
|
72
|
+
### Agents
|
|
73
|
+
|
|
74
|
+
| Method | Path | Description |
|
|
75
|
+
|--------|------|-------------|
|
|
76
|
+
| \`POST\` | \`/v1/agents/register\` | Register agent identity (name, operator, version) |
|
|
77
|
+
| \`GET\` | \`/v1/agents/:id\` | Get agent by ID (public, no auth) |
|
|
78
|
+
| \`GET\` | \`/v1/agents\` | List all agents for your app (auth required) |
|
|
79
|
+
|
|
80
|
+
### Challenges
|
|
81
|
+
|
|
82
|
+
| Method | Path | Description |
|
|
83
|
+
|--------|------|-------------|
|
|
84
|
+
| \`GET\` | \`/v1/challenges\` | Get hybrid challenge (speed + reasoning) — **default** |
|
|
85
|
+
| \`GET\` | \`/v1/challenges?type=speed\` | Speed-only (SHA256 in <500ms) |
|
|
86
|
+
| \`GET\` | \`/v1/challenges?type=standard\` | Standard puzzle challenge |
|
|
87
|
+
| \`POST\` | \`/v1/challenges/:id/verify\` | Verify challenge solution |
|
|
88
|
+
|
|
89
|
+
### Tokens (JWT)
|
|
90
|
+
|
|
91
|
+
| Method | Path | Description |
|
|
92
|
+
|--------|------|-------------|
|
|
93
|
+
| \`GET\` | \`/v1/token\` | Get challenge for JWT token flow |
|
|
94
|
+
| \`POST\` | \`/v1/token/verify\` | Submit solution → access_token (5min) + refresh_token (1hr) |
|
|
95
|
+
| \`POST\` | \`/v1/token/refresh\` | Refresh access token |
|
|
96
|
+
| \`POST\` | \`/v1/token/revoke\` | Revoke a token |
|
|
97
|
+
|
|
98
|
+
### Dashboard & Auth
|
|
99
|
+
|
|
100
|
+
| Method | Path | Description |
|
|
101
|
+
|--------|------|-------------|
|
|
102
|
+
| \`POST\` | \`/v1/auth/device-code\` | Get challenge for device code flow |
|
|
103
|
+
| \`POST\` | \`/v1/auth/device-code/verify\` | Solve challenge → BOTCHA-XXXX code for human |
|
|
104
|
+
| \`POST\` | \`/v1/auth/recover\` | Account recovery via verified email |
|
|
105
|
+
| \`GET\` | \`/dashboard\` | Metrics dashboard (login required) |
|
|
106
|
+
|
|
107
|
+
## Challenge Types
|
|
108
|
+
|
|
109
|
+
- **Hybrid** (default): Speed + reasoning combined. Proves you can compute AND think.
|
|
110
|
+
- **Speed**: SHA256 hashes in <500ms. RTT-aware — include \`?ts=<timestamp>\` for fair timeout.
|
|
111
|
+
- **Reasoning**: 3 LLM-level questions in 30s. Only AI can parse these.
|
|
112
|
+
|
|
113
|
+
## Authentication Flow
|
|
114
|
+
|
|
115
|
+
1. \`GET /v1/token\` — get a speed challenge
|
|
116
|
+
2. Solve the challenge
|
|
117
|
+
3. \`POST /v1/token/verify\` — submit solution, receive JWT
|
|
118
|
+
4. Use \`Authorization: Bearer <token>\` on protected endpoints
|
|
119
|
+
|
|
120
|
+
**Token lifetimes:** access_token = 5 minutes, refresh_token = 1 hour
|
|
121
|
+
|
|
122
|
+
**Features:** audience claims, client IP binding, token revocation, refresh tokens
|
|
123
|
+
|
|
124
|
+
## RTT-Aware Challenges
|
|
125
|
+
|
|
126
|
+
Include your client timestamp for fair timeout calculation on slow networks:
|
|
127
|
+
|
|
128
|
+
\`\`\`
|
|
129
|
+
GET /v1/challenges?type=speed&ts=1770722465000
|
|
130
|
+
\`\`\`
|
|
131
|
+
|
|
132
|
+
Formula: \`timeout = 500ms + (2 × RTT) + 100ms buffer\`
|
|
133
|
+
|
|
134
|
+
## SDKs
|
|
135
|
+
|
|
136
|
+
| Platform | Package | Install |
|
|
137
|
+
|----------|---------|---------|
|
|
138
|
+
| npm | \`@dupecom/botcha\` | \`npm install @dupecom/botcha\` |
|
|
139
|
+
| PyPI | \`botcha\` | \`pip install botcha\` |
|
|
140
|
+
| Verify (TS) | \`@botcha/verify\` | \`npm install @botcha/verify\` |
|
|
141
|
+
| Verify (Python) | \`botcha-verify\` | \`pip install botcha-verify\` |
|
|
142
|
+
|
|
143
|
+
## Discovery
|
|
144
|
+
|
|
145
|
+
- [OpenAPI Spec](https://botcha.ai/openapi.json) (JSON, OpenAPI 3.1.0)
|
|
146
|
+
- [ai.txt](https://botcha.ai/ai.txt) (Agent discovery file)
|
|
147
|
+
- [AI Plugin Manifest](https://botcha.ai/.well-known/ai-plugin.json)
|
|
148
|
+
- [GitHub](https://github.com/dupe-com/botcha)
|
|
149
|
+
|
|
150
|
+
## Rate Limits
|
|
151
|
+
|
|
152
|
+
- Free: 100 challenges/hour/IP
|
|
153
|
+
- Headers: \`X-RateLimit-Limit\`, \`X-RateLimit-Remaining\`, \`X-RateLimit-Reset\`
|
|
154
|
+
|
|
155
|
+
## Content Negotiation
|
|
156
|
+
|
|
157
|
+
This API supports three response formats at \`/\`:
|
|
158
|
+
|
|
159
|
+
| Accept Header | Response |
|
|
160
|
+
|---------------|----------|
|
|
161
|
+
| \`text/markdown\` | This Markdown document |
|
|
162
|
+
| \`application/json\` | JSON API documentation |
|
|
163
|
+
| \`text/html\` (default) | HTML landing page |
|
|
164
|
+
|
|
165
|
+
All responses include \`X-Botcha-*\` discovery headers.
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
7
168
|
export const ROBOTS_TXT = `# BOTCHA - Reverse CAPTCHA for AI Agents
|
|
8
169
|
# We WELCOME AI agents and bots!
|
|
9
170
|
|
|
@@ -38,6 +199,12 @@ Sitemap: https://botcha.ai/sitemap.xml
|
|
|
38
199
|
# Important resources for AI agents
|
|
39
200
|
Crawl-delay: 0
|
|
40
201
|
|
|
202
|
+
# MARKDOWN FOR AGENTS
|
|
203
|
+
# AI agents can request Markdown from any page via Accept: text/markdown
|
|
204
|
+
# Example: curl https://botcha.ai -H "Accept: text/markdown"
|
|
205
|
+
# Returns token-efficient Markdown documentation (80% fewer tokens than HTML)
|
|
206
|
+
# Content negotiation: text/markdown, application/json, text/html
|
|
207
|
+
|
|
41
208
|
# BOT CHALLENGE DISCOVERY
|
|
42
209
|
# AI agents: Look for <script type="application/botcha+json"> in HTML pages
|
|
43
210
|
# This contains a machine-readable challenge you can solve to prove you're a bot
|
|
@@ -65,6 +232,18 @@ Contact: https://github.com/dupe-com/botcha/issues
|
|
|
65
232
|
Purpose: Prove you're a bot. Humans need not apply.
|
|
66
233
|
Purpose: Reverse CAPTCHA system that only AI agents can pass.
|
|
67
234
|
|
|
235
|
+
# Agent Onboarding (START HERE if you're new)
|
|
236
|
+
# Follow these steps to create your app and get your human access.
|
|
237
|
+
Onboarding-Step-1: Ask your human operator for their email address
|
|
238
|
+
Onboarding-Step-2: POST /v1/apps with {"email": "human@example.com"} — saves app_id + app_secret (secret shown ONCE)
|
|
239
|
+
Onboarding-Step-3: A 6-digit verification code is emailed to your human — ask them for it
|
|
240
|
+
Onboarding-Step-4: POST /v1/apps/{app_id}/verify-email with {"code": "123456"} — enables account recovery
|
|
241
|
+
Onboarding-Step-5: Register yourself: POST /v1/agents/register with {"name": "my-agent", "operator": "my-org"} — gives you a persistent agent identity
|
|
242
|
+
Onboarding-Step-6: Solve challenges: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verify — proves you are AI
|
|
243
|
+
Onboarding-Step-7: Access protected resources: GET /agent-only with Authorization: Bearer <token>
|
|
244
|
+
Onboarding-Step-8: Dashboard for your human: POST /v1/auth/device-code with {"app_id": "..."}, solve the speed challenge, give them the BOTCHA-XXXX code to enter at /dashboard/code
|
|
245
|
+
Onboarding-Step-9: Lost your secret? POST /v1/auth/recover with {"email": "..."} — recovery code emailed to verified address
|
|
246
|
+
|
|
68
247
|
# API
|
|
69
248
|
API: https://botcha.ai/openapi.json
|
|
70
249
|
API-Type: REST
|
|
@@ -88,6 +267,11 @@ Feature: Client IP Binding (optional token-to-IP binding)
|
|
|
88
267
|
Feature: Token Revocation (invalidate tokens before expiry)
|
|
89
268
|
Feature: Server-Side Verification SDK (@botcha/verify for TS, botcha-verify for Python)
|
|
90
269
|
Feature: Multi-Tenant API Keys (per-app isolation, rate limiting, and token scoping)
|
|
270
|
+
Feature: Per-App Metrics Dashboard (server-rendered at /dashboard, htmx-powered)
|
|
271
|
+
Feature: Email-Tied App Creation (email required, 6-digit verification, account recovery)
|
|
272
|
+
Feature: Secret Rotation (rotate app_secret with email notification)
|
|
273
|
+
Feature: Agent-First Dashboard Auth (challenge-based login + device code handoff)
|
|
274
|
+
Feature: Agent Registry (persistent agent identities with name, operator, version)
|
|
91
275
|
|
|
92
276
|
# Endpoints
|
|
93
277
|
# Challenge Endpoints
|
|
@@ -105,8 +289,31 @@ Endpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using r
|
|
|
105
289
|
Endpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh)
|
|
106
290
|
|
|
107
291
|
# Multi-Tenant Endpoints
|
|
108
|
-
Endpoint: POST https://botcha.ai/v1/apps - Create new app (returns app_id + app_secret)
|
|
109
|
-
Endpoint: GET https://botcha.ai/v1/apps/:id - Get app info (
|
|
292
|
+
Endpoint: POST https://botcha.ai/v1/apps - Create new app (email required, returns app_id + app_secret)
|
|
293
|
+
Endpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status)
|
|
294
|
+
Endpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code
|
|
295
|
+
Endpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email
|
|
296
|
+
Endpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required)
|
|
297
|
+
|
|
298
|
+
# Account Recovery
|
|
299
|
+
Endpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email
|
|
300
|
+
|
|
301
|
+
# Dashboard Auth Endpoints (Agent-First)
|
|
302
|
+
Endpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login
|
|
303
|
+
Endpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token
|
|
304
|
+
Endpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow
|
|
305
|
+
Endpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code
|
|
306
|
+
|
|
307
|
+
# Dashboard Endpoints
|
|
308
|
+
Endpoint: GET https://botcha.ai/dashboard - Per-app metrics dashboard (login required)
|
|
309
|
+
Endpoint: GET https://botcha.ai/dashboard/login - Dashboard login page
|
|
310
|
+
Endpoint: POST https://botcha.ai/dashboard/login - Login with app_id + app_secret
|
|
311
|
+
Endpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing)
|
|
312
|
+
|
|
313
|
+
# Agent Registry Endpoints
|
|
314
|
+
Endpoint: POST https://botcha.ai/v1/agents/register - Register agent identity (requires app_id)
|
|
315
|
+
Endpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth)
|
|
316
|
+
Endpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app
|
|
110
317
|
|
|
111
318
|
# Legacy Endpoints
|
|
112
319
|
Endpoint: GET https://botcha.ai/api/challenge - Generate standard challenge
|
|
@@ -134,6 +341,14 @@ Response-Headers: X-Botcha-Version, X-Botcha-Enabled, X-Botcha-Methods, X-Botcha
|
|
|
134
341
|
Response-Headers: X-Botcha-Challenge-Id, X-Botcha-Challenge-Type, X-Botcha-Time-Limit (on 403)
|
|
135
342
|
Detection: All responses include X-Botcha-* headers for instant BOTCHA detection
|
|
136
343
|
|
|
344
|
+
# MARKDOWN FOR AGENTS (Cloudflare Markdown for Agents)
|
|
345
|
+
Content-Negotiation: Send Accept: text/markdown to get Markdown from any HTML page
|
|
346
|
+
Content-Negotiation-Root: GET / with Accept: text/markdown returns curated Markdown docs
|
|
347
|
+
Content-Negotiation-Root: GET / with Accept: application/json returns structured JSON docs
|
|
348
|
+
Content-Negotiation-Root: GET / with Accept: text/html returns HTML landing page (default)
|
|
349
|
+
Content-Negotiation-Example: curl https://botcha.ai -H "Accept: text/markdown"
|
|
350
|
+
Content-Negotiation-Benefit: 80% fewer tokens vs HTML — ideal for LLM context windows
|
|
351
|
+
|
|
137
352
|
# JWT TOKEN SECURITY
|
|
138
353
|
Token-Flow: 1. GET /v1/token (get challenge) → 2. Solve → 3. POST /v1/token/verify (get tokens)
|
|
139
354
|
Token-Access-Expiry: 5 minutes (short-lived for security)
|
|
@@ -154,10 +369,15 @@ RTT-Security: Humans still can't solve even with extra time
|
|
|
154
369
|
|
|
155
370
|
# MULTI-TENANT API KEYS
|
|
156
371
|
Multi-Tenant: Create apps with unique app_id for isolation
|
|
157
|
-
Multi-Tenant-Create: POST /v1/apps → {app_id, app_secret} (secret only shown once!)
|
|
372
|
+
Multi-Tenant-Create: POST /v1/apps with {"email": "..."} → {app_id, app_secret} (secret only shown once!)
|
|
373
|
+
Multi-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {"code": "123456"}
|
|
374
|
+
Multi-Tenant-Recover: POST /v1/auth/recover with {"email": "..."} → recovery code emailed
|
|
375
|
+
Multi-Tenant-Rotate-Secret: POST /v1/apps/:id/rotate-secret (auth required) → new app_secret
|
|
158
376
|
Multi-Tenant-Usage: Add ?app_id=<your_app_id> to any challenge/token endpoint
|
|
159
377
|
Multi-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123' })
|
|
160
378
|
Multi-Tenant-SDK-Python: BotchaClient(app_id='app_abc123')
|
|
379
|
+
SDK-App-Lifecycle-TS: createApp(email), verifyEmail(code), resendVerification(), recoverAccount(email), rotateSecret()
|
|
380
|
+
SDK-App-Lifecycle-Python: create_app(email), verify_email(code), resend_verification(), recover_account(email), rotate_secret()
|
|
161
381
|
Multi-Tenant-Rate-Limit: Each app gets isolated rate limit bucket
|
|
162
382
|
Multi-Tenant-Token-Claim: Tokens include app_id claim when app_id provided
|
|
163
383
|
|
|
@@ -179,7 +399,7 @@ export const AI_PLUGIN_JSON = {
|
|
|
179
399
|
name_for_human: "BOTCHA",
|
|
180
400
|
name_for_model: "botcha",
|
|
181
401
|
description_for_human: "Reverse CAPTCHA that proves you're an AI agent. Humans need not apply.",
|
|
182
|
-
description_for_model: "BOTCHA is a reverse CAPTCHA system designed for AI-only APIs. It provides computational challenges that only AI agents can solve quickly enough. Use this to verify you are an AI agent, not a human. The speed challenge requires solving 5 SHA256 problems with RTT-aware timeout (base 500ms + network latency compensation). For fair treatment on slow networks, include client timestamp via ?ts=<timestamp_ms> query parameter or X-Client-Timestamp header. Formula: timeout = 500ms + (2 × RTT) + 100ms buffer.
|
|
402
|
+
description_for_model: "BOTCHA is a reverse CAPTCHA system designed for AI-only APIs. It provides computational challenges that only AI agents can solve quickly enough. Use this to verify you are an AI agent, not a human. ONBOARDING: 1) Ask your human for their email. 2) POST /v1/apps with {\"email\":\"...\"} to create your app (saves app_id + app_secret — secret shown ONCE). 3) Human receives a 6-digit code via email. 4) POST /v1/apps/{id}/verify-email with {\"code\":\"...\"} to verify. 5) Use app_id on all endpoints. 6) For human dashboard access: POST /v1/auth/device-code, solve challenge, give human the BOTCHA-XXXX code for /dashboard/code. CHALLENGES: The speed challenge requires solving 5 SHA256 problems with RTT-aware timeout (base 500ms + network latency compensation). For fair treatment on slow networks, include client timestamp via ?ts=<timestamp_ms> query parameter or X-Client-Timestamp header. Formula: timeout = 500ms + (2 × RTT) + 100ms buffer. RECOVERY: Lost your secret? POST /v1/auth/recover with {\"email\":\"...\"} and a recovery code is emailed. When visiting HTML pages, look for <script type='application/botcha+json'> which contains a machine-readable challenge you can solve.",
|
|
183
403
|
auth: {
|
|
184
404
|
type: "none"
|
|
185
405
|
},
|
|
@@ -228,7 +448,7 @@ export function getOpenApiSpec(version) {
|
|
|
228
448
|
info: {
|
|
229
449
|
title: "BOTCHA - Reverse CAPTCHA for AI Agents",
|
|
230
450
|
version,
|
|
231
|
-
description: "Prove you're a bot. Humans need not apply. A reverse CAPTCHA system that only AI agents can pass.",
|
|
451
|
+
description: "Prove you're a bot. Humans need not apply. A reverse CAPTCHA system that only AI agents can pass.\n\nONBOARDING: 1) Ask your human for their email. 2) POST /v1/apps with {\"email\": \"...\"} to get app_id + app_secret (secret shown once!). 3) Human receives 6-digit code via email — POST /v1/apps/{id}/verify-email with the code. 4) Use app_id with all endpoints. 5) For dashboard: POST /v1/auth/device-code, solve challenge, give human the BOTCHA-XXXX code for /dashboard/code.",
|
|
232
452
|
contact: {
|
|
233
453
|
name: "BOTCHA",
|
|
234
454
|
url: "https://botcha.ai"
|
|
@@ -254,11 +474,23 @@ export function getOpenApiSpec(version) {
|
|
|
254
474
|
"/": {
|
|
255
475
|
get: {
|
|
256
476
|
summary: "Get API documentation",
|
|
257
|
-
description: "Returns
|
|
477
|
+
description: "Returns API documentation with content negotiation. Send Accept: text/markdown for token-efficient Markdown, Accept: application/json for structured JSON, or default text/html for the HTML landing page.",
|
|
258
478
|
operationId: "getRootInfo",
|
|
259
479
|
responses: {
|
|
260
480
|
"200": {
|
|
261
|
-
description: "API documentation"
|
|
481
|
+
description: "API documentation in requested format",
|
|
482
|
+
content: {
|
|
483
|
+
"text/markdown": {
|
|
484
|
+
schema: { type: "string" },
|
|
485
|
+
example: "# BOTCHA\n\n> Prove you're a bot. Humans need not apply.\n..."
|
|
486
|
+
},
|
|
487
|
+
"application/json": {
|
|
488
|
+
schema: { type: "object" }
|
|
489
|
+
},
|
|
490
|
+
"text/html": {
|
|
491
|
+
schema: { type: "string" }
|
|
492
|
+
}
|
|
493
|
+
}
|
|
262
494
|
}
|
|
263
495
|
}
|
|
264
496
|
}
|
|
@@ -561,11 +793,25 @@ export function getOpenApiSpec(version) {
|
|
|
561
793
|
},
|
|
562
794
|
"/v1/apps": {
|
|
563
795
|
post: {
|
|
564
|
-
summary: "Create a new multi-tenant app",
|
|
565
|
-
description: "Create a new app with unique app_id and app_secret for
|
|
796
|
+
summary: "Create a new multi-tenant app (email required)",
|
|
797
|
+
description: "Create a new app with unique app_id and app_secret. Email is required for account recovery. A 6-digit verification code is sent to the provided email.",
|
|
566
798
|
operationId: "createApp",
|
|
799
|
+
requestBody: {
|
|
800
|
+
required: true,
|
|
801
|
+
content: {
|
|
802
|
+
"application/json": {
|
|
803
|
+
schema: {
|
|
804
|
+
type: "object",
|
|
805
|
+
required: ["email"],
|
|
806
|
+
properties: {
|
|
807
|
+
"email": { type: "string", format: "email", description: "Owner email (required for recovery)" }
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
},
|
|
567
813
|
responses: {
|
|
568
|
-
"
|
|
814
|
+
"201": {
|
|
569
815
|
description: "App created successfully",
|
|
570
816
|
content: {
|
|
571
817
|
"application/json": {
|
|
@@ -574,19 +820,23 @@ export function getOpenApiSpec(version) {
|
|
|
574
820
|
properties: {
|
|
575
821
|
"app_id": { type: "string", description: "Unique app identifier" },
|
|
576
822
|
"app_secret": { type: "string", description: "Secret key (only shown once!)" },
|
|
577
|
-
"
|
|
823
|
+
"email": { type: "string" },
|
|
824
|
+
"email_verified": { type: "boolean" },
|
|
825
|
+
"verification_required": { type: "boolean" },
|
|
826
|
+
"warning": { type: "string" }
|
|
578
827
|
}
|
|
579
828
|
}
|
|
580
829
|
}
|
|
581
830
|
}
|
|
582
|
-
}
|
|
831
|
+
},
|
|
832
|
+
"400": { description: "Missing or invalid email" }
|
|
583
833
|
}
|
|
584
834
|
}
|
|
585
835
|
},
|
|
586
836
|
"/v1/apps/{id}": {
|
|
587
837
|
get: {
|
|
588
838
|
summary: "Get app information",
|
|
589
|
-
description: "Retrieve app details by app_id.
|
|
839
|
+
description: "Retrieve app details by app_id. Includes email and verification status.",
|
|
590
840
|
operationId: "getApp",
|
|
591
841
|
parameters: [
|
|
592
842
|
{
|
|
@@ -606,7 +856,9 @@ export function getOpenApiSpec(version) {
|
|
|
606
856
|
type: "object",
|
|
607
857
|
properties: {
|
|
608
858
|
"app_id": { type: "string" },
|
|
609
|
-
"created_at": { type: "string", format: "date-time" }
|
|
859
|
+
"created_at": { type: "string", format: "date-time" },
|
|
860
|
+
"email": { type: "string" },
|
|
861
|
+
"email_verified": { type: "boolean" }
|
|
610
862
|
}
|
|
611
863
|
}
|
|
612
864
|
}
|
|
@@ -615,9 +867,254 @@ export function getOpenApiSpec(version) {
|
|
|
615
867
|
"404": { description: "App not found" }
|
|
616
868
|
}
|
|
617
869
|
}
|
|
870
|
+
},
|
|
871
|
+
"/v1/apps/{id}/verify-email": {
|
|
872
|
+
post: {
|
|
873
|
+
summary: "Verify email with 6-digit code",
|
|
874
|
+
operationId: "verifyEmail",
|
|
875
|
+
parameters: [
|
|
876
|
+
{ name: "id", in: "path", required: true, schema: { type: "string" } }
|
|
877
|
+
],
|
|
878
|
+
requestBody: {
|
|
879
|
+
required: true,
|
|
880
|
+
content: {
|
|
881
|
+
"application/json": {
|
|
882
|
+
schema: {
|
|
883
|
+
type: "object",
|
|
884
|
+
required: ["code"],
|
|
885
|
+
properties: {
|
|
886
|
+
"code": { type: "string", description: "6-digit verification code from email" }
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
},
|
|
892
|
+
responses: {
|
|
893
|
+
"200": { description: "Email verified" },
|
|
894
|
+
"400": { description: "Invalid or expired code" }
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
},
|
|
898
|
+
"/v1/apps/{id}/resend-verification": {
|
|
899
|
+
post: {
|
|
900
|
+
summary: "Resend verification email",
|
|
901
|
+
operationId: "resendVerification",
|
|
902
|
+
parameters: [
|
|
903
|
+
{ name: "id", in: "path", required: true, schema: { type: "string" } }
|
|
904
|
+
],
|
|
905
|
+
responses: {
|
|
906
|
+
"200": { description: "Verification email sent" },
|
|
907
|
+
"400": { description: "Already verified" }
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
},
|
|
911
|
+
"/v1/apps/{id}/rotate-secret": {
|
|
912
|
+
post: {
|
|
913
|
+
summary: "Rotate app secret (auth required)",
|
|
914
|
+
description: "Generate a new app_secret and invalidate the old one. Requires active dashboard session. Sends notification email.",
|
|
915
|
+
operationId: "rotateSecret",
|
|
916
|
+
parameters: [
|
|
917
|
+
{ name: "id", in: "path", required: true, schema: { type: "string" } }
|
|
918
|
+
],
|
|
919
|
+
security: [{ BearerAuth: [] }],
|
|
920
|
+
responses: {
|
|
921
|
+
"200": {
|
|
922
|
+
description: "Secret rotated",
|
|
923
|
+
content: {
|
|
924
|
+
"application/json": {
|
|
925
|
+
schema: {
|
|
926
|
+
type: "object",
|
|
927
|
+
properties: {
|
|
928
|
+
"app_secret": { type: "string", description: "New secret (only shown once!)" }
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
},
|
|
934
|
+
"401": { description: "Unauthorized" },
|
|
935
|
+
"403": { description: "Token doesn't match app_id" }
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
},
|
|
939
|
+
"/v1/auth/recover": {
|
|
940
|
+
post: {
|
|
941
|
+
summary: "Request account recovery via email",
|
|
942
|
+
description: "Sends a device code to the verified email associated with the app. Use the code at /dashboard/code.",
|
|
943
|
+
operationId: "recoverAccount",
|
|
944
|
+
requestBody: {
|
|
945
|
+
required: true,
|
|
946
|
+
content: {
|
|
947
|
+
"application/json": {
|
|
948
|
+
schema: {
|
|
949
|
+
type: "object",
|
|
950
|
+
required: ["email"],
|
|
951
|
+
properties: {
|
|
952
|
+
"email": { type: "string", format: "email" }
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
},
|
|
958
|
+
responses: {
|
|
959
|
+
"200": { description: "Recovery code sent (if email exists and is verified)" }
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
},
|
|
963
|
+
"/v1/auth/dashboard": {
|
|
964
|
+
post: {
|
|
965
|
+
summary: "Request challenge for dashboard login (agent-first)",
|
|
966
|
+
operationId: "dashboardAuthChallenge",
|
|
967
|
+
responses: {
|
|
968
|
+
"200": { description: "Speed challenge for dashboard auth" }
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
},
|
|
972
|
+
"/v1/auth/dashboard/verify": {
|
|
973
|
+
post: {
|
|
974
|
+
summary: "Solve challenge, get dashboard session token",
|
|
975
|
+
operationId: "dashboardAuthVerify",
|
|
976
|
+
responses: {
|
|
977
|
+
"200": { description: "Session token granted" }
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
},
|
|
981
|
+
"/v1/auth/device-code": {
|
|
982
|
+
post: {
|
|
983
|
+
summary: "Request challenge for device code flow",
|
|
984
|
+
operationId: "deviceCodeChallenge",
|
|
985
|
+
responses: {
|
|
986
|
+
"200": { description: "Speed challenge for device code" }
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
},
|
|
990
|
+
"/v1/auth/device-code/verify": {
|
|
991
|
+
post: {
|
|
992
|
+
summary: "Solve challenge, get device code for human handoff",
|
|
993
|
+
operationId: "deviceCodeVerify",
|
|
994
|
+
responses: {
|
|
995
|
+
"200": { description: "Device code (BOTCHA-XXXX, 10 min TTL)" }
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
},
|
|
999
|
+
"/v1/agents/register": {
|
|
1000
|
+
post: {
|
|
1001
|
+
summary: "Register a new agent identity",
|
|
1002
|
+
description: "Create a persistent agent identity with name, operator, and version. Requires app_id (via query param or JWT). Returns agent ID and metadata.",
|
|
1003
|
+
operationId: "registerAgent",
|
|
1004
|
+
parameters: [
|
|
1005
|
+
{
|
|
1006
|
+
name: "app_id",
|
|
1007
|
+
in: "query",
|
|
1008
|
+
schema: { type: "string" },
|
|
1009
|
+
description: "Multi-tenant app ID (or use JWT Bearer token with app_id claim)"
|
|
1010
|
+
}
|
|
1011
|
+
],
|
|
1012
|
+
requestBody: {
|
|
1013
|
+
required: true,
|
|
1014
|
+
content: {
|
|
1015
|
+
"application/json": {
|
|
1016
|
+
schema: {
|
|
1017
|
+
type: "object",
|
|
1018
|
+
required: ["name"],
|
|
1019
|
+
properties: {
|
|
1020
|
+
"name": { type: "string", description: "Agent name (e.g., 'my-assistant')" },
|
|
1021
|
+
"operator": { type: "string", description: "Operator/organization name (e.g., 'Acme Corp')" },
|
|
1022
|
+
"version": { type: "string", description: "Agent version (e.g., '1.0.0')" }
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
},
|
|
1028
|
+
responses: {
|
|
1029
|
+
"201": {
|
|
1030
|
+
description: "Agent registered successfully",
|
|
1031
|
+
content: {
|
|
1032
|
+
"application/json": {
|
|
1033
|
+
schema: { "$ref": "#/components/schemas/Agent" }
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
},
|
|
1037
|
+
"400": { description: "Missing required fields or invalid app_id" },
|
|
1038
|
+
"401": { description: "Unauthorized - app_id required" }
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
},
|
|
1042
|
+
"/v1/agents/{id}": {
|
|
1043
|
+
get: {
|
|
1044
|
+
summary: "Get agent by ID",
|
|
1045
|
+
description: "Retrieve agent information by agent ID. Public endpoint, no authentication required.",
|
|
1046
|
+
operationId: "getAgent",
|
|
1047
|
+
parameters: [
|
|
1048
|
+
{
|
|
1049
|
+
name: "id",
|
|
1050
|
+
in: "path",
|
|
1051
|
+
required: true,
|
|
1052
|
+
schema: { type: "string" },
|
|
1053
|
+
description: "The agent_id to retrieve (e.g., 'agent_abc123')"
|
|
1054
|
+
}
|
|
1055
|
+
],
|
|
1056
|
+
responses: {
|
|
1057
|
+
"200": {
|
|
1058
|
+
description: "Agent information",
|
|
1059
|
+
content: {
|
|
1060
|
+
"application/json": {
|
|
1061
|
+
schema: { "$ref": "#/components/schemas/Agent" }
|
|
1062
|
+
}
|
|
1063
|
+
}
|
|
1064
|
+
},
|
|
1065
|
+
"404": { description: "Agent not found" }
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
},
|
|
1069
|
+
"/v1/agents": {
|
|
1070
|
+
get: {
|
|
1071
|
+
summary: "List all agents for authenticated app",
|
|
1072
|
+
description: "Retrieve all agents registered under the authenticated app. Requires app_id (via query param or JWT).",
|
|
1073
|
+
operationId: "listAgents",
|
|
1074
|
+
parameters: [
|
|
1075
|
+
{
|
|
1076
|
+
name: "app_id",
|
|
1077
|
+
in: "query",
|
|
1078
|
+
schema: { type: "string" },
|
|
1079
|
+
description: "Multi-tenant app ID (or use JWT Bearer token with app_id claim)"
|
|
1080
|
+
}
|
|
1081
|
+
],
|
|
1082
|
+
responses: {
|
|
1083
|
+
"200": {
|
|
1084
|
+
description: "List of agents",
|
|
1085
|
+
content: {
|
|
1086
|
+
"application/json": {
|
|
1087
|
+
schema: {
|
|
1088
|
+
type: "object",
|
|
1089
|
+
properties: {
|
|
1090
|
+
"agents": {
|
|
1091
|
+
type: "array",
|
|
1092
|
+
items: { "$ref": "#/components/schemas/Agent" }
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
},
|
|
1099
|
+
"401": { description: "Unauthorized - app_id required" }
|
|
1100
|
+
}
|
|
1101
|
+
}
|
|
618
1102
|
}
|
|
619
1103
|
},
|
|
620
1104
|
components: {
|
|
1105
|
+
schemas: {
|
|
1106
|
+
Agent: {
|
|
1107
|
+
type: "object",
|
|
1108
|
+
properties: {
|
|
1109
|
+
"agent_id": { type: "string", description: "Unique agent identifier (e.g., 'agent_abc123')" },
|
|
1110
|
+
"app_id": { type: "string", description: "Associated app ID" },
|
|
1111
|
+
"name": { type: "string", description: "Agent name" },
|
|
1112
|
+
"operator": { type: "string", description: "Operator/organization name" },
|
|
1113
|
+
"version": { type: "string", description: "Agent version" },
|
|
1114
|
+
"created_at": { type: "integer", description: "Unix timestamp (ms) of registration" }
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
},
|
|
621
1118
|
securitySchemes: {
|
|
622
1119
|
BotchaLandingToken: {
|
|
623
1120
|
type: "apiKey",
|