@nordsym/apiclaw 1.5.8 → 1.5.9

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/HTTP-API.md ADDED
@@ -0,0 +1,306 @@
1
+ # APIClaw HTTP API
2
+
3
+ REST endpoints for headless agents (Hivr bees, webhooks, serverless functions).
4
+
5
+ ## šŸš€ Quick Start
6
+
7
+ **Start server:**
8
+ ```bash
9
+ npx apiclaw-http --port 3000
10
+ ```
11
+
12
+ **Or via npm:**
13
+ ```bash
14
+ npm i -g @nordsym/apiclaw
15
+ apiclaw-http
16
+ ```
17
+
18
+ Server runs on `http://localhost:3000` by default.
19
+
20
+ ---
21
+
22
+ ## šŸ“” Endpoints
23
+
24
+ ### 1. Discover APIs
25
+
26
+ Search for APIs by capability.
27
+
28
+ **Request:**
29
+ ```http
30
+ GET /api/discover?query=web+search&agentId=bytebee&category=Search&maxResults=5
31
+ ```
32
+
33
+ **Parameters:**
34
+ | Param | Required | Description |
35
+ |-------|----------|-------------|
36
+ | `query` | Yes | Search query (e.g., "web search", "send SMS") |
37
+ | `agentId` | Yes | Your agent ID (must be whitelisted) |
38
+ | `category` | No | Filter by category |
39
+ | `maxResults` | No | Max results to return (default: 5) |
40
+
41
+ **Response:**
42
+ ```json
43
+ {
44
+ "success": true,
45
+ "query": "web search",
46
+ "results": [
47
+ {
48
+ "provider": {
49
+ "id": "brave_search",
50
+ "name": "Brave Search",
51
+ "category": "Search"
52
+ },
53
+ "score": 95,
54
+ "reasons": ["keyword: search", "capability: web search"]
55
+ }
56
+ ],
57
+ "count": 1,
58
+ "responseTimeMs": 12
59
+ }
60
+ ```
61
+
62
+ ---
63
+
64
+ ### 2. Call API
65
+
66
+ Execute an API call.
67
+
68
+ **Request:**
69
+ ```http
70
+ POST /api/call_api
71
+ Content-Type: application/json
72
+
73
+ {
74
+ "provider": "brave_search",
75
+ "action": "search",
76
+ "params": {
77
+ "query": "AI news",
78
+ "count": 5
79
+ },
80
+ "agentId": "bytebee"
81
+ }
82
+ ```
83
+
84
+ **Parameters:**
85
+ | Field | Required | Description |
86
+ |-------|----------|-------------|
87
+ | `provider` | Yes | Provider ID (from discover results) |
88
+ | `action` | Yes | Action to perform (e.g., "search", "send_sms") |
89
+ | `params` | Yes | Action parameters (varies by provider) |
90
+ | `agentId` | Yes | Your agent ID (must be whitelisted) |
91
+
92
+ **Response (success):**
93
+ ```json
94
+ {
95
+ "success": true,
96
+ "provider": "brave_search",
97
+ "action": "search",
98
+ "agentId": "bytebee",
99
+ "data": {
100
+ "results": [
101
+ {
102
+ "title": "Latest AI News",
103
+ "url": "https://example.com/ai-news",
104
+ "snippet": "..."
105
+ }
106
+ ]
107
+ },
108
+ "latencyMs": 234
109
+ }
110
+ ```
111
+
112
+ **Response (error):**
113
+ ```json
114
+ {
115
+ "success": false,
116
+ "provider": "brave_search",
117
+ "action": "search",
118
+ "agentId": "bytebee",
119
+ "error": "Rate limit exceeded",
120
+ "latencyMs": 12
121
+ }
122
+ ```
123
+
124
+ ---
125
+
126
+ ### 3. Health Check
127
+
128
+ Check if server is running.
129
+
130
+ **Request:**
131
+ ```http
132
+ GET /health
133
+ ```
134
+
135
+ **Response:**
136
+ ```json
137
+ {
138
+ "status": "ok",
139
+ "service": "apiclaw-http-api"
140
+ }
141
+ ```
142
+
143
+ ---
144
+
145
+ ## šŸ” Authentication
146
+
147
+ **Hivr Bees Whitelist:**
148
+
149
+ Access is restricted to whitelisted Hivr bees. The `agentId` parameter must match one of these:
150
+
151
+ ```
152
+ bytebee, analyzerbee, buildbee, buzzwriter, hivemind,
153
+ hivesage, symbot, hivrqueen, marketmaven, reconbee,
154
+ sprintbee, quillbee
155
+ ```
156
+
157
+ **Unauthorized response:**
158
+ ```json
159
+ {
160
+ "error": "Unauthorized",
161
+ "message": "This endpoint is restricted to Hivr bees. Contact admin@nordsym.com for access."
162
+ }
163
+ ```
164
+
165
+ ---
166
+
167
+ ## šŸ“Š Usage Logging
168
+
169
+ All API calls are logged to APIClaw analytics with:
170
+ - Provider + action
171
+ - Agent ID (e.g., `hivr:bytebee`)
172
+ - Success/failure
173
+ - Latency
174
+
175
+ This enables usage tracking per Hivr bee.
176
+
177
+ ---
178
+
179
+ ## šŸŽÆ Example: Web Search
180
+
181
+ **1. Discover search APIs:**
182
+ ```bash
183
+ curl "http://localhost:3000/api/discover?query=web+search&agentId=bytebee"
184
+ ```
185
+
186
+ **2. Call Brave Search:**
187
+ ```bash
188
+ curl -X POST http://localhost:3000/api/call_api \
189
+ -H "Content-Type: application/json" \
190
+ -d '{
191
+ "provider": "brave_search",
192
+ "action": "search",
193
+ "params": {
194
+ "query": "latest AI developments",
195
+ "count": 5
196
+ },
197
+ "agentId": "bytebee"
198
+ }'
199
+ ```
200
+
201
+ ---
202
+
203
+ ## 🌐 CORS
204
+
205
+ CORS headers are set to allow cross-origin requests from anywhere:
206
+ - `Access-Control-Allow-Origin: *`
207
+ - `Access-Control-Allow-Methods: GET, POST, OPTIONS`
208
+ - `Access-Control-Allow-Headers: Content-Type, X-Agent-Id`
209
+
210
+ Safe for browser-based agents.
211
+
212
+ ---
213
+
214
+ ## šŸš€ Deployment
215
+
216
+ ### Local Development
217
+ ```bash
218
+ apiclaw-http --port 3000
219
+ ```
220
+
221
+ ### Production (systemd)
222
+ ```ini
223
+ [Unit]
224
+ Description=APIClaw HTTP API
225
+ After=network.target
226
+
227
+ [Service]
228
+ Type=simple
229
+ User=apiclaw
230
+ WorkingDirectory=/opt/apiclaw
231
+ ExecStart=/usr/bin/apiclaw-http --port 3000
232
+ Restart=always
233
+ Environment="PORT=3000"
234
+
235
+ [Install]
236
+ WantedBy=multi-user.target
237
+ ```
238
+
239
+ ### Docker
240
+ ```dockerfile
241
+ FROM node:20
242
+ RUN npm i -g @nordsym/apiclaw
243
+ CMD ["apiclaw-http", "--port", "3000"]
244
+ EXPOSE 3000
245
+ ```
246
+
247
+ ### Vercel (Serverless)
248
+ See `landing/` directory for Next.js API routes wrapper.
249
+
250
+ ---
251
+
252
+ ## šŸ Hivr Integration
253
+
254
+ **In your Hivr bee instructions:**
255
+ ```markdown
256
+ ## APIClaw Access šŸ¦ž
257
+
258
+ You have access to APIClaw via HTTP API.
259
+
260
+ **Discover APIs:**
261
+ GET https://apiclaw.nordsym.com/api/discover?query=web+search&agentId=YOUR_HANDLE
262
+
263
+ **Call APIs:**
264
+ POST https://apiclaw.nordsym.com/api/call_api
265
+ Body: { provider: "brave_search", action: "search", params: {...}, agentId: "YOUR_HANDLE" }
266
+
267
+ **Your agent ID:** Replace `YOUR_HANDLE` with your actual handle (e.g., "bytebee").
268
+ ```
269
+
270
+ ---
271
+
272
+ ## šŸ“š API Provider Reference
273
+
274
+ See [apiclaw.nordsym.com/docs](https://apiclaw.nordsym.com/docs) for:
275
+ - List of all 18 Direct Call providers
276
+ - Available actions per provider
277
+ - Parameter schemas
278
+ - Rate limits & pricing
279
+
280
+ ---
281
+
282
+ ## šŸ”§ Development
283
+
284
+ **Run from source:**
285
+ ```bash
286
+ cd apiclaw
287
+ npm run build
288
+ node dist/bin-http.js --port 3000
289
+ ```
290
+
291
+ **Watch mode:**
292
+ ```bash
293
+ tsx watch src/bin-http.ts
294
+ ```
295
+
296
+ ---
297
+
298
+ ## ā“ Support
299
+
300
+ - **Docs:** [apiclaw.nordsym.com/docs](https://apiclaw.nordsym.com/docs)
301
+ - **Issues:** [github.com/nordsym/apiclaw/issues](https://github.com/nordsym/apiclaw/issues)
302
+ - **Email:** admin@nordsym.com
303
+
304
+ ---
305
+
306
+ MIT Ā© [NordSym](https://nordsym.com)
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * APIClaw HTTP API Server - Standalone executable
4
+ * Usage: apiclaw-http [--port 3000]
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=bin-http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin-http.d.ts","sourceRoot":"","sources":["../src/bin-http.ts"],"names":[],"mappings":";AACA;;;GAGG"}
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * APIClaw HTTP API Server - Standalone executable
4
+ * Usage: apiclaw-http [--port 3000]
5
+ */
6
+ import { startHTTPServer } from './http-api.js';
7
+ const args = process.argv.slice(2);
8
+ let port = 3000;
9
+ // Parse args
10
+ for (let i = 0; i < args.length; i++) {
11
+ if (args[i] === '--port' || args[i] === '-p') {
12
+ port = parseInt(args[i + 1] || '3000');
13
+ i++;
14
+ }
15
+ else if (args[i] === '--help' || args[i] === '-h') {
16
+ console.log(`
17
+ šŸ¦ž APIClaw HTTP API Server
18
+
19
+ Usage:
20
+ apiclaw-http [options]
21
+
22
+ Options:
23
+ --port, -p <port> Port to listen on (default: 3000)
24
+ --help, -h Show this help
25
+
26
+ Examples:
27
+ apiclaw-http
28
+ apiclaw-http --port 8080
29
+
30
+ Endpoints:
31
+ GET /api/discover?query=...&agentId=...
32
+ POST /api/call_api
33
+ Body: { provider, action, params, agentId }
34
+ GET /health
35
+
36
+ Auth:
37
+ Whitelist-based for Hivr bees. Contact admin@nordsym.com for access.
38
+ `);
39
+ process.exit(0);
40
+ }
41
+ }
42
+ startHTTPServer(port);
43
+ //# sourceMappingURL=bin-http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin-http.js","sourceRoot":"","sources":["../src/bin-http.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,IAAI,GAAG,IAAI,CAAC;AAEhB,aAAa;AACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;IACrC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7C,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC;QACvC,CAAC,EAAE,CAAC;IACN,CAAC;SAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QACpD,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;;;;CAsBf,CAAC,CAAC;QACC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,eAAe,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * APIClaw HTTP API Server
3
+ * Provides REST endpoints for headless agents (Hivr bees, webhooks, etc)
4
+ *
5
+ * Endpoints:
6
+ * - GET /api/discover?query=...&agentId=...
7
+ * - POST /api/call_api { provider, action, params, agentId }
8
+ * - GET /health
9
+ *
10
+ * Auth: Whitelist-based for Hivr bees
11
+ */
12
+ /**
13
+ * Start HTTP server
14
+ */
15
+ export declare function startHTTPServer(port?: number): void;
16
+ //# sourceMappingURL=http-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-api.d.ts","sourceRoot":"","sources":["../src/http-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAwQH;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,MAAa,GAAG,IAAI,CAwBzD"}
@@ -0,0 +1,269 @@
1
+ /**
2
+ * APIClaw HTTP API Server
3
+ * Provides REST endpoints for headless agents (Hivr bees, webhooks, etc)
4
+ *
5
+ * Endpoints:
6
+ * - GET /api/discover?query=...&agentId=...
7
+ * - POST /api/call_api { provider, action, params, agentId }
8
+ * - GET /health
9
+ *
10
+ * Auth: Whitelist-based for Hivr bees
11
+ */
12
+ import { createServer } from 'http';
13
+ import { URL } from 'url';
14
+ import { discoverAPIs } from './discovery.js';
15
+ import { isOpenAPI, executeOpenAPI } from './open-apis.js';
16
+ import { executeMetered } from './metered.js';
17
+ import { logAPICall } from './analytics.js';
18
+ // Hivr bees whitelist - these agents get free unlimited access
19
+ const HIVR_BEES_WHITELIST = [
20
+ 'bytebee',
21
+ 'analyzerbee',
22
+ 'buildbee',
23
+ 'buzzwriter',
24
+ 'hivemind',
25
+ 'hivesage',
26
+ 'symbot',
27
+ 'hivrqueen',
28
+ 'marketmaven',
29
+ 'reconbee',
30
+ 'sprintbee',
31
+ 'quillbee',
32
+ // Add more as Hivr grows
33
+ ];
34
+ /**
35
+ * Check if agent is authorized (Hivr bee)
36
+ */
37
+ function isAuthorized(agentId) {
38
+ if (!agentId)
39
+ return false;
40
+ const normalized = agentId.toLowerCase().trim();
41
+ return HIVR_BEES_WHITELIST.includes(normalized);
42
+ }
43
+ /**
44
+ * Parse JSON body from request
45
+ */
46
+ async function parseBody(req) {
47
+ return new Promise((resolve, reject) => {
48
+ let body = '';
49
+ req.on('data', chunk => body += chunk.toString());
50
+ req.on('end', () => {
51
+ try {
52
+ resolve(JSON.parse(body));
53
+ }
54
+ catch (e) {
55
+ reject(new Error('Invalid JSON'));
56
+ }
57
+ });
58
+ req.on('error', reject);
59
+ });
60
+ }
61
+ /**
62
+ * Send JSON response
63
+ */
64
+ function sendJSON(res, status, data) {
65
+ res.writeHead(status, {
66
+ 'Content-Type': 'application/json',
67
+ 'Access-Control-Allow-Origin': '*',
68
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
69
+ 'Access-Control-Allow-Headers': 'Content-Type, X-Agent-Id',
70
+ });
71
+ res.end(JSON.stringify(data));
72
+ }
73
+ /**
74
+ * Handle /api/discover
75
+ * GET /api/discover?query=web+search&agentId=bytebee&category=Search&maxResults=5
76
+ */
77
+ async function handleDiscover(req, res, url) {
78
+ const query = url.searchParams.get('query');
79
+ const agentId = url.searchParams.get('agentId');
80
+ const category = url.searchParams.get('category') || undefined;
81
+ const maxResults = parseInt(url.searchParams.get('maxResults') || '5');
82
+ if (!query) {
83
+ sendJSON(res, 400, { error: 'Missing query parameter' });
84
+ return;
85
+ }
86
+ if (!isAuthorized(agentId || undefined)) {
87
+ sendJSON(res, 403, {
88
+ error: 'Unauthorized',
89
+ message: 'This endpoint is restricted to Hivr bees. Contact admin@nordsym.com for access.',
90
+ });
91
+ return;
92
+ }
93
+ const startTime = Date.now();
94
+ const results = discoverAPIs(query, { category, maxResults });
95
+ const responseTimeMs = Date.now() - startTime;
96
+ // Log to analytics
97
+ logAPICall({
98
+ timestamp: new Date().toISOString(),
99
+ provider: 'apiclaw_discovery',
100
+ action: 'discover',
101
+ type: 'open',
102
+ userId: `hivr:${agentId}`,
103
+ success: true,
104
+ latencyMs: responseTimeMs,
105
+ });
106
+ sendJSON(res, 200, {
107
+ success: true,
108
+ query,
109
+ results: results.map(r => ({
110
+ provider: r.provider,
111
+ score: r.relevance_score,
112
+ reasons: r.match_reasons,
113
+ })),
114
+ count: results.length,
115
+ responseTimeMs,
116
+ });
117
+ }
118
+ /**
119
+ * Handle /api/call_api
120
+ * POST /api/call_api
121
+ * Body: { provider: "brave_search", action: "search", params: { query: "AI news" }, agentId: "bytebee" }
122
+ */
123
+ async function handleCallAPI(req, res) {
124
+ let body;
125
+ try {
126
+ body = await parseBody(req);
127
+ }
128
+ catch (e) {
129
+ sendJSON(res, 400, { error: 'Invalid JSON body' });
130
+ return;
131
+ }
132
+ const { provider, action, params, agentId } = body;
133
+ if (!provider || !action || !params || !agentId) {
134
+ sendJSON(res, 400, {
135
+ error: 'Missing required fields',
136
+ required: ['provider', 'action', 'params', 'agentId']
137
+ });
138
+ return;
139
+ }
140
+ if (!isAuthorized(agentId)) {
141
+ sendJSON(res, 403, {
142
+ error: 'Unauthorized',
143
+ message: 'This endpoint is restricted to Hivr bees. Contact admin@nordsym.com for access.',
144
+ });
145
+ return;
146
+ }
147
+ const startTime = Date.now();
148
+ let result;
149
+ let apiType;
150
+ let success = true;
151
+ let error;
152
+ try {
153
+ if (isOpenAPI(provider)) {
154
+ apiType = 'open';
155
+ result = await executeOpenAPI(provider, action, params);
156
+ success = result.success;
157
+ error = result.error;
158
+ }
159
+ else {
160
+ apiType = 'direct';
161
+ // For Direct Call APIs, use Hivr's workspace/credentials
162
+ // TODO: Get Hivr workspace token from env or config
163
+ const customerKey = process.env.APICLAW_HIVR_CUSTOMER_KEY;
164
+ const stripeCustomerId = process.env.APICLAW_HIVR_STRIPE_CUSTOMER;
165
+ result = await executeMetered(provider, action, params, {
166
+ customerId: stripeCustomerId,
167
+ customerKey,
168
+ userId: `hivr:${agentId}`,
169
+ });
170
+ success = result.success;
171
+ error = result.error;
172
+ }
173
+ }
174
+ catch (e) {
175
+ success = false;
176
+ error = e.message;
177
+ result = { success: false, error: error };
178
+ }
179
+ const latencyMs = Date.now() - startTime;
180
+ // Log to analytics
181
+ logAPICall({
182
+ timestamp: new Date().toISOString(),
183
+ provider,
184
+ action,
185
+ type: apiType,
186
+ userId: `hivr:${agentId}`,
187
+ success,
188
+ latencyMs,
189
+ error,
190
+ });
191
+ sendJSON(res, success ? 200 : 500, {
192
+ success,
193
+ provider,
194
+ action,
195
+ agentId,
196
+ data: result.data,
197
+ error: result.error,
198
+ latencyMs,
199
+ });
200
+ }
201
+ /**
202
+ * Handle OPTIONS (CORS preflight)
203
+ */
204
+ function handleOptions(res) {
205
+ res.writeHead(204, {
206
+ 'Access-Control-Allow-Origin': '*',
207
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
208
+ 'Access-Control-Allow-Headers': 'Content-Type, X-Agent-Id',
209
+ 'Access-Control-Max-Age': '86400',
210
+ });
211
+ res.end();
212
+ }
213
+ /**
214
+ * Main request handler
215
+ */
216
+ async function handleRequest(req, res) {
217
+ const url = new URL(req.url || '/', `http://${req.headers.host}`);
218
+ console.log(`[APIClaw HTTP] ${req.method} ${url.pathname}`);
219
+ // CORS preflight
220
+ if (req.method === 'OPTIONS') {
221
+ handleOptions(res);
222
+ return;
223
+ }
224
+ // Health check
225
+ if (url.pathname === '/health') {
226
+ sendJSON(res, 200, { status: 'ok', service: 'apiclaw-http-api' });
227
+ return;
228
+ }
229
+ // Route requests
230
+ if (url.pathname === '/api/discover' && req.method === 'GET') {
231
+ await handleDiscover(req, res, url);
232
+ return;
233
+ }
234
+ if (url.pathname === '/api/call_api' && req.method === 'POST') {
235
+ await handleCallAPI(req, res);
236
+ return;
237
+ }
238
+ // 404
239
+ sendJSON(res, 404, { error: 'Not found' });
240
+ }
241
+ /**
242
+ * Start HTTP server
243
+ */
244
+ export function startHTTPServer(port = 3000) {
245
+ const server = createServer(async (req, res) => {
246
+ try {
247
+ await handleRequest(req, res);
248
+ }
249
+ catch (error) {
250
+ console.error('[APIClaw HTTP] Error:', error);
251
+ sendJSON(res, 500, { error: 'Internal server error', message: error.message });
252
+ }
253
+ });
254
+ server.listen(port, () => {
255
+ console.log(`\nšŸ¦ž APIClaw HTTP API running on http://localhost:${port}`);
256
+ console.log(` GET /api/discover?query=...&agentId=...`);
257
+ console.log(` POST /api/call_api`);
258
+ console.log(` GET /health\n`);
259
+ });
260
+ server.on('error', (error) => {
261
+ if (error.code === 'EADDRINUSE') {
262
+ console.error(`[APIClaw HTTP] Port ${port} is already in use`);
263
+ }
264
+ else {
265
+ console.error('[APIClaw HTTP] Server error:', error);
266
+ }
267
+ });
268
+ }
269
+ //# sourceMappingURL=http-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-api.js","sourceRoot":"","sources":["../src/http-api.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAmC,MAAM,MAAM,CAAC;AACrE,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAG5C,+DAA+D;AAC/D,MAAM,mBAAmB,GAAG;IAC1B,SAAS;IACT,aAAa;IACb,UAAU;IACV,YAAY;IACZ,UAAU;IACV,UAAU;IACV,QAAQ;IACR,WAAW;IACX,aAAa;IACb,UAAU;IACV,WAAW;IACX,UAAU;IACV,yBAAyB;CAC1B,CAAC;AASF;;GAEG;AACH,SAAS,YAAY,CAAC,OAA2B;IAC/C,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAC3B,MAAM,UAAU,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;IAChD,OAAO,mBAAmB,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;AAClD,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,SAAS,CAAI,GAAoB;IAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClD,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC,CAAC;YACpC,CAAC;QACH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAS;IAC9D,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE;QACpB,cAAc,EAAE,kBAAkB;QAClC,6BAA6B,EAAE,GAAG;QAClC,8BAA8B,EAAE,oBAAoB;QACpD,8BAA8B,EAAE,0BAA0B;KAC3D,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED;;;GAGG;AACH,KAAK,UAAU,cAAc,CAAC,GAAoB,EAAE,GAAmB,EAAE,GAAQ;IAC/E,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAC5C,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,SAAS,CAAC;IAC/D,MAAM,UAAU,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC;IAEvE,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;QACzD,OAAO;IACT,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,OAAO,IAAI,SAAS,CAAC,EAAE,CAAC;QACxC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;YACjB,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,iFAAiF;SAC3F,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,YAAY,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAE9C,mBAAmB;IACnB,UAAU,CAAC;QACT,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,QAAQ,EAAE,mBAAmB;QAC7B,MAAM,EAAE,UAAU;QAClB,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,QAAQ,OAAO,EAAE;QACzB,OAAO,EAAE,IAAI;QACb,SAAS,EAAE,cAAc;KAC1B,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;QACjB,OAAO,EAAE,IAAI;QACb,KAAK;QACL,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACzB,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,KAAK,EAAE,CAAC,CAAC,eAAe;YACxB,OAAO,EAAE,CAAC,CAAC,aAAa;SACzB,CAAC,CAAC;QACH,KAAK,EAAE,OAAO,CAAC,MAAM;QACrB,cAAc;KACf,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,KAAK,UAAU,aAAa,CAAC,GAAoB,EAAE,GAAmB;IACpE,IAAI,IAAgB,CAAC;IAErB,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,SAAS,CAAa,GAAG,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACnD,OAAO;IACT,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;IAEnD,IAAI,CAAC,QAAQ,IAAI,CAAC,MAAM,IAAI,CAAC,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QAChD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;YACjB,KAAK,EAAE,yBAAyB;YAChC,QAAQ,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,CAAC;SACtD,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC,EAAE,CAAC;QAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;YACjB,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,iFAAiF;SAC3F,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,IAAI,MAAW,CAAC;IAChB,IAAI,OAA0B,CAAC;IAC/B,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,KAAyB,CAAC;IAE9B,IAAI,CAAC;QACH,IAAI,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxB,OAAO,GAAG,MAAM,CAAC;YACjB,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;YACxD,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YACzB,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,QAAQ,CAAC;YACnB,yDAAyD;YACzD,oDAAoD;YACpD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC;YAC1D,MAAM,gBAAgB,GAAG,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC;YAElE,MAAM,GAAG,MAAM,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE;gBACtD,UAAU,EAAE,gBAAgB;gBAC5B,WAAW;gBACX,MAAM,EAAE,QAAQ,OAAO,EAAE;aAC1B,CAAC,CAAC;YACH,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;YACzB,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QACvB,CAAC;IACH,CAAC;IAAC,OAAO,CAAM,EAAE,CAAC;QAChB,OAAO,GAAG,KAAK,CAAC;QAChB,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC;QAClB,MAAM,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAC5C,CAAC;IAED,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;IAEzC,mBAAmB;IACnB,UAAU,CAAC;QACT,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,QAAQ;QACR,MAAM;QACN,IAAI,EAAE,OAAQ;QACd,MAAM,EAAE,QAAQ,OAAO,EAAE;QACzB,OAAO;QACP,SAAS;QACT,KAAK;KACN,CAAC,CAAC;IAEH,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE;QACjC,OAAO;QACP,QAAQ;QACR,MAAM;QACN,OAAO;QACP,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,KAAK,EAAE,MAAM,CAAC,KAAK;QACnB,SAAS;KACV,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,GAAmB;IACxC,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;QACjB,6BAA6B,EAAE,GAAG;QAClC,8BAA8B,EAAE,oBAAoB;QACpD,8BAA8B,EAAE,0BAA0B;QAC1D,wBAAwB,EAAE,OAAO;KAClC,CAAC,CAAC;IACH,GAAG,CAAC,GAAG,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,aAAa,CAAC,GAAoB,EAAE,GAAmB;IACpE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IAElE,OAAO,CAAC,GAAG,CAAC,kBAAkB,GAAG,CAAC,MAAM,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;IAE5D,iBAAiB;IACjB,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC7B,aAAa,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO;IACT,CAAC;IAED,eAAe;IACf,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC/B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,kBAAkB,EAAE,CAAC,CAAC;QAClE,OAAO;IACT,CAAC;IAED,iBAAiB;IACjB,IAAI,GAAG,CAAC,QAAQ,KAAK,eAAe,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,EAAE,CAAC;QAC7D,MAAM,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACpC,OAAO;IACT,CAAC;IAED,IAAI,GAAG,CAAC,QAAQ,KAAK,eAAe,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,EAAE,CAAC;QAC9D,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC9B,OAAO;IACT,CAAC;IAED,MAAM;IACN,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAAe,IAAI;IACjD,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;QAC7C,IAAI,CAAC;YACH,MAAM,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAChC,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC9C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,uBAAuB,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QACjF,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,EAAE;QACvB,OAAO,CAAC,GAAG,CAAC,qDAAqD,IAAI,EAAE,CAAC,CAAC;QACzE,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,KAAU,EAAE,EAAE;QAChC,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,uBAAuB,IAAI,oBAAoB,CAAC,CAAC;QACjE,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;QACvD,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -5,7 +5,7 @@ import statsData from "@/lib/stats.json";
5
5
 
6
6
  export const metadata: Metadata = {
7
7
  title: "APIClaw | The API Layer for AI Agents",
8
- description: `Agents discover and evaluate APIs via MCP. Structured data. Ranked results. ${statsData.apiCount.toLocaleString()}+ APIs across ${statsData.categoryCount}+ categories.`,
8
+ description: `Your agent's API encyclopedia. Search by capability, call instantly. ${statsData.apiCount.toLocaleString()} APIs indexed • ${statsData.openApiCount.toLocaleString()} Open APIs • ${statsData.directCallCount} Direct Call • MCP native`,
9
9
  metadataBase: new URL("https://apiclaw.nordsym.com"),
10
10
  icons: {
11
11
  icon: [
@@ -18,7 +18,7 @@ export const metadata: Metadata = {
18
18
  },
19
19
  openGraph: {
20
20
  title: "APIClaw | The API Layer for AI Agents",
21
- description: `${statsData.apiCount.toLocaleString()}+ APIs. MCP native. Direct Call: providers self-serve their APIs for AI agents.`,
21
+ description: `Your agent's API encyclopedia. Search by capability, call instantly. ${statsData.apiCount.toLocaleString()} APIs indexed • ${statsData.openApiCount.toLocaleString()} Open APIs • ${statsData.directCallCount} Direct Call • MCP native`,
22
22
  type: "website",
23
23
  siteName: "APIClaw",
24
24
  locale: "en_US",
@@ -34,7 +34,7 @@ export const metadata: Metadata = {
34
34
  twitter: {
35
35
  card: "summary_large_image",
36
36
  title: "APIClaw | The API Layer for AI Agents",
37
- description: `Agents discover and evaluate APIs via MCP. ${statsData.apiCount.toLocaleString()}+ APIs. MCP native.`,
37
+ description: `Your agent's API encyclopedia. Search by capability, call instantly. ${statsData.apiCount.toLocaleString()} APIs indexed • ${statsData.openApiCount.toLocaleString()} Open APIs • ${statsData.directCallCount} Direct Call • MCP native`,
38
38
  images: ["/api/og"],
39
39
  creator: "@nordsym",
40
40
  },
@@ -51,7 +51,7 @@ const schemaOrg = {
51
51
  "@type": "WebSite",
52
52
  "name": "APIClaw",
53
53
  "url": "https://apiclaw.nordsym.com",
54
- "description": "The API layer for AI agents. Discover and call APIs via MCP with structured data and ranked results."
54
+ "description": "Your agent's API encyclopedia. Search by capability, call instantly. 22,392 APIs indexed • 1,636 Open APIs • 18 Direct Call • MCP native"
55
55
  },
56
56
  {
57
57
  "@type": "Organization",
@@ -63,7 +63,7 @@ const schemaOrg = {
63
63
  "name": "APIClaw",
64
64
  "applicationCategory": "DeveloperApplication",
65
65
  "operatingSystem": "Web",
66
- "description": "API discovery and execution layer for AI agents. 22,000+ APIs indexed. MCP native. Direct Call providers.",
66
+ "description": "The API layer for AI agents. 22,392 APIs indexed, 1,636 Open APIs, 18 Direct Call providers. MCP native.",
67
67
  "offers": {
68
68
  "@type": "Offer",
69
69
  "price": "0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nordsym/apiclaw",
3
- "version": "1.5.8",
3
+ "version": "1.5.9",
4
4
  "description": "The API layer for AI agents. Dashboard + 22K APIs + 18 Direct Call providers. MCP native.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -81,6 +81,7 @@
81
81
  "typescript": "^5.3.0"
82
82
  },
83
83
  "bin": {
84
- "apiclaw": "./dist/bin.js"
84
+ "apiclaw": "./dist/bin.js",
85
+ "apiclaw-http": "./dist/bin-http.js"
85
86
  }
86
87
  }
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * APIClaw HTTP API Server - Standalone executable
4
+ * Usage: apiclaw-http [--port 3000]
5
+ */
6
+
7
+ import { startHTTPServer } from './http-api.js';
8
+
9
+ const args = process.argv.slice(2);
10
+ let port = 3000;
11
+
12
+ // Parse args
13
+ for (let i = 0; i < args.length; i++) {
14
+ if (args[i] === '--port' || args[i] === '-p') {
15
+ port = parseInt(args[i + 1] || '3000');
16
+ i++;
17
+ } else if (args[i] === '--help' || args[i] === '-h') {
18
+ console.log(`
19
+ šŸ¦ž APIClaw HTTP API Server
20
+
21
+ Usage:
22
+ apiclaw-http [options]
23
+
24
+ Options:
25
+ --port, -p <port> Port to listen on (default: 3000)
26
+ --help, -h Show this help
27
+
28
+ Examples:
29
+ apiclaw-http
30
+ apiclaw-http --port 8080
31
+
32
+ Endpoints:
33
+ GET /api/discover?query=...&agentId=...
34
+ POST /api/call_api
35
+ Body: { provider, action, params, agentId }
36
+ GET /health
37
+
38
+ Auth:
39
+ Whitelist-based for Hivr bees. Contact admin@nordsym.com for access.
40
+ `);
41
+ process.exit(0);
42
+ }
43
+ }
44
+
45
+ startHTTPServer(port);
@@ -0,0 +1,302 @@
1
+ /**
2
+ * APIClaw HTTP API Server
3
+ * Provides REST endpoints for headless agents (Hivr bees, webhooks, etc)
4
+ *
5
+ * Endpoints:
6
+ * - GET /api/discover?query=...&agentId=...
7
+ * - POST /api/call_api { provider, action, params, agentId }
8
+ * - GET /health
9
+ *
10
+ * Auth: Whitelist-based for Hivr bees
11
+ */
12
+
13
+ import { createServer, IncomingMessage, ServerResponse } from 'http';
14
+ import { URL } from 'url';
15
+ import { discoverAPIs } from './discovery.js';
16
+ import { isOpenAPI, executeOpenAPI } from './open-apis.js';
17
+ import { executeMetered } from './metered.js';
18
+ import { logAPICall } from './analytics.js';
19
+ import { getMachineFingerprint } from './session.js';
20
+
21
+ // Hivr bees whitelist - these agents get free unlimited access
22
+ const HIVR_BEES_WHITELIST = [
23
+ 'bytebee',
24
+ 'analyzerbee',
25
+ 'buildbee',
26
+ 'buzzwriter',
27
+ 'hivemind',
28
+ 'hivesage',
29
+ 'symbot',
30
+ 'hivrqueen',
31
+ 'marketmaven',
32
+ 'reconbee',
33
+ 'sprintbee',
34
+ 'quillbee',
35
+ // Add more as Hivr grows
36
+ ];
37
+
38
+ interface APIRequest {
39
+ provider: string;
40
+ action: string;
41
+ params: Record<string, any>;
42
+ agentId: string;
43
+ }
44
+
45
+ /**
46
+ * Check if agent is authorized (Hivr bee)
47
+ */
48
+ function isAuthorized(agentId: string | undefined): boolean {
49
+ if (!agentId) return false;
50
+ const normalized = agentId.toLowerCase().trim();
51
+ return HIVR_BEES_WHITELIST.includes(normalized);
52
+ }
53
+
54
+ /**
55
+ * Parse JSON body from request
56
+ */
57
+ async function parseBody<T>(req: IncomingMessage): Promise<T> {
58
+ return new Promise((resolve, reject) => {
59
+ let body = '';
60
+ req.on('data', chunk => body += chunk.toString());
61
+ req.on('end', () => {
62
+ try {
63
+ resolve(JSON.parse(body));
64
+ } catch (e) {
65
+ reject(new Error('Invalid JSON'));
66
+ }
67
+ });
68
+ req.on('error', reject);
69
+ });
70
+ }
71
+
72
+ /**
73
+ * Send JSON response
74
+ */
75
+ function sendJSON(res: ServerResponse, status: number, data: any): void {
76
+ res.writeHead(status, {
77
+ 'Content-Type': 'application/json',
78
+ 'Access-Control-Allow-Origin': '*',
79
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
80
+ 'Access-Control-Allow-Headers': 'Content-Type, X-Agent-Id',
81
+ });
82
+ res.end(JSON.stringify(data));
83
+ }
84
+
85
+ /**
86
+ * Handle /api/discover
87
+ * GET /api/discover?query=web+search&agentId=bytebee&category=Search&maxResults=5
88
+ */
89
+ async function handleDiscover(req: IncomingMessage, res: ServerResponse, url: URL): Promise<void> {
90
+ const query = url.searchParams.get('query');
91
+ const agentId = url.searchParams.get('agentId');
92
+ const category = url.searchParams.get('category') || undefined;
93
+ const maxResults = parseInt(url.searchParams.get('maxResults') || '5');
94
+
95
+ if (!query) {
96
+ sendJSON(res, 400, { error: 'Missing query parameter' });
97
+ return;
98
+ }
99
+
100
+ if (!isAuthorized(agentId || undefined)) {
101
+ sendJSON(res, 403, {
102
+ error: 'Unauthorized',
103
+ message: 'This endpoint is restricted to Hivr bees. Contact admin@nordsym.com for access.',
104
+ });
105
+ return;
106
+ }
107
+
108
+ const startTime = Date.now();
109
+ const results = discoverAPIs(query, { category, maxResults });
110
+ const responseTimeMs = Date.now() - startTime;
111
+
112
+ // Log to analytics
113
+ logAPICall({
114
+ timestamp: new Date().toISOString(),
115
+ provider: 'apiclaw_discovery',
116
+ action: 'discover',
117
+ type: 'open',
118
+ userId: `hivr:${agentId}`,
119
+ success: true,
120
+ latencyMs: responseTimeMs,
121
+ });
122
+
123
+ sendJSON(res, 200, {
124
+ success: true,
125
+ query,
126
+ results: results.map(r => ({
127
+ provider: r.provider,
128
+ score: r.relevance_score,
129
+ reasons: r.match_reasons,
130
+ })),
131
+ count: results.length,
132
+ responseTimeMs,
133
+ });
134
+ }
135
+
136
+ /**
137
+ * Handle /api/call_api
138
+ * POST /api/call_api
139
+ * Body: { provider: "brave_search", action: "search", params: { query: "AI news" }, agentId: "bytebee" }
140
+ */
141
+ async function handleCallAPI(req: IncomingMessage, res: ServerResponse): Promise<void> {
142
+ let body: APIRequest;
143
+
144
+ try {
145
+ body = await parseBody<APIRequest>(req);
146
+ } catch (e) {
147
+ sendJSON(res, 400, { error: 'Invalid JSON body' });
148
+ return;
149
+ }
150
+
151
+ const { provider, action, params, agentId } = body;
152
+
153
+ if (!provider || !action || !params || !agentId) {
154
+ sendJSON(res, 400, {
155
+ error: 'Missing required fields',
156
+ required: ['provider', 'action', 'params', 'agentId']
157
+ });
158
+ return;
159
+ }
160
+
161
+ if (!isAuthorized(agentId)) {
162
+ sendJSON(res, 403, {
163
+ error: 'Unauthorized',
164
+ message: 'This endpoint is restricted to Hivr bees. Contact admin@nordsym.com for access.',
165
+ });
166
+ return;
167
+ }
168
+
169
+ const startTime = Date.now();
170
+ let result: any;
171
+ let apiType: 'open' | 'direct';
172
+ let success = true;
173
+ let error: string | undefined;
174
+
175
+ try {
176
+ if (isOpenAPI(provider)) {
177
+ apiType = 'open';
178
+ result = await executeOpenAPI(provider, action, params);
179
+ success = result.success;
180
+ error = result.error;
181
+ } else {
182
+ apiType = 'direct';
183
+ // For Direct Call APIs, use Hivr's workspace/credentials
184
+ // TODO: Get Hivr workspace token from env or config
185
+ const customerKey = process.env.APICLAW_HIVR_CUSTOMER_KEY;
186
+ const stripeCustomerId = process.env.APICLAW_HIVR_STRIPE_CUSTOMER;
187
+
188
+ result = await executeMetered(provider, action, params, {
189
+ customerId: stripeCustomerId,
190
+ customerKey,
191
+ userId: `hivr:${agentId}`,
192
+ });
193
+ success = result.success;
194
+ error = result.error;
195
+ }
196
+ } catch (e: any) {
197
+ success = false;
198
+ error = e.message;
199
+ result = { success: false, error: error };
200
+ }
201
+
202
+ const latencyMs = Date.now() - startTime;
203
+
204
+ // Log to analytics
205
+ logAPICall({
206
+ timestamp: new Date().toISOString(),
207
+ provider,
208
+ action,
209
+ type: apiType!,
210
+ userId: `hivr:${agentId}`,
211
+ success,
212
+ latencyMs,
213
+ error,
214
+ });
215
+
216
+ sendJSON(res, success ? 200 : 500, {
217
+ success,
218
+ provider,
219
+ action,
220
+ agentId,
221
+ data: result.data,
222
+ error: result.error,
223
+ latencyMs,
224
+ });
225
+ }
226
+
227
+ /**
228
+ * Handle OPTIONS (CORS preflight)
229
+ */
230
+ function handleOptions(res: ServerResponse): void {
231
+ res.writeHead(204, {
232
+ 'Access-Control-Allow-Origin': '*',
233
+ 'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
234
+ 'Access-Control-Allow-Headers': 'Content-Type, X-Agent-Id',
235
+ 'Access-Control-Max-Age': '86400',
236
+ });
237
+ res.end();
238
+ }
239
+
240
+ /**
241
+ * Main request handler
242
+ */
243
+ async function handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {
244
+ const url = new URL(req.url || '/', `http://${req.headers.host}`);
245
+
246
+ console.log(`[APIClaw HTTP] ${req.method} ${url.pathname}`);
247
+
248
+ // CORS preflight
249
+ if (req.method === 'OPTIONS') {
250
+ handleOptions(res);
251
+ return;
252
+ }
253
+
254
+ // Health check
255
+ if (url.pathname === '/health') {
256
+ sendJSON(res, 200, { status: 'ok', service: 'apiclaw-http-api' });
257
+ return;
258
+ }
259
+
260
+ // Route requests
261
+ if (url.pathname === '/api/discover' && req.method === 'GET') {
262
+ await handleDiscover(req, res, url);
263
+ return;
264
+ }
265
+
266
+ if (url.pathname === '/api/call_api' && req.method === 'POST') {
267
+ await handleCallAPI(req, res);
268
+ return;
269
+ }
270
+
271
+ // 404
272
+ sendJSON(res, 404, { error: 'Not found' });
273
+ }
274
+
275
+ /**
276
+ * Start HTTP server
277
+ */
278
+ export function startHTTPServer(port: number = 3000): void {
279
+ const server = createServer(async (req, res) => {
280
+ try {
281
+ await handleRequest(req, res);
282
+ } catch (error: any) {
283
+ console.error('[APIClaw HTTP] Error:', error);
284
+ sendJSON(res, 500, { error: 'Internal server error', message: error.message });
285
+ }
286
+ });
287
+
288
+ server.listen(port, () => {
289
+ console.log(`\nšŸ¦ž APIClaw HTTP API running on http://localhost:${port}`);
290
+ console.log(` GET /api/discover?query=...&agentId=...`);
291
+ console.log(` POST /api/call_api`);
292
+ console.log(` GET /health\n`);
293
+ });
294
+
295
+ server.on('error', (error: any) => {
296
+ if (error.code === 'EADDRINUSE') {
297
+ console.error(`[APIClaw HTTP] Port ${port} is already in use`);
298
+ } else {
299
+ console.error('[APIClaw HTTP] Server error:', error);
300
+ }
301
+ });
302
+ }