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 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
- ## Quick Start
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
- const result = await apinow.call('/api/endpoints/apinowfun/translate-TRANSLATE', {
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', selectedLanguage: 'es' },
21
+ body: { text: 'Hello world', targetLanguage: 'es' },
23
22
  });
24
23
 
25
- console.log(result);
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
- That's it. If the endpoint requires payment, the SDK handles the full [x402 payment flow](https://www.x402.org/) automatically — no manual token handling, no extra steps.
31
+ ### `createClient(config)`
29
32
 
30
- ## How It Works
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
- 1. You call an APINow endpoint via `apinow.call()`
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
- ## API
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
- ### `createClient(config)`
51
+ ### Workflows
41
52
 
42
- Creates an SDK client instance.
53
+ Workflows chain multiple x402 endpoints into a single paid DAG pipeline with automatic payment splitting.
43
54
 
44
55
  ```typescript
45
- import { createClient } from 'apinow-sdk';
46
- // or
47
- import createClient from 'apinow-sdk';
56
+ // list workflows
57
+ const { workflows } = await apinow.listWorkflows({ status: 'active', limit: 10 });
48
58
 
49
- const apinow = createClient({
50
- privateKey: '0x...', // required EVM private key
51
- baseUrl: 'https://apinow.fun', // optional — defaults to https://apinow.fun
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
- Returns an object with:
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
- ### `apinow.call(endpoint, opts?)`
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
- **Parameters:**
75
+ ### `search` — find endpoints
79
76
 
80
- | Param | Type | Default | Description |
81
- |-------|------|---------|-------------|
82
- | `endpoint` | `string` | — | Full URL or path (paths are resolved against `baseUrl`) |
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
- **Returns:** `Promise<any>`parsed JSON response.
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
- ### `apinow.search(query, limit?)`
90
+ ### `info` — endpoint details
92
91
 
93
- Semantic search across all APINow endpoints.
92
+ Shows cost, wallet, chain, input/output schemas, and examples.
94
93
 
95
- ```typescript
96
- const results = await apinow.search('translate text', 5);
94
+ ```bash
95
+ npx apinow info gg402/horoscope
97
96
  ```
98
97
 
99
- | Param | Type | Default | Description |
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
- ### `apinow.info(namespace, endpointName)`
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
- Get public endpoint details. Free no payment required.
111
+ ### `workflows`list workflows
109
112
 
110
- ```typescript
111
- const details = await apinow.info('apinowfun', 'translate-TRANSLATE');
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
- The raw x402-wrapped `fetch` function, if you need full control over requests.
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
- ## Types
125
+ ### `run-workflow` — run a workflow (paid)
129
126
 
130
- ```typescript
131
- interface ApinowConfig {
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+ (uses native `fetch`)
146
- - An EVM wallet with funds on Base for paid endpoints
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.15.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.15.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",