arispay 0.1.3 → 0.1.4

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 +183 -60
  2. package/package.json +1 -1
  3. package/src/cli.ts +184 -49
package/dist/cli.js CHANGED
@@ -110,6 +110,78 @@ ${bold("Get started")}
110
110
  }
111
111
  }
112
112
  }
113
+ async function collectAndTokenizeCard(client, userId) {
114
+ console.log(`
115
+ ${dim("Enter your card details below. They are sent directly to Fiserv for")}`);
116
+ console.log(` ${dim("tokenization \u2014 ArisPay never sees or stores your full card number.")}
117
+ `);
118
+ const cardNumber = await promptSecret(` Card number: `);
119
+ if (!cardNumber) {
120
+ console.log(dim(" Cancelled."));
121
+ return false;
122
+ }
123
+ const expiry = await prompt(` Expiry ${dim("(MM/YY)")}: `);
124
+ if (!expiry) {
125
+ console.log(dim(" Cancelled."));
126
+ return false;
127
+ }
128
+ const securityCode = await promptSecret(` CVV: `);
129
+ if (!securityCode) {
130
+ console.log(dim(" Cancelled."));
131
+ return false;
132
+ }
133
+ const [expiryMonth, expiryYear] = expiry.split("/").map((s) => s.trim());
134
+ if (!expiryMonth || !expiryYear) {
135
+ console.log(` ${dim("Invalid expiry format. Use MM/YY.")}`);
136
+ return false;
137
+ }
138
+ console.log(`
139
+ ${dim("Tokenizing and verifying card...")}`);
140
+ try {
141
+ const result = await client.users.addPaymentMethod({
142
+ userId,
143
+ type: "card",
144
+ cardNumber: cardNumber.replace(/\s/g, ""),
145
+ expiryMonth,
146
+ expiryYear: expiryYear.length === 2 ? `20${expiryYear}` : expiryYear,
147
+ securityCode
148
+ });
149
+ const r = result;
150
+ if (r.requiresVerification) {
151
+ const challengeUrl = r.challengeUrl;
152
+ if (challengeUrl) {
153
+ console.log();
154
+ console.log(` ${bold("Card verification required")}`);
155
+ console.log(` ${dim("Your bank requires 3D Secure verification. Open this link:")}
156
+ `);
157
+ console.log(` ${cyan(challengeUrl)}
158
+ `);
159
+ console.log(` ${dim("Complete the verification in your browser, then come back here.")}`);
160
+ await prompt(`
161
+ Press Enter when done...`);
162
+ success("Card added (verification pending)\n");
163
+ } else {
164
+ console.log();
165
+ success("Card tokenized (verification in progress)\n");
166
+ }
167
+ console.log(` ${bold("Card:")} ${r.cardBrand?.toUpperCase() || "Card"} ending in ${r.cardLast4 || "****"}
168
+ `);
169
+ return true;
170
+ }
171
+ console.log();
172
+ success(`Card verified!
173
+ `);
174
+ console.log(` ${bold("Card:")} ${r.cardBrand?.toUpperCase() || "Card"} ending in ${r.cardLast4 || "****"}`);
175
+ console.log(`
176
+ ${dim("Your card is now linked and verified. You can make payments.")}
177
+ `);
178
+ return true;
179
+ } catch (e) {
180
+ console.log();
181
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to tokenize card"}`);
182
+ return false;
183
+ }
184
+ }
113
185
  async function wizardConnectAgent(client) {
114
186
  console.log(`
115
187
  ${bold("Connect your agent to ArisPay")}`);
@@ -139,7 +211,7 @@ ${bold("Connect your agent to ArisPay")}`);
139
211
  });
140
212
  const a = agent;
141
213
  const config = loadConfig(BRAND);
142
- saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name });
214
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, agentMode: a.mode || mode });
143
215
  console.log();
144
216
  success(`Agent connected!
145
217
  `);
@@ -153,6 +225,96 @@ ${bold("Connect your agent to ArisPay")}`);
153
225
  console.log(` ${bold("Mode:")} ${a.mode || mode}`);
154
226
  console.log(` ${bold("Status:")} ${a.status}
155
227
  `);
228
+ if (mode === "autonomous") {
229
+ console.log(` ${bold("Set spend limits")}`);
230
+ console.log(` ${dim("Autonomous agents need spend limits so they can only spend within bounds you control.")}
231
+ `);
232
+ const perTxStr = await prompt(` Max per transaction ${dim("(e.g. 50.00)")}: $`);
233
+ const dailyStr = await prompt(` Max per day ${dim("(e.g. 200.00)")}: $`);
234
+ const monthlyStr = await prompt(` Max per month ${dim("(e.g. 1000.00)")}: $`);
235
+ const perTx = parseFloat(perTxStr);
236
+ const daily = parseFloat(dailyStr);
237
+ const monthly = parseFloat(monthlyStr);
238
+ if (perTx || daily || monthly) {
239
+ let endUserId = config.endUserId;
240
+ if (!endUserId) {
241
+ try {
242
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
243
+ endUserId = user.id;
244
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, endUserId });
245
+ } catch {
246
+ }
247
+ }
248
+ if (endUserId) {
249
+ try {
250
+ await client.users.setLimits({
251
+ userId: endUserId,
252
+ agentId: a.id,
253
+ ...perTx ? { maxPerTransaction: Math.round(perTx * 100) } : {},
254
+ ...daily ? { maxDaily: Math.round(daily * 100) } : {},
255
+ ...monthly ? { maxMonthly: Math.round(monthly * 100) } : {}
256
+ });
257
+ console.log();
258
+ success("Spend limits set\n");
259
+ } catch (e) {
260
+ console.log();
261
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to set spend limits"}`);
262
+ }
263
+ }
264
+ } else {
265
+ console.log(`
266
+ ${dim("No limits set. You can configure them later on your dashboard.")}
267
+ `);
268
+ }
269
+ console.log(` ${bold("Fund your agent")}`);
270
+ console.log(` ${dim("Autonomous agents spend from their own balance. You need to add a")}`);
271
+ console.log(` ${dim("payment method and top up your agent before it can make payments.")}
272
+ `);
273
+ const fundNow = await prompt(` Add a card and fund your agent now? ${dim("(Y/n)")}: `);
274
+ if (fundNow.toLowerCase() !== "n") {
275
+ const latestConfig = loadConfig(BRAND);
276
+ let endUserId = latestConfig.endUserId;
277
+ if (!endUserId) {
278
+ try {
279
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
280
+ endUserId = user.id;
281
+ saveConfig(BRAND, { ...latestConfig, endUserId });
282
+ } catch (e) {
283
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to set up account"}`);
284
+ return;
285
+ }
286
+ }
287
+ const cardOk = await collectAndTokenizeCard(client, endUserId);
288
+ if (!cardOk) return;
289
+ const topupStr = await prompt(`
290
+ Amount to load ${dim("(e.g. 50.00)")}: $`);
291
+ const topupDollars = parseFloat(topupStr);
292
+ if (!topupDollars || isNaN(topupDollars)) {
293
+ console.log(dim(" Skipped. You can top up later from your dashboard."));
294
+ } else {
295
+ console.log(`
296
+ ${dim(`Loading $${topupDollars.toFixed(2)} to ${a.name}...`)}`);
297
+ try {
298
+ const result = await client.agents.topup(a.id, {
299
+ amount: Math.round(topupDollars * 100),
300
+ userId: endUserId,
301
+ currency: "USD",
302
+ description: "Initial top-up via CLI"
303
+ });
304
+ console.log();
305
+ success(`Agent funded! Balance: $${((result.balance ?? result.availableBalance ?? 0) / 100).toFixed(2)}
306
+ `);
307
+ } catch (e) {
308
+ console.log();
309
+ console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to top up agent"}`);
310
+ }
311
+ }
312
+ } else {
313
+ console.log(`
314
+ ${dim("You can add a payment method and fund your agent from the menu or dashboard.")}
315
+ `);
316
+ }
317
+ }
156
318
  } catch (e) {
157
319
  console.log();
158
320
  console.error(` \x1B[31m\u2717\x1B[0m ${e.message || "Failed to connect agent"}`);
@@ -189,54 +351,7 @@ ${bold("Add a payment method")}`);
189
351
  `);
190
352
  const methodChoice = await prompt(` Enter choice: `);
191
353
  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
- }
354
+ await collectAndTokenizeCard(client, userId);
240
355
  } else if (methodChoice === "2") {
241
356
  console.log();
242
357
  const chain = await prompt(` Chain ${dim("(ethereum, base, polygon, solana)")}: `);
@@ -280,7 +395,8 @@ ${bold("Add a payment method")}`);
280
395
  async function wizardTestPayment(client) {
281
396
  console.log(`
282
397
  ${bold("Make a test payment")}`);
283
- console.log(` ${dim("Verify your integration works by sending a test payment.")}
398
+ console.log(` ${dim("Verify your integration works by sending a test payment.")}`);
399
+ console.log(` ${dim("This is a sandbox test \u2014 no real funds are moved.")}
284
400
  `);
285
401
  const config = loadConfig(BRAND);
286
402
  const storedAgentId = config.agentId;
@@ -317,24 +433,31 @@ ${bold("Make a test payment")}`);
317
433
  console.log(dim(" Cancelled."));
318
434
  return;
319
435
  }
320
- const userId = config.endUserId;
321
- if (!userId) {
322
- console.log(`
436
+ const agentMode = config.agentMode;
437
+ const isAutonomous = agentMode === "autonomous";
438
+ if (!isAutonomous) {
439
+ const userId = config.endUserId;
440
+ if (!userId) {
441
+ console.log(`
323
442
  ${dim("No payment method set up yet. Run option [2] first.")}`);
324
- return;
443
+ return;
444
+ }
325
445
  }
326
446
  console.log(`
327
447
  ${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
328
448
  try {
329
- const payment = await client.payments.create({
449
+ const paymentParams = {
330
450
  agentId,
331
- userId,
332
451
  amount,
333
452
  currency: "USD",
334
453
  memo,
335
- merchantUrl: "https://test.arispay.app",
336
454
  idempotencyKey: `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`
337
- });
455
+ };
456
+ if (!isAutonomous) {
457
+ paymentParams.userId = config.endUserId;
458
+ paymentParams.merchantUrl = "https://test.arispay.app";
459
+ }
460
+ const payment = await client.payments.create(paymentParams);
338
461
  const p = payment;
339
462
  console.log();
340
463
  if (p.status === "succeeded") {
@@ -399,8 +522,8 @@ ${bold("Examples:")}
399
522
  arispay init
400
523
  arispay agents create --name "BookingBot" --mode autonomous
401
524
  arispay agents list
402
- arispay pay --agent <id> --amount 2000 --memo "Dinner for 2"
403
- arispay transactions --agent <id> --from 2025-01-01
525
+ arispay pay --agent <id> --amount 20.00 --memo "Dinner for 2"
526
+ arispay transactions --agent <id> --from 2026-01-01
404
527
 
405
528
  ${bold("Environment:")}
406
529
  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.4",
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,73 @@ async function postInitMenu(config: { apiKey?: string; environment?: string; bas
130
130
  }
131
131
  }
132
132
 
133
+ // ── Card Tokenization + 3DS Helper ──────────────────────────────────
134
+
135
+ async function collectAndTokenizeCard(
136
+ client: ArisPayClient,
137
+ userId: string,
138
+ ): Promise<boolean> {
139
+ console.log(`\n ${dim('Enter your card details below. They are sent directly to Fiserv for')}`);
140
+ console.log(` ${dim('tokenization — ArisPay never sees or stores your full card number.')}\n`);
141
+
142
+ const cardNumber = await promptSecret(` Card number: `);
143
+ if (!cardNumber) { console.log(dim(' Cancelled.')); return false; }
144
+
145
+ const expiry = await prompt(` Expiry ${dim('(MM/YY)')}: `);
146
+ if (!expiry) { console.log(dim(' Cancelled.')); return false; }
147
+
148
+ const securityCode = await promptSecret(` CVV: `);
149
+ if (!securityCode) { console.log(dim(' Cancelled.')); return false; }
150
+
151
+ const [expiryMonth, expiryYear] = expiry.split('/').map(s => s.trim());
152
+ if (!expiryMonth || !expiryYear) {
153
+ console.log(` ${dim('Invalid expiry format. Use MM/YY.')}`);
154
+ return false;
155
+ }
156
+
157
+ console.log(`\n ${dim('Tokenizing and verifying card...')}`);
158
+ try {
159
+ const result = await client.users.addPaymentMethod({
160
+ userId,
161
+ type: 'card',
162
+ cardNumber: cardNumber.replace(/\s/g, ''),
163
+ expiryMonth,
164
+ expiryYear: expiryYear.length === 2 ? `20${expiryYear}` : expiryYear,
165
+ securityCode,
166
+ });
167
+ const r = result as any;
168
+
169
+ if (r.requiresVerification) {
170
+ // 3DS verification required — open browser
171
+ const challengeUrl = r.challengeUrl;
172
+ if (challengeUrl) {
173
+ console.log();
174
+ console.log(` ${bold('Card verification required')}`);
175
+ console.log(` ${dim('Your bank requires 3D Secure verification. Open this link:')}\n`);
176
+ console.log(` ${cyan(challengeUrl)}\n`);
177
+ console.log(` ${dim('Complete the verification in your browser, then come back here.')}`);
178
+ await prompt(`\n Press Enter when done...`);
179
+ success('Card added (verification pending)\n');
180
+ } else {
181
+ console.log();
182
+ success('Card tokenized (verification in progress)\n');
183
+ }
184
+ console.log(` ${bold('Card:')} ${r.cardBrand?.toUpperCase() || 'Card'} ending in ${r.cardLast4 || '****'}\n`);
185
+ return true;
186
+ }
187
+
188
+ console.log();
189
+ success(`Card verified!\n`);
190
+ console.log(` ${bold('Card:')} ${r.cardBrand?.toUpperCase() || 'Card'} ending in ${r.cardLast4 || '****'}`);
191
+ console.log(`\n ${dim('Your card is now linked and verified. You can make payments.')}\n`);
192
+ return true;
193
+ } catch (e: any) {
194
+ console.log();
195
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to tokenize card'}`);
196
+ return false;
197
+ }
198
+ }
199
+
133
200
  // ── Wizard: Connect Agent ────────────────────────────────────────────
134
201
 
135
202
  async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
@@ -159,7 +226,7 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
159
226
 
160
227
  // Store agent ID so other steps can auto-fill it
161
228
  const config = loadConfig(BRAND);
162
- saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name } as any);
229
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, agentMode: a.mode || mode } as any);
163
230
 
164
231
  console.log();
165
232
  success(`Agent connected!\n`);
@@ -171,6 +238,101 @@ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
171
238
  console.log(` ${bold('Name:')} ${a.name}`);
172
239
  console.log(` ${bold('Mode:')} ${a.mode || mode}`);
173
240
  console.log(` ${bold('Status:')} ${a.status}\n`);
241
+
242
+ // Prompt for spend limits when autonomous
243
+ if (mode === 'autonomous') {
244
+ console.log(` ${bold('Set spend limits')}`);
245
+ console.log(` ${dim('Autonomous agents need spend limits so they can only spend within bounds you control.')}\n`);
246
+
247
+ const perTxStr = await prompt(` Max per transaction ${dim('(e.g. 50.00)')}: $`);
248
+ const dailyStr = await prompt(` Max per day ${dim('(e.g. 200.00)')}: $`);
249
+ const monthlyStr = await prompt(` Max per month ${dim('(e.g. 1000.00)')}: $`);
250
+
251
+ const perTx = parseFloat(perTxStr);
252
+ const daily = parseFloat(dailyStr);
253
+ const monthly = parseFloat(monthlyStr);
254
+
255
+ if (perTx || daily || monthly) {
256
+ // Need an end user to attach limits — create one if not stored
257
+ let endUserId = (config as any).endUserId;
258
+ if (!endUserId) {
259
+ try {
260
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
261
+ endUserId = (user as any).id;
262
+ saveConfig(BRAND, { ...config, agentId: a.id, agentName: a.name || name, endUserId } as any);
263
+ } catch { /* will be created later in payment method step */ }
264
+ }
265
+
266
+ if (endUserId) {
267
+ try {
268
+ await client.users.setLimits({
269
+ userId: endUserId,
270
+ agentId: a.id,
271
+ ...(perTx ? { maxPerTransaction: Math.round(perTx * 100) } : {}),
272
+ ...(daily ? { maxDaily: Math.round(daily * 100) } : {}),
273
+ ...(monthly ? { maxMonthly: Math.round(monthly * 100) } : {}),
274
+ });
275
+ console.log();
276
+ success('Spend limits set\n');
277
+ } catch (e: any) {
278
+ console.log();
279
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to set spend limits'}`);
280
+ }
281
+ }
282
+ } else {
283
+ console.log(`\n ${dim('No limits set. You can configure them later on your dashboard.')}\n`);
284
+ }
285
+
286
+ // Offer to fund the autonomous agent
287
+ console.log(` ${bold('Fund your agent')}`);
288
+ console.log(` ${dim('Autonomous agents spend from their own balance. You need to add a')}`);
289
+ console.log(` ${dim('payment method and top up your agent before it can make payments.')}\n`);
290
+
291
+ const fundNow = await prompt(` Add a card and fund your agent now? ${dim('(Y/n)')}: `);
292
+ if (fundNow.toLowerCase() !== 'n') {
293
+ // Ensure end user exists
294
+ const latestConfig = loadConfig(BRAND);
295
+ let endUserId = (latestConfig as any).endUserId;
296
+ if (!endUserId) {
297
+ try {
298
+ const user = await client.users.create({ externalId: `cli_${Date.now()}` });
299
+ endUserId = (user as any).id;
300
+ saveConfig(BRAND, { ...latestConfig, endUserId } as any);
301
+ } catch (e: any) {
302
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to set up account'}`);
303
+ return;
304
+ }
305
+ }
306
+
307
+ // Collect card details and verify via 3DS
308
+ const cardOk = await collectAndTokenizeCard(client, endUserId);
309
+ if (!cardOk) return;
310
+
311
+ // Top up
312
+ const topupStr = await prompt(`\n Amount to load ${dim('(e.g. 50.00)')}: $`);
313
+ const topupDollars = parseFloat(topupStr);
314
+ if (!topupDollars || isNaN(topupDollars)) {
315
+ console.log(dim(' Skipped. You can top up later from your dashboard.'));
316
+ } else {
317
+ console.log(`\n ${dim(`Loading $${topupDollars.toFixed(2)} to ${a.name}...`)}`);
318
+ try {
319
+ const result = await client.agents.topup(a.id, {
320
+ amount: Math.round(topupDollars * 100),
321
+ userId: endUserId,
322
+ currency: 'USD',
323
+ description: 'Initial top-up via CLI',
324
+ }) as any;
325
+ console.log();
326
+ success(`Agent funded! Balance: $${((result.balance ?? result.availableBalance ?? 0) / 100).toFixed(2)}\n`);
327
+ } catch (e: any) {
328
+ console.log();
329
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to top up agent'}`);
330
+ }
331
+ }
332
+ } else {
333
+ console.log(`\n ${dim('You can add a payment method and fund your agent from the menu or dashboard.')}\n`);
334
+ }
335
+ }
174
336
  } catch (e: any) {
175
337
  console.log();
176
338
  console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to connect agent'}`);
@@ -211,44 +373,7 @@ async function wizardAddPaymentMethod(client: ArisPayClient): Promise<void> {
211
373
  const methodChoice = await prompt(` Enter choice: `);
212
374
 
213
375
  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
- }
376
+ await collectAndTokenizeCard(client, userId);
252
377
  } else if (methodChoice === '2') {
253
378
  console.log();
254
379
  const chain = await prompt(` Chain ${dim('(ethereum, base, polygon, solana)')}: `);
@@ -314,24 +439,34 @@ async function wizardTestPayment(client: ArisPayClient): Promise<void> {
314
439
  const memo = await prompt(` Description ${dim('(appears on the transaction record)')}: `);
315
440
  if (!memo) { console.log(dim(' Cancelled.')); return; }
316
441
 
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;
442
+ const agentMode = (config as any).agentMode;
443
+ const isAutonomous = agentMode === 'autonomous';
444
+
445
+ if (!isAutonomous) {
446
+ const userId = (config as any).endUserId;
447
+ if (!userId) {
448
+ console.log(`\n ${dim('No payment method set up yet. Run option [2] first.')}`);
449
+ return;
450
+ }
321
451
  }
322
452
 
323
453
  console.log(`\n ${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
324
454
 
325
455
  try {
326
- const payment = await client.payments.create({
456
+ const paymentParams: Record<string, unknown> = {
327
457
  agentId,
328
- userId,
329
458
  amount,
330
459
  currency: 'USD',
331
460
  memo,
332
- merchantUrl: 'https://test.arispay.app',
333
461
  idempotencyKey: `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
334
- } as any);
462
+ };
463
+
464
+ if (!isAutonomous) {
465
+ paymentParams.userId = (config as any).endUserId;
466
+ paymentParams.merchantUrl = 'https://test.arispay.app';
467
+ }
468
+
469
+ const payment = await client.payments.create(paymentParams as any);
335
470
  const p = payment as any;
336
471
  console.log();
337
472
  if (p.status === 'succeeded') {
@@ -400,8 +535,8 @@ ${bold('Examples:')}
400
535
  arispay init
401
536
  arispay agents create --name "BookingBot" --mode autonomous
402
537
  arispay agents list
403
- arispay pay --agent <id> --amount 2000 --memo "Dinner for 2"
404
- arispay transactions --agent <id> --from 2025-01-01
538
+ arispay pay --agent <id> --amount 20.00 --memo "Dinner for 2"
539
+ arispay transactions --agent <id> --from 2026-01-01
405
540
 
406
541
  ${bold('Environment:')}
407
542
  ARISPAY_API_KEY Override API key