apinow-sdk 0.15.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +83 -90
- package/dist/cli.js +97 -1
- package/dist/index.d.ts +19 -0
- package/dist/index.js +38 -0
- package/package.json +5 -3
package/README.md
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
# apinow-sdk
|
|
2
2
|
|
|
3
|
-
Pay-per-call API SDK for [APINow.fun](https://apinow.fun) — wraps [x402](https://www.x402.org/) so you don't have to.
|
|
4
|
-
|
|
5
|
-
## Install
|
|
3
|
+
Pay-per-call API SDK & CLI for [APINow.fun](https://apinow.fun) — wraps [x402](https://www.x402.org/) so you don't have to.
|
|
6
4
|
|
|
7
5
|
```bash
|
|
8
6
|
npm install apinow-sdk
|
|
9
7
|
```
|
|
10
8
|
|
|
11
|
-
##
|
|
9
|
+
## SDK
|
|
12
10
|
|
|
13
11
|
```typescript
|
|
14
12
|
import { createClient } from 'apinow-sdk';
|
|
@@ -17,133 +15,128 @@ const apinow = createClient({
|
|
|
17
15
|
privateKey: process.env.PRIVATE_KEY as `0x${string}`,
|
|
18
16
|
});
|
|
19
17
|
|
|
20
|
-
|
|
18
|
+
// call any endpoint — x402 payment is handled automatically
|
|
19
|
+
const data = await apinow.call('/api/endpoints/apinowfun/translate', {
|
|
21
20
|
method: 'POST',
|
|
22
|
-
body: { text: 'Hello world',
|
|
21
|
+
body: { text: 'Hello world', targetLanguage: 'es' },
|
|
23
22
|
});
|
|
24
23
|
|
|
25
|
-
|
|
24
|
+
// semantic search
|
|
25
|
+
const results = await apinow.search('weather forecast', 5);
|
|
26
|
+
|
|
27
|
+
// free endpoint info (cost, schema, wallet)
|
|
28
|
+
const info = await apinow.info('gg402', 'horoscope');
|
|
26
29
|
```
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
### `createClient(config)`
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
| Option | Type | Default | Description |
|
|
34
|
+
|--------|------|---------|-------------|
|
|
35
|
+
| `privateKey` | `` `0x${string}` `` | — | EVM private key (required) |
|
|
36
|
+
| `baseUrl` | `string` | `https://apinow.fun` | API base URL |
|
|
31
37
|
|
|
32
|
-
|
|
33
|
-
2. If the server responds with `402 Payment Required`, the underlying `@x402/fetch` layer intercepts it
|
|
34
|
-
3. Payment is signed and submitted using your wallet
|
|
35
|
-
4. The original request is retried with proof of payment
|
|
36
|
-
5. You get the API response back
|
|
38
|
+
Returns:
|
|
37
39
|
|
|
38
|
-
|
|
40
|
+
| Method | Description |
|
|
41
|
+
|--------|-------------|
|
|
42
|
+
| `call(endpoint, opts?)` | Call any endpoint with automatic x402 payment |
|
|
43
|
+
| `search(query, limit?)` | Semantic search across all endpoints |
|
|
44
|
+
| `info(ns, name)` | Get endpoint details (free) |
|
|
45
|
+
| `listWorkflows(opts?)` | List workflows (free) |
|
|
46
|
+
| `getWorkflow(id)` | Get workflow details (free) |
|
|
47
|
+
| `runWorkflow(id, input)` | Run a workflow with automatic x402 payment |
|
|
48
|
+
| `wallet` | Your wallet address |
|
|
49
|
+
| `fetch` | Raw x402-wrapped `fetch` for advanced use |
|
|
39
50
|
|
|
40
|
-
###
|
|
51
|
+
### Workflows
|
|
41
52
|
|
|
42
|
-
|
|
53
|
+
Workflows chain multiple x402 endpoints into a single paid DAG pipeline with automatic payment splitting.
|
|
43
54
|
|
|
44
55
|
```typescript
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
import createClient from 'apinow-sdk';
|
|
56
|
+
// list workflows
|
|
57
|
+
const { workflows } = await apinow.listWorkflows({ status: 'active', limit: 10 });
|
|
48
58
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
59
|
+
// get workflow details (nodes, splits, pricing)
|
|
60
|
+
const workflow = await apinow.getWorkflow('90931d9c8fb94df9');
|
|
61
|
+
console.log(workflow.name, workflow.totalPrice, workflow.graph.nodes);
|
|
62
|
+
|
|
63
|
+
// run a workflow — x402 payment covers all nodes + creator split
|
|
64
|
+
const result = await apinow.runWorkflow('90931d9c8fb94df9', {
|
|
65
|
+
query: 'birthday gift ideas for a friend who loves cooking',
|
|
52
66
|
});
|
|
53
67
|
```
|
|
54
68
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
| Property | Description |
|
|
58
|
-
|----------|-------------|
|
|
59
|
-
| `wallet` | Your wallet address (derived from private key) |
|
|
60
|
-
| `call()` | Call any APINow endpoint with automatic x402 payment |
|
|
61
|
-
| `search()` | Semantic search across all APINow endpoints |
|
|
62
|
-
| `info()` | Get public endpoint info (free, no payment) |
|
|
63
|
-
| `fetch` | The underlying x402-wrapped `fetch` for advanced use |
|
|
64
|
-
|
|
65
|
-
---
|
|
69
|
+
## CLI
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
Call any APINow endpoint. Handles x402 payment automatically.
|
|
70
|
-
|
|
71
|
-
```typescript
|
|
72
|
-
const data = await apinow.call('/api/endpoints/apinowfun/translate-TRANSLATE', {
|
|
73
|
-
method: 'POST',
|
|
74
|
-
body: { text: 'Hello world', selectedLanguage: 'es' },
|
|
75
|
-
});
|
|
71
|
+
```bash
|
|
72
|
+
npx apinow <command>
|
|
76
73
|
```
|
|
77
74
|
|
|
78
|
-
|
|
75
|
+
### `search` — find endpoints
|
|
79
76
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
| `opts.method` | `'GET' \| 'POST' \| 'PUT' \| 'DELETE'` | `'POST'` | HTTP method |
|
|
84
|
-
| `opts.body` | `Record<string, any>` | — | Request body (ignored for GET) |
|
|
85
|
-
| `opts.headers` | `Record<string, string>` | — | Additional headers |
|
|
77
|
+
```bash
|
|
78
|
+
npx apinow search "weather api" --limit 5
|
|
79
|
+
```
|
|
86
80
|
|
|
87
|
-
|
|
81
|
+
### `list` — browse endpoints
|
|
88
82
|
|
|
89
|
-
|
|
83
|
+
```bash
|
|
84
|
+
npx apinow list # popular endpoints
|
|
85
|
+
npx apinow list --sort newest --limit 10
|
|
86
|
+
npx apinow list --namespace gg402
|
|
87
|
+
npx apinow list --search translate
|
|
88
|
+
```
|
|
90
89
|
|
|
91
|
-
### `
|
|
90
|
+
### `info` — endpoint details
|
|
92
91
|
|
|
93
|
-
|
|
92
|
+
Shows cost, wallet, chain, input/output schemas, and examples.
|
|
94
93
|
|
|
95
|
-
```
|
|
96
|
-
|
|
94
|
+
```bash
|
|
95
|
+
npx apinow info gg402/horoscope
|
|
97
96
|
```
|
|
98
97
|
|
|
99
|
-
|
|
100
|
-
|-------|------|---------|-------------|
|
|
101
|
-
| `query` | `string` | — | Search query |
|
|
102
|
-
| `limit` | `number` | `10` | Max results |
|
|
98
|
+
### `call` — call an endpoint (paid)
|
|
103
99
|
|
|
104
|
-
|
|
100
|
+
```bash
|
|
101
|
+
APINOW_WALLET_PKEY=0x... npx apinow call gg402/horoscope -d '{"sign":"aries"}'
|
|
102
|
+
npx apinow call ns/endpoint -m GET -k 0xYOUR_KEY
|
|
103
|
+
```
|
|
105
104
|
|
|
106
|
-
|
|
105
|
+
| Flag | Description |
|
|
106
|
+
|------|-------------|
|
|
107
|
+
| `-d, --data <json>` | JSON request body |
|
|
108
|
+
| `-m, --method <method>` | HTTP method (default: from endpoint) |
|
|
109
|
+
| `-k, --key <privateKey>` | Wallet key (or set `APINOW_WALLET_PKEY`) |
|
|
107
110
|
|
|
108
|
-
|
|
111
|
+
### `workflows` — list workflows
|
|
109
112
|
|
|
110
|
-
```
|
|
111
|
-
|
|
113
|
+
```bash
|
|
114
|
+
npx apinow workflows
|
|
115
|
+
npx apinow workflows --status active --limit 10
|
|
116
|
+
npx apinow workflows --creator 0x32e8...E934
|
|
112
117
|
```
|
|
113
118
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
### `apinow.fetch`
|
|
119
|
+
### `workflow` — workflow details
|
|
117
120
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
const res = await apinow.fetch('https://apinow.fun/api/endpoints/...', {
|
|
122
|
-
method: 'POST',
|
|
123
|
-
headers: { 'Content-Type': 'application/json' },
|
|
124
|
-
body: JSON.stringify({ key: 'value' }),
|
|
125
|
-
});
|
|
121
|
+
```bash
|
|
122
|
+
npx apinow workflow 90931d9c8fb94df9
|
|
126
123
|
```
|
|
127
124
|
|
|
128
|
-
|
|
125
|
+
### `run-workflow` — run a workflow (paid)
|
|
129
126
|
|
|
130
|
-
```
|
|
131
|
-
|
|
132
|
-
privateKey: `0x${string}`;
|
|
133
|
-
baseUrl?: string;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
interface CallOptions {
|
|
137
|
-
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
138
|
-
body?: Record<string, any>;
|
|
139
|
-
headers?: Record<string, string>;
|
|
140
|
-
}
|
|
127
|
+
```bash
|
|
128
|
+
APINOW_WALLET_PKEY=0x... npx apinow run-workflow 90931d9c8fb94df9 -d '{"query":"birthday gift ideas"}'
|
|
141
129
|
```
|
|
142
130
|
|
|
131
|
+
| Flag | Description |
|
|
132
|
+
|------|-------------|
|
|
133
|
+
| `-d, --data <json>` | JSON input (default: `{"query":"hello world"}`) |
|
|
134
|
+
| `-k, --key <privateKey>` | Wallet key (or set `APINOW_WALLET_PKEY`) |
|
|
135
|
+
|
|
143
136
|
## Requirements
|
|
144
137
|
|
|
145
|
-
- Node.js v18+
|
|
146
|
-
-
|
|
138
|
+
- Node.js v18+
|
|
139
|
+
- EVM wallet with funds on Base for paid endpoints
|
|
147
140
|
|
|
148
141
|
## License
|
|
149
142
|
|
package/dist/cli.js
CHANGED
|
@@ -6,7 +6,7 @@ const program = new Command();
|
|
|
6
6
|
program
|
|
7
7
|
.name('apinow')
|
|
8
8
|
.description('CLI for APINow.fun — search, inspect, and call pay-per-request APIs')
|
|
9
|
-
.version('0.
|
|
9
|
+
.version('0.16.0');
|
|
10
10
|
// ─── Helpers ───
|
|
11
11
|
function getPrivateKey(opts) {
|
|
12
12
|
const raw = opts.key || process.env.APINOW_WALLET_PKEY || process.env.PRIVATE_KEY;
|
|
@@ -216,4 +216,100 @@ program
|
|
|
216
216
|
process.exit(1);
|
|
217
217
|
}
|
|
218
218
|
});
|
|
219
|
+
// ─── workflows ───
|
|
220
|
+
program
|
|
221
|
+
.command('workflows')
|
|
222
|
+
.description('List workflows')
|
|
223
|
+
.option('-l, --limit <n>', 'Max results', '20')
|
|
224
|
+
.option('-c, --creator <address>', 'Filter by creator wallet')
|
|
225
|
+
.option('-s, --status <status>', 'Filter by status: active | draft | all', 'all')
|
|
226
|
+
.action(async (opts) => {
|
|
227
|
+
try {
|
|
228
|
+
const params = new URLSearchParams({ limit: opts.limit, status: opts.status });
|
|
229
|
+
if (opts.creator)
|
|
230
|
+
params.set('creator', opts.creator);
|
|
231
|
+
const data = await fetchJson(`${API_BASE}/api/workflows?${params}`);
|
|
232
|
+
const workflows = data.workflows || [];
|
|
233
|
+
if (!workflows.length) {
|
|
234
|
+
console.log('No workflows found.');
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const rows = [['ID', 'NAME', 'STATUS', 'NODES', 'COST', 'DESCRIPTION']];
|
|
238
|
+
for (const w of workflows) {
|
|
239
|
+
rows.push([
|
|
240
|
+
w.workflowId,
|
|
241
|
+
truncate(w.name || '', 24),
|
|
242
|
+
w.status,
|
|
243
|
+
String(w.graph?.nodes?.length || 0),
|
|
244
|
+
`$${w.totalPrice}`,
|
|
245
|
+
truncate(w.description || '', 40),
|
|
246
|
+
]);
|
|
247
|
+
}
|
|
248
|
+
printTable(rows);
|
|
249
|
+
}
|
|
250
|
+
catch (err) {
|
|
251
|
+
console.error(`Error: ${err.message}`);
|
|
252
|
+
process.exit(1);
|
|
253
|
+
}
|
|
254
|
+
});
|
|
255
|
+
// ─── workflow info ───
|
|
256
|
+
program
|
|
257
|
+
.command('workflow <id>')
|
|
258
|
+
.description('Get workflow details')
|
|
259
|
+
.action(async (id) => {
|
|
260
|
+
try {
|
|
261
|
+
const data = await fetchJson(`${API_BASE}/api/workflows/${id}`);
|
|
262
|
+
console.log(`\n ${data.name}`);
|
|
263
|
+
console.log(` ${'─'.repeat(40)}`);
|
|
264
|
+
console.log(` ${data.description || '(no description)'}\n`);
|
|
265
|
+
console.log(` ID: ${data.workflowId}`);
|
|
266
|
+
console.log(` Status: ${data.status}`);
|
|
267
|
+
console.log(` Cost: $${data.totalPrice} USDC`);
|
|
268
|
+
console.log(` Chain: ${data.chain || 'base'}`);
|
|
269
|
+
console.log(` Creator: ${data.creatorWallet}`);
|
|
270
|
+
console.log(` Nodes: ${data.graph?.nodes?.length || 0}`);
|
|
271
|
+
if (data.graph?.nodes?.length) {
|
|
272
|
+
console.log(`\n Pipeline:`);
|
|
273
|
+
for (const node of data.graph.nodes) {
|
|
274
|
+
const deps = node.dependsOn?.length ? ` (depends on: ${node.dependsOn.join(', ')})` : '';
|
|
275
|
+
const isOutput = node.id === data.graph.outputNode ? ' [output]' : '';
|
|
276
|
+
console.log(` → ${node.id}: ${node.endpoint}${deps}${isOutput}`);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
if (data.splits?.length) {
|
|
280
|
+
console.log(`\n Payment Split:`);
|
|
281
|
+
for (const s of data.splits) {
|
|
282
|
+
const pct = (s.basisPoints / 100).toFixed(1);
|
|
283
|
+
const usd = (parseFloat(data.totalPrice) * s.basisPoints / 10000).toFixed(4);
|
|
284
|
+
console.log(` ${s.label}: ${pct}% ($${usd})`);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
console.log('');
|
|
288
|
+
}
|
|
289
|
+
catch (err) {
|
|
290
|
+
console.error(`Error: ${err.message}`);
|
|
291
|
+
process.exit(1);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
// ─── run workflow ───
|
|
295
|
+
program
|
|
296
|
+
.command('run-workflow <id>')
|
|
297
|
+
.description('Run a workflow (x402 paid)')
|
|
298
|
+
.option('-d, --data <json>', 'JSON input', '{"query":"hello world"}')
|
|
299
|
+
.option('-k, --key <privateKey>', 'Wallet private key')
|
|
300
|
+
.action(async (id, opts) => {
|
|
301
|
+
try {
|
|
302
|
+
const privateKey = getPrivateKey(opts);
|
|
303
|
+
const body = JSON.parse(opts.data);
|
|
304
|
+
const details = await fetchJson(`${API_BASE}/api/workflows/${id}`);
|
|
305
|
+
console.error(`Running workflow "${details.name}" — cost: $${details.totalPrice} USDC`);
|
|
306
|
+
const apinow = createClient({ privateKey });
|
|
307
|
+
const result = await apinow.runWorkflow(id, body);
|
|
308
|
+
console.log(JSON.stringify(result, null, 2));
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
console.error(`Error: ${err.message}`);
|
|
312
|
+
process.exit(1);
|
|
313
|
+
}
|
|
314
|
+
});
|
|
219
315
|
program.parse();
|
package/dist/index.d.ts
CHANGED
|
@@ -27,6 +27,25 @@ export declare function createClient(config: ApinowConfig): {
|
|
|
27
27
|
* Get public endpoint info (free, no payment).
|
|
28
28
|
*/
|
|
29
29
|
info(namespace: string, endpointName: string): Promise<any>;
|
|
30
|
+
/**
|
|
31
|
+
* List workflows. Optionally filter by creator or status.
|
|
32
|
+
*/
|
|
33
|
+
listWorkflows(opts?: {
|
|
34
|
+
creator?: string;
|
|
35
|
+
status?: string;
|
|
36
|
+
limit?: number;
|
|
37
|
+
}): Promise<any>;
|
|
38
|
+
/**
|
|
39
|
+
* Get workflow details by ID.
|
|
40
|
+
*/
|
|
41
|
+
getWorkflow(workflowId: string): Promise<any>;
|
|
42
|
+
/**
|
|
43
|
+
* Run a workflow. Handles x402 payment automatically.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* const result = await apinow.runWorkflow('90931d9c8fb94df9', { query: 'hello world' });
|
|
47
|
+
*/
|
|
48
|
+
runWorkflow(workflowId: string, input: Record<string, any>): Promise<any>;
|
|
30
49
|
/**
|
|
31
50
|
* The underlying x402-wrapped fetch, for advanced use.
|
|
32
51
|
*/
|
package/dist/index.js
CHANGED
|
@@ -58,6 +58,44 @@ export function createClient(config) {
|
|
|
58
58
|
throw new Error(`Failed to fetch info: ${res.status}`);
|
|
59
59
|
return res.json();
|
|
60
60
|
},
|
|
61
|
+
// ─── Workflows ───
|
|
62
|
+
/**
|
|
63
|
+
* List workflows. Optionally filter by creator or status.
|
|
64
|
+
*/
|
|
65
|
+
async listWorkflows(opts = {}) {
|
|
66
|
+
const params = new URLSearchParams();
|
|
67
|
+
if (opts.limit)
|
|
68
|
+
params.set('limit', String(opts.limit));
|
|
69
|
+
if (opts.creator)
|
|
70
|
+
params.set('creator', opts.creator);
|
|
71
|
+
if (opts.status)
|
|
72
|
+
params.set('status', opts.status);
|
|
73
|
+
const res = await fetch(`${baseUrl}/api/workflows?${params}`);
|
|
74
|
+
if (!res.ok)
|
|
75
|
+
throw new Error(`Failed to list workflows: ${res.status}`);
|
|
76
|
+
return res.json();
|
|
77
|
+
},
|
|
78
|
+
/**
|
|
79
|
+
* Get workflow details by ID.
|
|
80
|
+
*/
|
|
81
|
+
async getWorkflow(workflowId) {
|
|
82
|
+
const res = await fetch(`${baseUrl}/api/workflows/${workflowId}`);
|
|
83
|
+
if (!res.ok)
|
|
84
|
+
throw new Error(`Failed to get workflow: ${res.status}`);
|
|
85
|
+
return res.json();
|
|
86
|
+
},
|
|
87
|
+
/**
|
|
88
|
+
* Run a workflow. Handles x402 payment automatically.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* const result = await apinow.runWorkflow('90931d9c8fb94df9', { query: 'hello world' });
|
|
92
|
+
*/
|
|
93
|
+
async runWorkflow(workflowId, input) {
|
|
94
|
+
return this.call(`/api/workflows/${workflowId}/run`, {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
body: input,
|
|
97
|
+
});
|
|
98
|
+
},
|
|
61
99
|
/**
|
|
62
100
|
* The underlying x402-wrapped fetch, for advanced use.
|
|
63
101
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "apinow-sdk",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Pay-per-call API SDK & CLI for APINow.fun — wraps x402 so you don't have to",
|
|
3
|
+
"version": "0.16.0",
|
|
4
|
+
"description": "Pay-per-call API SDK & CLI for APINow.fun — endpoints + workflows, wraps x402 so you don't have to",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
7
7
|
"type": "module",
|
|
@@ -24,7 +24,9 @@
|
|
|
24
24
|
"web3",
|
|
25
25
|
"ai",
|
|
26
26
|
"llm",
|
|
27
|
-
"cli"
|
|
27
|
+
"cli",
|
|
28
|
+
"workflow",
|
|
29
|
+
"dag"
|
|
28
30
|
],
|
|
29
31
|
"author": "ApiNow.fun",
|
|
30
32
|
"license": "MIT",
|