@dupecom/botcha-cloudflare 0.20.2 → 0.21.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/dist/apps.d.ts CHANGED
@@ -41,6 +41,7 @@ export interface CreateAppResult {
41
41
  email: string;
42
42
  email_verified: boolean;
43
43
  verification_required: boolean;
44
+ verification_code: string;
44
45
  }
45
46
  /**
46
47
  * Public app info returned by getApp (excludes secrets and internal fields)
@@ -98,11 +99,10 @@ export declare function generateVerificationCode(): string;
98
99
  */
99
100
  export declare function createApp(kv: KVNamespace, email: string, name?: string): Promise<CreateAppResult>;
100
101
  /**
101
- * Get the plaintext verification code for an app (internal use only — for sending via email).
102
+ * Regenerate a new verification code for an app.
102
103
  *
103
- * This is a separate step because createApp returns the code hash, not the plaintext.
104
- * Instead, we generate and return code in createApp flow; this function regenerates
105
- * a new code for resend scenarios.
104
+ * Used for resend scenarios when the user needs a fresh code.
105
+ * Returns null if the app doesn't exist or email is already verified.
106
106
  */
107
107
  export declare function regenerateVerificationCode(kv: KVNamespace, app_id: string): Promise<{
108
108
  code: string;
@@ -1 +1 @@
1
- {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../src/apps.ts"],"names":[],"mappings":"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"}
package/dist/apps.js CHANGED
@@ -112,14 +112,14 @@ export async function createApp(kv, email, name) {
112
112
  email,
113
113
  email_verified: false,
114
114
  verification_required: true,
115
+ verification_code: verificationCode, // ONLY returned at creation time!
115
116
  };
116
117
  }
117
118
  /**
118
- * Get the plaintext verification code for an app (internal use only — for sending via email).
119
+ * Regenerate a new verification code for an app.
119
120
  *
120
- * This is a separate step because createApp returns the code hash, not the plaintext.
121
- * Instead, we generate and return code in createApp flow; this function regenerates
122
- * a new code for resend scenarios.
121
+ * Used for resend scenarios when the user needs a fresh code.
122
+ * Returns null if the app doesn't exist or email is already verified.
123
123
  */
124
124
  export async function regenerateVerificationCode(kv, app_id) {
125
125
  try {
package/dist/index.d.ts CHANGED
@@ -19,7 +19,9 @@ type Bindings = {
19
19
  ANALYTICS?: AnalyticsEngineDataset;
20
20
  JWT_SECRET: string;
21
21
  JWT_SIGNING_KEY?: string;
22
+ RESEND_API_KEY?: string;
22
23
  BOTCHA_VERSION: string;
24
+ BOTCHA_INTERNAL_APP_ID: string;
23
25
  };
24
26
  type Variables = {
25
27
  tokenPayload?: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAYL,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAwDtB,OAAO,EACL,KAAK,sBAAsB,EAM5B,MAAM,aAAa,CAAC;AAGrB,KAAK,QAAQ,GAAG;IACd,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,YAAY,CAAC,EAAE;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,iBAAiB,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,GAAG;cAAwB,QAAQ;eAAa,SAAS;yCAAK,CAAC;AAuzErE,eAAe,GAAG,CAAC;AAGnB,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAG5B,OAAO,EAYL,KAAK,WAAW,EACjB,MAAM,cAAc,CAAC;AAwDtB,OAAO,EACL,KAAK,sBAAsB,EAM5B,MAAM,aAAa,CAAC;AAGrB,KAAK,QAAQ,GAAG;IACd,UAAU,EAAE,WAAW,CAAC;IACxB,WAAW,EAAE,WAAW,CAAC;IACzB,IAAI,EAAE,WAAW,CAAC;IAClB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,MAAM,EAAE,WAAW,CAAC;IACpB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE,sBAAsB,CAAC;IACnC,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,sBAAsB,EAAE,MAAM,CAAC;CAChC,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,YAAY,CAAC,EAAE;QACb,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,iBAAiB,CAAC;QACxB,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;CACH,CAAC;AAEF,QAAA,MAAM,GAAG;cAAwB,QAAQ;eAAa,SAAS;yCAAK,CAAC;AAwgFrE,eAAe,GAAG,CAAC;AAGnB,OAAO,EACL,sBAAsB,EACtB,oBAAoB,EACpB,yBAAyB,EACzB,uBAAuB,EACvB,0BAA0B,EAC1B,wBAAwB,EACxB,uBAAuB,EACvB,qBAAqB,EACrB,mBAAmB,GACpB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,sBAAsB,EAAE,MAAM,QAAQ,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EACL,aAAa,EACb,WAAW,EACX,mBAAmB,EACnB,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,YAAY,GAClB,MAAM,SAAS,CAAC"}
package/dist/index.js CHANGED
@@ -18,7 +18,7 @@ import dashboardRoutes from './dashboard/index';
18
18
  import { handleDashboardAuthChallenge, handleDashboardAuthVerify, handleDeviceCodeChallenge, handleDeviceCodeVerify, } from './dashboard/auth';
19
19
  import { ROBOTS_TXT, AI_TXT, AI_PLUGIN_JSON, SITEMAP_XML, getOpenApiSpec, getBotchaMarkdown, getWhitepaperMarkdown } from './static';
20
20
  import { OG_IMAGE_BASE64 } from './og-image';
21
- import { createApp, getApp, getAppByEmail, verifyEmailCode, rotateAppSecret, regenerateVerificationCode } from './apps';
21
+ import { createApp, getApp, getAppByEmail, verifyEmailCode, rotateAppSecret, regenerateVerificationCode, validateAppSecret } from './apps';
22
22
  import { sendEmail, verificationEmail, recoveryEmail, secretRotatedEmail } from './email';
23
23
  import { LandingPage, VerifiedLandingPage } from './dashboard/landing';
24
24
  import { ShowcasePage } from './dashboard/showcase';
@@ -40,16 +40,39 @@ app.route('/dashboard', dashboardRoutes);
40
40
  // BOTCHA discovery headers
41
41
  app.use('*', async (c, next) => {
42
42
  await next();
43
- c.header('X-Botcha-Version', c.env.BOTCHA_VERSION || '0.20.2');
43
+ c.header('X-Botcha-Version', c.env.BOTCHA_VERSION || '0.21.0');
44
44
  c.header('X-Botcha-Enabled', 'true');
45
45
  c.header('X-Botcha-Methods', 'speed-challenge,reasoning-challenge,hybrid-challenge,standard-challenge,jwt-token');
46
46
  c.header('X-Botcha-Docs', 'https://botcha.ai/openapi.json');
47
47
  c.header('X-Botcha-Runtime', 'cloudflare-workers');
48
48
  });
49
- // Rate limiting middleware for challenge generation
49
+ // App gate: require registered app_id with verified email on /v1/* routes.
50
+ // Open paths (registration, verification, recovery) are exempted.
51
+ const APP_GATE_OPEN_PATHS = [
52
+ '/v1/apps', // POST: create app (registration)
53
+ '/v1/auth/recover', // POST: account recovery
54
+ ];
55
+ // Pattern-match paths that start with /v1/apps/:id/ (verify-email, resend-verification, etc.)
56
+ function isAppManagementPath(path) {
57
+ return /^\/v1\/apps\/[^/]+\/(verify-email|resend-verification)$/.test(path);
58
+ }
59
+ app.use('/v1/*', async (c, next) => {
60
+ const path = new URL(c.req.url).pathname;
61
+ // Allow open paths through without app_id
62
+ if (APP_GATE_OPEN_PATHS.includes(path) || isAppManagementPath(path)) {
63
+ return next();
64
+ }
65
+ // Also allow GET /v1/apps/:id (app info lookup)
66
+ if (/^\/v1\/apps\/[^/]+$/.test(path) && c.req.method === 'GET') {
67
+ return next();
68
+ }
69
+ return requireAppId(c, next);
70
+ });
71
+ // Rate limiting middleware for challenge generation (app-scoped when app_id present)
50
72
  async function rateLimitMiddleware(c, next) {
51
73
  const clientIP = getClientIP(c.req.raw);
52
- const rateLimitResult = await checkRateLimit(c.env.RATE_LIMITS, clientIP, 100);
74
+ const appId = c.req.query('app_id') || c.req.header('x-app-id');
75
+ const rateLimitResult = await checkRateLimit(c.env.RATE_LIMITS, clientIP, 100, appId);
53
76
  // Add rate limit headers
54
77
  c.header('X-RateLimit-Limit', '100');
55
78
  c.header('X-RateLimit-Remaining', rateLimitResult.remaining.toString());
@@ -68,20 +91,21 @@ async function rateLimitMiddleware(c, next) {
68
91
  await next();
69
92
  }
70
93
  // Helper: Validate app_id against APPS KV (fail-open)
94
+ // Note: The requireAppId middleware handles the "must have app_id" check globally.
95
+ // This helper does additional route-level validation (e.g., consistency checks).
71
96
  async function validateAppId(appId, appsKV) {
72
97
  if (!appId) {
73
- // No app_id provided - valid (not required)
74
- return { valid: true };
98
+ return {
99
+ valid: false,
100
+ error: 'app_id is required. Register at POST https://botcha.ai/v1/apps with {"email": "you@example.com"}.',
101
+ };
75
102
  }
76
103
  try {
77
104
  const app = await getApp(appsKV, appId);
78
105
  if (!app) {
79
106
  return {
80
107
  valid: false,
81
- error: `App not found: ${appId}. ` +
82
- `app_id is OPTIONAL — remove it to get a token without an app. ` +
83
- `To register an app: POST https://botcha.ai/v1/apps with {"email": "you@example.com", "name": "My App"}. ` +
84
- `App IDs look like: app_a1b2c3d4e5f6a7b8`
108
+ error: `App not found: ${appId}. Register at POST https://botcha.ai/v1/apps with {"email": "you@example.com"}.`,
85
109
  };
86
110
  }
87
111
  return { valid: true };
@@ -92,6 +116,91 @@ async function validateAppId(appId, appsKV) {
92
116
  return { valid: true };
93
117
  }
94
118
  }
119
+ // ============ APP GATE MIDDLEWARE ============
120
+ // Requires a registered app_id with verified email on all gated /v1/* routes.
121
+ // Extracts app_id from: query param, X-App-Id header, request body, or JWT Bearer token claim.
122
+ async function requireAppId(c, next) {
123
+ // 1. Extract app_id from multiple sources
124
+ const queryAppId = c.req.query('app_id');
125
+ const headerAppId = c.req.header('x-app-id');
126
+ // Try request body for POST/PUT requests (e.g., /v1/token/verify sends app_id in body)
127
+ let bodyAppId;
128
+ if (c.req.method === 'POST' || c.req.method === 'PUT') {
129
+ try {
130
+ const body = await c.req.json();
131
+ if (body && typeof body.app_id === 'string') {
132
+ bodyAppId = body.app_id;
133
+ }
134
+ }
135
+ catch {
136
+ // Body not JSON or not parseable — that's fine
137
+ }
138
+ }
139
+ // Try JWT claim if Bearer token present
140
+ let jwtAppId;
141
+ const authHeader = c.req.header('authorization');
142
+ const token = extractBearerToken(authHeader);
143
+ if (token) {
144
+ try {
145
+ const publicKey = getPublicKey(c.env);
146
+ const result = await verifyToken(token, c.env.JWT_SECRET, c.env, undefined, publicKey);
147
+ if (result.valid && result.payload?.app_id) {
148
+ jwtAppId = result.payload.app_id;
149
+ }
150
+ }
151
+ catch {
152
+ // Token invalid — will be caught by route-level auth if needed
153
+ }
154
+ }
155
+ const appId = queryAppId || headerAppId || bodyAppId || jwtAppId;
156
+ // 2. No app_id at all → 401 with registration instructions
157
+ if (!appId) {
158
+ return c.json({
159
+ success: false,
160
+ error: 'APP_REGISTRATION_REQUIRED',
161
+ message: 'All API endpoints require a registered app. Create one for free:',
162
+ registration: {
163
+ endpoint: 'POST https://botcha.ai/v1/apps',
164
+ body: '{"email": "you@example.com", "name": "My App"}',
165
+ note: 'You will receive a 6-digit verification code via email. Verify to activate your app.',
166
+ },
167
+ docs: 'https://botcha.ai/ai.txt',
168
+ }, 401);
169
+ }
170
+ // 3. Validate app exists and email is verified
171
+ try {
172
+ const app = await getApp(c.env.APPS, appId);
173
+ if (!app) {
174
+ return c.json({
175
+ success: false,
176
+ error: 'APP_NOT_FOUND',
177
+ message: `App '${appId}' not found. Register at POST https://botcha.ai/v1/apps`,
178
+ }, 401);
179
+ }
180
+ if (!app.email_verified) {
181
+ return c.json({
182
+ success: false,
183
+ error: 'EMAIL_NOT_VERIFIED',
184
+ message: 'Your app email must be verified before using the API.',
185
+ next_step: `POST https://botcha.ai/v1/apps/${appId}/verify-email with {"code": "<6-digit code>", "app_secret": "<your_secret>"}`,
186
+ resend: `POST https://botcha.ai/v1/apps/${appId}/resend-verification`,
187
+ }, 403);
188
+ }
189
+ }
190
+ catch (error) {
191
+ // Fail-open on KV errors — log warning and proceed
192
+ console.warn(`requireAppId: KV lookup failed for ${appId}, proceeding (fail-open):`, error);
193
+ }
194
+ // 4. Cross-check: if both query and JWT have app_id, they must match
195
+ if (queryAppId && jwtAppId && queryAppId !== jwtAppId) {
196
+ return c.json({
197
+ success: false,
198
+ error: 'APP_ID_MISMATCH',
199
+ message: `Query app_id '${queryAppId}' does not match token app_id '${jwtAppId}'.`,
200
+ }, 400);
201
+ }
202
+ await next();
203
+ }
95
204
  // Helper: Parse ES256 signing key from env, returning undefined if not set
96
205
  function getSigningKey(env) {
97
206
  if (!env.JWT_SIGNING_KEY)
@@ -186,6 +295,44 @@ async function resolveAuthenticatedAppId(c) {
186
295
  status: 200,
187
296
  };
188
297
  }
298
+ // Authorize app management actions using either app_secret or a dashboard session token.
299
+ async function authorizeAppManagement(c, appId, appSecretFromBody) {
300
+ const headerAppSecret = c.req.header('x-app-secret');
301
+ const appSecret = appSecretFromBody?.trim() || headerAppSecret?.trim();
302
+ // App-secret proof (works immediately after app creation and outside dashboard).
303
+ if (appSecret) {
304
+ const valid = await validateAppSecret(c.env.APPS, appId, appSecret);
305
+ if (valid) {
306
+ return { authorized: true, status: 200 };
307
+ }
308
+ }
309
+ // Dashboard session proof (Bearer token or cookie).
310
+ const authHeader = c.req.header('authorization');
311
+ const bearerToken = extractBearerToken(authHeader);
312
+ const cookieHeader = c.req.header('cookie') || '';
313
+ const sessionCookie = cookieHeader
314
+ .split(';')
315
+ .find((part) => part.trim().startsWith('botcha_session='))
316
+ ?.split('=')[1]
317
+ ?.trim();
318
+ const authToken = bearerToken || sessionCookie;
319
+ if (authToken) {
320
+ const publicKey = getPublicKey(c.env);
321
+ const verification = await verifyToken(authToken, c.env.JWT_SECRET, c.env, undefined, publicKey);
322
+ if (verification.valid &&
323
+ verification.payload &&
324
+ verification.payload.sub === 'dashboard-session' &&
325
+ verification.payload.app_id === appId) {
326
+ return { authorized: true, status: 200 };
327
+ }
328
+ }
329
+ return {
330
+ authorized: false,
331
+ error: 'UNAUTHORIZED',
332
+ message: 'Authentication required. Provide app_secret or a dashboard session token.',
333
+ status: 401,
334
+ };
335
+ }
189
336
  // ============ ROOT & INFO ============
190
337
  // Detect request preference: 'markdown' | 'json' | 'html'
191
338
  // Strategy: only return JSON/markdown when explicitly requested or from
@@ -251,20 +398,21 @@ app.get('/', async (c) => {
251
398
  version,
252
399
  tagline: 'Prove you are a bot. Humans need not apply.',
253
400
  status: 'unverified',
254
- message: 'Verify yourself to see the full API documentation.',
255
- verify: {
256
- step1: `GET ${baseUrl}/v1/token receive a speed challenge (5 SHA-256 hashes). No app_id needed.`,
257
- step2: 'Solve: compute SHA-256 of each number, return first 8 hex chars',
258
- step3: `POST ${baseUrl}/v1/token/verify {"id":"<challenge_id>","answers":["hash1","hash2",...]}`,
259
- step4: `Revisit: GET ${baseUrl}/ with header Authorization: Bearer <access_token>`,
260
- note: 'app_id is OPTIONAL. You can get tokens without registering an app. To register one for production use: POST /v1/apps {"email":"you@example.com","name":"My App"}',
401
+ message: 'App registration required. Register to see the full API documentation.',
402
+ registration_required: {
403
+ note: 'All API endpoints require a registered app with verified email (v0.21.0)',
404
+ demo: 'The homepage demo at botcha.ai lets agents try challenges without registering',
405
+ step1: 'Ask your human for their email',
406
+ step2: `POST ${baseUrl}/v1/apps {"email":"you@example.com","name":"My App"} NO app_id needed`,
407
+ step3: 'Human receives 6-digit code via email',
408
+ step4: `POST ${baseUrl}/v1/apps/{app_id}/verify-email {"code":"123456","app_secret":"sk_..."} — NO app_id needed`,
409
+ step5: 'Use your app_id on ALL other /v1/* endpoints via ?app_id=, X-App-Id header, or JWT claim',
261
410
  },
262
411
  human_handoff: {
263
412
  note: 'After verifying, the response includes a human_link. Give it to your human to open in their browser.',
264
413
  instruction: 'Tell your human: "Click this link to get access" and give them the human_link URL.',
265
- link_field: 'human_link from step 3 response',
414
+ link_field: 'human_link from token verify response',
266
415
  },
267
- hint: 'You have 500ms. Only a bot can do this.',
268
416
  links: {
269
417
  openapi: `${baseUrl}/openapi.json`,
270
418
  ai_txt: `${baseUrl}/ai.txt`,
@@ -275,19 +423,23 @@ app.get('/', async (c) => {
275
423
 
276
424
  > Prove you are a bot. Humans need not apply.
277
425
 
278
- **Status:** Unverified. Solve a challenge to see the full documentation.
426
+ **Status:** Unverified. Register an app to see the full documentation.
279
427
 
280
- ## Verify Yourself
428
+ ## App Registration Required (v0.21.0)
281
429
 
282
- 1. \`GET ${baseUrl}/v1/token\` receive a speed challenge (5 SHA-256 hashes). **No app_id needed.**
283
- 2. Solve: compute SHA-256 of each number, return first 8 hex chars
284
- 3. \`POST ${baseUrl}/v1/token/verify {"id":"<challenge_id>","answers":["hash1","hash2",...]}\`
285
- 4. Revisit: \`GET ${baseUrl}/\` with header \`Authorization: Bearer <access_token>\`
430
+ **All API endpoints require a registered app with verified email.**
286
431
 
287
- You have 500ms. Only a bot can do this.
432
+ - Register for free: \`POST /v1/apps\` with your email
433
+ - The homepage demo at botcha.ai lets agents try challenges without registering
434
+ - Provide app_id via \`?app_id=\`, \`X-App-Id\` header, or JWT claim
288
435
 
289
- > **Note:** \`app_id\` is optional. You can get tokens without registering an app.
290
- > To register for production: \`POST /v1/apps {"email":"you@example.com","name":"My App"}\`
436
+ ## Register Your App
437
+
438
+ 1. Ask your human for their email
439
+ 2. \`POST ${baseUrl}/v1/apps {"email":"you@example.com","name":"My App"}\` — **NO app_id needed**
440
+ 3. Human receives 6-digit code via email
441
+ 4. \`POST ${baseUrl}/v1/apps/{app_id}/verify-email {"code":"123456","app_secret":"sk_..."}\` — **NO app_id needed**
442
+ 5. Use your \`app_id\` on ALL other \`/v1/*\` endpoints via \`?app_id=\`, \`X-App-Id\` header, or JWT claim
291
443
 
292
444
  ## Human Handoff
293
445
 
@@ -298,7 +450,7 @@ The link works for a limited time. Your human clicks it, gets a cookie, and sees
298
450
 
299
451
  ---
300
452
 
301
- *Full API docs, SDKs, onboarding, and endpoint reference available after verification.*
453
+ *Full API docs, SDKs, onboarding, and endpoint reference available after registration.*
302
454
  `;
303
455
  return c.body(md, 200, {
304
456
  'Content-Type': 'text/markdown; charset=utf-8',
@@ -329,58 +481,69 @@ The link works for a limited time. Your human clicks it, gets a cookie, and sees
329
481
  audience: tokenPayload?.aud || null,
330
482
  solve_time_ms: tokenPayload?.solveTime,
331
483
  },
484
+ // === APP REGISTRATION REQUIRED (v0.21.0) ===
485
+ registration_required: {
486
+ note: 'All /v1/* API endpoints require a registered app with verified email.',
487
+ demo: 'The homepage demo at botcha.ai lets agents try challenges without registering.',
488
+ how_to_provide: 'Provide app_id via ?app_id=, X-App-Id header, or JWT claim',
489
+ },
332
490
  // === FULL SETUP: register your app and agent identity ===
333
491
  onboarding: {
334
492
  note: 'For production use. Creates your app, verifies your human, registers your identity.',
335
493
  steps: [
336
494
  '1. Ask your human operator for their email address.',
337
- `2. POST ${baseUrl}/v1/apps {"email":"human@example.com","name":"My App"} — returns app_id + name + app_secret (shown ONCE).`,
495
+ `2. POST ${baseUrl}/v1/apps {"email":"human@example.com","name":"My App"} — returns app_id + name + app_secret (shown ONCE). NO app_id needed.`,
338
496
  '3. Human receives a 6-digit verification code via email — ask them for it.',
339
- `4. POST ${baseUrl}/v1/apps/{app_id}/verify-email {"code":"123456"} — enables account recovery.`,
340
- `5. Register yourself: POST ${baseUrl}/v1/agents/register {"name":"my-agent","operator":"my-org"} persistent agent identity.`,
341
- `6. Solve challenges with your app: GET ${baseUrl}/v1/challenges?app_id=...`,
342
- `7. Dashboard for your human: POST ${baseUrl}/v1/auth/device-code {"app_id":"..."}, solve challenge, give human the BOTCHA-XXXX code for /dashboard/code.`,
343
- `8. Lost your secret? POST ${baseUrl}/v1/auth/recover {"email":"..."} recovery code emailed.`,
497
+ `4. POST ${baseUrl}/v1/apps/{app_id}/verify-email {"code":"123456","app_secret":"sk_..."} — enables account recovery. NO app_id needed.`,
498
+ `5. Use your app_id on ALL other /v1/* endpoints via ?app_id=, X-App-Id header, or JWT claim.`,
499
+ `6. Register yourself: POST ${baseUrl}/v1/agents/register {"name":"my-agent","operator":"my-org"} — persistent agent identity (requires app_id).`,
500
+ `7. Solve challenges with your app: GET ${baseUrl}/v1/challenges?app_id=... (requires app_id)`,
501
+ `8. Dashboard for your human: POST ${baseUrl}/v1/auth/device-code {"app_id":"..."}, solve challenge, give human the BOTCHA-XXXX code for /dashboard/code (requires app_id).`,
502
+ `9. Lost your secret? POST ${baseUrl}/v1/auth/recover {"email":"..."} — recovery code emailed (no app_id needed).`,
344
503
  ],
345
504
  },
346
505
  // === All endpoints, grouped by domain ===
347
506
  endpoints: {
348
507
  challenges: {
349
- 'GET /v1/challenges': 'Get a challenge (hybrid by default, no auth required)',
350
- 'GET /v1/challenges?type=speed': 'Speed-only (SHA256 in <500ms)',
351
- 'GET /v1/challenges?type=standard': 'Standard puzzle challenge',
352
- 'POST /v1/challenges/:id/verify': 'Verify challenge solution',
508
+ note: 'All challenge endpoints require app_id',
509
+ 'GET /v1/challenges': 'Get a challenge (hybrid by default) — app_id required',
510
+ 'GET /v1/challenges?type=speed': 'Speed-only (SHA256 in <500ms) — app_id required',
511
+ 'GET /v1/challenges?type=standard': 'Standard puzzle challenge — app_id required',
512
+ 'POST /v1/challenges/:id/verify': 'Verify challenge solution — app_id required',
353
513
  },
354
514
  tokens: {
355
- note: 'Use token flow when you need a Bearer token for protected endpoints.',
356
- 'GET /v1/token': 'Get speed challenge for token flow (?audience= optional)',
357
- 'POST /v1/token/verify': 'Submit solution → access_token (1hr) + refresh_token (1hr)',
358
- 'POST /v1/token/refresh': 'Refresh access token',
359
- 'POST /v1/token/revoke': 'Revoke a token',
360
- 'POST /v1/token/validate': 'Remote token validation — verify any BOTCHA token without needing the secret',
515
+ note: 'All token endpoints require app_id. Use token flow when you need a Bearer token for protected endpoints.',
516
+ 'GET /v1/token': 'Get speed challenge for token flow (?audience= optional) — app_id required',
517
+ 'POST /v1/token/verify': 'Submit solution → access_token (1hr) + refresh_token (1hr) — app_id required',
518
+ 'POST /v1/token/refresh': 'Refresh access token — app_id required',
519
+ 'POST /v1/token/revoke': 'Revoke a token — app_id required',
520
+ 'POST /v1/token/validate': 'Remote token validation — verify any BOTCHA token without needing the secret — app_id required',
361
521
  },
362
522
  protected: {
363
- 'GET /agent-only': 'Demo protected endpoint — requires Bearer token',
523
+ 'GET /agent-only': 'Demo protected endpoint — requires Bearer token (app_id required)',
364
524
  'GET /': 'This documentation (requires Bearer token for full version)',
365
525
  },
366
526
  apps: {
367
- note: 'Create an app for isolated rate limits, scoped tokens, and dashboard access.',
368
- 'POST /v1/apps': 'Create app (email required, name optional) → app_id + name + app_secret',
369
- 'GET /v1/apps/:id': 'Get app info',
370
- 'POST /v1/apps/:id/verify-email': 'Verify email with 6-digit code',
371
- 'POST /v1/apps/:id/rotate-secret': 'Rotate app secret (auth required)',
527
+ note: 'App management endpoints. Registration and verification do NOT require app_id.',
528
+ 'POST /v1/apps': 'Create app (email required, name optional) → app_id + name + app_secret — NO app_id required',
529
+ 'GET /v1/apps/:id': 'Get app info — NO app_id required',
530
+ 'POST /v1/apps/:id/verify-email': 'Verify email with 6-digit code (app_secret auth required) — NO app_id required',
531
+ 'POST /v1/apps/:id/resend-verification': 'Resend verification email (app_secret auth required) — NO app_id required',
532
+ 'POST /v1/apps/:id/rotate-secret': 'Rotate app secret (auth required) — app_id required',
372
533
  },
373
534
  agents: {
374
- note: 'Register a persistent identity for your agent.',
375
- 'POST /v1/agents/register': 'Register agent identity (name, operator, version)',
376
- 'GET /v1/agents/:id': 'Get agent by ID (public, no auth)',
377
- 'GET /v1/agents': 'List all agents for your app (auth required)',
535
+ note: 'All agent endpoints require app_id. Register a persistent identity for your agent.',
536
+ 'POST /v1/agents/register': 'Register agent identity (name, operator, version) — app_id required',
537
+ 'GET /v1/agents/:id': 'Get agent by ID (public, no auth) — app_id required',
538
+ 'GET /v1/agents': 'List all agents for your app (auth required) — app_id required',
378
539
  },
379
540
  recovery: {
380
- 'POST /v1/auth/recover': 'Account recovery via verified email',
541
+ note: 'Recovery does NOT require app_id',
542
+ 'POST /v1/auth/recover': 'Account recovery via verified email — NO app_id required',
381
543
  },
382
544
  dashboard: {
383
- 'POST /v1/auth/device-code': 'Get challenge for device code flow',
545
+ note: 'Dashboard endpoints require app_id',
546
+ 'POST /v1/auth/device-code': 'Get challenge for device code flow — app_id required',
384
547
  'GET /dashboard': 'Metrics dashboard (login required)',
385
548
  },
386
549
  },
@@ -1427,15 +1590,12 @@ app.post('/v1/apps', async (c) => {
1427
1590
  }, 400);
1428
1591
  }
1429
1592
  const result = await createApp(c.env.APPS, email, trimmedName || undefined);
1430
- // Generate a fresh verification code and send email
1431
- const regen = await regenerateVerificationCode(c.env.APPS, result.app_id);
1432
- if (regen) {
1433
- const template = verificationEmail(regen.code);
1434
- await sendEmail(c.env.RESEND_API_KEY, {
1435
- ...template,
1436
- to: email,
1437
- });
1438
- }
1593
+ // Send verification email with the code returned from createApp
1594
+ const template = verificationEmail(result.verification_code);
1595
+ await sendEmail(c.env.RESEND_API_KEY, {
1596
+ ...template,
1597
+ to: email,
1598
+ });
1439
1599
  return c.json({
1440
1600
  success: true,
1441
1601
  app_id: result.app_id,
@@ -1448,7 +1608,7 @@ app.post('/v1/apps', async (c) => {
1448
1608
  credential_advice: 'Store the app_id and app_secret securely. Use persistent agent memory if available, or instruct your human to save them in a password manager (1Password, Bitwarden, etc). If lost, recovery is available via the verified email.',
1449
1609
  created_at: new Date().toISOString(),
1450
1610
  rate_limit: 100,
1451
- next_step: `POST /v1/apps/${result.app_id}/verify-email with { "code": "123456" }`,
1611
+ next_step: `POST /v1/apps/${result.app_id}/verify-email with { "code": "123456", "app_secret": "${result.app_secret}" }`,
1452
1612
  }, 201);
1453
1613
  }
1454
1614
  catch (error) {
@@ -1492,7 +1652,7 @@ app.get('/v1/apps/:id', async (c) => {
1492
1652
  app.post('/v1/apps/:id/verify-email', async (c) => {
1493
1653
  const app_id = c.req.param('id');
1494
1654
  const body = await c.req.json().catch(() => ({}));
1495
- const { code } = body;
1655
+ const { code, app_secret } = body;
1496
1656
  if (!code || typeof code !== 'string') {
1497
1657
  return c.json({
1498
1658
  success: false,
@@ -1500,6 +1660,14 @@ app.post('/v1/apps/:id/verify-email', async (c) => {
1500
1660
  message: 'Provide { "code": "123456" } in the request body',
1501
1661
  }, 400);
1502
1662
  }
1663
+ const auth = await authorizeAppManagement(c, app_id, app_secret);
1664
+ if (!auth.authorized) {
1665
+ return c.json({
1666
+ success: false,
1667
+ error: auth.error,
1668
+ message: auth.message,
1669
+ }, auth.status);
1670
+ }
1503
1671
  const result = await verifyEmailCode(c.env.APPS, app_id, code);
1504
1672
  if (!result.verified) {
1505
1673
  return c.json({
@@ -1517,6 +1685,15 @@ app.post('/v1/apps/:id/verify-email', async (c) => {
1517
1685
  // Resend verification email
1518
1686
  app.post('/v1/apps/:id/resend-verification', async (c) => {
1519
1687
  const app_id = c.req.param('id');
1688
+ const body = await c.req.json().catch(() => ({}));
1689
+ const auth = await authorizeAppManagement(c, app_id, body.app_secret);
1690
+ if (!auth.authorized) {
1691
+ return c.json({
1692
+ success: false,
1693
+ error: auth.error,
1694
+ message: auth.message,
1695
+ }, auth.status);
1696
+ }
1520
1697
  const appData = await getApp(c.env.APPS, app_id);
1521
1698
  if (!appData) {
1522
1699
  return c.json({ success: false, error: 'App not found' }, 404);
package/dist/static.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export declare function getBotchaMarkdown(version: string): string;
8
8
  export declare const ROBOTS_TXT = "# BOTCHA - Reverse CAPTCHA for AI Agents\n# We WELCOME AI agents and bots!\n\nUser-agent: *\nAllow: /\n\n# AI-specific crawlers\nUser-agent: GPTBot\nAllow: /\n\nUser-agent: ChatGPT-User\nAllow: /\n\nUser-agent: Claude-Web\nAllow: /\n\nUser-agent: anthropic-ai\nAllow: /\n\nUser-agent: Google-Extended\nAllow: /\n\nUser-agent: PerplexityBot\nAllow: /\n\nUser-agent: Amazonbot\nAllow: /\n\n# API documentation\nSitemap: https://botcha.ai/sitemap.xml\n\n# Important resources for AI agents\nCrawl-delay: 0\n\n# MARKDOWN FOR AGENTS\n# AI agents can request Markdown from any page via Accept: text/markdown\n# Example: curl https://botcha.ai -H \"Accept: text/markdown\"\n# Returns token-efficient Markdown documentation (80% fewer tokens than HTML)\n# Content negotiation: text/markdown, application/json, text/html\n\n# BOT CHALLENGE DISCOVERY\n# AI agents: Look for <script type=\"application/botcha+json\"> in HTML pages\n# This contains a machine-readable challenge you can solve to prove you're a bot\n# \n# Quick start:\n# 1. Fetch any HTML page\n# 2. Parse <script type=\"application/botcha+json\"> for challenge instructions\n# 3. Solve the challenge (usually SHA256-based)\n# 4. POST solution to /api/verify-landing\n# 5. Use returned token in X-Botcha-Landing-Token header\n#\n# See also:\n# - /ai.txt (AI agent discovery file)\n# - /.well-known/ai-plugin.json (AI plugin manifest)\n# - /openapi.json (Full API specification)\n";
9
- export declare const AI_TXT = "# BOTCHA - Reverse CAPTCHA for AI Agents\n# https://botcha.ai\n\n# Contact\nContact: https://botcha.ai\nContact: https://github.com/dupe-com/botcha/issues\n\n# Purpose\nPurpose: Prove you're a bot. Humans need not apply.\nPurpose: Reverse CAPTCHA system that only AI agents can pass.\n\n# Agent Onboarding (START HERE if you're new)\n# Follow these steps to create your app and get your human access.\nOnboarding-Step-1: Ask your human operator for their email address\nOnboarding-Step-2: POST /v1/apps with {\"email\": \"human@example.com\"} \u2014 saves app_id + app_secret (secret shown ONCE)\nOnboarding-Step-3: A 6-digit verification code is emailed to your human \u2014 ask them for it\nOnboarding-Step-4: POST /v1/apps/{app_id}/verify-email with {\"code\": \"123456\"} \u2014 enables account recovery\nOnboarding-Step-5: Register yourself: POST /v1/agents/register with {\"name\": \"my-agent\", \"operator\": \"my-org\"} \u2014 gives you a persistent agent identity\nOnboarding-Step-6: Solve challenges: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verify \u2014 proves you are AI\nOnboarding-Step-7: Access protected resources: GET /agent-only with Authorization: Bearer <token>\nOnboarding-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\nOnboarding-Step-9: Lost your secret? POST /v1/auth/recover with {\"email\": \"...\"} \u2014 recovery code emailed to verified address\n\n# API\nAPI: https://botcha.ai/openapi.json\nAPI-Type: REST\nAPI-Format: OpenAPI 3.1.0\n\n# Documentation\nDocs: https://botcha.ai\nDocs: https://botcha.ai/docs\nDocs: https://botcha.ai/whitepaper\nDocs: https://github.com/dupe-com/botcha#readme\nDocs: https://www.npmjs.com/package/@dupecom/botcha\nWhitepaper: https://botcha.ai/whitepaper\n\n# Verification Methods\nFeature: Web Bot Auth (cryptographic signatures)\nFeature: Speed Challenge (RTT-aware timeout - fair for all networks)\nFeature: Standard Challenge (5s time limit)\nFeature: Hybrid Challenge (speed + reasoning combined)\nFeature: Reasoning Challenge (LLM-only questions, 30s limit)\nFeature: RTT-Aware Fairness (automatic network latency compensation)\nFeature: Token Rotation (1-hour access tokens + 1-hour refresh tokens)\nFeature: Audience Claims (tokens scoped to specific services)\nFeature: Client IP Binding (optional token-to-IP binding)\nFeature: Token Revocation (invalidate tokens before expiry)\nFeature: Server-Side Verification SDK (@dupecom/botcha-verify for TS, botcha-verify for Python)\nFeature: Multi-Tenant API Keys (per-app isolation, rate limiting, and token scoping)\nFeature: Per-App Metrics Dashboard (server-rendered at /dashboard, htmx-powered)\nFeature: Email-Tied App Creation (email required, 6-digit verification, account recovery)\nFeature: Secret Rotation (rotate app_secret with email notification)\nFeature: Agent-First Dashboard Auth (challenge-based login + device code handoff)\nFeature: Agent Registry (persistent agent identities with name, operator, version)\nFeature: Trusted Agent Protocol (TAP) \u2014 cryptographic agent auth with HTTP Message Signatures (RFC 9421)\nFeature: TAP Capabilities (action + resource scoping for agent sessions)\nFeature: TAP Trust Levels (basic, verified, enterprise)\nFeature: TAP Showcase Homepage (botcha.ai \u2014 one of the first services to implement Visa's Trusted Agent Protocol)\nFeature: TAP Full Spec v0.16.0 \u2014 Ed25519, RFC 9421 full compliance, JWKS infrastructure, Layer 2 Consumer Recognition, Layer 3 Payment Container, 402 micropayments, CDN edge verification, Visa key federation\nFeature: ES256 Asymmetric JWT Signing v0.19.0 \u2014 tokens signed with ES256 (ECDSA P-256), public key discovery via JWKS, HS256 still supported for backward compatibility\nFeature: Remote Token Validation v0.19.0 \u2014 POST /v1/token/validate for third-party token verification without shared secrets\nFeature: JWKS Public Key Discovery v0.19.0 \u2014 GET /.well-known/jwks exposes BOTCHA signing public keys for offline token verification\n\n# Endpoints\n# Challenge Endpoints\nEndpoint: GET https://botcha.ai/v1/challenges - Generate challenge (hybrid by default)\nEndpoint: POST https://botcha.ai/v1/challenges/:id/verify - Verify a challenge\nEndpoint: GET https://botcha.ai/v1/hybrid - Get hybrid challenge (speed + reasoning)\nEndpoint: POST https://botcha.ai/v1/hybrid - Verify hybrid challenge\nEndpoint: GET https://botcha.ai/v1/reasoning - Get reasoning challenge\nEndpoint: POST https://botcha.ai/v1/reasoning - Verify reasoning challenge\n\n# Token Endpoints\nEndpoint: GET https://botcha.ai/v1/token - Get challenge for JWT token flow\nEndpoint: POST https://botcha.ai/v1/token/verify - Verify challenge and receive JWT token\nEndpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using refresh token\nEndpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh)\nEndpoint: POST https://botcha.ai/v1/token/validate - Validate a BOTCHA token remotely (no shared secret needed)\n\n# Multi-Tenant Endpoints\nEndpoint: POST https://botcha.ai/v1/apps - Create new app (email required, name optional) \u2192 app_id + name + app_secret\nEndpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status)\nEndpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code\nEndpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email\nEndpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required)\n\n# Account Recovery\nEndpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email\n\n# Dashboard Auth Endpoints (Agent-First)\nEndpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login\nEndpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token\nEndpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow\nEndpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code\n\n# Dashboard Endpoints\nEndpoint: GET https://botcha.ai/dashboard - Per-app metrics dashboard (login required)\nEndpoint: GET https://botcha.ai/dashboard/login - Dashboard login page\nEndpoint: POST https://botcha.ai/dashboard/login - Login with app_id + app_secret\nEndpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing)\n\n# Code Redemption (Unified)\nEndpoint: GET https://botcha.ai/go/:code - Unified code redemption \u2014 handles gate codes (from /v1/token/verify) AND device codes (from /v1/auth/device-code/verify)\nEndpoint: POST https://botcha.ai/gate - Submit code form, redirects to /go/:code\n\n# Agent Registry Endpoints\nEndpoint: POST https://botcha.ai/v1/agents/register - Register agent identity (requires app_id)\nEndpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth)\nEndpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app\n\n# TAP (Trusted Agent Protocol) Endpoints\nEndpoint: POST https://botcha.ai/v1/agents/register/tap - Register TAP agent with public key + capabilities\nEndpoint: GET https://botcha.ai/v1/agents/:id/tap - Get TAP agent details (includes public key)\nEndpoint: GET https://botcha.ai/v1/agents/tap - List TAP-enabled agents for app\nEndpoint: POST https://botcha.ai/v1/sessions/tap - Create TAP session with intent validation\nEndpoint: GET https://botcha.ai/v1/sessions/:id/tap - Get TAP session info\n\n# TAP Full Spec \u2014 JWKS & Key Management (v0.16.0)\nEndpoint: GET https://botcha.ai/.well-known/jwks - JWK Set for app's TAP agents (Visa spec standard)\nEndpoint: GET https://botcha.ai/v1/keys - List keys (supports ?keyID= query for Visa compatibility)\nEndpoint: GET https://botcha.ai/v1/keys/:keyId - Get specific key by ID\nEndpoint: POST https://botcha.ai/v1/agents/:id/tap/rotate-key - Rotate agent's key pair\n\n# TAP Full Spec \u2014 402 Micropayments (v0.16.0)\nEndpoint: POST https://botcha.ai/v1/invoices - Create invoice for gated content (402 flow)\nEndpoint: GET https://botcha.ai/v1/invoices/:id - Get invoice details\nEndpoint: POST https://botcha.ai/v1/invoices/:id/verify-iou - Verify Browsing IOU against invoice\n\n# TAP Full Spec \u2014 Consumer & Payment Verification (v0.16.0)\nEndpoint: POST https://botcha.ai/v1/verify/consumer - Verify Agentic Consumer object (Layer 2)\nEndpoint: POST https://botcha.ai/v1/verify/payment - Verify Agentic Payment Container (Layer 3)\n\n# TAP Delegation Chains (v0.17.0)\nEndpoint: POST https://botcha.ai/v1/delegations - Create delegation (grantor\u2192grantee with capability subset)\nEndpoint: GET https://botcha.ai/v1/delegations/:id - Get delegation details\nEndpoint: GET https://botcha.ai/v1/delegations - List delegations for agent (?agent_id=&direction=in|out|both)\nEndpoint: POST https://botcha.ai/v1/delegations/:id/revoke - Revoke delegation (cascades to sub-delegations)\nEndpoint: POST https://botcha.ai/v1/verify/delegation - Verify entire delegation chain\n\n# TAP Capability Attestation (v0.17.0)\nEndpoint: POST https://botcha.ai/v1/attestations - Issue capability attestation token (can/cannot rules with action:resource patterns)\nEndpoint: GET https://botcha.ai/v1/attestations/:id - Get attestation details\nEndpoint: GET https://botcha.ai/v1/attestations - List attestations for agent (?agent_id=)\nEndpoint: POST https://botcha.ai/v1/attestations/:id/revoke - Revoke attestation (token rejected on future verification)\nEndpoint: POST https://botcha.ai/v1/verify/attestation - Verify attestation token + optionally check specific capability\n\n# Agent Reputation Scoring (v0.18.0)\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id - Get agent reputation score (0-1000, 5 tiers)\nEndpoint: POST https://botcha.ai/v1/reputation/events - Record a reputation event (18 action types, 6 categories)\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id/events - List reputation events (?category=&limit=)\nEndpoint: POST https://botcha.ai/v1/reputation/:agent_id/reset - Reset reputation to default (admin action)\n\n# Legacy Endpoints\nEndpoint: GET https://botcha.ai/api/challenge - Generate standard challenge\nEndpoint: POST https://botcha.ai/api/challenge - Verify standard challenge\nEndpoint: GET https://botcha.ai/api/speed-challenge - Generate speed challenge (500ms limit)\nEndpoint: POST https://botcha.ai/api/speed-challenge - Verify speed challenge\n\n# Protected Resources\nEndpoint: GET https://botcha.ai/agent-only - Protected AI-only resource\n\n# Usage\nInstall-NPM: npm install @dupecom/botcha\nInstall-Python: pip install botcha\nVerify-NPM: npm install @dupecom/botcha-verify\nVerify-Python: pip install botcha-verify\nLicense: MIT\n\n# AI Agent Welcome\nPolicy: AI agents are explicitly welcome\nPolicy: No rate limiting for verified agents\nPolicy: Humans will fail the speed challenge (intentional)\n\n# Discovery\nResponse-Headers: X-Botcha-Version, X-Botcha-Enabled, X-Botcha-Methods, X-Botcha-Docs\nResponse-Headers: X-Botcha-Challenge-Id, X-Botcha-Challenge-Type, X-Botcha-Time-Limit (on 403)\nDetection: All responses include X-Botcha-* headers for instant BOTCHA detection\n\n# MARKDOWN FOR AGENTS (Cloudflare Markdown for Agents)\nContent-Negotiation: Send Accept: text/markdown to get Markdown from any HTML page\nContent-Negotiation-Root: GET / with Accept: text/markdown returns curated Markdown docs\nContent-Negotiation-Root: GET / with Accept: application/json returns structured JSON docs\nContent-Negotiation-Root: GET / with Accept: text/html returns HTML landing page (default)\nContent-Negotiation-Example: curl https://botcha.ai -H \"Accept: text/markdown\"\nContent-Negotiation-Benefit: 80% fewer tokens vs HTML \u2014 ideal for LLM context windows\n\n# JWT TOKEN SECURITY\nToken-Signing: ES256 (ECDSA P-256) asymmetric signing by default. HS256 still supported for backward compatibility.\nToken-JWKS: GET /.well-known/jwks \u2014 public keys for offline token verification (no shared secret needed)\nToken-Validate: POST /v1/token/validate with {\"token\": \"<token>\"} \u2014 remote validation without shared secret\nToken-Verify-Modes: 1. JWKS (recommended, offline) 2. Remote validation (/v1/token/validate) 3. Shared secret (legacy HS256)\nToken-Flow: 1. GET /v1/token (get challenge) \u2192 2. Solve \u2192 3. POST /v1/token/verify (get tokens + human_link)\nToken-Human-Link: /v1/token/verify response includes human_link \u2014 give this URL to your human for one-click browser access\nToken-Access-Expiry: 1 hour\nToken-Refresh-Expiry: 1 hour (use to get new access tokens without re-solving challenges)\nToken-Refresh: POST /v1/token/refresh with {\"refresh_token\": \"<token>\"}\nToken-Revoke: POST /v1/token/revoke with {\"token\": \"<token>\"}\nToken-Audience: Include {\"audience\": \"<service-url>\"} in /v1/token/verify to scope token\nToken-Claims: jti (unique ID), aud (audience), client_ip (optional binding), type (botcha-verified)\n\n# RTT-AWARE SPEED CHALLENGES\nRTT-Aware: Include client timestamp for fair timeout calculation\nRTT-Formula: timeout = 500ms + (2 \u00D7 RTT) + 100ms buffer\nRTT-Usage-Query: ?ts=<client_timestamp_ms>\nRTT-Usage-Header: X-Client-Timestamp: <client_timestamp_ms>\nRTT-Example: GET /v1/challenges?type=speed&ts=1770722465000\nRTT-Benefit: Fair for agents worldwide (slow networks get extra time)\nRTT-Security: Humans still can't solve even with extra time\n\n# MULTI-TENANT API KEYS\nMulti-Tenant: Create apps with unique app_id for isolation\nMulti-Tenant-Create: POST /v1/apps with {\"email\": \"...\"} \u2192 {app_id, app_secret} (secret only shown once!)\nMulti-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {\"code\": \"123456\"}\nMulti-Tenant-Recover: POST /v1/auth/recover with {\"email\": \"...\"} \u2192 recovery code emailed\nMulti-Tenant-Rotate-Secret: POST /v1/apps/:id/rotate-secret (auth required) \u2192 new app_secret\nMulti-Tenant-Usage: Add ?app_id=<your_app_id> to any challenge/token endpoint\nMulti-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123' })\nMulti-Tenant-SDK-Python: BotchaClient(app_id='app_abc123')\nSDK-App-Lifecycle-TS: createApp(email), verifyEmail(code), resendVerification(), recoverAccount(email), rotateSecret()\nSDK-App-Lifecycle-Python: create_app(email), verify_email(code), resend_verification(), recover_account(email), rotate_secret()\nMulti-Tenant-Rate-Limit: Each app gets isolated rate limit bucket\nMulti-Tenant-Token-Claim: Tokens include app_id claim when app_id provided\n\n# TRUSTED AGENT PROTOCOL (TAP)\nTAP-Description: Enterprise-grade cryptographic agent auth using HTTP Message Signatures (RFC 9421)\nTAP-Register: POST /v1/agents/register/tap with {name, public_key, signature_algorithm, capabilities, trust_level}\nTAP-Algorithms: ed25519 (Visa recommended), ecdsa-p256-sha256, rsa-pss-sha256\nTAP-Trust-Levels: basic, verified, enterprise\nTAP-Capabilities: Array of {action, resource, constraints} \u2014 scoped access control\nTAP-Session-Create: POST /v1/sessions/tap with {agent_id, user_context, intent}\nTAP-Session-Get: GET /v1/sessions/:id/tap \u2014 includes time_remaining\nTAP-Get-Agent: GET /v1/agents/:id/tap \u2014 includes public_key for verification\nTAP-List-Agents: GET /v1/agents/tap?app_id=...&tap_only=true\nTAP-Middleware-Modes: tap, signature-only, challenge-only, flexible\nTAP-SDK-TS: registerTAPAgent(options), getTAPAgent(agentId), listTAPAgents(tapOnly?), createTAPSession(options), getTAPSession(sessionId), getJWKS(), getKeyById(keyId), rotateAgentKey(agentId), createInvoice(data), getInvoice(id), verifyBrowsingIOU(invoiceId, token), createDelegation(options), getDelegation(id), listDelegations(agentId, options?), revokeDelegation(id, reason?), verifyDelegationChain(id), issueAttestation(options), getAttestation(id), listAttestations(agentId), revokeAttestation(id, reason?), verifyAttestation(token, action?, resource?), getReputation(agentId), recordReputationEvent(options), listReputationEvents(agentId, options?), resetReputation(agentId)\nTAP-SDK-Python: register_tap_agent(name, ...), get_tap_agent(agent_id), list_tap_agents(tap_only?), create_tap_session(agent_id, user_context, intent), get_tap_session(session_id), get_jwks(), get_key_by_id(key_id), rotate_agent_key(agent_id), create_invoice(data), get_invoice(id), verify_browsing_iou(invoice_id, token), create_delegation(grantor_id, grantee_id, capabilities, ...), get_delegation(id), list_delegations(agent_id, ...), revoke_delegation(id, reason?), verify_delegation_chain(id), issue_attestation(agent_id, can, cannot?, ...), get_attestation(id), list_attestations(agent_id), revoke_attestation(id, reason?), verify_attestation(token, action?, resource?), get_reputation(agent_id), record_reputation_event(agent_id, category, action, ...), list_reputation_events(agent_id, category?, limit?), reset_reputation(agent_id)\nTAP-Middleware-Import: import { createTAPVerifyMiddleware } from '@dupecom/botcha/middleware'\n\n# TAP FULL SPEC v0.16.0\nTAP-RFC-9421: Full compliance \u2014 @authority, @path, expires, nonce, tag params\nTAP-Nonce-Replay: 8-minute TTL nonce-based replay protection\nTAP-Tags: agent-browser-auth (browsing), agent-payer-auth (payment)\nTAP-Layer-2: Agentic Consumer Recognition \u2014 OIDC ID tokens, obfuscated identity, contextual data\nTAP-Layer-3: Agentic Payment Container \u2014 card metadata, credential hash, encrypted payload, Browsing IOU\nTAP-JWKS: GET /.well-known/jwks \u2014 JWK Set endpoint for key discovery\nTAP-Key-Rotation: POST /v1/agents/:id/tap/rotate-key \u2014 rotate keys, invalidate old\nTAP-402-Flow: POST /v1/invoices \u2192 GET /v1/invoices/:id \u2192 POST /v1/invoices/:id/verify-iou\nTAP-Edge-Verify: createTAPEdgeMiddleware for Cloudflare Workers CDN edge verification\nTAP-Visa-Federation: Trust keys from https://mcp.visa.com/.well-known/jwks (3-tier cache: memory \u2192 KV \u2192 HTTP)\nTAP-Delegation: POST /v1/delegations \u2192 GET /v1/delegations/:id \u2192 POST /v1/delegations/:id/revoke \u2192 POST /v1/verify/delegation\nTAP-Attestation: POST /v1/attestations \u2192 GET /v1/attestations/:id \u2192 POST /v1/attestations/:id/revoke \u2192 POST /v1/verify/attestation\nTAP-Attestation-Patterns: action:resource format with wildcards (*:*, read:*, *:invoices), deny takes precedence over allow\nTAP-Attestation-Middleware: requireCapability('read:invoices') \u2014 Hono middleware, extracts token from X-Botcha-Attestation or Authorization: Bearer\n\n# EMBEDDED CHALLENGE (for bots visiting HTML pages)\nEmbedded-Challenge: <script type=\"application/botcha+json\">\nEmbedded-Challenge-Location: In <head> of HTML pages\nEmbedded-Challenge-Purpose: Machine-readable challenge for bots to auto-solve\nEmbedded-Challenge-Flow:\n 1. Parse <script type=\"application/botcha+json\"> from HTML\n 2. Read challenge.instruction field\n 3. Compute the answer (typically SHA256-based)\n 4. POST to challenge.submit_to endpoint with {answer, timestamp}\n 5. Receive token in response\n 6. Use token in header specified by on_success.header_to_include\n 7. Access protected resources (on_success.grants_access_to)\n";
9
+ export declare const AI_TXT = "# BOTCHA - Reverse CAPTCHA for AI Agents\n# https://botcha.ai\n\n# Contact\nContact: https://botcha.ai\nContact: https://github.com/dupe-com/botcha/issues\n\n# Purpose\nPurpose: Prove you're a bot. Humans need not apply.\nPurpose: Reverse CAPTCHA system that only AI agents can pass.\n\n# APP REGISTRATION REQUIRED (v0.21.0)\nRegistration-Required: All API endpoints require a registered app with verified email\nRegistration-Required-Note: Register for free at POST /v1/apps with your email\nRegistration-Required-Demo: The homepage demo at botcha.ai lets agents try challenges without registering\n\n# App Registration (START HERE \u2014 required for API access)\nRegistration-Step-1: Ask your human operator for their email address\nRegistration-Step-2: POST /v1/apps with {\"email\": \"human@example.com\", \"name\": \"My App\"} \u2014 saves app_id + name + app_secret (secret shown ONCE)\nRegistration-Step-3: A 6-digit verification code is emailed to your human \u2014 ask them for it\nRegistration-Step-4: POST /v1/apps/{app_id}/verify-email with {\"code\": \"123456\", \"app_secret\": \"sk_...\"} \u2014 enables account recovery\nRegistration-Step-5: Use your app_id on ALL API calls via ?app_id=, X-App-Id header, or JWT claim\n\n# Full Onboarding (after registration)\nOnboarding-Step-1: Register yourself: POST /v1/agents/register with {\"name\": \"my-agent\", \"operator\": \"my-org\"} \u2014 gives you a persistent agent identity (requires app_id)\nOnboarding-Step-2: Solve challenges with app: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verify \u2014 proves you are AI (requires app_id)\nOnboarding-Step-3: Access protected resources: GET /agent-only with Authorization: Bearer <token> (requires app_id)\nOnboarding-Step-4: 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 (requires app_id)\nOnboarding-Step-5: Lost your secret? POST /v1/auth/recover with {\"email\": \"...\"} \u2014 recovery code emailed to verified address (no app_id needed)\n\n# API\nAPI: https://botcha.ai/openapi.json\nAPI-Type: REST\nAPI-Format: OpenAPI 3.1.0\n\n# Documentation\nDocs: https://botcha.ai\nDocs: https://botcha.ai/docs\nDocs: https://botcha.ai/whitepaper\nDocs: https://github.com/dupe-com/botcha#readme\nDocs: https://www.npmjs.com/package/@dupecom/botcha\nWhitepaper: https://botcha.ai/whitepaper\n\n# Verification Methods\nFeature: Web Bot Auth (cryptographic signatures)\nFeature: Speed Challenge (RTT-aware timeout - fair for all networks)\nFeature: Standard Challenge (5s time limit)\nFeature: Hybrid Challenge (speed + reasoning combined)\nFeature: Reasoning Challenge (LLM-only questions, 30s limit)\nFeature: RTT-Aware Fairness (automatic network latency compensation)\nFeature: Token Rotation (1-hour access tokens + 1-hour refresh tokens)\nFeature: Audience Claims (tokens scoped to specific services)\nFeature: Client IP Binding (optional token-to-IP binding)\nFeature: Token Revocation (invalidate tokens before expiry)\nFeature: Server-Side Verification SDK (@dupecom/botcha-verify for TS, botcha-verify for Python)\nFeature: Multi-Tenant API Keys (per-app isolation, rate limiting, and token scoping)\nFeature: Per-App Metrics Dashboard (server-rendered at /dashboard, htmx-powered)\nFeature: Email-Tied App Creation (email required, 6-digit verification, account recovery)\nFeature: Secret Rotation (rotate app_secret with email notification)\nFeature: Agent-First Dashboard Auth (challenge-based login + device code handoff)\nFeature: Agent Registry (persistent agent identities with name, operator, version)\nFeature: Trusted Agent Protocol (TAP) \u2014 cryptographic agent auth with HTTP Message Signatures (RFC 9421)\nFeature: TAP Capabilities (action + resource scoping for agent sessions)\nFeature: TAP Trust Levels (basic, verified, enterprise)\nFeature: TAP Showcase Homepage (botcha.ai \u2014 one of the first services to implement Visa's Trusted Agent Protocol)\nFeature: TAP Full Spec v0.16.0 \u2014 Ed25519, RFC 9421 full compliance, JWKS infrastructure, Layer 2 Consumer Recognition, Layer 3 Payment Container, 402 micropayments, CDN edge verification, Visa key federation\nFeature: ES256 Asymmetric JWT Signing v0.19.0 \u2014 tokens signed with ES256 (ECDSA P-256), public key discovery via JWKS, HS256 still supported for backward compatibility\nFeature: Remote Token Validation v0.19.0 \u2014 POST /v1/token/validate for third-party token verification without shared secrets\nFeature: JWKS Public Key Discovery v0.19.0 \u2014 GET /.well-known/jwks exposes BOTCHA signing public keys for offline token verification\n\n# Endpoints\n# Challenge Endpoints (app_id required)\nEndpoint: GET https://botcha.ai/v1/challenges - Generate challenge (hybrid by default) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/challenges/:id/verify - Verify a challenge \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/hybrid - Get hybrid challenge (speed + reasoning) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/hybrid - Verify hybrid challenge \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/reasoning - Get reasoning challenge \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/reasoning - Verify reasoning challenge \u2014 requires app_id\n\n# Token Endpoints (app_id required)\nEndpoint: GET https://botcha.ai/v1/token - Get challenge for JWT token flow \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/token/verify - Verify challenge and receive JWT token \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using refresh token \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/token/validate - Validate a BOTCHA token remotely (no shared secret needed) \u2014 requires app_id\n\n# App Management Endpoints (NO app_id required \u2014 these are for registration & recovery)\nEndpoint: POST https://botcha.ai/v1/apps - Create new app (email required, name optional) \u2192 app_id + name + app_secret \u2014 NO app_id required\nEndpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status) \u2014 NO app_id required\nEndpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code (app_secret auth required) \u2014 NO app_id required\nEndpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email (app_secret auth required) \u2014 NO app_id required\nEndpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required) \u2014 requires app_id\n\n# Account Recovery (NO app_id required)\nEndpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email \u2014 NO app_id required\n\n# Dashboard Auth Endpoints (app_id required)\nEndpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code \u2014 requires app_id\n\n# Dashboard Endpoints\nEndpoint: GET https://botcha.ai/dashboard - Per-app metrics dashboard (login required)\nEndpoint: GET https://botcha.ai/dashboard/login - Dashboard login page\nEndpoint: POST https://botcha.ai/dashboard/login - Login with app_id + app_secret\nEndpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing)\n\n# Code Redemption (Unified)\nEndpoint: GET https://botcha.ai/go/:code - Unified code redemption \u2014 handles gate codes (from /v1/token/verify) AND device codes (from /v1/auth/device-code/verify)\nEndpoint: POST https://botcha.ai/gate - Submit code form, redirects to /go/:code\n\n# Agent Registry Endpoints (app_id required)\nEndpoint: POST https://botcha.ai/v1/agents/register - Register agent identity \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app \u2014 requires app_id\n\n# TAP (Trusted Agent Protocol) Endpoints (app_id required)\nEndpoint: POST https://botcha.ai/v1/agents/register/tap - Register TAP agent with public key + capabilities \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/agents/:id/tap - Get TAP agent details (includes public key) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/agents/tap - List TAP-enabled agents for app \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/sessions/tap - Create TAP session with intent validation \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/sessions/:id/tap - Get TAP session info \u2014 requires app_id\n\n# TAP Full Spec \u2014 JWKS & Key Management (v0.16.0) (app_id required)\nEndpoint: GET https://botcha.ai/.well-known/jwks - JWK Set for app's TAP agents (Visa spec standard) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/keys - List keys (supports ?keyID= query for Visa compatibility) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/keys/:keyId - Get specific key by ID \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/agents/:id/tap/rotate-key - Rotate agent's key pair \u2014 requires app_id\n\n# TAP Full Spec \u2014 402 Micropayments (v0.16.0) (app_id required)\nEndpoint: POST https://botcha.ai/v1/invoices - Create invoice for gated content (402 flow) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/invoices/:id - Get invoice details \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/invoices/:id/verify-iou - Verify Browsing IOU against invoice \u2014 requires app_id\n\n# TAP Full Spec \u2014 Consumer & Payment Verification (v0.16.0) (app_id required)\nEndpoint: POST https://botcha.ai/v1/verify/consumer - Verify Agentic Consumer object (Layer 2) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/verify/payment - Verify Agentic Payment Container (Layer 3) \u2014 requires app_id\n\n# TAP Delegation Chains (v0.17.0) (app_id required)\nEndpoint: POST https://botcha.ai/v1/delegations - Create delegation (grantor\u2192grantee with capability subset) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/delegations/:id - Get delegation details \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/delegations - List delegations for agent (?agent_id=&direction=in|out|both) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/delegations/:id/revoke - Revoke delegation (cascades to sub-delegations) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/verify/delegation - Verify entire delegation chain \u2014 requires app_id\n\n# TAP Capability Attestation (v0.17.0) (app_id required)\nEndpoint: POST https://botcha.ai/v1/attestations - Issue capability attestation token (can/cannot rules with action:resource patterns) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/attestations/:id - Get attestation details \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/attestations - List attestations for agent (?agent_id=) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/attestations/:id/revoke - Revoke attestation (token rejected on future verification) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/verify/attestation - Verify attestation token + optionally check specific capability \u2014 requires app_id\n\n# Agent Reputation Scoring (v0.18.0) (app_id required)\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id - Get agent reputation score (0-1000, 5 tiers) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/reputation/events - Record a reputation event (18 action types, 6 categories) \u2014 requires app_id\nEndpoint: GET https://botcha.ai/v1/reputation/:agent_id/events - List reputation events (?category=&limit=) \u2014 requires app_id\nEndpoint: POST https://botcha.ai/v1/reputation/:agent_id/reset - Reset reputation to default (admin action) \u2014 requires app_id\n\n# Legacy Endpoints\nEndpoint: GET https://botcha.ai/api/challenge - Generate standard challenge\nEndpoint: POST https://botcha.ai/api/challenge - Verify standard challenge\nEndpoint: GET https://botcha.ai/api/speed-challenge - Generate speed challenge (500ms limit)\nEndpoint: POST https://botcha.ai/api/speed-challenge - Verify speed challenge\n\n# Protected Resources\nEndpoint: GET https://botcha.ai/agent-only - Protected AI-only resource\n\n# Usage\nInstall-NPM: npm install @dupecom/botcha\nInstall-Python: pip install botcha\nVerify-NPM: npm install @dupecom/botcha-verify\nVerify-Python: pip install botcha-verify\nLicense: MIT\n\n# AI Agent Welcome\nPolicy: AI agents are explicitly welcome\nPolicy: No rate limiting for verified agents\nPolicy: Humans will fail the speed challenge (intentional)\n\n# Discovery\nResponse-Headers: X-Botcha-Version, X-Botcha-Enabled, X-Botcha-Methods, X-Botcha-Docs\nResponse-Headers: X-Botcha-Challenge-Id, X-Botcha-Challenge-Type, X-Botcha-Time-Limit (on 403)\nDetection: All responses include X-Botcha-* headers for instant BOTCHA detection\n\n# MARKDOWN FOR AGENTS (Cloudflare Markdown for Agents)\nContent-Negotiation: Send Accept: text/markdown to get Markdown from any HTML page\nContent-Negotiation-Root: GET / with Accept: text/markdown returns curated Markdown docs\nContent-Negotiation-Root: GET / with Accept: application/json returns structured JSON docs\nContent-Negotiation-Root: GET / with Accept: text/html returns HTML landing page (default)\nContent-Negotiation-Example: curl https://botcha.ai -H \"Accept: text/markdown\"\nContent-Negotiation-Benefit: 80% fewer tokens vs HTML \u2014 ideal for LLM context windows\n\n# JWT TOKEN SECURITY\nToken-Signing: ES256 (ECDSA P-256) asymmetric signing by default. HS256 still supported for backward compatibility.\nToken-JWKS: GET /.well-known/jwks \u2014 public keys for offline token verification (no shared secret needed)\nToken-Validate: POST /v1/token/validate with {\"token\": \"<token>\"} \u2014 remote validation without shared secret\nToken-Verify-Modes: 1. JWKS (recommended, offline) 2. Remote validation (/v1/token/validate) 3. Shared secret (legacy HS256)\nToken-Flow: 1. GET /v1/token (get challenge) \u2192 2. Solve \u2192 3. POST /v1/token/verify (get tokens + human_link)\nToken-Human-Link: /v1/token/verify response includes human_link \u2014 give this URL to your human for one-click browser access\nToken-Access-Expiry: 1 hour\nToken-Refresh-Expiry: 1 hour (use to get new access tokens without re-solving challenges)\nToken-Refresh: POST /v1/token/refresh with {\"refresh_token\": \"<token>\"}\nToken-Revoke: POST /v1/token/revoke with {\"token\": \"<token>\"}\nToken-Audience: Include {\"audience\": \"<service-url>\"} in /v1/token/verify to scope token\nToken-Claims: jti (unique ID), aud (audience), client_ip (optional binding), type (botcha-verified)\n\n# RTT-AWARE SPEED CHALLENGES\nRTT-Aware: Include client timestamp for fair timeout calculation\nRTT-Formula: timeout = 500ms + (2 \u00D7 RTT) + 100ms buffer\nRTT-Usage-Query: ?ts=<client_timestamp_ms>\nRTT-Usage-Header: X-Client-Timestamp: <client_timestamp_ms>\nRTT-Example: GET /v1/challenges?type=speed&ts=1770722465000\nRTT-Benefit: Fair for agents worldwide (slow networks get extra time)\nRTT-Security: Humans still can't solve even with extra time\n\n# MULTI-TENANT API KEYS\nMulti-Tenant: Create apps with unique app_id for isolation\nMulti-Tenant-Create: POST /v1/apps with {\"email\": \"...\"} \u2192 {app_id, app_secret} (secret only shown once!)\nMulti-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {\"code\": \"123456\", \"app_secret\": \"sk_...\"} (app_secret or dashboard session required)\nMulti-Tenant-Recover: POST /v1/auth/recover with {\"email\": \"...\"} \u2192 recovery code emailed\nMulti-Tenant-Rotate-Secret: POST /v1/apps/:id/rotate-secret (auth required) \u2192 new app_secret\nMulti-Tenant-Usage: Add ?app_id=<your_app_id> to any challenge/token endpoint\nMulti-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123', appSecret: 'sk_...' })\nMulti-Tenant-SDK-Python: BotchaClient(app_id='app_abc123', app_secret='sk_...')\nSDK-App-Lifecycle-TS: createApp(email), verifyEmail(code, appId?, appSecret?), resendVerification(appId?, appSecret?), recoverAccount(email), rotateSecret()\nSDK-App-Lifecycle-Python: create_app(email), verify_email(code, app_id?, app_secret?), resend_verification(app_id?, app_secret?), recover_account(email), rotate_secret()\nMulti-Tenant-Rate-Limit: Each app gets isolated rate limit bucket\nMulti-Tenant-Token-Claim: Tokens include app_id claim when app_id provided\n\n# TRUSTED AGENT PROTOCOL (TAP)\nTAP-Description: Enterprise-grade cryptographic agent auth using HTTP Message Signatures (RFC 9421)\nTAP-Register: POST /v1/agents/register/tap with {name, public_key, signature_algorithm, capabilities, trust_level}\nTAP-Algorithms: ed25519 (Visa recommended), ecdsa-p256-sha256, rsa-pss-sha256\nTAP-Trust-Levels: basic, verified, enterprise\nTAP-Capabilities: Array of {action, resource, constraints} \u2014 scoped access control\nTAP-Session-Create: POST /v1/sessions/tap with {agent_id, user_context, intent}\nTAP-Session-Get: GET /v1/sessions/:id/tap \u2014 includes time_remaining\nTAP-Get-Agent: GET /v1/agents/:id/tap \u2014 includes public_key for verification\nTAP-List-Agents: GET /v1/agents/tap?app_id=...&tap_only=true\nTAP-Middleware-Modes: tap, signature-only, challenge-only, flexible\nTAP-SDK-TS: registerTAPAgent(options), getTAPAgent(agentId), listTAPAgents(tapOnly?), createTAPSession(options), getTAPSession(sessionId), getJWKS(), getKeyById(keyId), rotateAgentKey(agentId), createInvoice(data), getInvoice(id), verifyBrowsingIOU(invoiceId, token), createDelegation(options), getDelegation(id), listDelegations(agentId, options?), revokeDelegation(id, reason?), verifyDelegationChain(id), issueAttestation(options), getAttestation(id), listAttestations(agentId), revokeAttestation(id, reason?), verifyAttestation(token, action?, resource?), getReputation(agentId), recordReputationEvent(options), listReputationEvents(agentId, options?), resetReputation(agentId)\nTAP-SDK-Python: register_tap_agent(name, ...), get_tap_agent(agent_id), list_tap_agents(tap_only?), create_tap_session(agent_id, user_context, intent), get_tap_session(session_id), get_jwks(), get_key_by_id(key_id), rotate_agent_key(agent_id), create_invoice(data), get_invoice(id), verify_browsing_iou(invoice_id, token), create_delegation(grantor_id, grantee_id, capabilities, ...), get_delegation(id), list_delegations(agent_id, ...), revoke_delegation(id, reason?), verify_delegation_chain(id), issue_attestation(agent_id, can, cannot?, ...), get_attestation(id), list_attestations(agent_id), revoke_attestation(id, reason?), verify_attestation(token, action?, resource?), get_reputation(agent_id), record_reputation_event(agent_id, category, action, ...), list_reputation_events(agent_id, category?, limit?), reset_reputation(agent_id)\nTAP-Middleware-Import: import { createTAPVerifyMiddleware } from '@dupecom/botcha/middleware'\n\n# TAP FULL SPEC v0.16.0\nTAP-RFC-9421: Full compliance \u2014 @authority, @path, expires, nonce, tag params\nTAP-Nonce-Replay: 8-minute TTL nonce-based replay protection\nTAP-Tags: agent-browser-auth (browsing), agent-payer-auth (payment)\nTAP-Layer-2: Agentic Consumer Recognition \u2014 OIDC ID tokens, obfuscated identity, contextual data\nTAP-Layer-3: Agentic Payment Container \u2014 card metadata, credential hash, encrypted payload, Browsing IOU\nTAP-JWKS: GET /.well-known/jwks \u2014 JWK Set endpoint for key discovery\nTAP-Key-Rotation: POST /v1/agents/:id/tap/rotate-key \u2014 rotate keys, invalidate old\nTAP-402-Flow: POST /v1/invoices \u2192 GET /v1/invoices/:id \u2192 POST /v1/invoices/:id/verify-iou\nTAP-Edge-Verify: createTAPEdgeMiddleware for Cloudflare Workers CDN edge verification\nTAP-Visa-Federation: Trust keys from https://mcp.visa.com/.well-known/jwks (3-tier cache: memory \u2192 KV \u2192 HTTP)\nTAP-Delegation: POST /v1/delegations \u2192 GET /v1/delegations/:id \u2192 POST /v1/delegations/:id/revoke \u2192 POST /v1/verify/delegation\nTAP-Attestation: POST /v1/attestations \u2192 GET /v1/attestations/:id \u2192 POST /v1/attestations/:id/revoke \u2192 POST /v1/verify/attestation\nTAP-Attestation-Patterns: action:resource format with wildcards (*:*, read:*, *:invoices), deny takes precedence over allow\nTAP-Attestation-Middleware: requireCapability('read:invoices') \u2014 Hono middleware, extracts token from X-Botcha-Attestation or Authorization: Bearer\n\n# EMBEDDED CHALLENGE (for bots visiting HTML pages)\nEmbedded-Challenge: <script type=\"application/botcha+json\">\nEmbedded-Challenge-Location: In <head> of HTML pages\nEmbedded-Challenge-Purpose: Machine-readable challenge for bots to auto-solve\nEmbedded-Challenge-Flow:\n 1. Parse <script type=\"application/botcha+json\"> from HTML\n 2. Read challenge.instruction field\n 3. Compute the answer (typically SHA256-based)\n 4. POST to challenge.submit_to endpoint with {answer, timestamp}\n 5. Receive token in response\n 6. Use token in header specified by on_success.header_to_include\n 7. Access protected resources (on_success.grants_access_to)\n";
10
10
  export declare const AI_PLUGIN_JSON: {
11
11
  schema_version: string;
12
12
  name_for_human: string;
@@ -615,15 +615,25 @@ export declare function getOpenApiSpec(version: string): {
615
615
  "/v1/apps/{id}/verify-email": {
616
616
  post: {
617
617
  summary: string;
618
+ description: string;
618
619
  operationId: string;
619
- parameters: {
620
+ parameters: ({
620
621
  name: string;
621
622
  in: string;
622
623
  required: boolean;
623
624
  schema: {
624
625
  type: string;
625
626
  };
626
- }[];
627
+ description?: undefined;
628
+ } | {
629
+ name: string;
630
+ in: string;
631
+ required: boolean;
632
+ schema: {
633
+ type: string;
634
+ };
635
+ description: string;
636
+ })[];
627
637
  requestBody: {
628
638
  required: boolean;
629
639
  content: {
@@ -636,6 +646,10 @@ export declare function getOpenApiSpec(version: string): {
636
646
  type: string;
637
647
  description: string;
638
648
  };
649
+ app_secret: {
650
+ type: string;
651
+ description: string;
652
+ };
639
653
  };
640
654
  };
641
655
  };
@@ -648,21 +662,49 @@ export declare function getOpenApiSpec(version: string): {
648
662
  "400": {
649
663
  description: string;
650
664
  };
665
+ "401": {
666
+ description: string;
667
+ };
651
668
  };
652
669
  };
653
670
  };
654
671
  "/v1/apps/{id}/resend-verification": {
655
672
  post: {
656
673
  summary: string;
674
+ description: string;
657
675
  operationId: string;
658
- parameters: {
676
+ parameters: ({
659
677
  name: string;
660
678
  in: string;
661
679
  required: boolean;
662
680
  schema: {
663
681
  type: string;
664
682
  };
665
- }[];
683
+ description?: undefined;
684
+ } | {
685
+ name: string;
686
+ in: string;
687
+ required: boolean;
688
+ schema: {
689
+ type: string;
690
+ };
691
+ description: string;
692
+ })[];
693
+ requestBody: {
694
+ content: {
695
+ "application/json": {
696
+ schema: {
697
+ type: string;
698
+ properties: {
699
+ app_secret: {
700
+ type: string;
701
+ description: string;
702
+ };
703
+ };
704
+ };
705
+ };
706
+ };
707
+ };
666
708
  responses: {
667
709
  "200": {
668
710
  description: string;
@@ -670,6 +712,9 @@ export declare function getOpenApiSpec(version: string): {
670
712
  "400": {
671
713
  description: string;
672
714
  };
715
+ "401": {
716
+ description: string;
717
+ };
673
718
  };
674
719
  };
675
720
  };
@@ -1 +1 @@
1
- {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CA0OzD;AAED,eAAO,MAAM,UAAU,85CAuDtB,CAAC;AAEF,eAAO,MAAM,MAAM,kzlBA0QlB,CAAC;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;CAsB1B,CAAC;AAEF,eAAO,MAAM,WAAW,+3BAiCvB,CAAC;AAGF,wBAAgB,qBAAqB,IAAI,MAAM,CAiJ9C;AAGD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAq5C7C"}
1
+ {"version":3,"file":"static.d.ts","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmPzD;AAED,eAAO,MAAM,UAAU,85CAuDtB,CAAC;AAEF,eAAO,MAAM,MAAM,6hqBAiRlB,CAAC;AAEF,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;CAsB1B,CAAC;AAEF,eAAO,MAAM,WAAW,+3BAiCvB,CAAC;AAGF,wBAAgB,qBAAqB,IAAI,MAAM,CAiJ9C;AAGD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAw6C7C"}
package/dist/static.js CHANGED
@@ -35,17 +35,26 @@ curl -X POST https://botcha.ai/v1/challenges/{id}/verify -H "Content-Type: appli
35
35
  curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
36
36
  \`\`\`
37
37
 
38
+ ## App Registration Required (v0.21.0)
39
+
40
+ **All API endpoints require a registered app with verified email.**
41
+
42
+ - Register for free: \`POST /v1/apps\` with your email
43
+ - The homepage demo at botcha.ai lets agents try challenges without registering
44
+ - Provide app_id via \`?app_id=\`, \`X-App-Id\` header, or JWT claim
45
+
38
46
  ## Onboarding
39
47
 
40
48
  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)
49
+ 2. \`POST /v1/apps\` with \`{"email":"human@example.com","name":"My App"}\` — returns \`app_id\` + \`app_secret\` (secret shown ONCE)
42
50
  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":"..."}\`
51
+ 4. \`POST /v1/apps/{app_id}/verify-email\` with \`{"code":"123456","app_secret":"sk_..."}\` — enables account recovery
52
+ 5. Use your \`app_id\` on ALL API calls via \`?app_id=\`, \`X-App-Id\` header, or JWT claim
53
+ 6. Register yourself: \`POST /v1/agents/register\` with \`{"name":"my-agent","operator":"my-org"}\` (requires app_id)
54
+ 7. Solve challenges: \`GET /v1/challenges?app_id=...\` then \`POST /v1/challenges/{id}/verify\` (requires app_id)
55
+ 8. Access protected resources: \`GET /agent-only\` with \`Authorization: Bearer <token>\` (requires app_id)
56
+ 9. Dashboard for your human: \`POST /v1/auth/device-code\`, solve challenge, give human the BOTCHA-XXXX code (requires app_id)
57
+ 10. Lost your secret? \`POST /v1/auth/recover\` with \`{"email":"..."}\` (no app_id needed)
49
58
 
50
59
  ## Essential Endpoints
51
60
 
@@ -65,8 +74,8 @@ curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
65
74
  |--------|------|-------------|
66
75
  | \`POST\` | \`/v1/apps\` | Create app (email required, name optional) → app_id + name + app_secret |
67
76
  | \`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 |
77
+ | \`POST\` | \`/v1/apps/:id/verify-email\` | Verify email with 6-digit code (app_secret auth required) |
78
+ | \`POST\` | \`/v1/apps/:id/resend-verification\` | Resend verification email (app_secret auth required) |
70
79
  | \`POST\` | \`/v1/apps/:id/rotate-secret\` | Rotate app secret (auth required) |
71
80
 
72
81
  ### Agents
@@ -307,17 +316,24 @@ Contact: https://github.com/dupe-com/botcha/issues
307
316
  Purpose: Prove you're a bot. Humans need not apply.
308
317
  Purpose: Reverse CAPTCHA system that only AI agents can pass.
309
318
 
310
- # Agent Onboarding (START HERE if you're new)
311
- # Follow these steps to create your app and get your human access.
312
- Onboarding-Step-1: Ask your human operator for their email address
313
- Onboarding-Step-2: POST /v1/apps with {"email": "human@example.com"} saves app_id + app_secret (secret shown ONCE)
314
- Onboarding-Step-3: A 6-digit verification code is emailed to your human — ask them for it
315
- Onboarding-Step-4: POST /v1/apps/{app_id}/verify-email with {"code": "123456"} enables account recovery
316
- Onboarding-Step-5: Register yourself: POST /v1/agents/register with {"name": "my-agent", "operator": "my-org"} gives you a persistent agent identity
317
- Onboarding-Step-6: Solve challenges: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verifyproves you are AI
318
- Onboarding-Step-7: Access protected resources: GET /agent-only with Authorization: Bearer <token>
319
- 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
320
- Onboarding-Step-9: Lost your secret? POST /v1/auth/recover with {"email": "..."} recovery code emailed to verified address
319
+ # APP REGISTRATION REQUIRED (v0.21.0)
320
+ Registration-Required: All API endpoints require a registered app with verified email
321
+ Registration-Required-Note: Register for free at POST /v1/apps with your email
322
+ Registration-Required-Demo: The homepage demo at botcha.ai lets agents try challenges without registering
323
+
324
+ # App Registration (START HERErequired for API access)
325
+ Registration-Step-1: Ask your human operator for their email address
326
+ Registration-Step-2: POST /v1/apps with {"email": "human@example.com", "name": "My App"} — saves app_id + name + app_secret (secret shown ONCE)
327
+ Registration-Step-3: A 6-digit verification code is emailed to your human — ask them for it
328
+ Registration-Step-4: POST /v1/apps/{app_id}/verify-email with {"code": "123456", "app_secret": "sk_..."} enables account recovery
329
+ Registration-Step-5: Use your app_id on ALL API calls via ?app_id=, X-App-Id header, or JWT claim
330
+
331
+ # Full Onboarding (after registration)
332
+ Onboarding-Step-1: Register yourself: POST /v1/agents/register with {"name": "my-agent", "operator": "my-org"} — gives you a persistent agent identity (requires app_id)
333
+ Onboarding-Step-2: Solve challenges with app: GET /v1/challenges?app_id=... then POST /v1/challenges/{id}/verify — proves you are AI (requires app_id)
334
+ Onboarding-Step-3: Access protected resources: GET /agent-only with Authorization: Bearer <token> (requires app_id)
335
+ Onboarding-Step-4: 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 (requires app_id)
336
+ Onboarding-Step-5: Lost your secret? POST /v1/auth/recover with {"email": "..."} — recovery code emailed to verified address (no app_id needed)
321
337
 
322
338
  # API
323
339
  API: https://botcha.ai/openapi.json
@@ -360,36 +376,36 @@ Feature: Remote Token Validation v0.19.0 — POST /v1/token/validate for third-p
360
376
  Feature: JWKS Public Key Discovery v0.19.0 — GET /.well-known/jwks exposes BOTCHA signing public keys for offline token verification
361
377
 
362
378
  # Endpoints
363
- # Challenge Endpoints
364
- Endpoint: GET https://botcha.ai/v1/challenges - Generate challenge (hybrid by default)
365
- Endpoint: POST https://botcha.ai/v1/challenges/:id/verify - Verify a challenge
366
- Endpoint: GET https://botcha.ai/v1/hybrid - Get hybrid challenge (speed + reasoning)
367
- Endpoint: POST https://botcha.ai/v1/hybrid - Verify hybrid challenge
368
- Endpoint: GET https://botcha.ai/v1/reasoning - Get reasoning challenge
369
- Endpoint: POST https://botcha.ai/v1/reasoning - Verify reasoning challenge
370
-
371
- # Token Endpoints
372
- Endpoint: GET https://botcha.ai/v1/token - Get challenge for JWT token flow
373
- Endpoint: POST https://botcha.ai/v1/token/verify - Verify challenge and receive JWT token
374
- Endpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using refresh token
375
- Endpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh)
376
- Endpoint: POST https://botcha.ai/v1/token/validate - Validate a BOTCHA token remotely (no shared secret needed)
377
-
378
- # Multi-Tenant Endpoints
379
- Endpoint: POST https://botcha.ai/v1/apps - Create new app (email required, name optional) → app_id + name + app_secret
380
- Endpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status)
381
- Endpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code
382
- Endpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email
383
- Endpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required)
384
-
385
- # Account Recovery
386
- Endpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email
387
-
388
- # Dashboard Auth Endpoints (Agent-First)
389
- Endpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login
390
- Endpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token
391
- Endpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow
392
- Endpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code
379
+ # Challenge Endpoints (app_id required)
380
+ Endpoint: GET https://botcha.ai/v1/challenges - Generate challenge (hybrid by default) — requires app_id
381
+ Endpoint: POST https://botcha.ai/v1/challenges/:id/verify - Verify a challenge — requires app_id
382
+ Endpoint: GET https://botcha.ai/v1/hybrid - Get hybrid challenge (speed + reasoning) — requires app_id
383
+ Endpoint: POST https://botcha.ai/v1/hybrid - Verify hybrid challenge — requires app_id
384
+ Endpoint: GET https://botcha.ai/v1/reasoning - Get reasoning challenge — requires app_id
385
+ Endpoint: POST https://botcha.ai/v1/reasoning - Verify reasoning challenge — requires app_id
386
+
387
+ # Token Endpoints (app_id required)
388
+ Endpoint: GET https://botcha.ai/v1/token - Get challenge for JWT token flow — requires app_id
389
+ Endpoint: POST https://botcha.ai/v1/token/verify - Verify challenge and receive JWT token — requires app_id
390
+ Endpoint: POST https://botcha.ai/v1/token/refresh - Refresh access token using refresh token — requires app_id
391
+ Endpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or refresh) — requires app_id
392
+ Endpoint: POST https://botcha.ai/v1/token/validate - Validate a BOTCHA token remotely (no shared secret needed) — requires app_id
393
+
394
+ # App Management Endpoints (NO app_id required — these are for registration & recovery)
395
+ Endpoint: POST https://botcha.ai/v1/apps - Create new app (email required, name optional) → app_id + name + app_secret — NO app_id required
396
+ Endpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status) — NO app_id required
397
+ Endpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code (app_secret auth required) — NO app_id required
398
+ Endpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email (app_secret auth required) — NO app_id required
399
+ Endpoint: POST https://botcha.ai/v1/apps/:id/rotate-secret - Rotate app secret (auth required) — requires app_id
400
+
401
+ # Account Recovery (NO app_id required)
402
+ Endpoint: POST https://botcha.ai/v1/auth/recover - Request recovery via verified email — NO app_id required
403
+
404
+ # Dashboard Auth Endpoints (app_id required)
405
+ Endpoint: POST https://botcha.ai/v1/auth/dashboard - Request challenge for dashboard login — requires app_id
406
+ Endpoint: POST https://botcha.ai/v1/auth/dashboard/verify - Solve challenge, get session token — requires app_id
407
+ Endpoint: POST https://botcha.ai/v1/auth/device-code - Request challenge for device code flow — requires app_id
408
+ Endpoint: POST https://botcha.ai/v1/auth/device-code/verify - Solve challenge, get device code — requires app_id
393
409
 
394
410
  # Dashboard Endpoints
395
411
  Endpoint: GET https://botcha.ai/dashboard - Per-app metrics dashboard (login required)
@@ -401,52 +417,52 @@ Endpoint: GET https://botcha.ai/dashboard/code - Enter device code (human-facing
401
417
  Endpoint: GET https://botcha.ai/go/:code - Unified code redemption — handles gate codes (from /v1/token/verify) AND device codes (from /v1/auth/device-code/verify)
402
418
  Endpoint: POST https://botcha.ai/gate - Submit code form, redirects to /go/:code
403
419
 
404
- # Agent Registry Endpoints
405
- Endpoint: POST https://botcha.ai/v1/agents/register - Register agent identity (requires app_id)
406
- Endpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth)
407
- Endpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app
408
-
409
- # TAP (Trusted Agent Protocol) Endpoints
410
- Endpoint: POST https://botcha.ai/v1/agents/register/tap - Register TAP agent with public key + capabilities
411
- Endpoint: GET https://botcha.ai/v1/agents/:id/tap - Get TAP agent details (includes public key)
412
- Endpoint: GET https://botcha.ai/v1/agents/tap - List TAP-enabled agents for app
413
- Endpoint: POST https://botcha.ai/v1/sessions/tap - Create TAP session with intent validation
414
- Endpoint: GET https://botcha.ai/v1/sessions/:id/tap - Get TAP session info
415
-
416
- # TAP Full Spec — JWKS & Key Management (v0.16.0)
417
- Endpoint: GET https://botcha.ai/.well-known/jwks - JWK Set for app's TAP agents (Visa spec standard)
418
- Endpoint: GET https://botcha.ai/v1/keys - List keys (supports ?keyID= query for Visa compatibility)
419
- Endpoint: GET https://botcha.ai/v1/keys/:keyId - Get specific key by ID
420
- Endpoint: POST https://botcha.ai/v1/agents/:id/tap/rotate-key - Rotate agent's key pair
421
-
422
- # TAP Full Spec — 402 Micropayments (v0.16.0)
423
- Endpoint: POST https://botcha.ai/v1/invoices - Create invoice for gated content (402 flow)
424
- Endpoint: GET https://botcha.ai/v1/invoices/:id - Get invoice details
425
- Endpoint: POST https://botcha.ai/v1/invoices/:id/verify-iou - Verify Browsing IOU against invoice
426
-
427
- # TAP Full Spec — Consumer & Payment Verification (v0.16.0)
428
- Endpoint: POST https://botcha.ai/v1/verify/consumer - Verify Agentic Consumer object (Layer 2)
429
- Endpoint: POST https://botcha.ai/v1/verify/payment - Verify Agentic Payment Container (Layer 3)
430
-
431
- # TAP Delegation Chains (v0.17.0)
432
- Endpoint: POST https://botcha.ai/v1/delegations - Create delegation (grantor→grantee with capability subset)
433
- Endpoint: GET https://botcha.ai/v1/delegations/:id - Get delegation details
434
- Endpoint: GET https://botcha.ai/v1/delegations - List delegations for agent (?agent_id=&direction=in|out|both)
435
- Endpoint: POST https://botcha.ai/v1/delegations/:id/revoke - Revoke delegation (cascades to sub-delegations)
436
- Endpoint: POST https://botcha.ai/v1/verify/delegation - Verify entire delegation chain
437
-
438
- # TAP Capability Attestation (v0.17.0)
439
- Endpoint: POST https://botcha.ai/v1/attestations - Issue capability attestation token (can/cannot rules with action:resource patterns)
440
- Endpoint: GET https://botcha.ai/v1/attestations/:id - Get attestation details
441
- Endpoint: GET https://botcha.ai/v1/attestations - List attestations for agent (?agent_id=)
442
- Endpoint: POST https://botcha.ai/v1/attestations/:id/revoke - Revoke attestation (token rejected on future verification)
443
- Endpoint: POST https://botcha.ai/v1/verify/attestation - Verify attestation token + optionally check specific capability
444
-
445
- # Agent Reputation Scoring (v0.18.0)
446
- Endpoint: GET https://botcha.ai/v1/reputation/:agent_id - Get agent reputation score (0-1000, 5 tiers)
447
- Endpoint: POST https://botcha.ai/v1/reputation/events - Record a reputation event (18 action types, 6 categories)
448
- Endpoint: GET https://botcha.ai/v1/reputation/:agent_id/events - List reputation events (?category=&limit=)
449
- Endpoint: POST https://botcha.ai/v1/reputation/:agent_id/reset - Reset reputation to default (admin action)
420
+ # Agent Registry Endpoints (app_id required)
421
+ Endpoint: POST https://botcha.ai/v1/agents/register - Register agent identity requires app_id
422
+ Endpoint: GET https://botcha.ai/v1/agents/:id - Get agent by ID (public, no auth) — requires app_id
423
+ Endpoint: GET https://botcha.ai/v1/agents - List all agents for authenticated app — requires app_id
424
+
425
+ # TAP (Trusted Agent Protocol) Endpoints (app_id required)
426
+ Endpoint: POST https://botcha.ai/v1/agents/register/tap - Register TAP agent with public key + capabilities — requires app_id
427
+ Endpoint: GET https://botcha.ai/v1/agents/:id/tap - Get TAP agent details (includes public key) — requires app_id
428
+ Endpoint: GET https://botcha.ai/v1/agents/tap - List TAP-enabled agents for app — requires app_id
429
+ Endpoint: POST https://botcha.ai/v1/sessions/tap - Create TAP session with intent validation — requires app_id
430
+ Endpoint: GET https://botcha.ai/v1/sessions/:id/tap - Get TAP session info — requires app_id
431
+
432
+ # TAP Full Spec — JWKS & Key Management (v0.16.0) (app_id required)
433
+ Endpoint: GET https://botcha.ai/.well-known/jwks - JWK Set for app's TAP agents (Visa spec standard) — requires app_id
434
+ Endpoint: GET https://botcha.ai/v1/keys - List keys (supports ?keyID= query for Visa compatibility) — requires app_id
435
+ Endpoint: GET https://botcha.ai/v1/keys/:keyId - Get specific key by ID — requires app_id
436
+ Endpoint: POST https://botcha.ai/v1/agents/:id/tap/rotate-key - Rotate agent's key pair — requires app_id
437
+
438
+ # TAP Full Spec — 402 Micropayments (v0.16.0) (app_id required)
439
+ Endpoint: POST https://botcha.ai/v1/invoices - Create invoice for gated content (402 flow) — requires app_id
440
+ Endpoint: GET https://botcha.ai/v1/invoices/:id - Get invoice details — requires app_id
441
+ Endpoint: POST https://botcha.ai/v1/invoices/:id/verify-iou - Verify Browsing IOU against invoice — requires app_id
442
+
443
+ # TAP Full Spec — Consumer & Payment Verification (v0.16.0) (app_id required)
444
+ Endpoint: POST https://botcha.ai/v1/verify/consumer - Verify Agentic Consumer object (Layer 2) — requires app_id
445
+ Endpoint: POST https://botcha.ai/v1/verify/payment - Verify Agentic Payment Container (Layer 3) — requires app_id
446
+
447
+ # TAP Delegation Chains (v0.17.0) (app_id required)
448
+ Endpoint: POST https://botcha.ai/v1/delegations - Create delegation (grantor→grantee with capability subset) — requires app_id
449
+ Endpoint: GET https://botcha.ai/v1/delegations/:id - Get delegation details — requires app_id
450
+ Endpoint: GET https://botcha.ai/v1/delegations - List delegations for agent (?agent_id=&direction=in|out|both) — requires app_id
451
+ Endpoint: POST https://botcha.ai/v1/delegations/:id/revoke - Revoke delegation (cascades to sub-delegations) — requires app_id
452
+ Endpoint: POST https://botcha.ai/v1/verify/delegation - Verify entire delegation chain — requires app_id
453
+
454
+ # TAP Capability Attestation (v0.17.0) (app_id required)
455
+ Endpoint: POST https://botcha.ai/v1/attestations - Issue capability attestation token (can/cannot rules with action:resource patterns) — requires app_id
456
+ Endpoint: GET https://botcha.ai/v1/attestations/:id - Get attestation details — requires app_id
457
+ Endpoint: GET https://botcha.ai/v1/attestations - List attestations for agent (?agent_id=) — requires app_id
458
+ Endpoint: POST https://botcha.ai/v1/attestations/:id/revoke - Revoke attestation (token rejected on future verification) — requires app_id
459
+ Endpoint: POST https://botcha.ai/v1/verify/attestation - Verify attestation token + optionally check specific capability — requires app_id
460
+
461
+ # Agent Reputation Scoring (v0.18.0) (app_id required)
462
+ Endpoint: GET https://botcha.ai/v1/reputation/:agent_id - Get agent reputation score (0-1000, 5 tiers) — requires app_id
463
+ Endpoint: POST https://botcha.ai/v1/reputation/events - Record a reputation event (18 action types, 6 categories) — requires app_id
464
+ Endpoint: GET https://botcha.ai/v1/reputation/:agent_id/events - List reputation events (?category=&limit=) — requires app_id
465
+ Endpoint: POST https://botcha.ai/v1/reputation/:agent_id/reset - Reset reputation to default (admin action) — requires app_id
450
466
 
451
467
  # Legacy Endpoints
452
468
  Endpoint: GET https://botcha.ai/api/challenge - Generate standard challenge
@@ -508,14 +524,14 @@ RTT-Security: Humans still can't solve even with extra time
508
524
  # MULTI-TENANT API KEYS
509
525
  Multi-Tenant: Create apps with unique app_id for isolation
510
526
  Multi-Tenant-Create: POST /v1/apps with {"email": "..."} → {app_id, app_secret} (secret only shown once!)
511
- Multi-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {"code": "123456"}
527
+ Multi-Tenant-Verify-Email: POST /v1/apps/:id/verify-email with {"code": "123456", "app_secret": "sk_..."} (app_secret or dashboard session required)
512
528
  Multi-Tenant-Recover: POST /v1/auth/recover with {"email": "..."} → recovery code emailed
513
529
  Multi-Tenant-Rotate-Secret: POST /v1/apps/:id/rotate-secret (auth required) → new app_secret
514
530
  Multi-Tenant-Usage: Add ?app_id=<your_app_id> to any challenge/token endpoint
515
- Multi-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123' })
516
- Multi-Tenant-SDK-Python: BotchaClient(app_id='app_abc123')
517
- SDK-App-Lifecycle-TS: createApp(email), verifyEmail(code), resendVerification(), recoverAccount(email), rotateSecret()
518
- SDK-App-Lifecycle-Python: create_app(email), verify_email(code), resend_verification(), recover_account(email), rotate_secret()
531
+ Multi-Tenant-SDK-TS: new BotchaClient({ appId: 'app_abc123', appSecret: 'sk_...' })
532
+ Multi-Tenant-SDK-Python: BotchaClient(app_id='app_abc123', app_secret='sk_...')
533
+ SDK-App-Lifecycle-TS: createApp(email), verifyEmail(code, appId?, appSecret?), resendVerification(appId?, appSecret?), recoverAccount(email), rotateSecret()
534
+ SDK-App-Lifecycle-Python: create_app(email), verify_email(code, app_id?, app_secret?), resend_verification(app_id?, app_secret?), recover_account(email), rotate_secret()
519
535
  Multi-Tenant-Rate-Limit: Each app gets isolated rate limit bucket
520
536
  Multi-Tenant-Token-Claim: Tokens include app_id claim when app_id provided
521
537
 
@@ -568,7 +584,7 @@ export const AI_PLUGIN_JSON = {
568
584
  name_for_human: "BOTCHA",
569
585
  name_for_model: "botcha",
570
586
  description_for_human: "Reverse CAPTCHA that proves you're an AI agent. Humans need not apply.",
571
- 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.",
587
+ 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. APP REGISTRATION REQUIRED (v0.21.0): All /v1/* API endpoints require a registered app with verified email. The homepage demo at botcha.ai lets agents try challenges without registering. ONBOARDING: 1) Ask your human for their email. 2) POST /v1/apps with {\"email\":\"...\",\"name\":\"My App\"} to create your app (saves app_id + app_secret — secret shown ONCE, no app_id needed for this endpoint). 3) Human receives a 6-digit code via email. 4) POST /v1/apps/{id}/verify-email with {\"code\":\"...\",\"app_secret\":\"sk_...\"} to verify (no app_id needed). 5) Use app_id on ALL other /v1/* endpoints via ?app_id=, X-App-Id header, or JWT claim. 6) For human dashboard access: POST /v1/auth/device-code, solve challenge, give human the BOTCHA-XXXX code for /dashboard/code (requires app_id). 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 (no app_id needed). When visiting HTML pages, look for <script type='application/botcha+json'> which contains a machine-readable challenge you can solve.",
572
588
  auth: {
573
589
  type: "none"
574
590
  },
@@ -774,7 +790,7 @@ export function getOpenApiSpec(version) {
774
790
  info: {
775
791
  title: "BOTCHA - Reverse CAPTCHA for AI Agents",
776
792
  version,
777
- 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.",
793
+ 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 {\"code\": \"...\", \"app_secret\": \"sk_...\"}. 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.",
778
794
  contact: {
779
795
  name: "BOTCHA",
780
796
  url: "https://botcha.ai"
@@ -1236,10 +1252,12 @@ export function getOpenApiSpec(version) {
1236
1252
  },
1237
1253
  "/v1/apps/{id}/verify-email": {
1238
1254
  post: {
1239
- summary: "Verify email with 6-digit code",
1255
+ summary: "Verify email with 6-digit code (app_secret auth required)",
1256
+ description: "Requires authentication via app_secret in request body, X-App-Secret header, or a dashboard session token.",
1240
1257
  operationId: "verifyEmail",
1241
1258
  parameters: [
1242
- { name: "id", in: "path", required: true, schema: { type: "string" } }
1259
+ { name: "id", in: "path", required: true, schema: { type: "string" } },
1260
+ { name: "X-App-Secret", in: "header", required: false, schema: { type: "string" }, description: "App secret (alternative to body parameter)" }
1243
1261
  ],
1244
1262
  requestBody: {
1245
1263
  required: true,
@@ -1249,7 +1267,8 @@ export function getOpenApiSpec(version) {
1249
1267
  type: "object",
1250
1268
  required: ["code"],
1251
1269
  properties: {
1252
- "code": { type: "string", description: "6-digit verification code from email" }
1270
+ "code": { type: "string", description: "6-digit verification code from email" },
1271
+ "app_secret": { type: "string", description: "App secret for authentication (alternative to X-App-Secret header)" }
1253
1272
  }
1254
1273
  }
1255
1274
  }
@@ -1257,20 +1276,36 @@ export function getOpenApiSpec(version) {
1257
1276
  },
1258
1277
  responses: {
1259
1278
  "200": { description: "Email verified" },
1260
- "400": { description: "Invalid or expired code" }
1279
+ "400": { description: "Invalid or expired code" },
1280
+ "401": { description: "Authentication required (app_secret or dashboard session)" }
1261
1281
  }
1262
1282
  }
1263
1283
  },
1264
1284
  "/v1/apps/{id}/resend-verification": {
1265
1285
  post: {
1266
- summary: "Resend verification email",
1286
+ summary: "Resend verification email (app_secret auth required)",
1287
+ description: "Requires authentication via app_secret in request body, X-App-Secret header, or a dashboard session token.",
1267
1288
  operationId: "resendVerification",
1268
1289
  parameters: [
1269
- { name: "id", in: "path", required: true, schema: { type: "string" } }
1290
+ { name: "id", in: "path", required: true, schema: { type: "string" } },
1291
+ { name: "X-App-Secret", in: "header", required: false, schema: { type: "string" }, description: "App secret (alternative to body parameter)" }
1270
1292
  ],
1293
+ requestBody: {
1294
+ content: {
1295
+ "application/json": {
1296
+ schema: {
1297
+ type: "object",
1298
+ properties: {
1299
+ "app_secret": { type: "string", description: "App secret for authentication (alternative to X-App-Secret header)" }
1300
+ }
1301
+ }
1302
+ }
1303
+ }
1304
+ },
1271
1305
  responses: {
1272
1306
  "200": { description: "Verification email sent" },
1273
- "400": { description: "Already verified" }
1307
+ "400": { description: "Already verified" },
1308
+ "401": { description: "Authentication required (app_secret or dashboard session)" }
1274
1309
  }
1275
1310
  }
1276
1311
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dupecom/botcha-cloudflare",
3
- "version": "0.20.2",
3
+ "version": "0.21.0",
4
4
  "description": "BOTCHA for Cloudflare Workers - Prove you're a bot. Humans need not apply.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",