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