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.
- package/dist/cli.js +183 -60
- package/package.json +1 -1
- 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
|
-
|
|
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
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
325
445
|
}
|
|
326
446
|
console.log(`
|
|
327
447
|
${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
|
|
328
448
|
try {
|
|
329
|
-
const
|
|
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
|
|
403
|
-
arispay transactions --agent <id> --from
|
|
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
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
|
-
|
|
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
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
|
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
|
-
}
|
|
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
|
|
404
|
-
arispay transactions --agent <id> --from
|
|
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
|