@ar-agents/mercadopago 0.1.0 → 0.2.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/dist/index.cjs CHANGED
@@ -145,31 +145,48 @@ var MercadoPagoClient = class {
145
145
  this.baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
146
146
  this.fetchImpl = options.fetch;
147
147
  }
148
- async request(method, path, body, classifyContext) {
149
- const init = {
150
- method,
151
- headers: {
152
- Authorization: `Bearer ${this.accessToken}`,
153
- "Content-Type": "application/json"
154
- }
148
+ async request(method, path, body, options) {
149
+ const headers = {
150
+ Authorization: `Bearer ${this.accessToken}`,
151
+ "Content-Type": "application/json"
155
152
  };
153
+ if (options?.idempotencyKey) {
154
+ headers["X-Idempotency-Key"] = options.idempotencyKey;
155
+ }
156
+ const init = { method, headers };
156
157
  if (body !== void 0) {
157
158
  init.body = JSON.stringify(body);
158
159
  }
160
+ let url = `${this.baseUrl}${path}`;
161
+ if (options?.query) {
162
+ const search = new URLSearchParams();
163
+ for (const [k, v] of Object.entries(options.query)) {
164
+ if (v !== void 0 && v !== null && v !== "") {
165
+ search.set(k, String(v));
166
+ }
167
+ }
168
+ const qs = search.toString();
169
+ if (qs) url += `?${qs}`;
170
+ }
159
171
  const fetchFn = this.fetchImpl ?? globalThis.fetch;
160
- const res = await fetchFn(`${this.baseUrl}${path}`, init);
172
+ const res = await fetchFn(url, init);
161
173
  if (!res.ok) {
162
174
  let parsed;
163
- const text = await res.text();
175
+ const text2 = await res.text();
164
176
  try {
165
- parsed = JSON.parse(text);
177
+ parsed = JSON.parse(text2);
166
178
  } catch {
167
- parsed = text;
179
+ parsed = text2;
168
180
  }
169
- throw classifyError(res.status, path, parsed, classifyContext);
181
+ throw classifyError(res.status, path, parsed, options?.classifyContext);
170
182
  }
171
- return await res.json();
183
+ const text = await res.text();
184
+ if (!text) return void 0;
185
+ return JSON.parse(text);
172
186
  }
187
+ // ───────────────────────────────────────────────────────────────────────────
188
+ // Subscriptions (Preapprovals) — v0.1 surface, kept stable
189
+ // ───────────────────────────────────────────────────────────────────────────
173
190
  /**
174
191
  * Create a recurring subscription (preapproval). The returned `init_point`
175
192
  * URL is where the buyer must complete the FIRST payment with their card +
@@ -191,70 +208,335 @@ var MercadoPagoClient = class {
191
208
  currency_id: params.currency
192
209
  }
193
210
  },
194
- { payerEmail: params.payerEmail }
211
+ { classifyContext: { payerEmail: params.payerEmail } }
212
+ );
213
+ }
214
+ async getPreapproval(id) {
215
+ return this.request("GET", `/preapproval/${id}`, void 0, {
216
+ classifyContext: { preapprovalId: id }
217
+ });
218
+ }
219
+ async cancelPreapproval(id) {
220
+ return this.request(
221
+ "PUT",
222
+ `/preapproval/${id}`,
223
+ { status: "cancelled" },
224
+ { classifyContext: { preapprovalId: id } }
195
225
  );
196
226
  }
227
+ async pausePreapproval(id) {
228
+ return this.request(
229
+ "PUT",
230
+ `/preapproval/${id}`,
231
+ { status: "paused" },
232
+ { classifyContext: { preapprovalId: id } }
233
+ );
234
+ }
235
+ async resumePreapproval(id) {
236
+ return this.request(
237
+ "PUT",
238
+ `/preapproval/${id}`,
239
+ { status: "authorized" },
240
+ { classifyContext: { preapprovalId: id } }
241
+ );
242
+ }
243
+ // ───────────────────────────────────────────────────────────────────────────
244
+ // Payments (v0.2)
245
+ // ───────────────────────────────────────────────────────────────────────────
197
246
  /**
198
- * Fetch the current state of a preapproval. Useful to confirm whether the
199
- * buyer has completed the first payment (`status: 'authorized'`) or whether
200
- * the subscription was cancelled.
247
+ * Create a payment. Two main flows:
248
+ * - **Card payment**: pass `token` (from MP frontend Cardform) + payment_method_id.
249
+ * - **Account money / cash**: omit token, pass payment_method_id like "account_money", "rapipago", "pagofacil".
250
+ *
251
+ * For credit card payments where you don't have a card token (i.e., you only
252
+ * have a payer email and want to send them a payment link), use
253
+ * `createPreference` (Checkout Pro) instead.
254
+ *
255
+ * Idempotency: pass `idempotencyKey` to safely retry. Required for production
256
+ * to dedupe network-failed requests.
201
257
  */
202
- async getPreapproval(id) {
258
+ async createPayment(params) {
259
+ const body = {
260
+ transaction_amount: params.transactionAmount,
261
+ payment_method_id: params.paymentMethodId,
262
+ payer: {
263
+ email: params.payerEmail,
264
+ ...params.identification ? { identification: params.identification } : {}
265
+ }
266
+ };
267
+ if (params.installments !== void 0) body.installments = params.installments;
268
+ if (params.token !== void 0) body.token = params.token;
269
+ if (params.description !== void 0) body.description = params.description;
270
+ if (params.externalReference !== void 0) body.external_reference = params.externalReference;
271
+ if (params.notificationUrl !== void 0) body.notification_url = params.notificationUrl;
272
+ if (params.statementDescriptor !== void 0)
273
+ body.statement_descriptor = params.statementDescriptor;
274
+ if (params.capture !== void 0) body.capture = params.capture;
275
+ if (params.additionalInfo !== void 0) body.additional_info = params.additionalInfo;
276
+ return this.request("POST", "/v1/payments", body, {
277
+ ...params.idempotencyKey ? { idempotencyKey: params.idempotencyKey } : {},
278
+ classifyContext: { payerEmail: params.payerEmail }
279
+ });
280
+ }
281
+ /** Fetch a payment by ID. */
282
+ async getPayment(id) {
283
+ return this.request("GET", `/v1/payments/${id}`, void 0, {
284
+ classifyContext: { paymentId: id }
285
+ });
286
+ }
287
+ /**
288
+ * Search payments with filters. Common: by external_reference (your-system
289
+ * id), by status, by date range. Pagination via offset + limit (max 100).
290
+ */
291
+ async searchPayments(params = {}) {
292
+ const query = {
293
+ limit: params.limit ?? 30,
294
+ offset: params.offset ?? 0
295
+ };
296
+ if (params.externalReference) query["external_reference"] = params.externalReference;
297
+ if (params.status) query["status"] = params.status;
298
+ if (params.payerEmail) query["payer.email"] = params.payerEmail;
299
+ if (params.beginDate) query["begin_date"] = params.beginDate;
300
+ if (params.endDate) query["end_date"] = params.endDate;
301
+ if (params.sort) query["sort"] = params.sort;
302
+ if (params.criteria) query["criteria"] = params.criteria;
203
303
  return this.request(
204
304
  "GET",
205
- `/preapproval/${id}`,
305
+ "/v1/payments/search",
206
306
  void 0,
207
- { preapprovalId: id }
307
+ { query }
208
308
  );
209
309
  }
210
310
  /**
211
- * Cancel an active preapproval. Irreversible: MP will not charge the buyer
212
- * again and the subscription cannot be reactivated.
311
+ * Capture a previously authorized payment. Only works for credit-card
312
+ * payments created with `capture: false`. Optional partial capture amount.
213
313
  */
214
- async cancelPreapproval(id) {
314
+ async capturePayment(id, amount) {
215
315
  return this.request(
216
316
  "PUT",
217
- `/preapproval/${id}`,
218
- { status: "cancelled" },
219
- { preapprovalId: id }
317
+ `/v1/payments/${id}`,
318
+ amount !== void 0 ? { capture: true, transaction_amount: amount } : { capture: true },
319
+ { classifyContext: { paymentId: id } }
220
320
  );
221
321
  }
222
322
  /**
223
- * Pause an authorized preapproval. The subscription stops auto-charging but
224
- * can be re-activated. Note: MP only allows pausing subs that are currently
225
- * `authorized` — pending/cancelled subs reject this.
323
+ * Cancel a pending or in_process payment. Once approved, you must use
324
+ * `createRefund` instead.
226
325
  */
227
- async pausePreapproval(id) {
326
+ async cancelPayment(id) {
228
327
  return this.request(
229
328
  "PUT",
230
- `/preapproval/${id}`,
231
- { status: "paused" },
232
- { preapprovalId: id }
329
+ `/v1/payments/${id}`,
330
+ { status: "cancelled" },
331
+ { classifyContext: { paymentId: id } }
233
332
  );
234
333
  }
334
+ // ───────────────────────────────────────────────────────────────────────────
335
+ // Refunds
336
+ // ───────────────────────────────────────────────────────────────────────────
235
337
  /**
236
- * Re-activate a paused preapproval. Charges resume on the next scheduled
237
- * date.
338
+ * Refund a payment fully (omit `amount`) or partially. Idempotency key
339
+ * recommended — refunds can fail mid-flight and you don't want double-refunds
340
+ * on retry.
238
341
  */
239
- async resumePreapproval(id) {
342
+ async createRefund(params) {
343
+ const body = params.amount !== void 0 ? { amount: params.amount } : void 0;
240
344
  return this.request(
241
- "PUT",
242
- `/preapproval/${id}`,
243
- { status: "authorized" },
244
- { preapprovalId: id }
345
+ "POST",
346
+ `/v1/payments/${params.paymentId}/refunds`,
347
+ body,
348
+ {
349
+ ...params.idempotencyKey ? { idempotencyKey: params.idempotencyKey } : {},
350
+ classifyContext: { paymentId: params.paymentId }
351
+ }
352
+ );
353
+ }
354
+ async listRefunds(paymentId) {
355
+ const res = await this.request(
356
+ "GET",
357
+ `/v1/payments/${paymentId}/refunds`,
358
+ void 0,
359
+ { classifyContext: { paymentId } }
360
+ );
361
+ return Array.isArray(res) ? res : res.refunds ?? [];
362
+ }
363
+ async getRefund(paymentId, refundId) {
364
+ return this.request(
365
+ "GET",
366
+ `/v1/payments/${paymentId}/refunds/${refundId}`,
367
+ void 0,
368
+ { classifyContext: { paymentId } }
245
369
  );
246
370
  }
371
+ // ───────────────────────────────────────────────────────────────────────────
372
+ // Checkout Pro (Preferences)
373
+ // ───────────────────────────────────────────────────────────────────────────
374
+ /**
375
+ * Create a payment preference for Checkout Pro. Returns `init_point` URL
376
+ * where the buyer completes payment on MP-hosted form. This is the
377
+ * recommended flow when you don't have a card token (most common path for
378
+ * agents — you don't want to handle PCI data).
379
+ *
380
+ * Sandbox: use `sandbox_init_point` instead of `init_point`.
381
+ */
382
+ async createPreference(params) {
383
+ const body = {
384
+ items: params.items.map((it) => ({
385
+ title: it.title,
386
+ quantity: it.quantity,
387
+ unit_price: it.unit_price,
388
+ currency_id: it.currency_id ?? "ARS",
389
+ ...it.description ? { description: it.description } : {},
390
+ ...it.picture_url ? { picture_url: it.picture_url } : {}
391
+ }))
392
+ };
393
+ if (params.payer) body.payer = params.payer;
394
+ if (params.backUrls) body.back_urls = params.backUrls;
395
+ if (params.autoReturn) body.auto_return = params.autoReturn;
396
+ if (params.notificationUrl) body.notification_url = params.notificationUrl;
397
+ if (params.externalReference) body.external_reference = params.externalReference;
398
+ if (params.paymentMethods) body.payment_methods = params.paymentMethods;
399
+ if (params.statementDescriptor)
400
+ body.statement_descriptor = params.statementDescriptor;
401
+ if (params.expires !== void 0) body.expires = params.expires;
402
+ if (params.expirationDateFrom) body.expiration_date_from = params.expirationDateFrom;
403
+ if (params.expirationDateTo) body.expiration_date_to = params.expirationDateTo;
404
+ return this.request("POST", "/checkout/preferences", body);
405
+ }
406
+ async getPreference(id) {
407
+ return this.request("GET", `/checkout/preferences/${id}`);
408
+ }
409
+ async updatePreference(id, patch) {
410
+ return this.request("PUT", `/checkout/preferences/${id}`, patch);
411
+ }
412
+ // ───────────────────────────────────────────────────────────────────────────
413
+ // Customers + Saved Cards
414
+ // ───────────────────────────────────────────────────────────────────────────
415
+ async createCustomer(params) {
416
+ const body = { email: params.email };
417
+ if (params.firstName) body.first_name = params.firstName;
418
+ if (params.lastName) body.last_name = params.lastName;
419
+ if (params.phone) body.phone = { area_code: params.phone.areaCode, number: params.phone.number };
420
+ if (params.identification) body.identification = params.identification;
421
+ if (params.description) body.description = params.description;
422
+ return this.request("POST", "/v1/customers", body, {
423
+ classifyContext: { payerEmail: params.email }
424
+ });
425
+ }
426
+ async getCustomer(id) {
427
+ return this.request("GET", `/v1/customers/${id}`, void 0, {
428
+ classifyContext: { customerId: id }
429
+ });
430
+ }
431
+ /**
432
+ * Search customers. Most common: by email (returns 0 or 1 result).
433
+ * Note: MP's `/v1/customers/search` returns a paginated wrapper, not a flat array.
434
+ */
435
+ async searchCustomers(params = {}) {
436
+ const query = {
437
+ limit: params.limit ?? 10,
438
+ offset: params.offset ?? 0
439
+ };
440
+ if (params.email) query["email"] = params.email;
441
+ return this.request("GET", "/v1/customers/search", void 0, { query });
442
+ }
443
+ async listCustomerCards(customerId) {
444
+ return this.request(
445
+ "GET",
446
+ `/v1/customers/${customerId}/cards`,
447
+ void 0,
448
+ { classifyContext: { customerId } }
449
+ );
450
+ }
451
+ async getCustomerCard(customerId, cardId) {
452
+ return this.request(
453
+ "GET",
454
+ `/v1/customers/${customerId}/cards/${cardId}`,
455
+ void 0,
456
+ { classifyContext: { customerId } }
457
+ );
458
+ }
459
+ async deleteCustomerCard(customerId, cardId) {
460
+ await this.request(
461
+ "DELETE",
462
+ `/v1/customers/${customerId}/cards/${cardId}`,
463
+ void 0,
464
+ { classifyContext: { customerId } }
465
+ );
466
+ }
467
+ // ───────────────────────────────────────────────────────────────────────────
468
+ // Payment Methods + Installments
469
+ // ───────────────────────────────────────────────────────────────────────────
470
+ /** List all payment methods enabled for the account's site (MLA = Argentina). */
471
+ async listPaymentMethods() {
472
+ return this.request("GET", "/v1/payment_methods");
473
+ }
474
+ /**
475
+ * Get installment options for an amount. THE killer AR feature — returns
476
+ * `payer_costs` with `recommended_message` strings like "12 cuotas sin
477
+ * interés de $X" that you should surface verbatim to the user.
478
+ *
479
+ * Pass `bin` (first 6 digits of card) for issuer-specific offers (e.g.,
480
+ * Naranja's interest-free promotions). Without bin, returns generic offers.
481
+ */
482
+ async getInstallments(params) {
483
+ const query = {
484
+ amount: params.amount
485
+ };
486
+ if (params.paymentMethodId) query["payment_method_id"] = params.paymentMethodId;
487
+ if (params.bin) query["bin"] = params.bin;
488
+ if (params.issuerId) query["issuer.id"] = params.issuerId;
489
+ return this.request(
490
+ "GET",
491
+ "/v1/payment_methods/installments",
492
+ void 0,
493
+ { query }
494
+ );
495
+ }
496
+ // ───────────────────────────────────────────────────────────────────────────
497
+ // Account
498
+ // ───────────────────────────────────────────────────────────────────────────
499
+ /** Get info about the account that owns this access token. */
500
+ async getMe() {
501
+ return this.request("GET", "/users/me");
502
+ }
247
503
  };
248
504
  var DEFAULT_DESCRIPTIONS = {
505
+ // ── Subscriptions ────────────────────────────────────────────────────────
249
506
  create_subscription: "Create a Mercado Pago recurring subscription. Returns an init_point URL where the customer must complete the FIRST payment with their card and CVV (this is a hard MP requirement; agents cannot bypass it). After they pay, MP will auto-charge at the configured frequency without further intervention.",
250
507
  get_subscription_status: "Check the current status of a Mercado Pago subscription. Use this to confirm the customer completed the first payment (status becomes 'authorized') or to inspect the next charge date.",
251
508
  cancel_subscription: "Cancel an active Mercado Pago subscription. After cancellation, MP will not charge the customer again. This action is irreversible \u2014 confirm with the user before calling.",
252
509
  pause_subscription: "Pause an authorized Mercado Pago subscription. Charges stop until resumed. Only works on subscriptions in 'authorized' status.",
253
- resume_subscription: "Resume a paused Mercado Pago subscription. Charges resume on the next scheduled date. Only works on subscriptions in 'paused' status."
510
+ resume_subscription: "Resume a paused Mercado Pago subscription. Charges resume on the next scheduled date. Only works on subscriptions in 'paused' status.",
511
+ // ── Payments ─────────────────────────────────────────────────────────────
512
+ create_payment: "Create a one-time payment. Two flows: (a) with a card token from MP frontend Cardform \u2014 for transparent checkout; (b) without token, for non-card methods like 'account_money', 'rapipago', 'pagofacil'. For most agent flows where you only have a payer email and want to send them a payment link, use create_payment_preference instead (Checkout Pro hosted form). Returns the Payment object with status \u2014 typically 'approved' for account_money and 'pending' for tickets.",
513
+ get_payment: "Fetch a single payment by ID. Use to confirm status after webhook arrives, or to inspect details (status_detail explains rejections).",
514
+ search_payments: "Search payments with filters. Most common: by external_reference (your-system identifier) to find all payments for an order, or by status='approved' to list successful charges in a date range. Returns paginated results.",
515
+ cancel_payment: "Cancel a pending or in_process payment (only works before approval). Once approved, use refund_payment instead. Common use: cancel an unpaid ticket payment that's still pending.",
516
+ capture_payment: "Capture an authorized credit-card payment that was created with capture=false. Use for hold-then-capture flows (e.g., authorize on order, capture on shipment). Optional partial amount.",
517
+ // ── Refunds ──────────────────────────────────────────────────────────────
518
+ refund_payment: "Refund an approved payment. Pass amount for partial refund; omit for full refund. Idempotency key is auto-generated based on paymentId+amount to prevent double-refunds on retries.",
519
+ list_refunds: "List all refunds for a given payment. Returns array of Refund objects. Useful to confirm a refund was processed or to inspect partial-refund history.",
520
+ // ── Checkout Pro ─────────────────────────────────────────────────────────
521
+ create_payment_preference: "Create a Mercado Pago Checkout Pro preference and get back a payment URL (init_point) to send to the customer. THIS is the recommended way for an agent to take a payment when you only have a payer email \u2014 the buyer enters card data on MP's hosted form (no PCI scope needed). Supports cuotas configuration, payment method exclusions, back URLs after success/failure/pending. In sandbox, use sandbox_init_point from the response.",
522
+ get_payment_preference: "Fetch a Checkout Pro preference by ID. Returns the preference config and current init_point URLs. Use to inspect a previously-created link.",
523
+ // ── Customers + Cards ────────────────────────────────────────────────────
524
+ create_customer: "Create a Mercado Pago customer record so the buyer can save cards for future charges. Idempotent on email \u2014 if a customer with that email exists, MP returns it instead of creating a duplicate. Use find_customer_by_email first if you're unsure.",
525
+ find_customer_by_email: "Find an existing customer by email address. Returns the customer object if found, or null. Use before create_customer to avoid duplicate records.",
526
+ list_customer_cards: "List the saved cards for a customer. Returns array with last 4 digits, expiration, payment method (visa, master, naranja, etc.). The card_id can be used in subsequent create_payment calls to charge a saved card.",
527
+ delete_customer_card: "Delete a saved card from a customer. Common use: customer requests removal, or expired card cleanup. Irreversible.",
528
+ // ── Payment Methods + Installments ───────────────────────────────────────
529
+ list_payment_methods: "List all payment methods enabled for the seller's MP account (visa, master, naranja, naranja_x, cabal, account_money, rapipago, pagofacil, etc.). Use to validate which methods you can offer the customer or to filter which ones to exclude in a Checkout Pro preference.",
530
+ calculate_installments: "Calculate cuotas (installments) options for a given amount. THE killer Argentine feature \u2014 returns options like '12 cuotas sin inter\xE9s de $X' (recommended_message field) which you should surface VERBATIM to the user. Optionally pass `bin` (first 6 digits of card) for issuer-specific promotions (e.g., Naranja's interest-free deals). Use before create_payment to let the user pick installments knowingly.",
531
+ // ── Account ──────────────────────────────────────────────────────────────
532
+ get_account_info: "Get info about the Mercado Pago account that owns the access token: site_id (MLA=Argentina), country_id, user_type (registered, partial, etc.). Useful to verify the agent is connected to the right account before taking actions."
254
533
  };
255
534
  function mercadoPagoTools(client, options) {
256
535
  const desc = (name) => options.descriptions?.[name] ?? DEFAULT_DESCRIPTIONS[name];
257
536
  return {
537
+ // ─────────────────────────────────────────────────────────────────────────
538
+ // Subscriptions (v0.1 — kept identical for backward compatibility)
539
+ // ─────────────────────────────────────────────────────────────────────────
258
540
  create_subscription: ai.tool({
259
541
  description: desc("create_subscription"),
260
542
  inputSchema: zod.z.object({
@@ -264,13 +546,7 @@ function mercadoPagoTools(client, options) {
264
546
  reason: zod.z.string().min(3).max(120).describe("Short description shown to the customer at checkout"),
265
547
  external_reference: zod.z.string().optional().describe("Optional id from your system to track this subscription")
266
548
  }),
267
- execute: async ({
268
- customer_email,
269
- amount_ars,
270
- frequency_months,
271
- reason,
272
- external_reference
273
- }) => {
549
+ execute: async ({ customer_email, amount_ars, frequency_months, reason, external_reference }) => {
274
550
  const created = await client.createPreapproval({
275
551
  reason,
276
552
  payerEmail: customer_email,
@@ -340,9 +616,7 @@ function mercadoPagoTools(client, options) {
340
616
  }),
341
617
  pause_subscription: ai.tool({
342
618
  description: desc("pause_subscription"),
343
- inputSchema: zod.z.object({
344
- subscription_id: zod.z.string()
345
- }),
619
+ inputSchema: zod.z.object({ subscription_id: zod.z.string() }),
346
620
  execute: async ({ subscription_id }) => {
347
621
  const paused = await client.pausePreapproval(subscription_id);
348
622
  await options.state.set(subscription_id, { status: paused.status });
@@ -355,9 +629,7 @@ function mercadoPagoTools(client, options) {
355
629
  }),
356
630
  resume_subscription: ai.tool({
357
631
  description: desc("resume_subscription"),
358
- inputSchema: zod.z.object({
359
- subscription_id: zod.z.string()
360
- }),
632
+ inputSchema: zod.z.object({ subscription_id: zod.z.string() }),
361
633
  execute: async ({ subscription_id }) => {
362
634
  const resumed = await client.resumePreapproval(subscription_id);
363
635
  await options.state.set(subscription_id, { status: resumed.status });
@@ -367,6 +639,396 @@ function mercadoPagoTools(client, options) {
367
639
  message: "Subscription resumed. Charges will continue on next scheduled date."
368
640
  };
369
641
  }
642
+ }),
643
+ // ─────────────────────────────────────────────────────────────────────────
644
+ // Payments (v0.2)
645
+ // ─────────────────────────────────────────────────────────────────────────
646
+ create_payment: ai.tool({
647
+ description: desc("create_payment"),
648
+ inputSchema: zod.z.object({
649
+ amount_ars: zod.z.number().positive().describe("Amount in ARS"),
650
+ payment_method_id: zod.z.string().describe("MP payment method id (e.g. 'account_money', 'rapipago', 'visa', 'master', 'naranja')"),
651
+ payer_email: zod.z.string().email().describe("Email of the payer. Cannot equal seller email."),
652
+ token: zod.z.string().optional().describe("Card token from MP frontend Cardform. Required for credit/debit; omit for cash/account_money."),
653
+ installments: zod.z.number().int().min(1).max(24).optional().describe("Number of installments (cuotas). Default 1. Use calculate_installments first to see options."),
654
+ description: zod.z.string().max(255).optional().describe("Short description"),
655
+ external_reference: zod.z.string().optional().describe("Your-system identifier"),
656
+ identification: zod.z.object({
657
+ type: zod.z.enum(["DNI", "CUIT", "CUIL"]),
658
+ number: zod.z.string()
659
+ }).optional().describe("Payer identification \u2014 required for some payment types in AR"),
660
+ statement_descriptor: zod.z.string().max(13).optional().describe("Shows on buyer's card statement (max 13 chars)")
661
+ }),
662
+ execute: async (input) => {
663
+ const payment = await client.createPayment({
664
+ transactionAmount: input.amount_ars,
665
+ paymentMethodId: input.payment_method_id,
666
+ payerEmail: input.payer_email,
667
+ ...input.token !== void 0 ? { token: input.token } : {},
668
+ ...input.installments !== void 0 ? { installments: input.installments } : {},
669
+ ...input.description !== void 0 ? { description: input.description } : {},
670
+ ...input.external_reference !== void 0 ? { externalReference: input.external_reference } : {},
671
+ ...input.identification !== void 0 ? { identification: input.identification } : {},
672
+ ...input.statement_descriptor !== void 0 ? { statementDescriptor: input.statement_descriptor } : {},
673
+ ...options.notificationUrl !== void 0 ? { notificationUrl: options.notificationUrl } : {},
674
+ // Auto-generate idempotency key from caller-meaningful fields
675
+ idempotencyKey: `${input.external_reference ?? input.payer_email}-${input.amount_ars}-${Date.now()}`
676
+ });
677
+ return {
678
+ payment_id: payment.id,
679
+ status: payment.status,
680
+ status_detail: payment.status_detail,
681
+ amount: payment.transaction_amount,
682
+ currency: payment.currency_id,
683
+ installments: payment.installments,
684
+ payment_method: payment.payment_method_id,
685
+ payer_email: payment.payer?.email ?? null,
686
+ external_reference: payment.external_reference,
687
+ date_created: payment.date_created,
688
+ date_approved: payment.date_approved
689
+ };
690
+ }
691
+ }),
692
+ get_payment: ai.tool({
693
+ description: desc("get_payment"),
694
+ inputSchema: zod.z.object({
695
+ payment_id: zod.z.string().describe("The MP payment ID")
696
+ }),
697
+ execute: async ({ payment_id }) => {
698
+ const p = await client.getPayment(payment_id);
699
+ return {
700
+ payment_id: p.id,
701
+ status: p.status,
702
+ status_detail: p.status_detail,
703
+ amount: p.transaction_amount,
704
+ currency: p.currency_id,
705
+ payment_method: p.payment_method_id,
706
+ installments: p.installments,
707
+ payer_email: p.payer?.email ?? null,
708
+ external_reference: p.external_reference,
709
+ date_created: p.date_created,
710
+ date_approved: p.date_approved,
711
+ net_received: p.transaction_details?.net_received_amount ?? null
712
+ };
713
+ }
714
+ }),
715
+ search_payments: ai.tool({
716
+ description: desc("search_payments"),
717
+ inputSchema: zod.z.object({
718
+ external_reference: zod.z.string().optional(),
719
+ status: zod.z.string().optional().describe("'approved' | 'pending' | 'rejected' | 'cancelled' | 'refunded' etc."),
720
+ payer_email: zod.z.string().optional(),
721
+ begin_date: zod.z.string().optional().describe("ISO 8601, e.g. 2026-01-01T00:00:00Z"),
722
+ end_date: zod.z.string().optional().describe("ISO 8601"),
723
+ limit: zod.z.number().int().min(1).max(100).optional().describe("Default 30, max 100"),
724
+ offset: zod.z.number().int().min(0).optional().describe("Pagination offset (default 0)")
725
+ }),
726
+ execute: async (input) => {
727
+ const result = await client.searchPayments({
728
+ ...input.external_reference !== void 0 ? { externalReference: input.external_reference } : {},
729
+ ...input.status !== void 0 ? { status: input.status } : {},
730
+ ...input.payer_email !== void 0 ? { payerEmail: input.payer_email } : {},
731
+ ...input.begin_date !== void 0 ? { beginDate: input.begin_date } : {},
732
+ ...input.end_date !== void 0 ? { endDate: input.end_date } : {},
733
+ ...input.limit !== void 0 ? { limit: input.limit } : {},
734
+ ...input.offset !== void 0 ? { offset: input.offset } : {}
735
+ });
736
+ return {
737
+ total: result.paging.total,
738
+ returned: result.results.length,
739
+ offset: result.paging.offset,
740
+ payments: result.results.map((p) => ({
741
+ payment_id: p.id,
742
+ status: p.status,
743
+ amount: p.transaction_amount,
744
+ currency: p.currency_id,
745
+ payer_email: p.payer?.email ?? null,
746
+ external_reference: p.external_reference,
747
+ date_created: p.date_created
748
+ }))
749
+ };
750
+ }
751
+ }),
752
+ cancel_payment: ai.tool({
753
+ description: desc("cancel_payment"),
754
+ inputSchema: zod.z.object({ payment_id: zod.z.string() }),
755
+ execute: async ({ payment_id }) => {
756
+ const cancelled = await client.cancelPayment(payment_id);
757
+ return {
758
+ payment_id: cancelled.id,
759
+ status: cancelled.status,
760
+ message: "Payment cancelled. If it was already approved, use refund_payment instead."
761
+ };
762
+ }
763
+ }),
764
+ capture_payment: ai.tool({
765
+ description: desc("capture_payment"),
766
+ inputSchema: zod.z.object({
767
+ payment_id: zod.z.string(),
768
+ amount_ars: zod.z.number().positive().optional().describe("Optional partial-capture amount. Omit to capture full authorized amount.")
769
+ }),
770
+ execute: async ({ payment_id, amount_ars }) => {
771
+ const captured = await client.capturePayment(payment_id, amount_ars);
772
+ return {
773
+ payment_id: captured.id,
774
+ status: captured.status,
775
+ amount: captured.transaction_amount
776
+ };
777
+ }
778
+ }),
779
+ // ─────────────────────────────────────────────────────────────────────────
780
+ // Refunds
781
+ // ─────────────────────────────────────────────────────────────────────────
782
+ refund_payment: ai.tool({
783
+ description: desc("refund_payment"),
784
+ inputSchema: zod.z.object({
785
+ payment_id: zod.z.string(),
786
+ amount_ars: zod.z.number().positive().optional().describe("Partial-refund amount in ARS. Omit for full refund.")
787
+ }),
788
+ execute: async ({ payment_id, amount_ars }) => {
789
+ const refund = await client.createRefund({
790
+ paymentId: payment_id,
791
+ ...amount_ars !== void 0 ? { amount: amount_ars } : {},
792
+ idempotencyKey: `refund-${payment_id}-${amount_ars ?? "full"}`
793
+ });
794
+ return {
795
+ refund_id: refund.id,
796
+ payment_id: refund.payment_id,
797
+ amount: refund.amount,
798
+ status: refund.status,
799
+ message: amount_ars === void 0 ? "Full refund issued. Funds return to the buyer in 3-10 business days." : `Partial refund of ${amount_ars} ARS issued.`
800
+ };
801
+ }
802
+ }),
803
+ list_refunds: ai.tool({
804
+ description: desc("list_refunds"),
805
+ inputSchema: zod.z.object({ payment_id: zod.z.string() }),
806
+ execute: async ({ payment_id }) => {
807
+ const refunds = await client.listRefunds(payment_id);
808
+ return {
809
+ payment_id,
810
+ count: refunds.length,
811
+ refunds: refunds.map((r) => ({
812
+ refund_id: r.id,
813
+ amount: r.amount,
814
+ status: r.status,
815
+ date_created: r.date_created
816
+ }))
817
+ };
818
+ }
819
+ }),
820
+ // ─────────────────────────────────────────────────────────────────────────
821
+ // Checkout Pro
822
+ // ─────────────────────────────────────────────────────────────────────────
823
+ create_payment_preference: ai.tool({
824
+ description: desc("create_payment_preference"),
825
+ inputSchema: zod.z.object({
826
+ items: zod.z.array(zod.z.object({
827
+ title: zod.z.string().min(1).max(256),
828
+ quantity: zod.z.number().int().positive(),
829
+ unit_price: zod.z.number().positive(),
830
+ description: zod.z.string().optional(),
831
+ picture_url: zod.z.string().url().optional()
832
+ })).min(1).describe("Items being charged. At least one required."),
833
+ payer_email: zod.z.string().email().optional().describe("Pre-fill the payer email on Checkout Pro form"),
834
+ external_reference: zod.z.string().optional(),
835
+ max_installments: zod.z.number().int().min(1).max(24).optional().describe("Limit max cuotas offered. Defaults to MP account config."),
836
+ statement_descriptor: zod.z.string().max(13).optional(),
837
+ excluded_payment_types: zod.z.array(zod.z.enum(["credit_card", "debit_card", "ticket", "atm", "bank_transfer"])).optional().describe("Block payment types \u2014 e.g., ['ticket'] to disable Rapipago/Pago F\xE1cil")
838
+ }),
839
+ execute: async (input) => {
840
+ const pref = await client.createPreference({
841
+ items: input.items.map((it) => ({
842
+ title: it.title,
843
+ quantity: it.quantity,
844
+ unit_price: it.unit_price,
845
+ currency_id: "ARS",
846
+ ...it.description !== void 0 ? { description: it.description } : {},
847
+ ...it.picture_url !== void 0 ? { picture_url: it.picture_url } : {}
848
+ })),
849
+ ...input.payer_email !== void 0 ? { payer: { email: input.payer_email } } : {},
850
+ ...input.external_reference !== void 0 ? { externalReference: input.external_reference } : {},
851
+ ...input.statement_descriptor !== void 0 ? { statementDescriptor: input.statement_descriptor } : {},
852
+ backUrls: { success: options.backUrl, failure: options.backUrl, pending: options.backUrl },
853
+ autoReturn: "approved",
854
+ ...options.notificationUrl !== void 0 ? { notificationUrl: options.notificationUrl } : {},
855
+ ...input.max_installments !== void 0 || input.excluded_payment_types !== void 0 ? {
856
+ paymentMethods: {
857
+ ...input.max_installments !== void 0 ? { installments: input.max_installments } : {},
858
+ ...input.excluded_payment_types !== void 0 ? { excluded_payment_types: input.excluded_payment_types.map((id) => ({ id })) } : {}
859
+ }
860
+ } : {}
861
+ });
862
+ return {
863
+ preference_id: pref.id,
864
+ init_point_url: pref.init_point ?? null,
865
+ sandbox_init_point_url: pref.sandbox_init_point ?? null,
866
+ external_reference: pref.external_reference,
867
+ date_created: pref.date_created,
868
+ next_step: "Send init_point_url (or sandbox_init_point_url in sandbox) to the customer. After they pay, MP fires a webhook with the payment_id; use get_payment to confirm status."
869
+ };
870
+ }
871
+ }),
872
+ get_payment_preference: ai.tool({
873
+ description: desc("get_payment_preference"),
874
+ inputSchema: zod.z.object({ preference_id: zod.z.string() }),
875
+ execute: async ({ preference_id }) => {
876
+ const pref = await client.getPreference(preference_id);
877
+ return {
878
+ preference_id: pref.id,
879
+ init_point_url: pref.init_point ?? null,
880
+ sandbox_init_point_url: pref.sandbox_init_point ?? null,
881
+ external_reference: pref.external_reference,
882
+ items: pref.items,
883
+ date_created: pref.date_created
884
+ };
885
+ }
886
+ }),
887
+ // ─────────────────────────────────────────────────────────────────────────
888
+ // Customers + Saved Cards
889
+ // ─────────────────────────────────────────────────────────────────────────
890
+ create_customer: ai.tool({
891
+ description: desc("create_customer"),
892
+ inputSchema: zod.z.object({
893
+ email: zod.z.string().email(),
894
+ first_name: zod.z.string().optional(),
895
+ last_name: zod.z.string().optional(),
896
+ identification: zod.z.object({
897
+ type: zod.z.enum(["DNI", "CUIT", "CUIL"]),
898
+ number: zod.z.string()
899
+ }).optional(),
900
+ description: zod.z.string().optional()
901
+ }),
902
+ execute: async (input) => {
903
+ const customer = await client.createCustomer({
904
+ email: input.email,
905
+ ...input.first_name !== void 0 ? { firstName: input.first_name } : {},
906
+ ...input.last_name !== void 0 ? { lastName: input.last_name } : {},
907
+ ...input.identification !== void 0 ? { identification: input.identification } : {},
908
+ ...input.description !== void 0 ? { description: input.description } : {}
909
+ });
910
+ return {
911
+ customer_id: customer.id,
912
+ email: customer.email,
913
+ first_name: customer.first_name,
914
+ last_name: customer.last_name,
915
+ date_created: customer.date_created
916
+ };
917
+ }
918
+ }),
919
+ find_customer_by_email: ai.tool({
920
+ description: desc("find_customer_by_email"),
921
+ inputSchema: zod.z.object({ email: zod.z.string().email() }),
922
+ execute: async ({ email }) => {
923
+ const result = await client.searchCustomers({ email, limit: 1 });
924
+ const customer = result.results[0] ?? null;
925
+ return customer ? {
926
+ found: true,
927
+ customer_id: customer.id,
928
+ email: customer.email,
929
+ first_name: customer.first_name,
930
+ last_name: customer.last_name
931
+ } : { found: false, customer_id: null };
932
+ }
933
+ }),
934
+ list_customer_cards: ai.tool({
935
+ description: desc("list_customer_cards"),
936
+ inputSchema: zod.z.object({ customer_id: zod.z.string() }),
937
+ execute: async ({ customer_id }) => {
938
+ const cards = await client.listCustomerCards(customer_id);
939
+ return {
940
+ customer_id,
941
+ count: cards.length,
942
+ cards: cards.map((c) => ({
943
+ card_id: c.id,
944
+ last_four_digits: c.last_four_digits,
945
+ expiration_month: c.expiration_month,
946
+ expiration_year: c.expiration_year,
947
+ payment_method: c.payment_method?.id ?? null,
948
+ payment_method_name: c.payment_method?.name ?? null
949
+ }))
950
+ };
951
+ }
952
+ }),
953
+ delete_customer_card: ai.tool({
954
+ description: desc("delete_customer_card"),
955
+ inputSchema: zod.z.object({
956
+ customer_id: zod.z.string(),
957
+ card_id: zod.z.string()
958
+ }),
959
+ execute: async ({ customer_id, card_id }) => {
960
+ await client.deleteCustomerCard(customer_id, card_id);
961
+ return { customer_id, card_id, deleted: true };
962
+ }
963
+ }),
964
+ // ─────────────────────────────────────────────────────────────────────────
965
+ // Payment Methods + Installments
966
+ // ─────────────────────────────────────────────────────────────────────────
967
+ list_payment_methods: ai.tool({
968
+ description: desc("list_payment_methods"),
969
+ inputSchema: zod.z.object({}),
970
+ execute: async () => {
971
+ const methods = await client.listPaymentMethods();
972
+ return {
973
+ count: methods.length,
974
+ methods: methods.map((m) => ({
975
+ id: m.id,
976
+ name: m.name,
977
+ payment_type: m.payment_type_id,
978
+ status: m.status,
979
+ min_amount: m.min_allowed_amount,
980
+ max_amount: m.max_allowed_amount
981
+ }))
982
+ };
983
+ }
984
+ }),
985
+ calculate_installments: ai.tool({
986
+ description: desc("calculate_installments"),
987
+ inputSchema: zod.z.object({
988
+ amount_ars: zod.z.number().positive(),
989
+ payment_method_id: zod.z.string().optional().describe("E.g. 'visa', 'master', 'naranja'. Omit for all available methods."),
990
+ bin: zod.z.string().min(6).max(8).optional().describe("First 6-8 digits of card for issuer-specific offers (e.g., Naranja interest-free promotions)")
991
+ }),
992
+ execute: async (input) => {
993
+ const offers = await client.getInstallments({
994
+ amount: input.amount_ars,
995
+ ...input.payment_method_id !== void 0 ? { paymentMethodId: input.payment_method_id } : {},
996
+ ...input.bin !== void 0 ? { bin: input.bin } : {}
997
+ });
998
+ return {
999
+ amount: input.amount_ars,
1000
+ offers: offers.map((o) => ({
1001
+ payment_method_id: o.payment_method_id,
1002
+ payment_type_id: o.payment_type_id,
1003
+ issuer_name: o.issuer?.name ?? null,
1004
+ options: o.payer_costs.map((pc) => ({
1005
+ installments: pc.installments,
1006
+ installment_amount: pc.installment_amount,
1007
+ total_amount: pc.total_amount,
1008
+ installment_rate: pc.installment_rate,
1009
+ recommended_message: pc.recommended_message
1010
+ }))
1011
+ }))
1012
+ };
1013
+ }
1014
+ }),
1015
+ // ─────────────────────────────────────────────────────────────────────────
1016
+ // Account
1017
+ // ─────────────────────────────────────────────────────────────────────────
1018
+ get_account_info: ai.tool({
1019
+ description: desc("get_account_info"),
1020
+ inputSchema: zod.z.object({}),
1021
+ execute: async () => {
1022
+ const me = await client.getMe();
1023
+ return {
1024
+ account_id: me.id,
1025
+ email: me.email,
1026
+ nickname: me.nickname,
1027
+ country_id: me.country_id,
1028
+ site_id: me.site_id,
1029
+ user_type: me.user_type
1030
+ };
1031
+ }
370
1032
  })
371
1033
  };
372
1034
  }
@@ -431,6 +1093,151 @@ var WebhookBodySchema = zod.z.object({
431
1093
  id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
432
1094
  live_mode: zod.z.boolean().optional()
433
1095
  }).passthrough();
1096
+ var PaymentStatusSchema = zod.z.union([
1097
+ zod.z.literal("pending"),
1098
+ zod.z.literal("approved"),
1099
+ zod.z.literal("authorized"),
1100
+ zod.z.literal("in_process"),
1101
+ zod.z.literal("in_mediation"),
1102
+ zod.z.literal("rejected"),
1103
+ zod.z.literal("cancelled"),
1104
+ zod.z.literal("refunded"),
1105
+ zod.z.literal("charged_back"),
1106
+ zod.z.string()
1107
+ ]);
1108
+ var PaymentSchema = zod.z.object({
1109
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1110
+ status: PaymentStatusSchema,
1111
+ status_detail: zod.z.string().nullable().optional(),
1112
+ date_created: zod.z.string().nullable().optional(),
1113
+ date_approved: zod.z.string().nullable().optional(),
1114
+ date_last_updated: zod.z.string().nullable().optional(),
1115
+ transaction_amount: zod.z.number(),
1116
+ currency_id: zod.z.string(),
1117
+ installments: zod.z.number().int().nullable().optional(),
1118
+ payment_method_id: zod.z.string().nullable().optional(),
1119
+ payment_type_id: zod.z.string().nullable().optional(),
1120
+ external_reference: zod.z.string().nullable().optional(),
1121
+ description: zod.z.string().nullable().optional(),
1122
+ payer: zod.z.object({
1123
+ id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1124
+ email: zod.z.string().nullable().optional(),
1125
+ identification: zod.z.object({
1126
+ type: zod.z.string().nullable().optional(),
1127
+ number: zod.z.string().nullable().optional()
1128
+ }).nullable().optional()
1129
+ }).passthrough().optional(),
1130
+ transaction_details: zod.z.object({
1131
+ net_received_amount: zod.z.number().nullable().optional(),
1132
+ total_paid_amount: zod.z.number().nullable().optional(),
1133
+ installment_amount: zod.z.number().nullable().optional()
1134
+ }).passthrough().optional()
1135
+ }).passthrough();
1136
+ zod.z.object({
1137
+ paging: zod.z.object({
1138
+ total: zod.z.number(),
1139
+ limit: zod.z.number(),
1140
+ offset: zod.z.number()
1141
+ }),
1142
+ results: zod.z.array(PaymentSchema)
1143
+ });
1144
+ zod.z.object({
1145
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1146
+ payment_id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1147
+ amount: zod.z.number(),
1148
+ source: zod.z.object({
1149
+ id: zod.z.string().nullable().optional(),
1150
+ name: zod.z.string().nullable().optional(),
1151
+ type: zod.z.string().nullable().optional()
1152
+ }).nullable().optional(),
1153
+ date_created: zod.z.string().nullable().optional(),
1154
+ status: zod.z.string().nullable().optional()
1155
+ }).passthrough();
1156
+ var PreferenceItemSchema = zod.z.object({
1157
+ id: zod.z.string().optional(),
1158
+ title: zod.z.string(),
1159
+ description: zod.z.string().optional(),
1160
+ picture_url: zod.z.string().url().optional(),
1161
+ category_id: zod.z.string().optional(),
1162
+ quantity: zod.z.number().int().positive(),
1163
+ unit_price: zod.z.number().positive(),
1164
+ currency_id: CurrencyIdSchema.optional()
1165
+ });
1166
+ zod.z.object({
1167
+ id: zod.z.string(),
1168
+ init_point: zod.z.string().url().optional(),
1169
+ sandbox_init_point: zod.z.string().url().optional(),
1170
+ client_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1171
+ collector_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1172
+ items: zod.z.array(PreferenceItemSchema).optional(),
1173
+ external_reference: zod.z.string().nullable().optional(),
1174
+ date_created: zod.z.string().nullable().optional(),
1175
+ expires: zod.z.boolean().optional(),
1176
+ expiration_date_from: zod.z.string().nullable().optional(),
1177
+ expiration_date_to: zod.z.string().nullable().optional()
1178
+ }).passthrough();
1179
+ zod.z.object({
1180
+ id: zod.z.string(),
1181
+ email: zod.z.string(),
1182
+ first_name: zod.z.string().nullable().optional(),
1183
+ last_name: zod.z.string().nullable().optional(),
1184
+ phone: zod.z.object({ area_code: zod.z.string().nullable().optional(), number: zod.z.string().nullable().optional() }).nullable().optional(),
1185
+ identification: zod.z.object({ type: zod.z.string().nullable().optional(), number: zod.z.string().nullable().optional() }).nullable().optional(),
1186
+ date_created: zod.z.string().nullable().optional(),
1187
+ date_last_updated: zod.z.string().nullable().optional(),
1188
+ description: zod.z.string().nullable().optional()
1189
+ }).passthrough();
1190
+ zod.z.object({
1191
+ id: zod.z.string(),
1192
+ customer_id: zod.z.string(),
1193
+ expiration_month: zod.z.number().int().nullable().optional(),
1194
+ expiration_year: zod.z.number().int().nullable().optional(),
1195
+ first_six_digits: zod.z.string().nullable().optional(),
1196
+ last_four_digits: zod.z.string().nullable().optional(),
1197
+ payment_method: zod.z.object({
1198
+ id: zod.z.string().nullable().optional(),
1199
+ name: zod.z.string().nullable().optional(),
1200
+ payment_type_id: zod.z.string().nullable().optional()
1201
+ }).nullable().optional(),
1202
+ date_created: zod.z.string().nullable().optional()
1203
+ }).passthrough();
1204
+ zod.z.object({
1205
+ id: zod.z.string(),
1206
+ name: zod.z.string(),
1207
+ payment_type_id: zod.z.string(),
1208
+ status: zod.z.string(),
1209
+ thumbnail: zod.z.string().nullable().optional(),
1210
+ secure_thumbnail: zod.z.string().nullable().optional(),
1211
+ min_allowed_amount: zod.z.number().nullable().optional(),
1212
+ max_allowed_amount: zod.z.number().nullable().optional()
1213
+ }).passthrough();
1214
+ zod.z.object({
1215
+ payment_method_id: zod.z.string(),
1216
+ payment_type_id: zod.z.string(),
1217
+ issuer: zod.z.object({
1218
+ id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1219
+ name: zod.z.string().nullable().optional()
1220
+ }).nullable().optional(),
1221
+ payer_costs: zod.z.array(
1222
+ zod.z.object({
1223
+ installments: zod.z.number().int(),
1224
+ installment_rate: zod.z.number(),
1225
+ discount_rate: zod.z.number().nullable().optional(),
1226
+ installment_amount: zod.z.number(),
1227
+ total_amount: zod.z.number(),
1228
+ recommended_message: zod.z.string().nullable().optional()
1229
+ }).passthrough()
1230
+ )
1231
+ }).passthrough();
1232
+ zod.z.object({
1233
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1234
+ email: zod.z.string().nullable().optional(),
1235
+ nickname: zod.z.string().nullable().optional(),
1236
+ country_id: zod.z.string().nullable().optional(),
1237
+ site_id: zod.z.string().nullable().optional(),
1238
+ user_type: zod.z.string().nullable().optional(),
1239
+ status: zod.z.object({ user_type: zod.z.string().nullable().optional() }).passthrough().nullable().optional()
1240
+ }).passthrough();
434
1241
 
435
1242
  // src/webhook.ts
436
1243
  function parseWebhookEvent(body, searchParams) {