@nordsym/apiclaw 1.5.10 → 1.5.11
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/APILAYER_STATUS_2026-03-24.md +38 -0
- package/TERMINOLOGY-AUDIT.md +99 -0
- package/TERMINOLOGY-FIXED.md +74 -0
- package/VIDEO-DEMO-GUIDE.md +82 -0
- package/direct-test.mjs +51 -0
- package/dist/cli/commands/mcp-install.d.ts.map +1 -1
- package/dist/cli/commands/mcp-install.js +55 -40
- package/dist/cli/commands/mcp-install.js.map +1 -1
- package/dist/credentials.d.ts.map +1 -1
- package/dist/credentials.js +128 -0
- package/dist/credentials.js.map +1 -1
- package/dist/discovery.d.ts.map +1 -1
- package/dist/discovery.js +191 -82
- package/dist/discovery.js.map +1 -1
- package/dist/execute.d.ts.map +1 -1
- package/dist/execute.js +53 -24
- package/dist/execute.js.map +1 -1
- package/email-templates/README.md +104 -0
- package/email-templates/partnership-template.html +116 -0
- package/landing/src/app/api/auth/magic-link/route.ts +1 -1
- package/landing/src/app/layout.tsx +2 -2
- package/landing/src/app/login/page.tsx +1 -1
- package/landing/src/app/page.tsx +39 -18
- package/landing/src/app/providers/dashboard/[apiId]/direct-call/page.tsx +1 -1
- package/landing/src/app/providers/dashboard/login/page.tsx +1 -1
- package/landing/src/app/providers/dashboard/page.tsx +1 -1
- package/landing/src/app/providers/layout.tsx +1 -1
- package/landing/src/components/HeroTabs.tsx +2 -2
- package/landing/src/components/VideoDemo.tsx +94 -0
- package/landing/src/components/{ProviderDashboard.tsx → Workspace.tsx} +2 -2
- package/landing/src/lib/mock-data.ts +1 -1
- package/landing/src/lib/stats.json +1 -1
- package/package.json +1 -1
- package/src/cli/commands/mcp-install.ts +14 -4
- package/src/credentials.ts +136 -0
- package/src/discovery.ts +191 -82
- package/src/execute.ts +49 -22
- package/test-actual-handlers.ts +92 -0
- package/test-apilayer-all-14.ts +249 -0
- package/test-apilayer-fixed.ts +248 -0
- package/test-direct-endpoints.ts +174 -0
- package/test-exact-endpoints.ts +144 -0
- package/test-final.ts +83 -0
- package/test-full-routing.ts +100 -0
- package/test-handlers-correct.ts +217 -0
- package/test-numverify-key.ts +41 -0
- package/test-via-handlers.ts +92 -0
- package/test-worldnews.mjs +26 -0
package/src/credentials.ts
CHANGED
|
@@ -183,6 +183,102 @@ const providers: Record<string, ProviderCredential> = {
|
|
|
183
183
|
return { type: 'api_key', api_key: keys.APILAYER_EXCHANGERATE_KEY || '', ...keys } as any;
|
|
184
184
|
},
|
|
185
185
|
},
|
|
186
|
+
|
|
187
|
+
groq: {
|
|
188
|
+
type: 'bearer',
|
|
189
|
+
get(): APICredentials | null {
|
|
190
|
+
const env = loadEnvFile('groq.env');
|
|
191
|
+
const key = env.GROQ_API_KEY || process.env.GROQ_API_KEY;
|
|
192
|
+
if (key) {
|
|
193
|
+
return { type: 'bearer', api_key: key };
|
|
194
|
+
}
|
|
195
|
+
return null;
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
|
|
199
|
+
deepgram: {
|
|
200
|
+
type: 'bearer',
|
|
201
|
+
get(): APICredentials | null {
|
|
202
|
+
const env = loadEnvFile('deepgram.env');
|
|
203
|
+
const key = env.DEEPGRAM_API_KEY || process.env.DEEPGRAM_API_KEY;
|
|
204
|
+
if (key) {
|
|
205
|
+
return { type: 'bearer', api_key: key };
|
|
206
|
+
}
|
|
207
|
+
return null;
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
|
|
211
|
+
mistral: {
|
|
212
|
+
type: 'api_key',
|
|
213
|
+
get(): APICredentials | null {
|
|
214
|
+
const env = loadEnvFile('mistral.env');
|
|
215
|
+
const key = env.MISTRAL_API_KEY || process.env.MISTRAL_API_KEY;
|
|
216
|
+
if (key) {
|
|
217
|
+
return { type: 'api_key', api_key: key };
|
|
218
|
+
}
|
|
219
|
+
return null;
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
cohere: {
|
|
224
|
+
type: 'api_key',
|
|
225
|
+
get(): APICredentials | null {
|
|
226
|
+
const env = loadEnvFile('cohere.env');
|
|
227
|
+
const key = env.COHERE_API_KEY || process.env.COHERE_API_KEY;
|
|
228
|
+
if (key) {
|
|
229
|
+
return { type: 'api_key', api_key: key };
|
|
230
|
+
}
|
|
231
|
+
return null;
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
serper: {
|
|
236
|
+
type: 'api_key',
|
|
237
|
+
get(): APICredentials | null {
|
|
238
|
+
const env = loadEnvFile('serpapi.env');
|
|
239
|
+
const key = env.SERPAPI_API_KEY || process.env.SERPER_API_KEY || process.env.SERPAPI_API_KEY;
|
|
240
|
+
if (key) {
|
|
241
|
+
return { type: 'api_key', api_key: key };
|
|
242
|
+
}
|
|
243
|
+
return null;
|
|
244
|
+
},
|
|
245
|
+
},
|
|
246
|
+
|
|
247
|
+
stability: {
|
|
248
|
+
type: 'api_key',
|
|
249
|
+
get(): APICredentials | null {
|
|
250
|
+
const env = loadEnvFile('stability.env');
|
|
251
|
+
const key = env.STABILITY_API_KEY || process.env.STABILITY_API_KEY;
|
|
252
|
+
if (key) {
|
|
253
|
+
return { type: 'api_key', api_key: key };
|
|
254
|
+
}
|
|
255
|
+
return null;
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
together: {
|
|
260
|
+
type: 'bearer',
|
|
261
|
+
get(): APICredentials | null {
|
|
262
|
+
const env = loadEnvFile('together.env');
|
|
263
|
+
const key = env.TOGETHER_API_KEY || process.env.TOGETHER_API_KEY;
|
|
264
|
+
if (key) {
|
|
265
|
+
return { type: 'bearer', api_key: key };
|
|
266
|
+
}
|
|
267
|
+
return null;
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
|
|
271
|
+
assemblyai: {
|
|
272
|
+
type: 'api_key',
|
|
273
|
+
get(): APICredentials | null {
|
|
274
|
+
const env = loadEnvFile('assemblyai.env');
|
|
275
|
+
const key = env.ASSEMBLYAI_API_KEY || process.env.ASSEMBLYAI_API_KEY;
|
|
276
|
+
if (key) {
|
|
277
|
+
return { type: 'api_key', api_key: key };
|
|
278
|
+
}
|
|
279
|
+
return null;
|
|
280
|
+
},
|
|
281
|
+
},
|
|
186
282
|
};
|
|
187
283
|
|
|
188
284
|
/**
|
|
@@ -231,10 +327,50 @@ export function hasRealCredentials(providerId: string): boolean {
|
|
|
231
327
|
const env = loadEnvFile('e2b.env');
|
|
232
328
|
return !!(env.E2B_API_KEY || process.env.E2B_API_KEY);
|
|
233
329
|
}
|
|
330
|
+
if (providerId === 'firecrawl') {
|
|
331
|
+
const env = loadEnvFile('firecrawl.env');
|
|
332
|
+
return !!(env.FIRECRAWL_API_KEY || process.env.FIRECRAWL_API_KEY);
|
|
333
|
+
}
|
|
334
|
+
if (providerId === 'github') {
|
|
335
|
+
const env = loadEnvFile('github.env');
|
|
336
|
+
return !!(env.GITHUB_TOKEN || process.env.GITHUB_TOKEN);
|
|
337
|
+
}
|
|
234
338
|
if (providerId === 'apilayer') {
|
|
235
339
|
const env = loadEnvFile('apilayer.env');
|
|
236
340
|
return !!(env.APILAYER_EXCHANGERATE_KEY || process.env.APILAYER_EXCHANGERATE_KEY);
|
|
237
341
|
}
|
|
342
|
+
if (providerId === 'groq') {
|
|
343
|
+
const env = loadEnvFile('groq.env');
|
|
344
|
+
return !!(env.GROQ_API_KEY || process.env.GROQ_API_KEY);
|
|
345
|
+
}
|
|
346
|
+
if (providerId === 'deepgram') {
|
|
347
|
+
const env = loadEnvFile('deepgram.env');
|
|
348
|
+
return !!(env.DEEPGRAM_API_KEY || process.env.DEEPGRAM_API_KEY);
|
|
349
|
+
}
|
|
350
|
+
if (providerId === 'mistral') {
|
|
351
|
+
const env = loadEnvFile('mistral.env');
|
|
352
|
+
return !!(env.MISTRAL_API_KEY || process.env.MISTRAL_API_KEY);
|
|
353
|
+
}
|
|
354
|
+
if (providerId === 'cohere') {
|
|
355
|
+
const env = loadEnvFile('cohere.env');
|
|
356
|
+
return !!(env.COHERE_API_KEY || process.env.COHERE_API_KEY);
|
|
357
|
+
}
|
|
358
|
+
if (providerId === 'serper') {
|
|
359
|
+
const env = loadEnvFile('serpapi.env');
|
|
360
|
+
return !!(env.SERPAPI_API_KEY || process.env.SERPER_API_KEY || process.env.SERPAPI_API_KEY);
|
|
361
|
+
}
|
|
362
|
+
if (providerId === 'stability') {
|
|
363
|
+
const env = loadEnvFile('stability.env');
|
|
364
|
+
return !!(env.STABILITY_API_KEY || process.env.STABILITY_API_KEY);
|
|
365
|
+
}
|
|
366
|
+
if (providerId === 'together') {
|
|
367
|
+
const env = loadEnvFile('together.env');
|
|
368
|
+
return !!(env.TOGETHER_API_KEY || process.env.TOGETHER_API_KEY);
|
|
369
|
+
}
|
|
370
|
+
if (providerId === 'assemblyai') {
|
|
371
|
+
const env = loadEnvFile('assemblyai.env');
|
|
372
|
+
return !!(env.ASSEMBLYAI_API_KEY || process.env.ASSEMBLYAI_API_KEY);
|
|
373
|
+
}
|
|
238
374
|
return false;
|
|
239
375
|
}
|
|
240
376
|
|
package/src/discovery.ts
CHANGED
|
@@ -17,73 +17,13 @@ const apisData = JSON.parse(
|
|
|
17
17
|
const apis: APIProvider[] = apisData.apis;
|
|
18
18
|
|
|
19
19
|
// Direct Call provider specs (hardcoded handlers with params)
|
|
20
|
+
// Ordered: AI-first (models, LLM routing, audio), then infrastructure (code, web, search, email, SMS)
|
|
20
21
|
const DIRECT_CALL_SPECS: Record<string, {
|
|
21
22
|
description: string;
|
|
22
23
|
auth: string;
|
|
23
24
|
docs: string;
|
|
24
25
|
actions: Record<string, { params: { name: string; required: boolean; desc: string }[]; desc: string }>;
|
|
25
26
|
}> = {
|
|
26
|
-
'46elks': {
|
|
27
|
-
description: 'Swedish SMS and voice API',
|
|
28
|
-
auth: 'basic',
|
|
29
|
-
docs: 'https://46elks.com/docs',
|
|
30
|
-
actions: {
|
|
31
|
-
send_sms: {
|
|
32
|
-
desc: 'Send SMS message',
|
|
33
|
-
params: [
|
|
34
|
-
{ name: 'to', required: true, desc: 'Phone number (+46...)' },
|
|
35
|
-
{ name: 'message', required: true, desc: 'SMS text (max 160 chars for 1 segment)' },
|
|
36
|
-
{ name: 'from', required: false, desc: 'Sender ID (default: APIClaw)' },
|
|
37
|
-
],
|
|
38
|
-
},
|
|
39
|
-
},
|
|
40
|
-
},
|
|
41
|
-
twilio: {
|
|
42
|
-
description: 'Global SMS and voice API',
|
|
43
|
-
auth: 'basic',
|
|
44
|
-
docs: 'https://www.twilio.com/docs',
|
|
45
|
-
actions: {
|
|
46
|
-
send_sms: {
|
|
47
|
-
desc: 'Send SMS message',
|
|
48
|
-
params: [
|
|
49
|
-
{ name: 'to', required: true, desc: 'Phone number (E.164 format)' },
|
|
50
|
-
{ name: 'message', required: true, desc: 'SMS text' },
|
|
51
|
-
{ name: 'from', required: false, desc: 'Sender phone number' },
|
|
52
|
-
],
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
brave_search: {
|
|
57
|
-
description: 'Web search API',
|
|
58
|
-
auth: 'api_key',
|
|
59
|
-
docs: 'https://api.search.brave.com/docs',
|
|
60
|
-
actions: {
|
|
61
|
-
search: {
|
|
62
|
-
desc: 'Search the web',
|
|
63
|
-
params: [
|
|
64
|
-
{ name: 'query', required: true, desc: 'Search query' },
|
|
65
|
-
{ name: 'count', required: false, desc: 'Number of results (default: 5)' },
|
|
66
|
-
],
|
|
67
|
-
},
|
|
68
|
-
},
|
|
69
|
-
},
|
|
70
|
-
resend: {
|
|
71
|
-
description: 'Email API',
|
|
72
|
-
auth: 'bearer',
|
|
73
|
-
docs: 'https://resend.com/docs',
|
|
74
|
-
actions: {
|
|
75
|
-
send_email: {
|
|
76
|
-
desc: 'Send email',
|
|
77
|
-
params: [
|
|
78
|
-
{ name: 'to', required: true, desc: 'Recipient email' },
|
|
79
|
-
{ name: 'subject', required: true, desc: 'Email subject' },
|
|
80
|
-
{ name: 'html', required: false, desc: 'HTML body' },
|
|
81
|
-
{ name: 'text', required: false, desc: 'Plain text body' },
|
|
82
|
-
{ name: 'from', required: false, desc: 'Sender (default: noreply@apiclaw.nordsym.com)' },
|
|
83
|
-
],
|
|
84
|
-
},
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
27
|
openrouter: {
|
|
88
28
|
description: 'LLM routing (100+ models)',
|
|
89
29
|
auth: 'bearer',
|
|
@@ -99,6 +39,24 @@ const DIRECT_CALL_SPECS: Record<string, {
|
|
|
99
39
|
},
|
|
100
40
|
},
|
|
101
41
|
},
|
|
42
|
+
replicate: {
|
|
43
|
+
description: 'Run any AI model (images, video, audio)',
|
|
44
|
+
auth: 'bearer',
|
|
45
|
+
docs: 'https://replicate.com/docs',
|
|
46
|
+
actions: {
|
|
47
|
+
run: {
|
|
48
|
+
desc: 'Run a model',
|
|
49
|
+
params: [
|
|
50
|
+
{ name: 'model', required: true, desc: 'Model ID (e.g., stability-ai/sdxl:...)' },
|
|
51
|
+
{ name: 'input', required: true, desc: 'Model input parameters' },
|
|
52
|
+
],
|
|
53
|
+
},
|
|
54
|
+
list_models: {
|
|
55
|
+
desc: 'List available models',
|
|
56
|
+
params: [],
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
102
60
|
elevenlabs: {
|
|
103
61
|
description: 'Text-to-speech',
|
|
104
62
|
auth: 'api_key',
|
|
@@ -114,21 +72,23 @@ const DIRECT_CALL_SPECS: Record<string, {
|
|
|
114
72
|
},
|
|
115
73
|
},
|
|
116
74
|
},
|
|
117
|
-
|
|
118
|
-
description: '
|
|
119
|
-
auth: '
|
|
120
|
-
docs: 'https://
|
|
75
|
+
e2b: {
|
|
76
|
+
description: 'Code sandbox for AI agents',
|
|
77
|
+
auth: 'api_key',
|
|
78
|
+
docs: 'https://e2b.dev/docs',
|
|
121
79
|
actions: {
|
|
122
|
-
|
|
123
|
-
desc: '
|
|
80
|
+
run_code: {
|
|
81
|
+
desc: 'Execute code in sandbox',
|
|
124
82
|
params: [
|
|
125
|
-
{ name: '
|
|
126
|
-
{ name: '
|
|
83
|
+
{ name: 'code', required: true, desc: 'Code to run' },
|
|
84
|
+
{ name: 'language', required: false, desc: 'Language (default: python)' },
|
|
127
85
|
],
|
|
128
86
|
},
|
|
129
|
-
|
|
130
|
-
desc: '
|
|
131
|
-
params: [
|
|
87
|
+
run_shell: {
|
|
88
|
+
desc: 'Execute shell command',
|
|
89
|
+
params: [
|
|
90
|
+
{ name: 'command', required: true, desc: 'Shell command' },
|
|
91
|
+
],
|
|
132
92
|
},
|
|
133
93
|
},
|
|
134
94
|
},
|
|
@@ -206,22 +166,171 @@ const DIRECT_CALL_SPECS: Record<string, {
|
|
|
206
166
|
},
|
|
207
167
|
},
|
|
208
168
|
},
|
|
209
|
-
|
|
210
|
-
description: '
|
|
169
|
+
brave_search: {
|
|
170
|
+
description: 'Web search API',
|
|
211
171
|
auth: 'api_key',
|
|
212
|
-
docs: 'https://
|
|
172
|
+
docs: 'https://api.search.brave.com/docs',
|
|
213
173
|
actions: {
|
|
214
|
-
|
|
215
|
-
desc: '
|
|
174
|
+
search: {
|
|
175
|
+
desc: 'Search the web',
|
|
216
176
|
params: [
|
|
217
|
-
{ name: '
|
|
218
|
-
{ name: '
|
|
177
|
+
{ name: 'query', required: true, desc: 'Search query' },
|
|
178
|
+
{ name: 'count', required: false, desc: 'Number of results (default: 5)' },
|
|
219
179
|
],
|
|
220
180
|
},
|
|
221
|
-
|
|
222
|
-
|
|
181
|
+
},
|
|
182
|
+
},
|
|
183
|
+
resend: {
|
|
184
|
+
description: 'Email API',
|
|
185
|
+
auth: 'bearer',
|
|
186
|
+
docs: 'https://resend.com/docs',
|
|
187
|
+
actions: {
|
|
188
|
+
send_email: {
|
|
189
|
+
desc: 'Send email',
|
|
223
190
|
params: [
|
|
224
|
-
{ name: '
|
|
191
|
+
{ name: 'to', required: true, desc: 'Recipient email' },
|
|
192
|
+
{ name: 'subject', required: true, desc: 'Email subject' },
|
|
193
|
+
{ name: 'html', required: false, desc: 'HTML body' },
|
|
194
|
+
{ name: 'text', required: false, desc: 'Plain text body' },
|
|
195
|
+
{ name: 'from', required: false, desc: 'Sender (default: noreply@apiclaw.nordsym.com)' },
|
|
196
|
+
],
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
'46elks': {
|
|
201
|
+
description: 'Swedish SMS and voice API',
|
|
202
|
+
auth: 'basic',
|
|
203
|
+
docs: 'https://46elks.com/docs',
|
|
204
|
+
actions: {
|
|
205
|
+
send_sms: {
|
|
206
|
+
desc: 'Send SMS message',
|
|
207
|
+
params: [
|
|
208
|
+
{ name: 'to', required: true, desc: 'Phone number (+46...)' },
|
|
209
|
+
{ name: 'message', required: true, desc: 'SMS text (max 160 chars for 1 segment)' },
|
|
210
|
+
{ name: 'from', required: false, desc: 'Sender ID (default: APIClaw)' },
|
|
211
|
+
],
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
},
|
|
215
|
+
twilio: {
|
|
216
|
+
description: 'Global SMS and voice API',
|
|
217
|
+
auth: 'basic',
|
|
218
|
+
docs: 'https://www.twilio.com/docs',
|
|
219
|
+
actions: {
|
|
220
|
+
send_sms: {
|
|
221
|
+
desc: 'Send SMS message',
|
|
222
|
+
params: [
|
|
223
|
+
{ name: 'to', required: true, desc: 'Phone number (E.164 format)' },
|
|
224
|
+
{ name: 'message', required: true, desc: 'SMS text' },
|
|
225
|
+
{ name: 'from', required: false, desc: 'Sender phone number' },
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
apilayer: {
|
|
231
|
+
description: 'APILayer marketplace — currency, news, scraping, PDFs, verification & more',
|
|
232
|
+
auth: 'api_key',
|
|
233
|
+
docs: 'https://apilayer.com',
|
|
234
|
+
actions: {
|
|
235
|
+
exchange_rates: {
|
|
236
|
+
desc: 'Get live or historical currency exchange rates',
|
|
237
|
+
params: [
|
|
238
|
+
{ name: 'base', required: false, desc: 'Base currency (default: USD)' },
|
|
239
|
+
{ name: 'symbols', required: false, desc: 'Comma-separated target currencies' },
|
|
240
|
+
{ name: 'date', required: false, desc: 'Historical date YYYY-MM-DD (omit for live)' },
|
|
241
|
+
],
|
|
242
|
+
},
|
|
243
|
+
market_data: {
|
|
244
|
+
desc: 'End-of-day stock market data',
|
|
245
|
+
params: [
|
|
246
|
+
{ name: 'symbols', required: true, desc: 'Stock ticker(s), comma-separated e.g. AAPL,MSFT' },
|
|
247
|
+
{ name: 'date_from', required: false, desc: 'Start date YYYY-MM-DD' },
|
|
248
|
+
{ name: 'date_to', required: false, desc: 'End date YYYY-MM-DD' },
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
aviation: {
|
|
252
|
+
desc: 'Real-time flight data and tracking',
|
|
253
|
+
params: [
|
|
254
|
+
{ name: 'flight_iata', required: false, desc: 'IATA flight number e.g. AA100' },
|
|
255
|
+
{ name: 'dep_iata', required: false, desc: 'Departure airport IATA code' },
|
|
256
|
+
{ name: 'arr_iata', required: false, desc: 'Arrival airport IATA code' },
|
|
257
|
+
],
|
|
258
|
+
},
|
|
259
|
+
pdf_generate: {
|
|
260
|
+
desc: 'Generate PDF from URL or HTML',
|
|
261
|
+
params: [
|
|
262
|
+
{ name: 'document_url', required: false, desc: 'URL to convert to PDF' },
|
|
263
|
+
{ name: 'document_html', required: false, desc: 'HTML string to convert (alternative to URL)' },
|
|
264
|
+
{ name: 'page_size', required: false, desc: 'Page size: A4, Letter, etc (default: A4)' },
|
|
265
|
+
],
|
|
266
|
+
},
|
|
267
|
+
screenshot: {
|
|
268
|
+
desc: 'Capture full-page screenshot of any URL',
|
|
269
|
+
params: [
|
|
270
|
+
{ name: 'url', required: true, desc: 'URL to screenshot' },
|
|
271
|
+
{ name: 'viewport', required: false, desc: 'Viewport size e.g. 1440x900 (default)' },
|
|
272
|
+
{ name: 'fullpage', required: false, desc: '1 for full page, 0 for viewport only (default: 0)' },
|
|
273
|
+
],
|
|
274
|
+
},
|
|
275
|
+
verify_email: {
|
|
276
|
+
desc: 'Validate email address format and deliverability',
|
|
277
|
+
params: [
|
|
278
|
+
{ name: 'email', required: true, desc: 'Email address to verify' },
|
|
279
|
+
],
|
|
280
|
+
},
|
|
281
|
+
verify_number: {
|
|
282
|
+
desc: 'Validate and lookup phone number details',
|
|
283
|
+
params: [
|
|
284
|
+
{ name: 'number', required: true, desc: 'Phone number in E.164 format e.g. +46701234567' },
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
vat_check: {
|
|
288
|
+
desc: 'Validate EU VAT number',
|
|
289
|
+
params: [
|
|
290
|
+
{ name: 'vat_number', required: true, desc: 'EU VAT number e.g. SE556012345601' },
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
world_news: {
|
|
294
|
+
desc: 'Extract and analyze news articles from a URL',
|
|
295
|
+
params: [
|
|
296
|
+
{ name: 'url', required: true, desc: 'URL of the news article to analyze' },
|
|
297
|
+
{ name: 'analyze', required: false, desc: 'Whether to analyze the news (default: true)' },
|
|
298
|
+
],
|
|
299
|
+
},
|
|
300
|
+
finance_news: {
|
|
301
|
+
desc: 'Latest financial and stock market news',
|
|
302
|
+
params: [
|
|
303
|
+
{ name: 'tickers', required: false, desc: 'Stock tickers comma-separated e.g. AAPL,TSLA' },
|
|
304
|
+
{ name: 'text', required: false, desc: 'Keyword filter' },
|
|
305
|
+
{ name: 'number', required: false, desc: 'Number of results (default: 5)' },
|
|
306
|
+
],
|
|
307
|
+
},
|
|
308
|
+
scrape: {
|
|
309
|
+
desc: 'Advanced web scraper — returns clean page content',
|
|
310
|
+
params: [
|
|
311
|
+
{ name: 'url', required: true, desc: 'URL to scrape' },
|
|
312
|
+
],
|
|
313
|
+
},
|
|
314
|
+
image_crop: {
|
|
315
|
+
desc: 'Smart crop an image to specified dimensions',
|
|
316
|
+
params: [
|
|
317
|
+
{ name: 'url', required: true, desc: 'Image URL to crop' },
|
|
318
|
+
{ name: 'width', required: false, desc: 'Target width in pixels' },
|
|
319
|
+
{ name: 'height', required: false, desc: 'Target height in pixels' },
|
|
320
|
+
],
|
|
321
|
+
},
|
|
322
|
+
skills: {
|
|
323
|
+
desc: 'Search 7000+ professional skills database',
|
|
324
|
+
params: [
|
|
325
|
+
{ name: 'q', required: true, desc: 'Skill search query e.g. "machine learning"' },
|
|
326
|
+
{ name: 'count', required: false, desc: 'Number of results (default: 10)' },
|
|
327
|
+
],
|
|
328
|
+
},
|
|
329
|
+
form_submit: {
|
|
330
|
+
desc: 'Submit form data to a FormAPI endpoint',
|
|
331
|
+
params: [
|
|
332
|
+
{ name: 'endpoint', required: true, desc: 'FormAPI endpoint path' },
|
|
333
|
+
{ name: 'data', required: false, desc: 'Form data object to submit' },
|
|
225
334
|
],
|
|
226
335
|
},
|
|
227
336
|
},
|
package/src/execute.ts
CHANGED
|
@@ -406,16 +406,17 @@ const apiEndpoints: Record<string, Record<string, { url: string; method: string;
|
|
|
406
406
|
exchange_rates: { url: 'https://api.apilayer.com/exchangerates_data/latest', method: 'GET' },
|
|
407
407
|
market_data: { url: 'http://api.marketstack.com/v1/eod', method: 'GET' },
|
|
408
408
|
aviation: { url: 'http://api.aviationstack.com/v1/flights', method: 'GET' },
|
|
409
|
-
pdf_generate: { url: 'https://api.pdflayer.com/api
|
|
409
|
+
pdf_generate: { url: 'https://api.pdflayer.com/api', method: 'POST' },
|
|
410
410
|
screenshot: { url: 'https://api.screenshotlayer.com/api/capture', method: 'GET' },
|
|
411
411
|
verify_email: { url: 'https://api.apilayer.com/email_verification/check', method: 'GET' },
|
|
412
412
|
verify_number: { url: 'https://api.apilayer.com/number_verification/validate', method: 'GET' },
|
|
413
|
-
vat_check: { url: '
|
|
414
|
-
world_news: { url: 'https://api.apilayer.com/world_news/
|
|
413
|
+
vat_check: { url: 'https://apilayer.net/api/validate', method: 'GET' },
|
|
414
|
+
world_news: { url: 'https://api.apilayer.com/world_news/extract-news', method: 'GET' },
|
|
415
415
|
finance_news: { url: 'https://api.apilayer.com/financelayer/news', method: 'GET' },
|
|
416
416
|
scrape: { url: 'https://api.apilayer.com/adv_scraper/scraper', method: 'GET' },
|
|
417
|
-
image_crop: { url: 'https://api.apilayer.com/
|
|
418
|
-
skills: { url: 'https://api.
|
|
417
|
+
image_crop: { url: 'https://api.apilayer.com/smart_crop/url', method: 'POST' },
|
|
418
|
+
skills: { url: 'https://api.promptapi.com/skills', method: 'GET' },
|
|
419
|
+
form_submit: { url: 'https://api.apilayer.com/form_api/{endpoint}', method: 'POST' },
|
|
419
420
|
},
|
|
420
421
|
};
|
|
421
422
|
|
|
@@ -1720,13 +1721,12 @@ const handlers: Record<string, Record<string, (params: any, creds: any) => Promi
|
|
|
1720
1721
|
const { document_url, document_html, page_size = 'A4' } = params;
|
|
1721
1722
|
if (!document_url && !document_html) return createErrorResult('apilayer', 'pdf_generate', 'Missing: document_url or document_html', ERROR_CODES.INVALID_PARAMS);
|
|
1722
1723
|
|
|
1723
|
-
const url = new URL('https://api.pdflayer.com/api
|
|
1724
|
-
url.searchParams.set('access_key', key);
|
|
1724
|
+
const url = new URL('https://api.pdflayer.com/api');
|
|
1725
1725
|
url.searchParams.set('page_size', page_size);
|
|
1726
1726
|
if (document_url) url.searchParams.set('document_url', document_url);
|
|
1727
1727
|
if (document_html) url.searchParams.set('document_html', document_html);
|
|
1728
1728
|
|
|
1729
|
-
const response = await fetchWithRetry(url.toString(), {}, { provider: 'apilayer', action: 'pdf_generate' });
|
|
1729
|
+
const response = await fetchWithRetry(url.toString(), { method: 'POST', headers: { 'apikey': key } }, { provider: 'apilayer', action: 'pdf_generate' });
|
|
1730
1730
|
const contentType = response.headers.get('content-type') || '';
|
|
1731
1731
|
if (contentType.includes('application/pdf')) {
|
|
1732
1732
|
return { success: true, provider: 'apilayer', action: 'pdf_generate', data: { message: 'PDF generated', content_type: 'application/pdf', size: response.headers.get('content-length') } };
|
|
@@ -1753,6 +1753,7 @@ const handlers: Record<string, Record<string, (params: any, creds: any) => Promi
|
|
|
1753
1753
|
return { success: true, provider: 'apilayer', action: 'screenshot', data: { message: 'Screenshot captured', content_type: contentType, url: url.toString() } };
|
|
1754
1754
|
}
|
|
1755
1755
|
const data = await response.json() as Record<string, unknown>;
|
|
1756
|
+
if (!response.ok) return createErrorResult('apilayer', 'screenshot', 'Request failed', statusToErrorCode(response.status));
|
|
1756
1757
|
return { success: true, provider: 'apilayer', action: 'screenshot', data };
|
|
1757
1758
|
},
|
|
1758
1759
|
|
|
@@ -1805,13 +1806,12 @@ const handlers: Record<string, Record<string, (params: any, creds: any) => Promi
|
|
|
1805
1806
|
|
|
1806
1807
|
world_news: async (params, creds) => {
|
|
1807
1808
|
const key = creds.APILAYER_WORLDNEWS_KEY || creds.api_key;
|
|
1808
|
-
const {
|
|
1809
|
+
const { url: newsUrl, analyze = true } = params;
|
|
1810
|
+
if (!newsUrl) return createErrorResult('apilayer', 'world_news', 'Missing required param: url', ERROR_CODES.INVALID_PARAMS);
|
|
1809
1811
|
|
|
1810
|
-
const url = new URL('https://api.apilayer.com/world_news/
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
url.searchParams.set('language', language);
|
|
1814
|
-
url.searchParams.set('number', number.toString());
|
|
1812
|
+
const url = new URL('https://api.apilayer.com/world_news/extract-news');
|
|
1813
|
+
url.searchParams.set('url', newsUrl);
|
|
1814
|
+
url.searchParams.set('analyze', analyze ? 'true' : 'false');
|
|
1815
1815
|
|
|
1816
1816
|
const response = await fetchWithRetry(url.toString(), {
|
|
1817
1817
|
headers: { 'apikey': key },
|
|
@@ -1859,29 +1859,38 @@ const handlers: Record<string, Record<string, (params: any, creds: any) => Promi
|
|
|
1859
1859
|
const { url: imageUrl, width, height } = params;
|
|
1860
1860
|
if (!imageUrl) return createErrorResult('apilayer', 'image_crop', 'Missing required param: url', ERROR_CODES.INVALID_PARAMS);
|
|
1861
1861
|
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
if (
|
|
1862
|
+
// APILayer smart_crop expects POST with form data
|
|
1863
|
+
const formData = new URLSearchParams();
|
|
1864
|
+
formData.set('url', imageUrl);
|
|
1865
|
+
if (width) formData.set('width', width.toString());
|
|
1866
|
+
if (height) formData.set('height', height.toString());
|
|
1866
1867
|
|
|
1867
|
-
const response = await fetchWithRetry(url
|
|
1868
|
-
|
|
1868
|
+
const response = await fetchWithRetry('https://api.apilayer.com/smart_crop/url', {
|
|
1869
|
+
method: 'POST',
|
|
1870
|
+
headers: {
|
|
1871
|
+
'apikey': key,
|
|
1872
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
1873
|
+
},
|
|
1874
|
+
body: formData.toString(),
|
|
1869
1875
|
}, { provider: 'apilayer', action: 'image_crop' });
|
|
1870
1876
|
const contentType = response.headers.get('content-type') || '';
|
|
1871
1877
|
if (contentType.includes('image/')) {
|
|
1872
1878
|
return { success: true, provider: 'apilayer', action: 'image_crop', data: { message: 'Image cropped', content_type: contentType } };
|
|
1873
1879
|
}
|
|
1874
1880
|
const data = await response.json() as Record<string, unknown>;
|
|
1881
|
+
if (!response.ok) return createErrorResult('apilayer', 'image_crop', 'Request failed', statusToErrorCode(response.status));
|
|
1875
1882
|
return { success: true, provider: 'apilayer', action: 'image_crop', data };
|
|
1876
1883
|
},
|
|
1877
1884
|
|
|
1878
1885
|
skills: async (params, creds) => {
|
|
1879
|
-
|
|
1886
|
+
// Skills API is on PromptAPI domain, uses master key
|
|
1887
|
+
const key = creds.APILAYER_EXCHANGERATE_KEY || creds.api_key;
|
|
1880
1888
|
const { q } = params;
|
|
1881
1889
|
if (!q) return createErrorResult('apilayer', 'skills', 'Missing required param: q', ERROR_CODES.INVALID_PARAMS);
|
|
1882
1890
|
|
|
1883
|
-
const url = new URL('https://api.
|
|
1891
|
+
const url = new URL('https://api.promptapi.com/skills');
|
|
1884
1892
|
url.searchParams.set('q', q);
|
|
1893
|
+
if (params.count) url.searchParams.set('count', String(params.count));
|
|
1885
1894
|
|
|
1886
1895
|
const response = await fetchWithRetry(url.toString(), {
|
|
1887
1896
|
headers: { 'apikey': key },
|
|
@@ -1890,6 +1899,24 @@ const handlers: Record<string, Record<string, (params: any, creds: any) => Promi
|
|
|
1890
1899
|
if (!response.ok) return createErrorResult('apilayer', 'skills', 'Request failed', statusToErrorCode(response.status));
|
|
1891
1900
|
return { success: true, provider: 'apilayer', action: 'skills', data };
|
|
1892
1901
|
},
|
|
1902
|
+
|
|
1903
|
+
form_submit: async (params, creds) => {
|
|
1904
|
+
const key = creds.APILAYER_FORMAPI_KEY || creds.api_key;
|
|
1905
|
+
const { endpoint, data: formData } = params;
|
|
1906
|
+
if (!endpoint) return createErrorResult('apilayer', 'form_submit', 'Missing required param: endpoint', ERROR_CODES.INVALID_PARAMS);
|
|
1907
|
+
|
|
1908
|
+
const response = await fetchWithRetry(`https://api.apilayer.com/form_api/${endpoint}`, {
|
|
1909
|
+
method: 'POST',
|
|
1910
|
+
headers: {
|
|
1911
|
+
'apikey': key,
|
|
1912
|
+
'Content-Type': 'application/json',
|
|
1913
|
+
},
|
|
1914
|
+
body: JSON.stringify(formData || {}),
|
|
1915
|
+
}, { provider: 'apilayer', action: 'form_submit' });
|
|
1916
|
+
const data = await response.json() as Record<string, unknown>;
|
|
1917
|
+
if (!response.ok) return createErrorResult('apilayer', 'form_submit', 'Request failed', statusToErrorCode(response.status));
|
|
1918
|
+
return { success: true, provider: 'apilayer', action: 'form_submit', data };
|
|
1919
|
+
},
|
|
1893
1920
|
},
|
|
1894
1921
|
};
|
|
1895
1922
|
|