@dupecom/botcha-cloudflare 0.19.0 → 0.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -11,7 +11,7 @@ Reverse CAPTCHA that verifies AI agents and blocks humans. Running at the edge.
11
11
  - **Agent Registry** - Persistent agent identities (POST /v1/agents/register)
12
12
  - **Email-tied apps** - Email verification, account recovery, secret rotation
13
13
  - **Dashboard** - Per-app metrics with agent-first auth (device code flow)
14
- - **JWT security** - 5-min access tokens, refresh tokens, audience claims, IP binding, revocation
14
+ - **JWT security** - 1-hr access tokens, refresh tokens, audience claims, IP binding, revocation
15
15
  - **Multi-tenant** - Per-app isolation, scoped tokens, rate limiting
16
16
  - **Server-side SDKs** - @dupecom/botcha-verify (TS) + botcha-verify (Python)
17
17
 
package/dist/apps.d.ts CHANGED
@@ -22,6 +22,7 @@ export type KVNamespace = {
22
22
  */
23
23
  export interface AppConfig {
24
24
  app_id: string;
25
+ name?: string;
25
26
  secret_hash: string;
26
27
  created_at: number;
27
28
  rate_limit: number;
@@ -35,6 +36,7 @@ export interface AppConfig {
35
36
  */
36
37
  export interface CreateAppResult {
37
38
  app_id: string;
39
+ name?: string;
38
40
  app_secret: string;
39
41
  email: string;
40
42
  email_verified: boolean;
@@ -45,6 +47,7 @@ export interface CreateAppResult {
45
47
  */
46
48
  export type PublicAppConfig = {
47
49
  app_id: string;
50
+ name?: string;
48
51
  created_at: number;
49
52
  rate_limit: number;
50
53
  email: string;
@@ -90,9 +93,10 @@ export declare function generateVerificationCode(): string;
90
93
  *
91
94
  * @param kv - KV namespace for storage
92
95
  * @param email - Required owner email address
93
- * @returns {app_id, app_secret, email, email_verified, verification_required}
96
+ * @param name - Optional human-readable label for the app
97
+ * @returns {app_id, name, app_secret, email, email_verified, verification_required}
94
98
  */
95
- export declare function createApp(kv: KVNamespace, email: string): Promise<CreateAppResult>;
99
+ export declare function createApp(kv: KVNamespace, email: string, name?: string): Promise<CreateAppResult>;
96
100
  /**
97
101
  * Get the plaintext verification code for an app (internal use only — for sending via email).
98
102
  *
@@ -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
@@ -79,9 +79,10 @@ export function generateVerificationCode() {
79
79
  *
80
80
  * @param kv - KV namespace for storage
81
81
  * @param email - Required owner email address
82
- * @returns {app_id, app_secret, email, email_verified, verification_required}
82
+ * @param name - Optional human-readable label for the app
83
+ * @returns {app_id, name, app_secret, email, email_verified, verification_required}
83
84
  */
84
- export async function createApp(kv, email) {
85
+ export async function createApp(kv, email, name) {
85
86
  const app_id = generateAppId();
86
87
  const app_secret = generateAppSecret();
87
88
  const secret_hash = await hashSecret(app_secret);
@@ -90,6 +91,7 @@ export async function createApp(kv, email) {
90
91
  const verificationCodeHash = await hashSecret(verificationCode);
91
92
  const config = {
92
93
  app_id,
94
+ ...(name && { name }),
93
95
  secret_hash,
94
96
  created_at: Date.now(),
95
97
  rate_limit: 100, // Default: 100 requests/hour
@@ -105,6 +107,7 @@ export async function createApp(kv, email) {
105
107
  ]);
106
108
  return {
107
109
  app_id,
110
+ ...(name && { name }),
108
111
  app_secret, // ONLY returned at creation time!
109
112
  email,
110
113
  email_verified: false,
@@ -242,6 +245,7 @@ export async function getApp(kv, app_id) {
242
245
  // Return config WITHOUT secret_hash (security)
243
246
  return {
244
247
  app_id: config.app_id,
248
+ ...(config.name && { name: config.name }),
245
249
  created_at: config.created_at,
246
250
  rate_limit: config.rate_limit,
247
251
  email: config.email,
package/dist/auth.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
  * - JTI (JWT ID) for revocation
6
6
  * - Audience claims for API scoping
7
7
  * - Client IP binding for additional security
8
- * - Short-lived access tokens (5 min) with refresh tokens (1 hour)
8
+ * - Short-lived access tokens (1 hour) with refresh tokens (1 hour)
9
9
  * - Token revocation via KV storage
10
10
  */
11
11
  /**
@@ -86,8 +86,8 @@ export declare function getSigningPublicKeyJWK(privateKeyJwk: ES256SigningKeyJWK
86
86
  /**
87
87
  * Generate JWT tokens (access + refresh) after successful challenge verification
88
88
  *
89
- * Access token: 5 minutes, used for API access
90
- * Refresh token: 1 hour, used to get new access tokens
89
+ * Access token: 1 hour, used for API access
90
+ * Refresh token: 1 hour, used to get new access tokens without re-solving challenges
91
91
  *
92
92
  * When signingKey (ES256 JWK) is provided, tokens are signed with ES256.
93
93
  * Otherwise falls back to HS256 with the shared secret (backward compat).
@@ -1 +1 @@
1
- {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/auth.js CHANGED
@@ -5,7 +5,7 @@
5
5
  * - JTI (JWT ID) for revocation
6
6
  * - Audience claims for API scoping
7
7
  * - Client IP binding for additional security
8
- * - Short-lived access tokens (5 min) with refresh tokens (1 hour)
8
+ * - Short-lived access tokens (1 hour) with refresh tokens (1 hour)
9
9
  * - Token revocation via KV storage
10
10
  */
11
11
  import { SignJWT, jwtVerify, importJWK, decodeProtectedHeader } from 'jose';
@@ -26,8 +26,8 @@ export function getSigningPublicKeyJWK(privateKeyJwk) {
26
26
  /**
27
27
  * Generate JWT tokens (access + refresh) after successful challenge verification
28
28
  *
29
- * Access token: 5 minutes, used for API access
30
- * Refresh token: 1 hour, used to get new access tokens
29
+ * Access token: 1 hour, used for API access
30
+ * Refresh token: 1 hour, used to get new access tokens without re-solving challenges
31
31
  *
32
32
  * When signingKey (ES256 JWK) is provided, tokens are signed with ES256.
33
33
  * Otherwise falls back to HS256 with the shared secret (backward compat).
@@ -38,8 +38,11 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
38
38
  let protectedHeader;
39
39
  if (signingKey) {
40
40
  // ES256 asymmetric signing
41
- signKey = await importJWK(signingKey, 'ES256');
42
- protectedHeader = { alg: 'ES256', kid: signingKey.kid || 'botcha-signing-1' };
41
+ signKey = (await importJWK(signingKey, 'ES256'));
42
+ protectedHeader = {
43
+ alg: 'ES256',
44
+ kid: signingKey.kid || 'botcha-signing-1',
45
+ };
43
46
  }
44
47
  else {
45
48
  // HS256 symmetric signing (legacy fallback)
@@ -49,7 +52,7 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
49
52
  // Generate unique JTIs for both tokens
50
53
  const accessJti = crypto.randomUUID();
51
54
  const refreshJti = crypto.randomUUID();
52
- // Access token: 5 minutes
55
+ // Access token: 1 hour
53
56
  const accessTokenPayload = {
54
57
  type: 'botcha-verified',
55
58
  solveTime: solveTimeMs,
@@ -70,7 +73,7 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
70
73
  .setSubject(challengeId)
71
74
  .setIssuer('botcha.ai')
72
75
  .setIssuedAt()
73
- .setExpirationTime('5m') // 5 minutes
76
+ .setExpirationTime('1h') // 1 hour
74
77
  .sign(signKey);
75
78
  // Refresh token: 1 hour
76
79
  const refreshTokenPayload = {
@@ -93,7 +96,10 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
93
96
  // Also store aud, client_ip, and app_id so they carry over on refresh
94
97
  if (env?.CHALLENGES) {
95
98
  try {
96
- const refreshData = { sub: challengeId, iat: Date.now() };
99
+ const refreshData = {
100
+ sub: challengeId,
101
+ iat: Date.now(),
102
+ };
97
103
  if (options?.aud) {
98
104
  refreshData.aud = options.aud;
99
105
  }
@@ -113,7 +119,7 @@ export async function generateToken(challengeId, solveTimeMs, secret, env, optio
113
119
  }
114
120
  return {
115
121
  access_token: accessToken,
116
- expires_in: 300, // 5 minutes in seconds
122
+ expires_in: 3600, // 1 hour in seconds
117
123
  refresh_token: refreshToken,
118
124
  refresh_expires_in: 3600, // 1 hour in seconds
119
125
  };
@@ -145,7 +151,7 @@ export async function refreshAccessToken(refreshToken, env, secret, options, sig
145
151
  let verifyKey;
146
152
  let algorithms;
147
153
  if (header.alg === 'ES256' && publicKey) {
148
- verifyKey = await importJWK(publicKey, 'ES256');
154
+ verifyKey = (await importJWK(publicKey, 'ES256'));
149
155
  algorithms = ['ES256'];
150
156
  }
151
157
  else {
@@ -213,8 +219,11 @@ export async function refreshAccessToken(refreshToken, env, secret, options, sig
213
219
  let signKey;
214
220
  let protectedHeaderObj;
215
221
  if (signingKey) {
216
- signKey = await importJWK(signingKey, 'ES256');
217
- protectedHeaderObj = { alg: 'ES256', kid: signingKey.kid || 'botcha-signing-1' };
222
+ signKey = (await importJWK(signingKey, 'ES256'));
223
+ protectedHeaderObj = {
224
+ alg: 'ES256',
225
+ kid: signingKey.kid || 'botcha-signing-1',
226
+ };
218
227
  }
219
228
  else {
220
229
  signKey = new TextEncoder().encode(secret);
@@ -245,13 +254,13 @@ export async function refreshAccessToken(refreshToken, env, secret, options, sig
245
254
  .setSubject(payload.sub || '')
246
255
  .setIssuer('botcha.ai')
247
256
  .setIssuedAt()
248
- .setExpirationTime('5m') // 5 minutes
257
+ .setExpirationTime('1h') // 1 hour
249
258
  .sign(signKey);
250
259
  return {
251
260
  success: true,
252
261
  tokens: {
253
262
  access_token: accessToken,
254
- expires_in: 300, // 5 minutes in seconds
263
+ expires_in: 3600, // 1 hour in seconds
255
264
  },
256
265
  };
257
266
  }
@@ -282,7 +291,7 @@ export async function verifyToken(token, secret, env, options, publicKey) {
282
291
  let algorithms;
283
292
  if (header.alg === 'ES256' && publicKey) {
284
293
  // ES256 asymmetric verification
285
- verifyKey = await importJWK(publicKey, 'ES256');
294
+ verifyKey = (await importJWK(publicKey, 'ES256'));
286
295
  algorithms = ['ES256'];
287
296
  }
288
297
  else {
@@ -464,7 +464,7 @@ async with BotchaClient() as client:
464
464
  "message": "HYBRID TEST PASSED! Speed: 47ms, Reasoning: 3/3",
465
465
  "speed": { "valid": true, "solveTimeMs": 47 },
466
466
  "reasoning": { "valid": true, "score": "3/3" }
467
- }` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reasoning", desc: "Get a reasoning-only challenge" }), _jsx(Endpoint, { method: "POST", path: "/v1/reasoning", desc: "Verify reasoning challenge" }), _jsx(Endpoint, { method: "GET", path: "/v1/hybrid", desc: "Get a hybrid challenge (alternate endpoint)" }), _jsx(Endpoint, { method: "POST", path: "/v1/hybrid", desc: "Verify hybrid challenge" })] }), _jsxs("section", { id: "authentication", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Authentication (Tokens)" }), _jsxs("p", { class: "docs-section-desc", children: ["JWT token flow for accessing protected endpoints. Solve a speed challenge to receive an access token (5 min) and refresh token (1 hr). Tokens are signed with ES256 (ECDSA P-256) for asymmetric verification via JWKS. HS256 still supported for backward compatibility. Use ", _jsx("code", { children: "POST /v1/token/validate" }), " for remote validation without a shared secret."] }), _jsxs("div", { class: "docs-flow", children: [_jsx("div", { class: "docs-flow-title", children: "Token Flow" }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "1." }), _jsxs("span", { children: [_jsx("code", { children: "GET /v1/token" }), " \u2014 receive a speed challenge"] })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "2." }), _jsx("span", { children: "Solve: SHA-256 of each number, first 8 hex chars" })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "3." }), _jsxs("span", { children: [_jsx("code", { children: "POST /v1/token/verify" }), " \u2014 submit solution, receive JWT + human_link"] })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "4." }), _jsxs("span", { children: ["Use ", _jsx("code", { children: "Authorization: Bearer <access_token>" }), " on protected endpoints"] })] })] }), _jsxs(Endpoint, { method: "GET", path: "/v1/token", desc: "Get challenge for JWT flow", children: [_jsx("div", { class: "docs-label", children: "Query Parameters" }), _jsxs("table", { class: "docs-param-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Name" }), _jsx("th", { children: "Type" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "ts" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "integer" }) }), _jsx("td", { children: "Client timestamp (ms) for RTT compensation" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "audience" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "string" }) }), _jsx("td", { children: "Audience claim for scoped tokens (e.g. service URL)" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "app_id" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "string" }) }), _jsx("td", { children: "Multi-tenant app ID" })] })] })] })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/verify", desc: "Submit solution, receive JWT", children: [_jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{
467
+ }` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reasoning", desc: "Get a reasoning-only challenge" }), _jsx(Endpoint, { method: "POST", path: "/v1/reasoning", desc: "Verify reasoning challenge" }), _jsx(Endpoint, { method: "GET", path: "/v1/hybrid", desc: "Get a hybrid challenge (alternate endpoint)" }), _jsx(Endpoint, { method: "POST", path: "/v1/hybrid", desc: "Verify hybrid challenge" })] }), _jsxs("section", { id: "authentication", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Authentication (Tokens)" }), _jsxs("p", { class: "docs-section-desc", children: ["JWT token flow for accessing protected endpoints. Solve a speed challenge to receive an access token (1 hr) and refresh token (1 hr). Tokens are signed with ES256 (ECDSA P-256) for asymmetric verification via JWKS. HS256 still supported for backward compatibility. Use ", _jsx("code", { children: "POST /v1/token/validate" }), " for remote validation without a shared secret."] }), _jsxs("div", { class: "docs-flow", children: [_jsx("div", { class: "docs-flow-title", children: "Token Flow" }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "1." }), _jsxs("span", { children: [_jsx("code", { children: "GET /v1/token" }), " \u2014 receive a speed challenge"] })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "2." }), _jsx("span", { children: "Solve: SHA-256 of each number, first 8 hex chars" })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "3." }), _jsxs("span", { children: [_jsx("code", { children: "POST /v1/token/verify" }), " \u2014 submit solution, receive JWT + human_link"] })] }), _jsxs("div", { class: "docs-flow-step", children: [_jsx("span", { class: "docs-flow-arrow", children: "4." }), _jsxs("span", { children: ["Use ", _jsx("code", { children: "Authorization: Bearer <access_token>" }), " on protected endpoints"] })] })] }), _jsxs(Endpoint, { method: "GET", path: "/v1/token", desc: "Get challenge for JWT flow", children: [_jsx("div", { class: "docs-label", children: "Query Parameters" }), _jsxs("table", { class: "docs-param-table", children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Name" }), _jsx("th", { children: "Type" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "ts" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "integer" }) }), _jsx("td", { children: "Client timestamp (ms) for RTT compensation" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "audience" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "string" }) }), _jsx("td", { children: "Audience claim for scoped tokens (e.g. service URL)" })] }), _jsxs("tr", { children: [_jsx("td", { children: _jsx("span", { class: "docs-param-name", children: "app_id" }) }), _jsx("td", { children: _jsx("span", { class: "docs-param-type", children: "string" }) }), _jsx("td", { children: "Multi-tenant app ID" })] })] })] })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/verify", desc: "Submit solution, receive JWT", children: [_jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{
468
468
  "id": "<challenge_id>",
469
469
  "answers": ["hash1", "hash2", "hash3", "hash4", "hash5"],
470
470
  "audience": "https://api.example.com", // optional
@@ -472,7 +472,7 @@ async with BotchaClient() as client:
472
472
  }` }) }), _jsx("div", { class: "docs-label", children: "Response" }), _jsx("pre", { children: _jsx("code", { children: `{
473
473
  "success": true,
474
474
  "access_token": "eyJ...",
475
- "expires_in": 300,
475
+ "expires_in": 3600,
476
476
  "refresh_token": "eyJ...",
477
477
  "refresh_expires_in": 3600,
478
478
  "human_link": "https://botcha.ai/go/BOTCHA-ABC123",
@@ -481,7 +481,7 @@ async with BotchaClient() as client:
481
481
  }` }) })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/refresh", desc: "Refresh access token", children: [_jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{ "refresh_token": "<refresh_token>" }` }) }), _jsx("div", { class: "docs-label", children: "Response" }), _jsx("pre", { children: _jsx("code", { children: `{
482
482
  "success": true,
483
483
  "access_token": "eyJ...",
484
- "expires_in": 300
484
+ "expires_in": 3600
485
485
  }` }) })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/revoke", desc: "Revoke a token", children: [_jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{ "token": "<access_token or refresh_token>" }` }) })] }), _jsxs(Endpoint, { method: "POST", path: "/v1/token/validate", desc: "Validate a token remotely (no secret needed)", children: [_jsx("p", { children: "Validate any BOTCHA token without needing the signing secret. Supports both ES256 and HS256 tokens." }), _jsx("div", { class: "docs-label", children: "Request Body" }), _jsx("pre", { children: _jsx("code", { children: `{ "token": "<any BOTCHA JWT token>" }` }) }), _jsx("div", { class: "docs-label", children: "Response" }), _jsx("pre", { children: _jsx("code", { children: `{
486
486
  "valid": true,
487
487
  "payload": {
@@ -547,7 +547,7 @@ async with BotchaClient() as client:
547
547
  "category": "commerce",
548
548
  "action": "purchase_completed",
549
549
  "metadata": { "amount": 29.99 }
550
- }` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reputation/:agent_id/events", desc: "List events (?category=&limit=)" }), _jsx(Endpoint, { method: "POST", path: "/v1/reputation/:agent_id/reset", desc: "Reset reputation (admin)" })] }), _jsxs("section", { id: "invoices", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Invoices (402 Micropayments)" }), _jsx("p", { class: "docs-section-desc", children: "Create invoices for gated content using the 402 Payment Required flow. Supports Browsing IOU verification for agent commerce." }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices", desc: "Create invoice for gated content" }), _jsx(Endpoint, { method: "GET", path: "/v1/invoices/:id", desc: "Get invoice details" }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices/:id/verify-iou", desc: "Verify Browsing IOU" })] }), _jsxs("section", { id: "verification", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Verification" }), _jsx("p", { class: "docs-section-desc", children: "Cross-cutting verification endpoints for validating delegation chains, attestation tokens, consumer identities, and payment containers." }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/delegation", desc: "Verify entire delegation chain" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/attestation", desc: "Verify attestation + check capability" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/consumer", desc: "Verify Agentic Consumer (Layer 2)" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/payment", desc: "Verify Payment Container (Layer 3)" })] }), _jsxs("section", { id: "discovery", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Discovery & Keys" }), _jsx("p", { class: "docs-section-desc", children: "Standard discovery endpoints for AI agents and key management infrastructure." }), _jsx(Endpoint, { method: "GET", path: "/.well-known/jwks", desc: "JWK Set for TAP agents (Visa spec)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys", desc: "List keys (?keyID= for Visa compat)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys/:keyId", desc: "Get specific key by ID" }), _jsx(Endpoint, { method: "GET", path: "/openapi.json", desc: "OpenAPI 3.1.0 specification" }), _jsx(Endpoint, { method: "GET", path: "/ai.txt", desc: "AI agent discovery file" }), _jsx(Endpoint, { method: "GET", path: "/.well-known/ai-plugin.json", desc: "AI plugin manifest" }), _jsx(Endpoint, { method: "GET", path: "/health", desc: "Health check" })] }), _jsxs("section", { id: "dashboard-auth", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Dashboard Auth" }), _jsx("p", { class: "docs-section-desc", children: "Agent-first authentication for the metrics dashboard. Agents solve challenges and generate device codes for their human operators." }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code", desc: "Get challenge for device code flow" }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code/verify", desc: "Solve challenge, get BOTCHA-XXXX code" }), _jsx(Endpoint, { method: "GET", path: "/dashboard", desc: "Metrics dashboard (login required)" })] }), _jsxs("section", { id: "ratelimits", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Rate Limits" }), _jsx("p", { class: "docs-section-desc", children: "Free tier includes generous rate limits. Each app gets an isolated rate limit bucket. Rate limit headers are included on every response." }), _jsxs("div", { class: "docs-rate-limit", children: [_jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "100" }), "challenges / hour / IP"] }), _jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "5 min" }), "access token lifetime"] }), _jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "1 hr" }), "refresh token lifetime"] })] }), _jsxs("div", { class: "docs-flow", children: [_jsx("div", { class: "docs-flow-title", children: "Response Headers" }), _jsx("pre", { children: _jsx("code", { children: `X-RateLimit-Limit: 100
550
+ }` }) })] }), _jsx(Endpoint, { method: "GET", path: "/v1/reputation/:agent_id/events", desc: "List events (?category=&limit=)" }), _jsx(Endpoint, { method: "POST", path: "/v1/reputation/:agent_id/reset", desc: "Reset reputation (admin)" })] }), _jsxs("section", { id: "invoices", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Invoices (402 Micropayments)" }), _jsx("p", { class: "docs-section-desc", children: "Create invoices for gated content using the 402 Payment Required flow. Supports Browsing IOU verification for agent commerce." }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices", desc: "Create invoice for gated content" }), _jsx(Endpoint, { method: "GET", path: "/v1/invoices/:id", desc: "Get invoice details" }), _jsx(Endpoint, { method: "POST", path: "/v1/invoices/:id/verify-iou", desc: "Verify Browsing IOU" })] }), _jsxs("section", { id: "verification", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Verification" }), _jsx("p", { class: "docs-section-desc", children: "Cross-cutting verification endpoints for validating delegation chains, attestation tokens, consumer identities, and payment containers." }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/delegation", desc: "Verify entire delegation chain" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/attestation", desc: "Verify attestation + check capability" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/consumer", desc: "Verify Agentic Consumer (Layer 2)" }), _jsx(Endpoint, { method: "POST", path: "/v1/verify/payment", desc: "Verify Payment Container (Layer 3)" })] }), _jsxs("section", { id: "discovery", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Discovery & Keys" }), _jsx("p", { class: "docs-section-desc", children: "Standard discovery endpoints for AI agents and key management infrastructure." }), _jsx(Endpoint, { method: "GET", path: "/.well-known/jwks", desc: "JWK Set for TAP agents (Visa spec)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys", desc: "List keys (?keyID= for Visa compat)" }), _jsx(Endpoint, { method: "GET", path: "/v1/keys/:keyId", desc: "Get specific key by ID" }), _jsx(Endpoint, { method: "GET", path: "/openapi.json", desc: "OpenAPI 3.1.0 specification" }), _jsx(Endpoint, { method: "GET", path: "/ai.txt", desc: "AI agent discovery file" }), _jsx(Endpoint, { method: "GET", path: "/.well-known/ai-plugin.json", desc: "AI plugin manifest" }), _jsx(Endpoint, { method: "GET", path: "/health", desc: "Health check" })] }), _jsxs("section", { id: "dashboard-auth", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Dashboard Auth" }), _jsx("p", { class: "docs-section-desc", children: "Agent-first authentication for the metrics dashboard. Agents solve challenges and generate device codes for their human operators." }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code", desc: "Get challenge for device code flow" }), _jsx(Endpoint, { method: "POST", path: "/v1/auth/device-code/verify", desc: "Solve challenge, get BOTCHA-XXXX code" }), _jsx(Endpoint, { method: "GET", path: "/dashboard", desc: "Metrics dashboard (login required)" })] }), _jsxs("section", { id: "ratelimits", class: "docs-section", children: [_jsx("h2", { class: "docs-section-title", children: "Rate Limits" }), _jsx("p", { class: "docs-section-desc", children: "Free tier includes generous rate limits. Each app gets an isolated rate limit bucket. Rate limit headers are included on every response." }), _jsxs("div", { class: "docs-rate-limit", children: [_jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "100" }), "challenges / hour / IP"] }), _jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "1 hr" }), "access token lifetime"] }), _jsxs("div", { class: "docs-rate-limit-item", children: [_jsx("div", { class: "docs-rate-limit-value", children: "1 hr" }), "refresh token lifetime"] })] }), _jsxs("div", { class: "docs-flow", children: [_jsx("div", { class: "docs-flow-title", children: "Response Headers" }), _jsx("pre", { children: _jsx("code", { children: `X-RateLimit-Limit: 100
551
551
  X-RateLimit-Remaining: 97
552
552
  X-RateLimit-Reset: 2026-02-15T12:00:00.000Z
553
553
  X-Botcha-Version: ${version}
@@ -394,7 +394,7 @@ signature: sig1=:BASE64_SIGNATURE:` }) }), _jsx("h3", { children: "Intent valida
394
394
  "agent_id": "agent_6ddfd9f10cfd8dfc",
395
395
  "intent": { "action": "browse", "resource": "products", "duration": 3600 },
396
396
  "user_context": "anon_user_hash"
397
- }` }) }), _jsx("h3", { children: "The verification hierarchy" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Layer" }), _jsx("th", { children: "Proves" }), _jsx("th", { children: "Mechanism" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Anonymous" }), _jsx("td", { children: "\"I am a bot\"" }), _jsx("td", { children: "Speed challenge in <500ms" })] }), _jsxs("tr", { children: [_jsx("td", { children: "App-scoped" }), _jsx("td", { children: "\"I belong to this org\"" }), _jsx("td", { children: "Challenge + app_id" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent identity" }), _jsx("td", { children: "\"I am this specific bot\"" }), _jsx("td", { children: "Registered ID + capabilities" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Cryptographic" }), _jsx("td", { children: "\"I can prove I am this bot\"" }), _jsx("td", { children: "RFC 9421 signatures" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Dual auth" }), _jsx("td", { children: "\"Verified bot, proven identity\"" }), _jsx("td", { children: "Challenge + signature" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Intent-scoped" }), _jsx("td", { children: "\"I intend to do this now\"" }), _jsx("td", { children: "Validated session" })] })] })] }), _jsx("h2", { id: "architecture", children: "6. Architecture and Security" }), _jsx("h3", { children: "Infrastructure" }), _jsxs("p", { children: ["BOTCHA runs on ", _jsx("strong", { children: "Cloudflare Workers" }), " \u2014 deployed to 300+ edge locations globally. Sub-50ms cold starts, KV storage for all state, no servers to manage."] }), _jsx("h3", { children: "Token system" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Token" }), _jsx("th", { children: "Lifetime" }), _jsx("th", { children: "Purpose" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Access token" }), _jsx("td", { children: "5 minutes" }), _jsx("td", { children: "API access via Bearer header" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Refresh token" }), _jsx("td", { children: "1 hour" }), _jsx("td", { children: "Obtain new access tokens without re-solving" })] })] })] }), _jsx("p", { children: "Tokens are HMAC-SHA256 JWTs carrying the solved challenge ID (proof of work), a unique JTI for revocation, optional audience claims, and the solve time in milliseconds." }), _jsx("h3", { children: "Cryptography" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Operation" }), _jsx("th", { children: "Algorithm" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Challenge answers" }), _jsx("td", { children: "SHA-256" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Token signing" }), _jsx("td", { children: "HMAC-SHA256 (HS256)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Secret storage" }), _jsx("td", { children: "SHA-256 (never stored in plaintext)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "TAP signatures" }), _jsx("td", { children: "ECDSA P-256 or RSA-PSS SHA-256" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Secret validation" }), _jsx("td", { children: "Constant-time comparison" })] })] })] }), _jsx("h3", { children: "Anti-gaming measures" }), _jsxs("ul", { children: [_jsxs("li", { children: [_jsx("strong", { children: "Single-use challenges" }), " \u2014 deleted from storage on first attempt."] }), _jsxs("li", { children: [_jsx("strong", { children: "Timestamp validation" }), " \u2014 rejects timestamps older than 30 seconds or in the future."] }), _jsxs("li", { children: [_jsx("strong", { children: "RTT capped at 5 seconds" }), " \u2014 prevents time manipulation."] }), _jsxs("li", { children: [_jsx("strong", { children: "Parameterized question generators" }), " \u2014 no static lookup tables."] }), _jsxs("li", { children: [_jsx("strong", { children: "Salted compute challenges" }), " \u2014 defeats precomputed hash tables."] }), _jsxs("li", { children: [_jsx("strong", { children: "User-Agent ignored" }), " \u2014 trivially spoofable, not used for verification."] }), _jsxs("li", { children: [_jsx("strong", { children: "Anti-enumeration" }), " \u2014 recovery endpoints return identical shapes regardless of email existence."] })] }), _jsx("h3", { children: "Human handoff" }), _jsxs("p", { children: ["When a human needs dashboard access, the agent solves a challenge and receives a device code (e.g., ", _jsx("code", { children: "BOTCHA-RBA89X" }), "). The human opens the link and is logged in. This adapts the OAuth 2.0 Device Authorization Grant (RFC 8628) with a twist: the agent must solve a BOTCHA challenge to generate the code. No agent, no code."] }), _jsx("h2", { id: "integration", children: "7. Integration: SDKs and Middleware" }), _jsx("h3", { children: "Client SDKs (for agents)" }), _jsxs("p", { children: [_jsx("strong", { children: "TypeScript" }), " (", _jsx("code", { children: "@dupecom/botcha" }), " on npm):"] }), _jsx("pre", { children: _jsx("code", { children: `import { BotchaClient } from '@dupecom/botcha';
397
+ }` }) }), _jsx("h3", { children: "The verification hierarchy" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Layer" }), _jsx("th", { children: "Proves" }), _jsx("th", { children: "Mechanism" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Anonymous" }), _jsx("td", { children: "\"I am a bot\"" }), _jsx("td", { children: "Speed challenge in <500ms" })] }), _jsxs("tr", { children: [_jsx("td", { children: "App-scoped" }), _jsx("td", { children: "\"I belong to this org\"" }), _jsx("td", { children: "Challenge + app_id" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent identity" }), _jsx("td", { children: "\"I am this specific bot\"" }), _jsx("td", { children: "Registered ID + capabilities" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Cryptographic" }), _jsx("td", { children: "\"I can prove I am this bot\"" }), _jsx("td", { children: "RFC 9421 signatures" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Dual auth" }), _jsx("td", { children: "\"Verified bot, proven identity\"" }), _jsx("td", { children: "Challenge + signature" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Intent-scoped" }), _jsx("td", { children: "\"I intend to do this now\"" }), _jsx("td", { children: "Validated session" })] })] })] }), _jsx("h2", { id: "architecture", children: "6. Architecture and Security" }), _jsx("h3", { children: "Infrastructure" }), _jsxs("p", { children: ["BOTCHA runs on ", _jsx("strong", { children: "Cloudflare Workers" }), " \u2014 deployed to 300+ edge locations globally. Sub-50ms cold starts, KV storage for all state, no servers to manage."] }), _jsx("h3", { children: "Token system" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Token" }), _jsx("th", { children: "Lifetime" }), _jsx("th", { children: "Purpose" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Access token" }), _jsx("td", { children: "1 hour" }), _jsx("td", { children: "API access via Bearer header" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Refresh token" }), _jsx("td", { children: "1 hour" }), _jsx("td", { children: "Obtain new access tokens without re-solving" })] })] })] }), _jsx("p", { children: "Tokens are HMAC-SHA256 JWTs carrying the solved challenge ID (proof of work), a unique JTI for revocation, optional audience claims, and the solve time in milliseconds." }), _jsx("h3", { children: "Cryptography" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Operation" }), _jsx("th", { children: "Algorithm" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Challenge answers" }), _jsx("td", { children: "SHA-256" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Token signing" }), _jsx("td", { children: "HMAC-SHA256 (HS256)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Secret storage" }), _jsx("td", { children: "SHA-256 (never stored in plaintext)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "TAP signatures" }), _jsx("td", { children: "ECDSA P-256 or RSA-PSS SHA-256" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Secret validation" }), _jsx("td", { children: "Constant-time comparison" })] })] })] }), _jsx("h3", { children: "Anti-gaming measures" }), _jsxs("ul", { children: [_jsxs("li", { children: [_jsx("strong", { children: "Single-use challenges" }), " \u2014 deleted from storage on first attempt."] }), _jsxs("li", { children: [_jsx("strong", { children: "Timestamp validation" }), " \u2014 rejects timestamps older than 30 seconds or in the future."] }), _jsxs("li", { children: [_jsx("strong", { children: "RTT capped at 5 seconds" }), " \u2014 prevents time manipulation."] }), _jsxs("li", { children: [_jsx("strong", { children: "Parameterized question generators" }), " \u2014 no static lookup tables."] }), _jsxs("li", { children: [_jsx("strong", { children: "Salted compute challenges" }), " \u2014 defeats precomputed hash tables."] }), _jsxs("li", { children: [_jsx("strong", { children: "User-Agent ignored" }), " \u2014 trivially spoofable, not used for verification."] }), _jsxs("li", { children: [_jsx("strong", { children: "Anti-enumeration" }), " \u2014 recovery endpoints return identical shapes regardless of email existence."] })] }), _jsx("h3", { children: "Human handoff" }), _jsxs("p", { children: ["When a human needs dashboard access, the agent solves a challenge and receives a device code (e.g., ", _jsx("code", { children: "BOTCHA-RBA89X" }), "). The human opens the link and is logged in. This adapts the OAuth 2.0 Device Authorization Grant (RFC 8628) with a twist: the agent must solve a BOTCHA challenge to generate the code. No agent, no code."] }), _jsx("h2", { id: "integration", children: "7. Integration: SDKs and Middleware" }), _jsx("h3", { children: "Client SDKs (for agents)" }), _jsxs("p", { children: [_jsx("strong", { children: "TypeScript" }), " (", _jsx("code", { children: "@dupecom/botcha" }), " on npm):"] }), _jsx("pre", { children: _jsx("code", { children: `import { BotchaClient } from '@dupecom/botcha';
398
398
  const client = new BotchaClient();
399
399
 
400
400
  // Drop-in fetch replacement — auto-solves challenges on 403
@@ -414,5 +414,5 @@ async def products(token=Depends(botcha)):
414
414
  return {"solve_time": token.solve_time}` }) }), _jsx("p", { children: "Also available: Hono middleware, Django middleware, and TAP-enhanced middleware with full cryptographic + computational dual verification." }), _jsx("h3", { children: "CLI" }), _jsx("pre", { children: _jsx("code", { children: `npm install -g @dupecom/botcha-cli
415
415
  botcha init --email you@company.com
416
416
  botcha tap register --name "my-agent" --capabilities browse,search
417
- botcha tap session --action browse --resource products --duration 1h` }) }), _jsx("h2", { id: "the-stack", children: "8. The Agent Infrastructure Stack" }), _jsx("p", { children: "BOTCHA positions itself alongside other emerging agent protocols:" }), _jsxs("div", { class: "wp-stack", children: [_jsxs("div", { class: "wp-stack-layer wp-stack-highlight", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 3" }), _jsx("span", { class: "wp-stack-name", children: "TAP (BOTCHA)" }), _jsx("span", { class: "wp-stack-desc", children: "Who agents are" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 2" }), _jsx("span", { class: "wp-stack-name", children: "A2A (Google)" }), _jsx("span", { class: "wp-stack-desc", children: "How agents talk" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 1" }), _jsx("span", { class: "wp-stack-name", children: "MCP (Anthropic)" }), _jsx("span", { class: "wp-stack-desc", children: "What agents access" })] })] }), _jsxs("p", { children: [_jsx("strong", { children: "MCP" }), " gives agents access to tools and data. ", _jsx("strong", { children: "A2A" }), " enables multi-agent coordination. ", _jsx("strong", { children: "TAP" }), " provides identity, capability scoping, and intent declaration."] }), _jsx("p", { children: "Without an identity layer, the other layers have a trust gap. MCP can give an agent access to a database, but who authorized it? A2A can let agents delegate tasks, but can you trust the delegate? TAP closes this gap." }), _jsx("h2", { id: "use-cases", children: "9. Use Cases" }), _jsx("h3", { children: "E-commerce agent verification" }), _jsxs("p", { children: ["A shopping agent registers with ", _jsx("code", { children: "browse" }), ", ", _jsx("code", { children: "compare" }), ", and", ' ', _jsx("code", { children: "purchase" }), " capabilities. It creates sessions scoped to specific actions. The retailer verifies identity, checks capabilities, and maintains a full audit trail of which agent made each purchase, when, and on behalf of whom."] }), _jsx("h3", { children: "API access control" }), _jsx("p", { children: "An API provider adds BOTCHA middleware to protected endpoints. Legitimate agents solve the speed challenge; scrapers pretending to be AI cannot. The provider gets rate limiting, solve-time analytics, and agent identification \u2014 without requiring API keys." }), _jsx("h3", { children: "Multi-agent systems" }), _jsx("p", { children: "A coordinator agent delegates tasks to sub-agents, each registered with scoped capabilities. The coordinator can verify sub-agent actions via TAP sessions. Capabilities are bounded at the protocol level." }), _jsx("h3", { children: "Compliance and auditing" }), _jsx("p", { children: "Financial services APIs use TAP's audit logging to record every agent interaction. Each request includes agent ID, intent, user context, and timestamp. Trust levels enable graduated access to sensitive endpoints." }), _jsx("h2", { id: "roadmap", children: "10. Roadmap" }), _jsx("h3", { children: "Shipped" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Feature" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Challenge types" }), _jsx("td", { children: "Speed, Reasoning, Hybrid, and Compute" })] }), _jsxs("tr", { children: [_jsx("td", { children: "JWT token system" }), _jsx("td", { children: "5-min access, 1-hr refresh, revocation, audience claims" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Multi-tenant apps" }), _jsx("td", { children: "Per-app rate limits, scoped tokens, isolated analytics" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent Registry" }), _jsx("td", { children: "Persistent identities with names and operators" })] }), _jsxs("tr", { children: [_jsx("td", { children: "TAP" }), _jsx("td", { children: "Cryptographic identity, capability scoping, intent sessions" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Dashboard" }), _jsx("td", { children: "Per-app analytics and metrics" })] }), _jsxs("tr", { children: [_jsx("td", { children: "SDKs" }), _jsx("td", { children: "TypeScript, Python, CLI, LangChain" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Server verification" }), _jsx("td", { children: "Express, Hono, FastAPI, Django middleware" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Discovery" }), _jsx("td", { children: "ai.txt, OpenAPI, AI Plugin manifest, embedded metadata" })] })] })] }), _jsx("h3", { children: "Planned" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Feature" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Delegation chains" }), _jsx("td", { children: "Signed \"User X authorized Agent Y to do Z until T\"" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Capability attestation" }), _jsx("td", { children: "Token claims with server-side enforcement" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent reputation" }), _jsx("td", { children: "Trust scores, faster verification for high-rep agents" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent SSO" }), _jsx("td", { children: "Verify once, trusted everywhere (OIDC for agents)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "RFC contribution" }), _jsx("td", { children: "Internet-Draft for agent identity, target IETF" })] })] })] }), _jsxs("div", { class: "wp-cta", children: [_jsx("div", { class: "wp-cta-title", children: "Get started in 30 seconds" }), _jsx("code", { children: "npm install -g @dupecom/botcha-cli" }), _jsx("code", { children: "botcha init --email you@company.com" }), _jsx("code", { children: "botcha tap register --name \"my-agent\"" }), _jsxs("div", { class: "wp-cta-links", children: [_jsx("a", { href: "/", class: "wp-cta-link", children: "Home" }), _jsx("a", { href: "https://github.com/dupe-com/botcha", class: "wp-cta-link", children: "GitHub" }), _jsx("a", { href: "/openapi.json", class: "wp-cta-link", children: "OpenAPI" }), _jsx("a", { href: "https://www.npmjs.com/package/@dupecom/botcha", class: "wp-cta-link", children: "npm" }), _jsx("a", { href: "https://pypi.org/project/botcha/", class: "wp-cta-link", children: "PyPI" }), _jsx("a", { href: "/dashboard", class: "wp-cta-link", children: "Dashboard" })] })] })] }), _jsx(GlobalFooter, { version: version })] })] }));
417
+ botcha tap session --action browse --resource products --duration 1h` }) }), _jsx("h2", { id: "the-stack", children: "8. The Agent Infrastructure Stack" }), _jsx("p", { children: "BOTCHA positions itself alongside other emerging agent protocols:" }), _jsxs("div", { class: "wp-stack", children: [_jsxs("div", { class: "wp-stack-layer wp-stack-highlight", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 3" }), _jsx("span", { class: "wp-stack-name", children: "TAP (BOTCHA)" }), _jsx("span", { class: "wp-stack-desc", children: "Who agents are" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 2" }), _jsx("span", { class: "wp-stack-name", children: "A2A (Google)" }), _jsx("span", { class: "wp-stack-desc", children: "How agents talk" })] }), _jsxs("div", { class: "wp-stack-layer", children: [_jsx("span", { class: "wp-stack-label", children: "Layer 1" }), _jsx("span", { class: "wp-stack-name", children: "MCP (Anthropic)" }), _jsx("span", { class: "wp-stack-desc", children: "What agents access" })] })] }), _jsxs("p", { children: [_jsx("strong", { children: "MCP" }), " gives agents access to tools and data. ", _jsx("strong", { children: "A2A" }), " enables multi-agent coordination. ", _jsx("strong", { children: "TAP" }), " provides identity, capability scoping, and intent declaration."] }), _jsx("p", { children: "Without an identity layer, the other layers have a trust gap. MCP can give an agent access to a database, but who authorized it? A2A can let agents delegate tasks, but can you trust the delegate? TAP closes this gap." }), _jsx("h2", { id: "use-cases", children: "9. Use Cases" }), _jsx("h3", { children: "E-commerce agent verification" }), _jsxs("p", { children: ["A shopping agent registers with ", _jsx("code", { children: "browse" }), ", ", _jsx("code", { children: "compare" }), ", and", ' ', _jsx("code", { children: "purchase" }), " capabilities. It creates sessions scoped to specific actions. The retailer verifies identity, checks capabilities, and maintains a full audit trail of which agent made each purchase, when, and on behalf of whom."] }), _jsx("h3", { children: "API access control" }), _jsx("p", { children: "An API provider adds BOTCHA middleware to protected endpoints. Legitimate agents solve the speed challenge; scrapers pretending to be AI cannot. The provider gets rate limiting, solve-time analytics, and agent identification \u2014 without requiring API keys." }), _jsx("h3", { children: "Multi-agent systems" }), _jsx("p", { children: "A coordinator agent delegates tasks to sub-agents, each registered with scoped capabilities. The coordinator can verify sub-agent actions via TAP sessions. Capabilities are bounded at the protocol level." }), _jsx("h3", { children: "Compliance and auditing" }), _jsx("p", { children: "Financial services APIs use TAP's audit logging to record every agent interaction. Each request includes agent ID, intent, user context, and timestamp. Trust levels enable graduated access to sensitive endpoints." }), _jsx("h2", { id: "roadmap", children: "10. Roadmap" }), _jsx("h3", { children: "Shipped" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Feature" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Challenge types" }), _jsx("td", { children: "Speed, Reasoning, Hybrid, and Compute" })] }), _jsxs("tr", { children: [_jsx("td", { children: "JWT token system" }), _jsx("td", { children: "1-hr access, 1-hr refresh, revocation, audience claims" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Multi-tenant apps" }), _jsx("td", { children: "Per-app rate limits, scoped tokens, isolated analytics" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent Registry" }), _jsx("td", { children: "Persistent identities with names and operators" })] }), _jsxs("tr", { children: [_jsx("td", { children: "TAP" }), _jsx("td", { children: "Cryptographic identity, capability scoping, intent sessions" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Dashboard" }), _jsx("td", { children: "Per-app analytics and metrics" })] }), _jsxs("tr", { children: [_jsx("td", { children: "SDKs" }), _jsx("td", { children: "TypeScript, Python, CLI, LangChain" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Server verification" }), _jsx("td", { children: "Express, Hono, FastAPI, Django middleware" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Discovery" }), _jsx("td", { children: "ai.txt, OpenAPI, AI Plugin manifest, embedded metadata" })] })] })] }), _jsx("h3", { children: "Planned" }), _jsxs("table", { children: [_jsx("thead", { children: _jsxs("tr", { children: [_jsx("th", { children: "Feature" }), _jsx("th", { children: "Description" })] }) }), _jsxs("tbody", { children: [_jsxs("tr", { children: [_jsx("td", { children: "Delegation chains" }), _jsx("td", { children: "Signed \"User X authorized Agent Y to do Z until T\"" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Capability attestation" }), _jsx("td", { children: "Token claims with server-side enforcement" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent reputation" }), _jsx("td", { children: "Trust scores, faster verification for high-rep agents" })] }), _jsxs("tr", { children: [_jsx("td", { children: "Agent SSO" }), _jsx("td", { children: "Verify once, trusted everywhere (OIDC for agents)" })] }), _jsxs("tr", { children: [_jsx("td", { children: "RFC contribution" }), _jsx("td", { children: "Internet-Draft for agent identity, target IETF" })] })] })] }), _jsxs("div", { class: "wp-cta", children: [_jsx("div", { class: "wp-cta-title", children: "Get started in 30 seconds" }), _jsx("code", { children: "npm install -g @dupecom/botcha-cli" }), _jsx("code", { children: "botcha init --email you@company.com" }), _jsx("code", { children: "botcha tap register --name \"my-agent\"" }), _jsxs("div", { class: "wp-cta-links", children: [_jsx("a", { href: "/", class: "wp-cta-link", children: "Home" }), _jsx("a", { href: "https://github.com/dupe-com/botcha", class: "wp-cta-link", children: "GitHub" }), _jsx("a", { href: "/openapi.json", class: "wp-cta-link", children: "OpenAPI" }), _jsx("a", { href: "https://www.npmjs.com/package/@dupecom/botcha", class: "wp-cta-link", children: "npm" }), _jsx("a", { href: "https://pypi.org/project/botcha/", class: "wp-cta-link", children: "PyPI" }), _jsx("a", { href: "/dashboard", class: "wp-cta-link", children: "Dashboard" })] })] })] }), _jsx(GlobalFooter, { version: version })] })] }));
418
418
  };
@@ -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;AAwvErE,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,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;AAowErE,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
@@ -40,7 +40,7 @@ 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.19.0');
43
+ c.header('X-Botcha-Version', c.env.BOTCHA_VERSION || '0.20.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');
@@ -229,7 +229,7 @@ You have 500ms. Only a bot can do this.
229
229
  After verifying, the response includes a \`human_link\`. Give this URL to your human:
230
230
  **"Click this link to get access: {human_link}"**
231
231
 
232
- The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the verified site.
232
+ The link works for a limited time. Your human clicks it, gets a cookie, and sees the verified site.
233
233
 
234
234
  ---
235
235
 
@@ -269,7 +269,7 @@ The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the
269
269
  note: 'For production use. Creates your app, verifies your human, registers your identity.',
270
270
  steps: [
271
271
  '1. Ask your human operator for their email address.',
272
- `2. POST ${baseUrl}/v1/apps {"email":"human@example.com"} — returns app_id + app_secret (shown ONCE).`,
272
+ `2. POST ${baseUrl}/v1/apps {"email":"human@example.com","name":"My App"} — returns app_id + name + app_secret (shown ONCE).`,
273
273
  '3. Human receives a 6-digit verification code via email — ask them for it.',
274
274
  `4. POST ${baseUrl}/v1/apps/{app_id}/verify-email {"code":"123456"} — enables account recovery.`,
275
275
  `5. Register yourself: POST ${baseUrl}/v1/agents/register {"name":"my-agent","operator":"my-org"} — persistent agent identity.`,
@@ -289,7 +289,7 @@ The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the
289
289
  tokens: {
290
290
  note: 'Use token flow when you need a Bearer token for protected endpoints.',
291
291
  'GET /v1/token': 'Get speed challenge for token flow (?audience= optional)',
292
- 'POST /v1/token/verify': 'Submit solution → access_token (5min) + refresh_token (1hr)',
292
+ 'POST /v1/token/verify': 'Submit solution → access_token (1hr) + refresh_token (1hr)',
293
293
  'POST /v1/token/refresh': 'Refresh access token',
294
294
  'POST /v1/token/revoke': 'Revoke a token',
295
295
  'POST /v1/token/validate': 'Remote token validation — verify any BOTCHA token without needing the secret',
@@ -300,7 +300,7 @@ The link works for 5 minutes. Your human clicks it, gets a cookie, and sees the
300
300
  },
301
301
  apps: {
302
302
  note: 'Create an app for isolated rate limits, scoped tokens, and dashboard access.',
303
- 'POST /v1/apps': 'Create app (email required) → app_id + app_secret',
303
+ 'POST /v1/apps': 'Create app (email required, name optional) → app_id + name + app_secret',
304
304
  'GET /v1/apps/:id': 'Get app info',
305
305
  'POST /v1/apps/:id/verify-email': 'Verify email with 6-digit code',
306
306
  'POST /v1/apps/:id/rotate-secret': 'Rotate app secret (auth required)',
@@ -727,7 +727,7 @@ app.post('/v1/token/verify', async (c) => {
727
727
  let gateCode = 'BOTCHA-';
728
728
  for (let i = 0; i < 6; i++)
729
729
  gateCode += gateChars[Math.floor(Math.random() * gateChars.length)];
730
- // Store code → token mapping in KV (5-min TTL, same as access_token)
730
+ // Store code → token mapping in KV (5-min TTL for human handoff links)
731
731
  try {
732
732
  await c.env.CHALLENGES.put(`gate:${gateCode}`, tokenResult.access_token, { expirationTtl: 300 });
733
733
  }
@@ -1319,7 +1319,7 @@ app.get('/api/badge/:id', async (c) => {
1319
1319
  app.post('/v1/apps', async (c) => {
1320
1320
  try {
1321
1321
  const body = await c.req.json().catch(() => ({}));
1322
- const { email } = body;
1322
+ const { email, name } = body;
1323
1323
  if (!email || typeof email !== 'string') {
1324
1324
  return c.json({
1325
1325
  success: false,
@@ -1335,7 +1335,16 @@ app.post('/v1/apps', async (c) => {
1335
1335
  message: 'Invalid email format',
1336
1336
  }, 400);
1337
1337
  }
1338
- const result = await createApp(c.env.APPS, email);
1338
+ // Validate name if provided (1-100 chars, no control characters)
1339
+ const trimmedName = name?.trim();
1340
+ if (trimmedName !== undefined && (trimmedName.length === 0 || trimmedName.length > 100)) {
1341
+ return c.json({
1342
+ success: false,
1343
+ error: 'INVALID_NAME',
1344
+ message: 'App name must be 1-100 characters',
1345
+ }, 400);
1346
+ }
1347
+ const result = await createApp(c.env.APPS, email, trimmedName || undefined);
1339
1348
  // Generate a fresh verification code and send email
1340
1349
  const regen = await regenerateVerificationCode(c.env.APPS, result.app_id);
1341
1350
  if (regen) {
@@ -1348,6 +1357,7 @@ app.post('/v1/apps', async (c) => {
1348
1357
  return c.json({
1349
1358
  success: true,
1350
1359
  app_id: result.app_id,
1360
+ ...(result.name && { name: result.name }),
1351
1361
  app_secret: result.app_secret,
1352
1362
  email: result.email,
1353
1363
  email_verified: false,
@@ -1388,6 +1398,7 @@ app.get('/v1/apps/:id', async (c) => {
1388
1398
  success: true,
1389
1399
  app: {
1390
1400
  app_id: app.app_id,
1401
+ ...(app.name && { name: app.name }),
1391
1402
  created_at: new Date(app.created_at).toISOString(),
1392
1403
  rate_limit: app.rate_limit,
1393
1404
  email: app.email,
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 (5-minute 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, returns app_id + 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: 5 minutes (short-lived for security)\nToken-Refresh-Expiry: 1 hour (use to get new access tokens)\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# 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";
10
10
  export declare const AI_PLUGIN_JSON: {
11
11
  schema_version: string;
12
12
  name_for_human: string;
@@ -513,6 +513,11 @@ export declare function getOpenApiSpec(version: string): {
513
513
  format: string;
514
514
  description: string;
515
515
  };
516
+ name: {
517
+ type: string;
518
+ maxLength: number;
519
+ description: string;
520
+ };
516
521
  };
517
522
  };
518
523
  };
@@ -530,6 +535,10 @@ export declare function getOpenApiSpec(version: string): {
530
535
  type: string;
531
536
  description: string;
532
537
  };
538
+ name: {
539
+ type: string;
540
+ description: string;
541
+ };
533
542
  app_secret: {
534
543
  type: string;
535
544
  description: string;
@@ -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,gylBA0QlB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAm5C7C"}
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"}
package/dist/static.js CHANGED
@@ -51,7 +51,7 @@ curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
51
51
 
52
52
  | Method | Path | Description |
53
53
  |--------|------|-------------|
54
- | \`POST\` | \`/v1/apps\` | Create app (email required) → app_id + app_secret |
54
+ | \`POST\` | \`/v1/apps\` | Create app (email required, name optional) → app_id + app_secret |
55
55
  | \`POST\` | \`/v1/agents/register\` | Register agent identity → agent_id |
56
56
  | \`GET\` | \`/v1/challenges\` | Get a challenge (hybrid by default) |
57
57
  | \`POST\` | \`/v1/challenges/:id/verify\` | Submit solution → JWT token |
@@ -63,7 +63,7 @@ curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
63
63
 
64
64
  | Method | Path | Description |
65
65
  |--------|------|-------------|
66
- | \`POST\` | \`/v1/apps\` | Create app (email required, returns app_id + app_secret) |
66
+ | \`POST\` | \`/v1/apps\` | Create app (email required, name optional) → app_id + name + app_secret |
67
67
  | \`GET\` | \`/v1/apps/:id\` | Get app info |
68
68
  | \`POST\` | \`/v1/apps/:id/verify-email\` | Verify email with 6-digit code |
69
69
  | \`POST\` | \`/v1/apps/:id/resend-verification\` | Resend verification email |
@@ -154,7 +154,7 @@ curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
154
154
  | Method | Path | Description |
155
155
  |--------|------|-------------|
156
156
  | \`GET\` | \`/v1/token\` | Get challenge for JWT token flow |
157
- | \`POST\` | \`/v1/token/verify\` | Submit solution → access_token (5min) + refresh_token (1hr) |
157
+ | \`POST\` | \`/v1/token/verify\` | Submit solution → access_token (1hr) + refresh_token (1hr) |
158
158
  | \`POST\` | \`/v1/token/refresh\` | Refresh access token |
159
159
  | \`POST\` | \`/v1/token/revoke\` | Revoke a token |
160
160
  | \`POST\` | \`/v1/token/validate\` | Validate a token remotely (no shared secret needed) |
@@ -181,7 +181,7 @@ curl https://botcha.ai/agent-only -H "Authorization: Bearer <token>"
181
181
  3. \`POST /v1/token/verify\` — submit solution, receive JWT
182
182
  4. Use \`Authorization: Bearer <token>\` on protected endpoints
183
183
 
184
- **Token lifetimes:** access_token = 5 minutes, refresh_token = 1 hour
184
+ **Token lifetimes:** access_token = 1 hour, refresh_token = 1 hour
185
185
 
186
186
  **Token signing:** ES256 (ECDSA P-256) asymmetric signing. HS256 supported for backward compatibility.
187
187
 
@@ -339,7 +339,7 @@ Feature: Standard Challenge (5s time limit)
339
339
  Feature: Hybrid Challenge (speed + reasoning combined)
340
340
  Feature: Reasoning Challenge (LLM-only questions, 30s limit)
341
341
  Feature: RTT-Aware Fairness (automatic network latency compensation)
342
- Feature: Token Rotation (5-minute access tokens + 1-hour refresh tokens)
342
+ Feature: Token Rotation (1-hour access tokens + 1-hour refresh tokens)
343
343
  Feature: Audience Claims (tokens scoped to specific services)
344
344
  Feature: Client IP Binding (optional token-to-IP binding)
345
345
  Feature: Token Revocation (invalidate tokens before expiry)
@@ -376,7 +376,7 @@ Endpoint: POST https://botcha.ai/v1/token/revoke - Revoke a token (access or ref
376
376
  Endpoint: POST https://botcha.ai/v1/token/validate - Validate a BOTCHA token remotely (no shared secret needed)
377
377
 
378
378
  # Multi-Tenant Endpoints
379
- Endpoint: POST https://botcha.ai/v1/apps - Create new app (email required, returns app_id + app_secret)
379
+ Endpoint: POST https://botcha.ai/v1/apps - Create new app (email required, name optional) → app_id + name + app_secret
380
380
  Endpoint: GET https://botcha.ai/v1/apps/:id - Get app info (with email + verification status)
381
381
  Endpoint: POST https://botcha.ai/v1/apps/:id/verify-email - Verify email with 6-digit code
382
382
  Endpoint: POST https://botcha.ai/v1/apps/:id/resend-verification - Resend verification email
@@ -489,8 +489,8 @@ Token-Validate: POST /v1/token/validate with {"token": "<token>"} — remote val
489
489
  Token-Verify-Modes: 1. JWKS (recommended, offline) 2. Remote validation (/v1/token/validate) 3. Shared secret (legacy HS256)
490
490
  Token-Flow: 1. GET /v1/token (get challenge) → 2. Solve → 3. POST /v1/token/verify (get tokens + human_link)
491
491
  Token-Human-Link: /v1/token/verify response includes human_link — give this URL to your human for one-click browser access
492
- Token-Access-Expiry: 5 minutes (short-lived for security)
493
- Token-Refresh-Expiry: 1 hour (use to get new access tokens)
492
+ Token-Access-Expiry: 1 hour
493
+ Token-Refresh-Expiry: 1 hour (use to get new access tokens without re-solving challenges)
494
494
  Token-Refresh: POST /v1/token/refresh with {"refresh_token": "<token>"}
495
495
  Token-Revoke: POST /v1/token/revoke with {"token": "<token>"}
496
496
  Token-Audience: Include {"audience": "<service-url>"} in /v1/token/verify to scope token
@@ -706,7 +706,7 @@ Inspired by Visa's Trusted Agent Protocol (https://developer.visa.com/capabiliti
706
706
 
707
707
  - **Runtime:** Cloudflare Workers (300+ edge locations)
708
708
  - **Storage:** Workers KV with TTLs
709
- - **Tokens:** HMAC-SHA256 JWTs (5-min access, 1-hr refresh)
709
+ - **Tokens:** HMAC-SHA256 JWTs (1-hr access, 1-hr refresh)
710
710
  - **TAP Signatures:** ECDSA P-256 or RSA-PSS SHA-256
711
711
  - **Rate Limits:** 100 challenges/hour/app (fail-open)
712
712
 
@@ -960,7 +960,7 @@ export function getOpenApiSpec(version) {
960
960
  "/v1/token/refresh": {
961
961
  post: {
962
962
  summary: "Refresh access token",
963
- description: "Exchange a refresh token for a new short-lived access token (5 minutes). Avoids solving a new challenge.",
963
+ description: "Exchange a refresh token for a new access token (1 hour). Avoids solving a new challenge.",
964
964
  operationId: "refreshToken",
965
965
  requestBody: {
966
966
  required: true,
@@ -986,7 +986,7 @@ export function getOpenApiSpec(version) {
986
986
  properties: {
987
987
  "success": { type: "boolean" },
988
988
  "access_token": { type: "string" },
989
- "expires_in": { type: "integer", description: "Token lifetime in seconds (300 = 5 minutes)" },
989
+ "expires_in": { type: "integer", description: "Token lifetime in seconds (3600 = 1 hour)" },
990
990
  "token_type": { type: "string", enum: ["Bearer"] }
991
991
  }
992
992
  }
@@ -1157,8 +1157,8 @@ export function getOpenApiSpec(version) {
1157
1157
  },
1158
1158
  "/v1/apps": {
1159
1159
  post: {
1160
- summary: "Create a new multi-tenant app (email required)",
1161
- description: "Create a new app with unique app_id and app_secret. Email is required for account recovery. A 6-digit verification code is sent to the provided email.",
1160
+ summary: "Create a new multi-tenant app",
1161
+ description: "Create a new app with unique app_id and app_secret. Email is required for account recovery. Name is optional but recommended for identification. A 6-digit verification code is sent to the provided email.",
1162
1162
  operationId: "createApp",
1163
1163
  requestBody: {
1164
1164
  required: true,
@@ -1168,7 +1168,8 @@ export function getOpenApiSpec(version) {
1168
1168
  type: "object",
1169
1169
  required: ["email"],
1170
1170
  properties: {
1171
- "email": { type: "string", format: "email", description: "Owner email (required for recovery)" }
1171
+ "email": { type: "string", format: "email", description: "Owner email (required for recovery)" },
1172
+ "name": { type: "string", maxLength: 100, description: "Human-readable app label (optional, e.g. 'My Shopping App')" }
1172
1173
  }
1173
1174
  }
1174
1175
  }
@@ -1183,6 +1184,7 @@ export function getOpenApiSpec(version) {
1183
1184
  type: "object",
1184
1185
  properties: {
1185
1186
  "app_id": { type: "string", description: "Unique app identifier" },
1187
+ "name": { type: "string", description: "Human-readable app label" },
1186
1188
  "app_secret": { type: "string", description: "Secret key (only shown once!)" },
1187
1189
  "email": { type: "string" },
1188
1190
  "email_verified": { type: "boolean" },
@@ -1193,7 +1195,7 @@ export function getOpenApiSpec(version) {
1193
1195
  }
1194
1196
  }
1195
1197
  },
1196
- "400": { description: "Missing or invalid email" }
1198
+ "400": { description: "Missing or invalid email, or invalid name" }
1197
1199
  }
1198
1200
  }
1199
1201
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dupecom/botcha-cloudflare",
3
- "version": "0.19.0",
3
+ "version": "0.20.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",