arispay 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/cli.ts ADDED
@@ -0,0 +1,439 @@
1
+ /**
2
+ * ArisPay CLI — Traditional API key auth
3
+ *
4
+ * npm install arispay
5
+ * arispay init → paste API key
6
+ */
7
+
8
+ import { readFileSync, existsSync } from 'node:fs';
9
+ import { ArisPay, type ArisPayClient } from './index.js';
10
+ import {
11
+ type Brand,
12
+ createBrand,
13
+ configFile,
14
+ loadConfig,
15
+ saveConfig,
16
+ parseFlags,
17
+ prompt,
18
+ promptSecret,
19
+ error,
20
+ success,
21
+ dim,
22
+ bold,
23
+ cyan,
24
+ table,
25
+ getVersion,
26
+ cmdAgents,
27
+ cmdUsers,
28
+ cmdPay,
29
+ cmdPaymentGet,
30
+ cmdTransactions,
31
+ cmdWebhooks,
32
+ cmdStatus,
33
+ } from './cli-shared.js';
34
+
35
+ const BRAND: Brand = createBrand('arispay', 'arispay init');
36
+
37
+ // ── Init (paste API key) ────────────────────────────────────────────
38
+
39
+ async function cmdInit(args: string[]): Promise<void> {
40
+ const { flags } = parseFlags(args);
41
+ const file = configFile(BRAND);
42
+
43
+ console.log(`\n${bold('ArisPay CLI Setup')}\n`);
44
+ console.log(` ${dim('Get your API key from the ArisPay dashboard:')}`);
45
+ console.log(` ${dim('→ Dashboard → API Keys → Create Key')}\n`);
46
+
47
+ const existing = existsSync(file) ? JSON.parse(readFileSync(file, 'utf-8')) : {};
48
+
49
+ const apiKey =
50
+ flags['api-key'] ||
51
+ (await promptSecret(` API key${existing.apiKey ? ` ${dim(`[${existing.apiKey.slice(0, 12)}...]`)}` : ''}: `));
52
+
53
+ if (!apiKey && !existing.apiKey) error('API key is required');
54
+
55
+ console.log(`\n ${dim('Choose your environment:')}`);
56
+ console.log(` ${dim(' sandbox — Test payments, no real money (recommended to start)')}`);
57
+ console.log(` ${dim(' production — Live payments via Fiserv')}\n`);
58
+
59
+ const envChoice =
60
+ flags['env'] ||
61
+ (await prompt(` Environment ${dim(`[${existing.environment || 'sandbox'}]`)}: `));
62
+
63
+ const baseUrl = flags['base-url'] || undefined;
64
+
65
+ const config = {
66
+ apiKey: apiKey || existing.apiKey,
67
+ environment: (envChoice || existing.environment || 'sandbox') as 'sandbox' | 'production',
68
+ ...(baseUrl ? { baseUrl } : {}),
69
+ };
70
+
71
+ saveConfig(BRAND, config);
72
+
73
+ try {
74
+ const client = ArisPay.init({
75
+ apiKey: config.apiKey!,
76
+ environment: config.environment,
77
+ baseUrl: config.baseUrl,
78
+ });
79
+ await (client as any).transactions?.list?.({ limit: 1 }).catch(() => {});
80
+ console.log();
81
+ success('Connected to ArisPay API');
82
+ } catch {
83
+ console.log();
84
+ console.log(` ${dim('Could not connect — check your API key and try again.')}`);
85
+ }
86
+
87
+ await postInitMenu(config);
88
+ }
89
+
90
+ // ── Interactive menu after init ──────────────────────────────────────
91
+
92
+ async function postInitMenu(config: { apiKey?: string; environment?: string; baseUrl?: string }): Promise<void> {
93
+ const client = ArisPay.init({
94
+ apiKey: config.apiKey!,
95
+ environment: config.environment as any,
96
+ baseUrl: config.baseUrl,
97
+ });
98
+
99
+ while (true) {
100
+ console.log(`\n${bold('Get started')}\n`);
101
+ console.log(` ${cyan('[1]')} Connect your agent to ArisPay`);
102
+ console.log(` ${cyan('[2]')} Add a payment method`);
103
+ console.log(` ${cyan('[3]')} Make a test payment`);
104
+ console.log(` ${cyan('[4]')} View transactions`);
105
+ console.log(` ${cyan('[q]')} Quit\n`);
106
+
107
+ const choice = await prompt(' Enter choice: ');
108
+
109
+ switch (choice) {
110
+ case '1':
111
+ await wizardConnectAgent(client);
112
+ break;
113
+ case '2':
114
+ await wizardAddPaymentMethod(client);
115
+ break;
116
+ case '3':
117
+ await wizardTestPayment(client);
118
+ break;
119
+ case '4':
120
+ await wizardTransactions(client);
121
+ break;
122
+ case 'q':
123
+ case 'quit':
124
+ case 'exit':
125
+ console.log(`\n ${dim('Run')} ${bold('arispay --help')} ${dim('to see all commands.')}\n`);
126
+ return;
127
+ default:
128
+ console.log(` ${dim('Enter 1, 2, 3, 4, or q')}`);
129
+ }
130
+ }
131
+ }
132
+
133
+ // ── Wizard: Connect Agent ────────────────────────────────────────────
134
+
135
+ async function wizardConnectAgent(client: ArisPayClient): Promise<void> {
136
+ console.log(`\n${bold('Connect your agent to ArisPay')}`);
137
+ console.log(` ${dim('Register your existing AI agent so it can send and receive payments.')}`);
138
+ console.log(` ${dim('This gives your agent a cryptographic identity on the ArisPay network.')}\n`);
139
+
140
+ const name = await prompt(` What is your agent called? `);
141
+ if (!name) { console.log(dim(' Cancelled.')); return; }
142
+
143
+ console.log(`\n ${dim('How does your agent make payments?')}`);
144
+ console.log(` ${dim(' platform — Your app triggers payments on behalf of the agent (default)')}`);
145
+ console.log(` ${dim(' autonomous — The agent decides when to pay, within spend limits you set')}\n`);
146
+
147
+ const modeInput = await prompt(` Mode ${dim('[platform]')}: `);
148
+ const mode = modeInput === 'autonomous' ? 'autonomous' : 'platform';
149
+
150
+ console.log(`\n ${dim('Connecting agent...')}`);
151
+
152
+ try {
153
+ const agent = await client.agents.register({
154
+ name,
155
+ mode,
156
+ permissions: ['browse', 'payment'],
157
+ });
158
+ const a = agent as any;
159
+
160
+ // Store agent ID so other steps can auto-fill it
161
+ const config = loadConfig(BRAND);
162
+ saveConfig(BRAND, { ...config, agentId: a.id } as any);
163
+
164
+ console.log();
165
+ success(`Agent connected!\n`);
166
+ console.log(` ${bold('Agent ID:')} ${a.id}`);
167
+ console.log(` ${bold('Name:')} ${a.name}`);
168
+ console.log(` ${bold('Mode:')} ${a.mode || mode}`);
169
+ console.log(` ${bold('Status:')} ${a.status}\n`);
170
+ } catch (e: any) {
171
+ console.log();
172
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to connect agent'}`);
173
+ }
174
+ }
175
+
176
+ // ── Wizard: Add Payment Method ───────────────────────────────────────
177
+
178
+ async function wizardAddPaymentMethod(client: ArisPayClient): Promise<void> {
179
+ console.log(`\n${bold('Add a payment method')}`);
180
+ console.log(` ${dim('Before your agent can spend, you need a funding source.')}\n`);
181
+
182
+ // Auto-create end user if not already stored in config
183
+ const config = loadConfig(BRAND);
184
+ let userId = (config as any).endUserId;
185
+
186
+ if (!userId) {
187
+ const email = await prompt(` Your email ${dim('(for payment receipts)')}: `);
188
+
189
+ console.log(`\n ${dim('Setting up your account...')}`);
190
+ try {
191
+ const user = await client.users.create({
192
+ externalId: `cli_${Date.now()}`,
193
+ email: email || undefined,
194
+ });
195
+ userId = (user as any).id;
196
+ // Store in config so they never have to do this again
197
+ saveConfig(BRAND, { ...config, endUserId: userId } as any);
198
+ success('Account ready');
199
+ } catch (e: any) {
200
+ console.log();
201
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to set up account'}`);
202
+ return;
203
+ }
204
+ }
205
+
206
+ console.log(`\n ${dim('How would you like to fund your agent?')}\n`);
207
+ console.log(` ${cyan('[1]')} Card ${dim('— Visa, Mastercard')}`);
208
+ console.log(` ${cyan('[2]')} Crypto wallet ${dim('— USDC on Ethereum, Base, Polygon, or Solana')}\n`);
209
+
210
+ const methodChoice = await prompt(` Enter choice: `);
211
+
212
+ if (methodChoice === '1') {
213
+ console.log(`\n ${dim('Starting card setup...')}`);
214
+ try {
215
+ const result = await client.users.addPaymentMethod({
216
+ userId,
217
+ type: 'card',
218
+ returnUrl: 'https://app.arispay.app/card-setup/complete',
219
+ });
220
+ const r = result as any;
221
+ console.log();
222
+ success(`Card setup ready!\n`);
223
+ console.log(` ${bold('Open this URL to securely enter your card details:')}\n`);
224
+ console.log(` ${cyan(r.setupUrl)}\n`);
225
+ console.log(` ${dim('Your card is tokenized — ArisPay never sees or stores the full number.')}\n`);
226
+ } catch (e: any) {
227
+ console.log();
228
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to start card setup'}`);
229
+ }
230
+ } else if (methodChoice === '2') {
231
+ console.log();
232
+ const chain = await prompt(` Chain ${dim('(ethereum, base, polygon, solana)')}: `);
233
+ if (!chain) { console.log(dim(' Cancelled.')); return; }
234
+ const address = await prompt(` Wallet address: `);
235
+ if (!address) { console.log(dim(' Cancelled.')); return; }
236
+
237
+ console.log(`\n ${dim('Registering wallet...')}`);
238
+ try {
239
+ const result = await client.users.addPaymentMethod({
240
+ userId,
241
+ type: 'wallet',
242
+ walletAddress: address,
243
+ chain: chain as any,
244
+ });
245
+ const r = result as any;
246
+ console.log();
247
+ success(`Wallet registered!\n`);
248
+ console.log(` ${bold('Next step:')} Approve ArisPay to spend USDC from your wallet.\n`);
249
+ console.log(` ${bold('Spender:')} ${r.spenderAddress}`);
250
+ console.log(` ${bold('USDC:')} ${r.usdcContractAddress}`);
251
+ console.log(`\n ${dim('Call approve() on the USDC contract with the spender address above.')}\n`);
252
+ } catch (e: any) {
253
+ console.log();
254
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to register wallet'}`);
255
+ }
256
+ } else {
257
+ console.log(dim(' Cancelled.'));
258
+ }
259
+ }
260
+
261
+ // ── Wizard: Test Payment ─────────────────────────────────────────────
262
+
263
+ async function wizardTestPayment(client: ArisPayClient): Promise<void> {
264
+ console.log(`\n${bold('Make a test payment')}`);
265
+ console.log(` ${dim('Verify your integration works by sending a test payment.')}\n`);
266
+
267
+ const config = loadConfig(BRAND);
268
+ const storedAgentId = (config as any).agentId;
269
+
270
+ let agentId: string;
271
+ if (storedAgentId) {
272
+ const useStored = await prompt(` Use agent ${dim(storedAgentId.slice(0, 12) + '...')}? ${dim('(Y/n)')}: `);
273
+ if (useStored.toLowerCase() === 'n') {
274
+ agentId = await prompt(` Agent ID: `);
275
+ if (!agentId) { console.log(dim(' Cancelled.')); return; }
276
+ } else {
277
+ agentId = storedAgentId;
278
+ }
279
+ } else {
280
+ agentId = await prompt(` Agent ID: `);
281
+ if (!agentId) { console.log(dim(' Cancelled.')); return; }
282
+ }
283
+
284
+ const amountStr = await prompt(` Amount in cents ${dim('(e.g. 500 = $5.00)')}: `);
285
+ const amount = Number(amountStr);
286
+ if (!amount || isNaN(amount)) { console.log(dim(' Invalid amount. Cancelled.')); return; }
287
+
288
+ const memo = await prompt(` What is this payment for? `);
289
+ if (!memo) { console.log(dim(' Cancelled.')); return; }
290
+
291
+ console.log(`\n ${dim(`Sending $${(amount / 100).toFixed(2)} test payment...`)}`);
292
+
293
+ try {
294
+ const payment = await client.payments.create({
295
+ agentId,
296
+ amount,
297
+ currency: 'USD',
298
+ memo,
299
+ idempotencyKey: `cli_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`,
300
+ } as any);
301
+ const p = payment as any;
302
+ console.log();
303
+ if (p.status === 'succeeded') {
304
+ success(`Payment successful!\n`);
305
+ } else {
306
+ console.log(` ${bold('Status:')} ${p.status}\n`);
307
+ }
308
+ console.log(` ${bold('Payment ID:')} ${p.id}`);
309
+ console.log(` ${bold('Amount:')} $${(amount / 100).toFixed(2)} USD`);
310
+ console.log(` ${bold('Status:')} ${p.status}`);
311
+ console.log();
312
+ } catch (e: any) {
313
+ console.log();
314
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Payment failed'}`);
315
+ }
316
+ }
317
+
318
+ // ── Wizard: View Transactions ────────────────────────────────────────
319
+
320
+ async function wizardTransactions(client: ArisPayClient): Promise<void> {
321
+ console.log(`\n${bold('Recent Transactions')}\n`);
322
+
323
+ try {
324
+ const result = await client.transactions.list({ limit: 10 });
325
+ const payments = (result as any).payments ?? (result as any).transactions ?? [];
326
+
327
+ if (payments.length === 0) {
328
+ console.log(` ${dim('No transactions yet. Connect an agent and make a test payment to get started.')}\n`);
329
+ return;
330
+ }
331
+
332
+ table(
333
+ payments.map((p: any) => ({
334
+ id: p.id.slice(0, 12) + '…',
335
+ amount: '$' + (p.amount / 100).toFixed(2),
336
+ status: p.status,
337
+ memo: (p.memo || '').slice(0, 25),
338
+ date: p.createdAt?.slice(0, 10),
339
+ })),
340
+ );
341
+ console.log();
342
+ } catch (e: any) {
343
+ console.error(` \x1b[31m✗\x1b[0m ${e.message || 'Failed to fetch transactions'}`);
344
+ }
345
+ }
346
+
347
+ // ── Main ────────────────────────────────────────────────────────────
348
+
349
+ const HELP = `
350
+ ${bold('arispay')} — Agentic payment infrastructure CLI
351
+
352
+ ${bold('Usage:')}
353
+ arispay <command> [options]
354
+
355
+ ${bold('Commands:')}
356
+ ${cyan('init')} Configure API key & environment
357
+ ${cyan('status')} Show config & connection status
358
+ ${cyan('agents')} Manage AI payment agents
359
+ ${cyan('users')} Manage end users & payment methods
360
+ ${cyan('pay')} Create a payment
361
+ ${cyan('payment <id>')} Get payment details
362
+ ${cyan('transactions')} List transactions
363
+ ${cyan('webhooks')} Manage webhook endpoints
364
+
365
+ ${bold('Examples:')}
366
+ arispay init
367
+ arispay agents create --name "BookingBot" --mode autonomous
368
+ arispay agents list
369
+ arispay pay --agent <id> --amount 2000 --memo "Dinner for 2"
370
+ arispay transactions --agent <id> --from 2025-01-01
371
+
372
+ ${bold('Environment:')}
373
+ ARISPAY_API_KEY Override API key
374
+ ARISPAY_ENV Override environment (sandbox|production)
375
+ ARISPAY_BASE_URL Override API base URL
376
+
377
+ ${bold('Config:')} ~/.arispay/config.json
378
+ `;
379
+
380
+ async function main(): Promise<void> {
381
+ const args = process.argv.slice(2);
382
+ const command = args[0];
383
+ const rest = args.slice(1);
384
+
385
+ if (!command || command === 'help' || command === '--help' || command === '-h') {
386
+ console.log(HELP);
387
+ return;
388
+ }
389
+
390
+ if (command === '--version' || command === '-v') {
391
+ console.log(getVersion());
392
+ return;
393
+ }
394
+
395
+ try {
396
+ switch (command) {
397
+ case 'init':
398
+ await cmdInit(rest);
399
+ break;
400
+ case 'status':
401
+ await cmdStatus(BRAND);
402
+ break;
403
+ case 'agents':
404
+ case 'agent':
405
+ await cmdAgents(rest, BRAND);
406
+ break;
407
+ case 'users':
408
+ case 'user':
409
+ await cmdUsers(rest, BRAND);
410
+ break;
411
+ case 'pay':
412
+ await cmdPay(rest, BRAND);
413
+ break;
414
+ case 'payment':
415
+ await cmdPaymentGet(rest, BRAND);
416
+ break;
417
+ case 'transactions':
418
+ case 'txs':
419
+ await cmdTransactions(rest, BRAND);
420
+ break;
421
+ case 'webhooks':
422
+ case 'webhook':
423
+ await cmdWebhooks(rest, BRAND);
424
+ break;
425
+ default:
426
+ console.error(`Unknown command: ${command}`);
427
+ console.log(HELP);
428
+ process.exit(1);
429
+ }
430
+ } catch (e: any) {
431
+ if (e.code && e.message && e.statusCode) {
432
+ error(`[${e.code}] ${e.message} (HTTP ${e.statusCode})`);
433
+ } else {
434
+ error(e.message || String(e));
435
+ }
436
+ }
437
+ }
438
+
439
+ main();
package/src/client.ts ADDED
@@ -0,0 +1,65 @@
1
+ import type { ErrorResponse, ErrorCode } from '@arispay/shared';
2
+ import { ArisPayError, ERROR_CODES } from '@arispay/shared';
3
+
4
+ const SDK_REQUEST_TIMEOUT_MS = 30_000; // 30 seconds
5
+
6
+ // Valid error codes for runtime validation
7
+ const VALID_ERROR_CODES = new Set(Object.values(ERROR_CODES));
8
+
9
+ function toErrorCode(code: unknown): ErrorCode {
10
+ if (typeof code === 'string' && VALID_ERROR_CODES.has(code as ErrorCode)) {
11
+ return code as ErrorCode;
12
+ }
13
+ return 'INTERNAL_ERROR' as ErrorCode;
14
+ }
15
+
16
+ export class HttpClient {
17
+ constructor(
18
+ private baseUrl: string,
19
+ private apiKey: string,
20
+ ) {}
21
+
22
+ private async request<T>(method: string, path: string, body?: unknown): Promise<T> {
23
+ const url = `${this.baseUrl}${path}`;
24
+ const headers: Record<string, string> = {
25
+ Authorization: `Bearer ${this.apiKey}`,
26
+ 'Content-Type': 'application/json',
27
+ };
28
+
29
+ const res = await fetch(url, {
30
+ method,
31
+ headers,
32
+ body: body ? JSON.stringify(body) : undefined,
33
+ signal: AbortSignal.timeout(SDK_REQUEST_TIMEOUT_MS),
34
+ });
35
+
36
+ const data = await res.json();
37
+
38
+ if (!res.ok) {
39
+ const err = data as ErrorResponse;
40
+ throw new ArisPayError(
41
+ toErrorCode(err.error?.code),
42
+ err.error?.message ?? 'Request failed',
43
+ res.status,
44
+ );
45
+ }
46
+
47
+ return data as T;
48
+ }
49
+
50
+ get<T>(path: string): Promise<T> {
51
+ return this.request<T>('GET', path);
52
+ }
53
+
54
+ post<T>(path: string, body?: unknown): Promise<T> {
55
+ return this.request<T>('POST', path, body);
56
+ }
57
+
58
+ put<T>(path: string, body?: unknown): Promise<T> {
59
+ return this.request<T>('PUT', path, body);
60
+ }
61
+
62
+ delete<T>(path: string): Promise<T> {
63
+ return this.request<T>('DELETE', path);
64
+ }
65
+ }
package/src/index.ts ADDED
@@ -0,0 +1,98 @@
1
+ import { HttpClient } from './client.js';
2
+ import { AgentService } from './agents.js';
3
+ import { UserService } from './users.js';
4
+ import { PaymentService } from './payments.js';
5
+ import { TransactionService } from './transactions.js';
6
+ import { WebhookService } from './webhooks.js';
7
+
8
+ export { AgentService } from './agents.js';
9
+ export { UserService } from './users.js';
10
+ export { PaymentService } from './payments.js';
11
+ export { TransactionService } from './transactions.js';
12
+ export { WebhookService } from './webhooks.js';
13
+ export {
14
+ ArisPayError,
15
+ SpendLimitExceededError,
16
+ InsufficientFundsError,
17
+ InsufficientBalanceError,
18
+ AgentModeMismatchError,
19
+ } from '@arispay/shared';
20
+
21
+ // Re-export autonomous mode types for convenience
22
+ export type {
23
+ AgentTopupRequest,
24
+ AgentTopupResponse,
25
+ AgentSweepRequest,
26
+ AgentSweepResponse,
27
+ AgentEarningRequest,
28
+ AgentBalanceResponse,
29
+ LedgerEntryResponse,
30
+ LedgerHistoryResponse,
31
+ } from '@arispay/shared';
32
+
33
+ export interface ArisPayConfig {
34
+ apiKey: string;
35
+ environment?: 'sandbox' | 'production';
36
+ baseUrl?: string;
37
+ }
38
+
39
+ export interface ArisPayClient {
40
+ agents: AgentService;
41
+ users: UserService;
42
+ payments: PaymentService;
43
+ transactions: TransactionService;
44
+ webhooks: WebhookService;
45
+ }
46
+
47
+ export class ArisPay {
48
+ /**
49
+ * Initialize the ArisPay SDK.
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * import ArisPay from 'arispay';
54
+ *
55
+ * const arispay = ArisPay.init({
56
+ * apiKey: 'ap_test_abc123',
57
+ * environment: 'sandbox',
58
+ * });
59
+ *
60
+ * const agent = await arispay.agents.register({
61
+ * name: 'TableClaw',
62
+ * description: 'AI restaurant booking agent',
63
+ * permissions: ['browse', 'payment'],
64
+ * });
65
+ *
66
+ * const user = await arispay.users.create({
67
+ * externalId: 'user_123',
68
+ * email: 'jane@example.com',
69
+ * });
70
+ *
71
+ * const payment = await arispay.payments.create({
72
+ * agentId: agent.id,
73
+ * userId: user.id,
74
+ * amount: 20000,
75
+ * currency: 'USD',
76
+ * merchantUrl: 'https://nobu.com',
77
+ * memo: 'Table for 2',
78
+ * idempotencyKey: 'booking_123',
79
+ * });
80
+ * ```
81
+ */
82
+ static init(config: ArisPayConfig): ArisPayClient {
83
+ const defaultUrl =
84
+ config.environment === 'production' ? 'https://api.arispay.app' : 'https://api-production-79ea.up.railway.app';
85
+ const baseUrl = config.baseUrl || defaultUrl;
86
+ const client = new HttpClient(baseUrl, config.apiKey);
87
+
88
+ return {
89
+ agents: new AgentService(client),
90
+ users: new UserService(client),
91
+ payments: new PaymentService(client),
92
+ transactions: new TransactionService(client),
93
+ webhooks: new WebhookService(client),
94
+ };
95
+ }
96
+ }
97
+
98
+ export default ArisPay;
@@ -0,0 +1,22 @@
1
+ import type { CreatePaymentRequest, PaymentResponse, Complete3dsRequest } from '@arispay/shared';
2
+ import type { HttpClient } from './client.js';
3
+
4
+ export class PaymentService {
5
+ constructor(private client: HttpClient) {}
6
+
7
+ async create(params: CreatePaymentRequest): Promise<PaymentResponse> {
8
+ return this.client.post<PaymentResponse>('/v1/payments', params);
9
+ }
10
+
11
+ async get(paymentId: string): Promise<PaymentResponse> {
12
+ return this.client.get<PaymentResponse>(`/v1/payments/${paymentId}`);
13
+ }
14
+
15
+ /** Complete a 3D Secure authentication step (method or challenge) */
16
+ async complete3ds(paymentId: string, params: Complete3dsRequest): Promise<PaymentResponse> {
17
+ return this.client.post<PaymentResponse>(
18
+ `/v1/payments/${paymentId}/3ds/complete`,
19
+ params,
20
+ );
21
+ }
22
+ }
@@ -0,0 +1,19 @@
1
+ import type { ListTransactionsQuery, TransactionListResponse } from '@arispay/shared';
2
+ import type { HttpClient } from './client.js';
3
+
4
+ export class TransactionService {
5
+ constructor(private client: HttpClient) {}
6
+
7
+ async list(params?: ListTransactionsQuery): Promise<TransactionListResponse> {
8
+ const searchParams = new URLSearchParams();
9
+ if (params?.userId) searchParams.set('userId', params.userId);
10
+ if (params?.agentId) searchParams.set('agentId', params.agentId);
11
+ if (params?.from) searchParams.set('from', params.from);
12
+ if (params?.to) searchParams.set('to', params.to);
13
+ if (params?.limit) searchParams.set('limit', String(params.limit));
14
+ if (params?.offset) searchParams.set('offset', String(params.offset));
15
+
16
+ const qs = searchParams.toString();
17
+ return this.client.get<TransactionListResponse>(`/v1/transactions${qs ? `?${qs}` : ''}`);
18
+ }
19
+ }