arispay 0.1.3 → 0.1.6

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.
Files changed (3) hide show
  1. package/dist/cli.js +178 -60
  2. package/package.json +1 -1
  3. package/src/cli.ts +198 -49
package/dist/cli.js CHANGED
@@ -110,6 +110,72 @@ ${bold("Get started")}
110
110
  }
111
111
  }
112
112
  }
113
+ async function setupCardViaBrowser(endUserId, agentId) {
114
+ const config = loadConfig(BRAND);
115
+ const { apiKey, environment, baseUrl } = config;
116
+ const defaultUrl = environment === "production" ? "https://api.arispay.app" : "https://api-production-79ea.up.railway.app";
117
+ const apiUrl = baseUrl || defaultUrl;
118
+ console.log(`
119
+ ${dim("Creating secure card setup link...")}`);
120
+ try {
121
+ const res = await fetch(`${apiUrl}/v1/card-setup-sessions`, {
122
+ method: "POST",
123
+ headers: {
124
+ "Content-Type": "application/json",
125
+ Authorization: `Bearer ${apiKey}`
126
+ },
127
+ body: JSON.stringify({ endUserId, ...agentId ? { agentId } : {} }),
128
+ signal: AbortSignal.timeout(15e3)
129
+ });
130
+ if (!res.ok) {
131
+ const body = await res.json().catch(() => ({}));
132
+ throw new Error(body.error?.message || `Failed to create card setup (HTTP ${res.status})`);
133
+ }
134
+ const data = await res.json();
135
+ console.log();
136
+ console.log(` ${bold("Open this link to securely add and verify your card:")}
137
+ `);
138
+ console.log(` ${cyan(data.setupUrl)}
139
+ `);
140
+ console.log(` ${dim("Your card details are entered on a secure page hosted by ArisPay.")}`);
141
+ console.log(` ${dim("3D Secure verification is handled automatically in the browser.")}`);
142
+ console.log(` ${dim("This link expires in 15 minutes.")}
143
+ `);
144
+ console.log(` ${dim("Waiting for you to complete card setup...")}`);
145
+ const deadline = Date.now() + 15 * 60 * 1e3;
146
+ while (Date.now() < deadline) {
147
+ await new Promise((r) => setTimeout(r, 3e3));
148
+ try {
149
+ const statusRes = await fetch(`${apiUrl}/v1/card-setup-sessions/${data.token}/status`, {
150
+ signal: AbortSignal.timeout(1e4)
151
+ });
152
+ const statusData = await statusRes.json();
153
+ if (statusData.status === "completed") {
154
+ console.log();
155
+ success("Card verified!\n");
156
+ console.log(` ${bold("Card:")} ${statusData.cardBrand?.toUpperCase() || "Card"} ending in ${statusData.cardLast4 || "****"}`);
157
+ console.log(`
158
+ ${dim("Your card is linked and verified. All payments will process instantly.")}
159
+ `);
160
+ return true;
161
+ }
162
+ if (statusData.status === "failed") {
163
+ console.log();
164
+ console.error(` \x1B[31m\u2717\x1B[0m Card verification failed. Please try again.`);
165
+ return false;
166
+ }
167
+ } catch {
168
+ }
169
+ }
170
+ console.log(`
171
+ ${dim("Card setup link expired. Run option [2] to try again.")}`);
172
+ return false;
173
+ } catch (e) {
174
+ console.log();
175
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to start card setup"}`);
176
+ return false;
177
+ }
178
+ }
113
179
  async function wizardConnectAgent(client) {
114
180
  console.log(`
115
181
  ${bold("Connect your agent to ArisPay")}`);
@@ -139,7 +205,7 @@ ${bold("Connect your agent to ArisPay")}`);
139
205
  });
140
206
  const a = agent;
141
207
  const config = loadConfig(BRAND);
142
- saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name });
208
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, agentMode: a.mode || mode });
143
209
  console.log();
144
210
  success(`Agent connected!
145
211
  `);
@@ -153,6 +219,96 @@ ${bold("Connect your agent to ArisPay")}`);
153
219
  console.log(` ${bold("Mode:")} ${a.mode || mode}`);
154
220
  console.log(` ${bold("Status:")} ${a.status}
155
221
  `);
222
+ if (mode === "autonomous") {
223
+ console.log(` ${bold("Set spend limits")}`);
224
+ console.log(` ${dim("Autonomous agents need spend limits so they can only spend within bounds you control.")}
225
+ `);
226
+ const perTxStr = await prompt(` Max per transaction ${dim("(e.g. 50.00)")}: $`);
227
+ const dailyStr = await prompt(` Max per day ${dim("(e.g. 200.00)")}: $`);
228
+ const monthlyStr = await prompt(` Max per month ${dim("(e.g. 1000.00)")}: $`);
229
+ const perTx = parseFloat(perTxStr);
230
+ const daily = parseFloat(dailyStr);
231
+ const monthly = parseFloat(monthlyStr);
232
+ if (perTx || daily || monthly) {
233
+ let endUserId = config.endUserId;
234
+ if (!endUserId) {
235
+ try {
236
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
237
+ endUserId = user.id;
238
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, endUserId });
239
+ } catch {
240
+ }
241
+ }
242
+ if (endUserId) {
243
+ try {
244
+ await client.users.setLimits({
245
+ userId: endUserId,
246
+ agentId: a.id,
247
+ ...perTx ? { maxPerTransaction: Math.round(perTx * 100) } : {},
248
+ ...daily ? { maxDaily: Math.round(daily * 100) } : {},
249
+ ...monthly ? { maxMonthly: Math.round(monthly * 100) } : {}
250
+ });
251
+ console.log();
252
+ success("Spend limits set\n");
253
+ } catch (e) {
254
+ console.log();
255
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to set spend limits"}`);
256
+ }
257
+ }
258
+ } else {
259
+ console.log(`
260
+ ${dim("No limits set. You can configure them later on your dashboard.")}
261
+ `);
262
+ }
263
+ console.log(` ${bold("Fund your agent")}`);
264
+ console.log(` ${dim("Autonomous agents spend from their own balance. You need to add a")}`);
265
+ console.log(` ${dim("payment method and top up your agent before it can make payments.")}
266
+ `);
267
+ const fundNow = await prompt(` Add a card and fund your agent now? ${dim("(Y/n)")}: `);
268
+ if (fundNow.toLowerCase() !== "n") {
269
+ const latestConfig = loadConfig(BRAND);
270
+ let endUserId = latestConfig.endUserId;
271
+ if (!endUserId) {
272
+ try {
273
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
274
+ endUserId = user.id;
275
+ saveConfig(BRAND, { ...latestConfig, endUserId });
276
+ } catch (e) {
277
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to set up account"}`);
278
+ return;
279
+ }
280
+ }
281
+ const cardOk = await setupCardViaBrowser(endUserId, a.id);
282
+ if (!cardOk) return;
283
+ const topupStr = await prompt(`
284
+ Amount to load ${dim("(e.g. 50.00)")}: $`);
285
+ const topupDollars = parseFloat(topupStr);
286
+ if (!topupDollars || isNaN(topupDollars)) {
287
+ console.log(dim(" Skipped. You can top up later from your dashboard."));
288
+ } else {
289
+ console.log(`
290
+ ${dim(`Loading $${topupDollars.toFixed(2)} to ${a.name}...`)}`);
291
+ try {
292
+ const result = await client.agents.topup(a.id, {
293
+ amount: Math.round(topupDollars * 100),
294
+ userId: endUserId,
295
+ currency: "USD",
296
+ description: "Initial top-up via CLI"
297
+ });
298
+ console.log();
299
+ success(`Agent funded! Balance: $${((result.balance ?? result.availableBalance ?? 0) / 100).toFixed(2)}
300
+ `);
301
+ } catch (e) {
302
+ console.log();
303
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to top up agent"}`);
304
+ }
305
+ }
306
+ } else {
307
+ console.log(`
308
+ ${dim("You can add a payment method and fund your agent from the menu or dashboard.")}
309
+ `);
310
+ }
311
+ }
156
312
  } catch (e) {
157
313
  console.log();
158
314
  console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to connect agent"}`);
@@ -189,54 +345,8 @@ ${bold("Add a payment method")}`);
189
345
  `);
190
346
  const methodChoice = await prompt(` Enter choice: `);
191
347
  if (methodChoice === "1") {
192
- console.log(`
193
- ${dim("Enter your card details below. They are sent directly to Fiserv for")}`);
194
- console.log(` ${dim("tokenization \u2014 ArisPay never sees or stores your full card number.")}
195
- `);
196
- const cardNumber = await promptSecret(` Card number: `);
197
- if (!cardNumber) {
198
- console.log(dim(" Cancelled."));
199
- return;
200
- }
201
- const expiry = await prompt(` Expiry ${dim("(MM/YY)")}: `);
202
- if (!expiry) {
203
- console.log(dim(" Cancelled."));
204
- return;
205
- }
206
- const securityCode = await promptSecret(` CVV: `);
207
- if (!securityCode) {
208
- console.log(dim(" Cancelled."));
209
- return;
210
- }
211
- const [expiryMonth, expiryYear] = expiry.split("/").map((s) => s.trim());
212
- if (!expiryMonth || !expiryYear) {
213
- console.log(` ${dim("Invalid expiry format. Use MM/YY.")}`);
214
- return;
215
- }
216
- console.log(`
217
- ${dim("Tokenizing card...")}`);
218
- try {
219
- const result = await client.users.addPaymentMethod({
220
- userId,
221
- type: "card",
222
- cardNumber: cardNumber.replace(/\s/g, ""),
223
- expiryMonth,
224
- expiryYear: expiryYear.length === 2 ? `20${expiryYear}` : expiryYear,
225
- securityCode
226
- });
227
- const r = result;
228
- console.log();
229
- success(`Card tokenized!
230
- `);
231
- console.log(` ${bold("Card:")} ${r.cardBrand?.toUpperCase() || "Card"} ending in ${r.cardLast4 || "****"}`);
232
- console.log(` ${bold("Token:")} ${dim(r.tokenId || "stored securely")}`);
233
- console.log(`
234
- ${dim("Your card is now linked to your agent. You can make test payments.")}
235
- `);
236
- } catch (e) {
237
- console.log();
238
- console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to tokenize card"}`);
239
- }
348
+ const storedAgentId = config.agentId;
349
+ await setupCardViaBrowser(userId, storedAgentId);
240
350
  } else if (methodChoice === "2") {
241
351
  console.log();
242
352
  const chain = await prompt(` Chain ${dim("(ethereum, base, polygon, solana)")}: `);
@@ -280,7 +390,8 @@ ${bold("Add a payment method")}`);
280
390
  async function wizardTestPayment(client) {
281
391
  console.log(`
282
392
  ${bold("Make a test payment")}`);
283
- console.log(` ${dim("Verify your integration works by sending a test payment.")}
393
+ console.log(` ${dim("Verify your integration works by sending a test payment.")}`);
394
+ console.log(` ${dim("This is a sandbox test \u2014 no real funds are moved.")}
284
395
  `);
285
396
  const config = loadConfig(BRAND);
286
397
  const storedAgentId = config.agentId;
@@ -317,24 +428,31 @@ ${bold("Make a test payment")}`);
317
428
  console.log(dim(" Cancelled."));
318
429
  return;
319
430
  }
320
- const userId = config.endUserId;
321
- if (!userId) {
322
- console.log(`
431
+ const agentMode = config.agentMode;
432
+ const isAutonomous = agentMode === "autonomous";
433
+ if (!isAutonomous) {
434
+ const userId = config.endUserId;
435
+ if (!userId) {
436
+ console.log(`
323
437
  ${dim("No payment method set up yet. Run option [2] first.")}`);
324
- return;
438
+ return;
439
+ }
325
440
  }
326
441
  console.log(`
327
442
  ${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
328
443
  try {
329
- const payment = await client.payments.create({
444
+ const paymentParams = {
330
445
  agentId,
331
- userId,
332
446
  amount,
333
447
  currency: "USD",
334
448
  memo,
335
- merchantUrl: "https://test.arispay.app",
336
449
  idempotencyKey: `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
337
- });
450
+ };
451
+ if (!isAutonomous) {
452
+ paymentParams.userId = config.endUserId;
453
+ paymentParams.merchantUrl = "https://test.arispay.app";
454
+ }
455
+ const payment = await client.payments.create(paymentParams);
338
456
  const p = payment;
339
457
  console.log();
340
458
  if (p.status === "succeeded") {
@@ -399,8 +517,8 @@ ${bold("Examples:")}
399
517
  arispay init
400
518
  arispay agents create --name "BookingBot" --mode autonomous
401
519
  arispay agents list
402
- arispay pay --agent <id> --amount 2000 --memo "Dinner for 2"
403
- arispay transactions --agent <id> --from 2025-01-01
520
+ arispay pay --agent <id> --amount 20.00 --memo "Dinner for 2"
521
+ arispay transactions --agent <id> --from 2026-01-01
404
522
 
405
523
  ${bold("Environment:")}
406
524
  ARISPAY_API_KEY Override API key
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "arispay",
3
- "version": "0.1.3",
3
+ "version": "0.1.6",
4
4
  "description": "SDK and CLI for enabling agent-initiated payments via Visa TAP + Fiserv",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/src/cli.ts CHANGED
@@ -130,6 +130,86 @@ async function postInitMenu(config: { apiKey?: string; environment?: string; bas
130
130
  }
131
131
  }
132
132
 
133
+ // ── Card Setup Helper (browser-based with 3DS) ─────────────────────
134
+
135
+ async function setupCardViaBrowser(
136
+ endUserId: string,
137
+ agentId?: string,
138
+ ): Promise<boolean> {
139
+ const config = loadConfig(BRAND);
140
+ const { apiKey, environment, baseUrl } = config;
141
+ const defaultUrl = environment === 'production'
142
+ ? 'https://api.arispay.app'
143
+ : 'https://api-production-79ea.up.railway.app';
144
+ const apiUrl = baseUrl || defaultUrl;
145
+
146
+ console.log(`\n ${dim('Creating secure card setup link...')}`);
147
+
148
+ try {
149
+ // Create card setup session
150
+ const res = await fetch(`${apiUrl}/v1/card-setup-sessions`, {
151
+ method: 'POST',
152
+ headers: {
153
+ 'Content-Type': 'application/json',
154
+ Authorization: `Bearer ${apiKey}`,
155
+ },
156
+ body: JSON.stringify({ endUserId, ...(agentId ? { agentId } : {}) }),
157
+ signal: AbortSignal.timeout(15_000),
158
+ });
159
+
160
+ if (!res.ok) {
161
+ const body = await res.json().catch(() => ({}));
162
+ throw new Error((body as any).error?.message || `Failed to create card setup (HTTP ${res.status})`);
163
+ }
164
+
165
+ const data = await res.json() as { token: string; setupUrl: string; expiresAt: string };
166
+
167
+ console.log();
168
+ console.log(` ${bold('Open this link to securely add and verify your card:')}\n`);
169
+ console.log(` ${cyan(data.setupUrl)}\n`);
170
+ console.log(` ${dim('Your card details are entered on a secure page hosted by ArisPay.')}`);
171
+ console.log(` ${dim('3D Secure verification is handled automatically in the browser.')}`);
172
+ console.log(` ${dim('This link expires in 15 minutes.')}\n`);
173
+
174
+ // Poll for completion
175
+ console.log(` ${dim('Waiting for you to complete card setup...')}`);
176
+ const deadline = Date.now() + 15 * 60 * 1000; // 15 min
177
+ while (Date.now() < deadline) {
178
+ await new Promise(r => setTimeout(r, 3000));
179
+
180
+ try {
181
+ const statusRes = await fetch(`${apiUrl}/v1/card-setup-sessions/${data.token}/status`, {
182
+ signal: AbortSignal.timeout(10_000),
183
+ });
184
+ const statusData = await statusRes.json() as any;
185
+
186
+ if (statusData.status === 'completed') {
187
+ console.log();
188
+ success('Card verified!\n');
189
+ console.log(` ${bold('Card:')} ${statusData.cardBrand?.toUpperCase() || 'Card'} ending in ${statusData.cardLast4 || '****'}`);
190
+ console.log(`\n ${dim('Your card is linked and verified. All payments will process instantly.')}\n`);
191
+ return true;
192
+ }
193
+
194
+ if (statusData.status === 'failed') {
195
+ console.log();
196
+ console.error(` \x1b[31m✗\x1b[0m Card verification failed. Please try again.`);
197
+ return false;
198
+ }
199
+ } catch {
200
+ // Network error — keep polling
201
+ }
202
+ }
203
+
204
+ console.log(`\n ${dim('Card setup link expired. Run option [2] to try again.')}`);
205
+ return false;
206
+ } catch (e: any) {
207
+ console.log();
208
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to start card setup'}`);
209
+ return false;
210
+ }
211
+ }
212
+
133
213
  // ── Wizard: Connect Agent ────────────────────────────────────────────
134
214
 
135
215
  async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
@@ -159,7 +239,7 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
159
239
 
160
240
  // Store agent ID so other steps can auto-fill it
161
241
  const config = loadConfig(BRAND);
162
- saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name } as any);
242
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, agentMode: a.mode || mode } as any);
163
243
 
164
244
  console.log();
165
245
  success(`Agent connected!\n`);
@@ -171,6 +251,101 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
171
251
  console.log(` ${bold('Name:')} ${a.name}`);
172
252
  console.log(` ${bold('Mode:')} ${a.mode || mode}`);
173
253
  console.log(` ${bold('Status:')} ${a.status}\n`);
254
+
255
+ // Prompt for spend limits when autonomous
256
+ if (mode === 'autonomous') {
257
+ console.log(` ${bold('Set spend limits')}`);
258
+ console.log(` ${dim('Autonomous agents need spend limits so they can only spend within bounds you control.')}\n`);
259
+
260
+ const perTxStr = await prompt(` Max per transaction ${dim('(e.g. 50.00)')}: $`);
261
+ const dailyStr = await prompt(` Max per day ${dim('(e.g. 200.00)')}: $`);
262
+ const monthlyStr = await prompt(` Max per month ${dim('(e.g. 1000.00)')}: $`);
263
+
264
+ const perTx = parseFloat(perTxStr);
265
+ const daily = parseFloat(dailyStr);
266
+ const monthly = parseFloat(monthlyStr);
267
+
268
+ if (perTx || daily || monthly) {
269
+ // Need an end user to attach limits — create one if not stored
270
+ let endUserId = (config as any).endUserId;
271
+ if (!endUserId) {
272
+ try {
273
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
274
+ endUserId = (user as any).id;
275
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, endUserId } as any);
276
+ } catch { /* will be created later in payment method step */ }
277
+ }
278
+
279
+ if (endUserId) {
280
+ try {
281
+ await client.users.setLimits({
282
+ userId: endUserId,
283
+ agentId: a.id,
284
+ ...(perTx ? { maxPerTransaction: Math.round(perTx * 100) } : {}),
285
+ ...(daily ? { maxDaily: Math.round(daily * 100) } : {}),
286
+ ...(monthly ? { maxMonthly: Math.round(monthly * 100) } : {}),
287
+ });
288
+ console.log();
289
+ success('Spend limits set\n');
290
+ } catch (e: any) {
291
+ console.log();
292
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to set spend limits'}`);
293
+ }
294
+ }
295
+ } else {
296
+ console.log(`\n ${dim('No limits set. You can configure them later on your dashboard.')}\n`);
297
+ }
298
+
299
+ // Offer to fund the autonomous agent
300
+ console.log(` ${bold('Fund your agent')}`);
301
+ console.log(` ${dim('Autonomous agents spend from their own balance. You need to add a')}`);
302
+ console.log(` ${dim('payment method and top up your agent before it can make payments.')}\n`);
303
+
304
+ const fundNow = await prompt(` Add a card and fund your agent now? ${dim('(Y/n)')}: `);
305
+ if (fundNow.toLowerCase() !== 'n') {
306
+ // Ensure end user exists
307
+ const latestConfig = loadConfig(BRAND);
308
+ let endUserId = (latestConfig as any).endUserId;
309
+ if (!endUserId) {
310
+ try {
311
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
312
+ endUserId = (user as any).id;
313
+ saveConfig(BRAND, { ...latestConfig, endUserId } as any);
314
+ } catch (e: any) {
315
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to set up account'}`);
316
+ return;
317
+ }
318
+ }
319
+
320
+ // Collect card details and verify via 3DS
321
+ const cardOk = await setupCardViaBrowser(endUserId, a.id);
322
+ if (!cardOk) return;
323
+
324
+ // Top up
325
+ const topupStr = await prompt(`\n Amount to load ${dim('(e.g. 50.00)')}: $`);
326
+ const topupDollars = parseFloat(topupStr);
327
+ if (!topupDollars || isNaN(topupDollars)) {
328
+ console.log(dim(' Skipped. You can top up later from your dashboard.'));
329
+ } else {
330
+ console.log(`\n ${dim(`Loading $${topupDollars.toFixed(2)} to ${a.name}...`)}`);
331
+ try {
332
+ const result = await client.agents.topup(a.id, {
333
+ amount: Math.round(topupDollars * 100),
334
+ userId: endUserId,
335
+ currency: 'USD',
336
+ description: 'Initial top-up via CLI',
337
+ }) as any;
338
+ console.log();
339
+ success(`Agent funded! Balance: $${((result.balance ?? result.availableBalance ?? 0) / 100).toFixed(2)}\n`);
340
+ } catch (e: any) {
341
+ console.log();
342
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to top up agent'}`);
343
+ }
344
+ }
345
+ } else {
346
+ console.log(`\n ${dim('You can add a payment method and fund your agent from the menu or dashboard.')}\n`);
347
+ }
348
+ }
174
349
  } catch (e: any) {
175
350
  console.log();
176
351
  console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to connect agent'}`);
@@ -211,44 +386,8 @@ async function wizardAddPaymentMethod(client: ArisPayClient): Promise<void> {
211
386
  const methodChoice = await prompt(` Enter choice: `);
212
387
 
213
388
  if (methodChoice === '1') {
214
- console.log(`\n ${dim('Enter your card details below. They are sent directly to Fiserv for')}`);
215
- console.log(` ${dim('tokenization — ArisPay never sees or stores your full card number.')}\n`);
216
-
217
- const cardNumber = await promptSecret(` Card number: `);
218
- if (!cardNumber) { console.log(dim(' Cancelled.')); return; }
219
-
220
- const expiry = await prompt(` Expiry ${dim('(MM/YY)')}: `);
221
- if (!expiry) { console.log(dim(' Cancelled.')); return; }
222
-
223
- const securityCode = await promptSecret(` CVV: `);
224
- if (!securityCode) { console.log(dim(' Cancelled.')); return; }
225
-
226
- const [expiryMonth, expiryYear] = expiry.split('/').map(s => s.trim());
227
- if (!expiryMonth || !expiryYear) {
228
- console.log(` ${dim('Invalid expiry format. Use MM/YY.')}`);
229
- return;
230
- }
231
-
232
- console.log(`\n ${dim('Tokenizing card...')}`);
233
- try {
234
- const result = await client.users.addPaymentMethod({
235
- userId,
236
- type: 'card',
237
- cardNumber: cardNumber.replace(/\s/g, ''),
238
- expiryMonth,
239
- expiryYear: expiryYear.length === 2 ? `20${expiryYear}` : expiryYear,
240
- securityCode,
241
- });
242
- const r = result as any;
243
- console.log();
244
- success(`Card tokenized!\n`);
245
- console.log(` ${bold('Card:')} ${r.cardBrand?.toUpperCase() || 'Card'} ending in ${r.cardLast4 || '****'}`);
246
- console.log(` ${bold('Token:')} ${dim(r.tokenId || 'stored securely')}`);
247
- console.log(`\n ${dim('Your card is now linked to your agent. You can make test payments.')}\n`);
248
- } catch (e: any) {
249
- console.log();
250
- console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to tokenize card'}`);
251
- }
389
+ const storedAgentId = (config as any).agentId;
390
+ await setupCardViaBrowser(userId, storedAgentId);
252
391
  } else if (methodChoice === '2') {
253
392
  console.log();
254
393
  const chain = await prompt(` Chain ${dim('(ethereum, base, polygon, solana)')}: `);
@@ -314,24 +453,34 @@ async function wizardTestPayment(client: ArisPayClient): Promise<void> {
314
453
  const memo = await prompt(` Description ${dim('(appears on the transaction record)')}: `);
315
454
  if (!memo) { console.log(dim(' Cancelled.')); return; }
316
455
 
317
- const userId = (config as any).endUserId;
318
- if (!userId) {
319
- console.log(`\n ${dim('No payment method set up yet. Run option [2] first.')}`);
320
- return;
456
+ const agentMode = (config as any).agentMode;
457
+ const isAutonomous = agentMode === 'autonomous';
458
+
459
+ if (!isAutonomous) {
460
+ const userId = (config as any).endUserId;
461
+ if (!userId) {
462
+ console.log(`\n ${dim('No payment method set up yet. Run option [2] first.')}`);
463
+ return;
464
+ }
321
465
  }
322
466
 
323
467
  console.log(`\n ${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
324
468
 
325
469
  try {
326
- const payment = await client.payments.create({
470
+ const paymentParams: Record<string, unknown> = {
327
471
  agentId,
328
- userId,
329
472
  amount,
330
473
  currency: 'USD',
331
474
  memo,
332
- merchantUrl: 'https://test.arispay.app',
333
475
  idempotencyKey: `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
334
- } as any);
476
+ };
477
+
478
+ if (!isAutonomous) {
479
+ paymentParams.userId = (config as any).endUserId;
480
+ paymentParams.merchantUrl = 'https://test.arispay.app';
481
+ }
482
+
483
+ const payment = await client.payments.create(paymentParams as any);
335
484
  const p = payment as any;
336
485
  console.log();
337
486
  if (p.status === 'succeeded') {
@@ -400,8 +549,8 @@ ${bold('Examples:')}
400
549
  arispay init
401
550
  arispay agents create --name "BookingBot" --mode autonomous
402
551
  arispay agents list
403
- arispay pay --agent <id> --amount 2000 --memo "Dinner for 2"
404
- arispay transactions --agent <id> --from 2025-01-01
552
+ arispay pay --agent <id> --amount 20.00 --memo "Dinner for 2"
553
+ arispay transactions --agent <id> --from 2026-01-01
405
554
 
406
555
  ${bold('Environment:')}
407
556
  ARISPAY_API_KEY Override API key