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.
- package/dist/cli.js +178 -60
- package/package.json +1 -1
- 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
|
-
|
|
193
|
-
|
|
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
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
325
440
|
}
|
|
326
441
|
console.log(`
|
|
327
442
|
${dim(`Sending $${dollars.toFixed(2)} test payment...`)}`);
|
|
328
443
|
try {
|
|
329
|
-
const
|
|
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
|
|
403
|
-
arispay transactions --agent <id> --from
|
|
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
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
|
-
|
|
215
|
-
|
|
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
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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
|
|
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
|
-
}
|
|
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
|
|
404
|
-
arispay transactions --agent <id> --from
|
|
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
|