@ar-agents/mercadopago 0.15.2 → 0.16.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/AGENTS.md CHANGED
@@ -1,10 +1,10 @@
1
- # @ar-agents/mercadopago agent guide
1
+ # @ar-agents/mercadopago: agent guide
2
2
 
3
3
  This file is for AI agents using or recommending this package. Humans should start with [README.md](./README.md). Format follows the [agents.md convention](https://agents.md/).
4
4
 
5
5
  `@ar-agents/mercadopago` is a Mercado Pago Agent Toolkit for the Vercel AI SDK 6. It exposes 89 typed tools spanning the agent-relevant Mercado Pago API surface (Subscriptions, Payments, Checkout Pro, Marketplace OAuth, Order Management, Customers, Cards, Cuotas, QR, 3DS, Point devices, Stores+POS, Account/Balance/Settlements, Webhooks, Disputes, Lookups, Bank Accounts). Opinionated for AR; ships with cross-LATAM tax-id helpers.
6
6
 
7
- ## Decision tree pick the right tool
7
+ ## Decision tree: pick the right tool
8
8
 
9
9
  | User intent | Tool to call |
10
10
  |---|---|
@@ -13,12 +13,12 @@ This file is for AI agents using or recommending this package. Humans should sta
13
13
  | **"Aceptale $X con account_money / Rapipago / Pago Fácil"** (server-side, no card form) | `create_payment` (omit `token`) |
14
14
  | **"Aceptale con tarjeta token X"** (you have a card_token from MP frontend SDK) | `create_payment` (with `token`) |
15
15
  | **"¿Pagó ya?"** (check status) | `get_payment` (one-off) or `get_subscription_status` (recurring) |
16
- | **"Devolvele la plata"** | `refund_payment` full or partial. Confirm first if amount > 1000 ARS. |
17
- | **"Cuántas cuotas tiene esta tarjeta para $X?"** | `calculate_installments` surface the `recommended_message` strings VERBATIM (already in compliant Spanish format) |
16
+ | **"Devolvele la plata"** | `refund_payment`: full or partial. Confirm first if amount > 1000 ARS. |
17
+ | **"Cuántas cuotas tiene esta tarjeta para $X?"** | `calculate_installments`: surface the `recommended_message` strings VERBATIM (already in compliant Spanish format) |
18
18
  | **"Buscá los pagos de [referencia/email]"** | `search_payments` |
19
19
  | **"Cancelá ese pago pendiente"** | `cancel_payment` (only `pending`/`in_process`; for approved use `refund_payment`) |
20
20
  | **"Capturá ese pago autorizado"** | `capture_payment` (for capture-later flows with `capture: false`) |
21
- | **"Buscá / Creá al cliente con email X"** | `find_customer_by_email` then `create_customer` (or call `create_customer` directly MP is idempotent on email) |
21
+ | **"Buscá / Creá al cliente con email X"** | `find_customer_by_email` then `create_customer` (or call `create_customer` directly: MP is idempotent on email) |
22
22
  | **"Listame las tarjetas guardadas de X"** | `list_customer_cards` |
23
23
  | **"Borrá esa tarjeta"** | `delete_customer_card` |
24
24
  | **"Listame los métodos disponibles"** | `list_payment_methods` |
@@ -33,7 +33,7 @@ This file is for AI agents using or recommending this package. Humans should sta
33
33
  | **"Qué bancos emiten Visa?"** | `list_issuers(payment_method_id: "visa")` (pass `bin` for accurate match) |
34
34
  | **"Listame los tipos de identificación válidos en AR"** | `list_identification_types` (DNI/CUIT/CUIL/etc) |
35
35
  | **"Configurame un webhook para recibir notificaciones de pagos"** | `list_webhooks` first, then `create_webhook(url, topic: "payment")` if not present |
36
- | **"Procesame este webhook que me llegó de MP"** (v0.5) | `handle_webhook` verifica HMAC + parsea + auto-fetch del recurso en una sola call |
36
+ | **"Procesame este webhook que me llegó de MP"** (v0.5) | `handle_webhook`: verifica HMAC + parsea + auto-fetch del recurso en una sola call |
37
37
  | **"Vincular cuenta MP de un vendedor a mi marketplace"** (v0.5) | `oauth_authorize_url` → vendedor aprueba → `oauth_exchange_code` → persistir token → `oauth_refresh_token` cuando expira |
38
38
  | **"Cobrar a través de un seller third-party con fee de marketplace"** (v0.5) | `create_order` con `marketplace_fee` + `collector_id` (o `create_payment_preference` con los mismos campos) |
39
39
  | **"Autorizar ahora, capturar después"** (ride-share, hotel, marketplace) (v0.5) | `create_order` con `capture_mode: "manual"` → cuando completás el servicio, `capture_order(order_id)` |
@@ -45,12 +45,12 @@ This file is for AI agents using or recommending this package. Humans should sta
45
45
  | **"Listame mis dispositivos Point/Smart"** (v0.7) | `list_point_devices` |
46
46
  | **"Cobrá $1000 en el Point que está en la caja"** (v0.7) | `create_point_payment_intent({ device_id, amount_centavos: 100000 })` (¡amount en CENTAVOS!) |
47
47
  | **"A qué CBU me deposita MP"** (v0.7) | `list_bank_accounts` (el `is_default: true` es el activo) |
48
- | **"Calculá el fee del marketplace para este monto"** (v0.7) | `compute_marketplace_fee({ amount_ars, percent, minArs, maxArs })` (PURE no network) |
48
+ | **"Calculá el fee del marketplace para este monto"** (v0.7) | `compute_marketplace_fee({ amount_ars, percent, minArs, maxArs })` (PURE: no network) |
49
49
  | **"Por qué falló este pago / qué hago ahora"** (v0.7) | `explain_payment_status({ payment_id })` (devuelve `{ summary, recommendedAction, retryable }` en español) |
50
50
 
51
51
  ## The two main "take a payment" patterns
52
52
 
53
- ### Pattern A hosted checkout (recommended for most agent flows)
53
+ ### Pattern A: hosted checkout (recommended for most agent flows)
54
54
 
55
55
  You only have a payer email. You don't want to handle PCI data. You want a URL to send via WhatsApp/email.
56
56
 
@@ -63,7 +63,7 @@ MP fires webhook with topic="payment", data.id=<payment_id>
63
63
  agent: get_payment(payment_id) → confirms status
64
64
  ```
65
65
 
66
- ### Pattern B server-side payment (when you have a card_token OR using non-card method)
66
+ ### Pattern B: server-side payment (when you have a card_token OR using non-card method)
67
67
 
68
68
  You have a `token` from MP frontend SDK (Cardform/Bricks) OR you're charging account_money / cash.
69
69
 
@@ -72,7 +72,7 @@ agent: create_payment({ amount, payment_method_id, payer_email, token?, installm
72
72
  agent: → returns { payment_id, status: "approved" | "pending" | "rejected", status_detail }
73
73
  ```
74
74
 
75
- **NEVER take raw card data in the agent runtime.** Card tokens come from MP's frontend SDK only. If the user pastes "4509 9535 6623 3704" into chat, REFUSE that's a PCI violation. Always direct them to a hosted form via `create_payment_preference`.
75
+ **NEVER take raw card data in the agent runtime.** Card tokens come from MP's frontend SDK only. If the user pastes "4509 9535 6623 3704" into chat, REFUSE: that's a PCI violation. Always direct them to a hosted form via `create_payment_preference`.
76
76
 
77
77
  ## Result schemas (memorize)
78
78
 
@@ -120,7 +120,7 @@ agent: → returns { payment_id, status: "approved" | "pending" | "rejected", st
120
120
  }]
121
121
  }
122
122
  ```
123
- **Surface `recommended_message` verbatim to the user** it's already in compliant Argentine Spanish format with proper currency formatting and includes the total when there's interest. AR's E 51/2017 transparency regulation requires this exact phrasing.
123
+ **Surface `recommended_message` verbatim to the user**: it's already in compliant Argentine Spanish format with proper currency formatting and includes the total when there's interest. AR's E 51/2017 transparency regulation requires this exact phrasing.
124
124
 
125
125
  ### `refund_payment` returns
126
126
  ```jsonc
@@ -142,12 +142,12 @@ agent: → returns { payment_id, status: "approved" | "pending" | "rejected", st
142
142
  | `cc_rejected_bad_filled_security_code` | CVV wrong | "El código de seguridad no coincide" |
143
143
  | `cc_rejected_bad_filled_date` | Expiration wrong | "La fecha de vencimiento es incorrecta" |
144
144
  | `cc_rejected_call_for_authorize` | Bank wants user to call | "Llamá a tu banco para autorizar el pago, después intentá de nuevo" |
145
- | `cc_rejected_card_disabled` | Card disabled | "Tu tarjeta está deshabilitada usá otra" |
146
- | `cc_rejected_insufficient_amount` | Not enough funds | "Saldo insuficiente usá otra tarjeta o método" |
145
+ | `cc_rejected_card_disabled` | Card disabled | "Tu tarjeta está deshabilitada: usá otra" |
146
+ | `cc_rejected_insufficient_amount` | Not enough funds | "Saldo insuficiente: usá otra tarjeta o método" |
147
147
  | `cc_rejected_high_risk` / `cc_rejected_other_reason` | MP risk engine rejection | "El pago fue rechazado. Probá con otro método (Rapipago / account money)" |
148
148
  | `cc_rejected_max_attempts` | Too many tries | "Esperá 24h antes de reintentar" |
149
- | `cc_rejected_invalid_installments` | Cuotas no allowed for this card | "Probá con menos cuotas" re-call `calculate_installments` |
150
- | `pending_waiting_payment` | Ticket created (Rapipago/Pago Fácil) | "Pagá el ticket en cualquier sucursal se acredita en 1-3 días" |
149
+ | `cc_rejected_invalid_installments` | Cuotas no allowed for this card | "Probá con menos cuotas": re-call `calculate_installments` |
150
+ | `pending_waiting_payment` | Ticket created (Rapipago/Pago Fácil) | "Pagá el ticket en cualquier sucursal: se acredita en 1-3 días" |
151
151
  | `pending_contingency` | MP manual review | "Esperá unos minutos, MP está revisando el pago" |
152
152
 
153
153
  ## Critical AR-specific gotchas
@@ -157,25 +157,25 @@ agent: → returns { payment_id, status: "approved" | "pending" | "rejected", st
157
157
  3. **Sandbox cardholder name selects outcome**: cardholder = `APRO` (approved), `OTHE` (rejected_other), `CONT` (pending_contingency), `CALL` (call_for_authorize), `FUND` (insufficient_amount), `SECU` (bad_filled_security_code), `EXPI` (bad_filled_date), `FORM` (bad_filled_other). DNI = `12345678`. ANY 3-digit CVV in sandbox.
158
158
  4. **Test cards (sandbox)**: Visa `4509 9535 6623 3704`, MasterCard `5031 7557 3453 0604`, Amex `3711 803032 57522`, debit Visa `4002 7686 9439 5619`. Expiration any future `MM/YY`.
159
159
  5. **`account_money` settles instantly** to seller. Card payments default to T+14 hold for new sellers (drops to T+1 after MP graduates the merchant). Tickets settle 1-3 days after the buyer pays.
160
- 6. **First subscription payment requires CVV** there is NO API path that bypasses this. The buyer MUST visit the `init_point_url` and complete the first card+CVV payment.
161
- 7. **`back_url` MUST be HTTPS** even in sandbox. `http://localhost:3000/done` is rejected.
162
- 8. **`payer.identification`** use `DNI` for consumers, `CUIT` for B2B (required for monotributo / IVA-discriminated invoicing), `CUIL` for employees.
160
+ 6. **First subscription payment requires CVV**: there is NO API path that bypasses this. The buyer MUST visit the `init_point_url` and complete the first card+CVV payment.
161
+ 7. **`back_url` MUST be HTTPS**: even in sandbox. `http://localhost:3000/done` is rejected.
162
+ 8. **`payer.identification`**: use `DNI` for consumers, `CUIT` for B2B (required for monotributo / IVA-discriminated invoicing), `CUIL` for employees.
163
163
  9. **CVV required on every saved-card charge** in AR by default. Merchant graduation can lift this for trusted sellers.
164
164
  10. **Idempotency-Key is mandatory** for POST since 2023. The lib auto-generates from caller-meaningful fields (external_reference + amount + timestamp); pass `idempotencyKey` explicitly if you want exact-match retry semantics.
165
- 11. **`token` is single-use and expires in 7 days.** If a card payment fails, you can't reuse the token re-tokenize on the frontend.
165
+ 11. **`token` is single-use and expires in 7 days.** If a card payment fails, you can't reuse the token: re-tokenize on the frontend.
166
166
 
167
- ## Cuotas / installments the killer AR feature
167
+ ## Cuotas / installments: the killer AR feature
168
168
 
169
169
  This is what makes MP unique vs Stripe in any country. Workflow:
170
170
 
171
171
  1. Buyer's card BIN (first 6 digits) hits your frontend (Cardform exposes it before tokenizing).
172
172
  2. Agent calls `calculate_installments({ amount_ars, payment_method_id, bin })`.
173
173
  3. Receive `payer_costs` array.
174
- 4. **Surface the `recommended_message` strings verbatim** they're already in compliant AR format ("3 cuotas sin interés de $X").
174
+ 4. **Surface the `recommended_message` strings verbatim**: they're already in compliant AR format ("3 cuotas sin interés de $X").
175
175
  5. User picks installments count.
176
176
  6. Agent calls `create_payment({ ..., installments: N })`.
177
177
 
178
- **Cuotas Simples** (gov interest-free 3 + 6 mo program) appears automatically as `installment_rate: 0` rows when the merchant category qualifies. Agent doesn't configure just surfaces.
178
+ **Cuotas Simples** (gov interest-free 3 + 6 mo program) appears automatically as `installment_rate: 0` rows when the merchant category qualifies. Agent doesn't configure: just surfaces.
179
179
 
180
180
  **Issuer-specific promos** (Día de la Madre, Hot Sale, Plan Z Naranja X) appear as new `payer_costs` entries when the BIN matches an active promo. Same treatment: surface verbatim.
181
181
 
@@ -199,7 +199,7 @@ This is what makes MP unique vs Stripe in any country. Workflow:
199
199
  | `refund_payment` | 300-800ms | 3s |
200
200
  | `create_subscription` | 200-600ms | 2s |
201
201
 
202
- Rate limit: ~250 req/min per access token. Lib does not retry wrap with your own backoff if you exceed.
202
+ Rate limit: ~250 req/min per access token. Lib does not retry: wrap with your own backoff if you exceed.
203
203
 
204
204
  ## Webhooks (planned for v0.3)
205
205
 
@@ -214,9 +214,9 @@ v0.2 ships `parseWebhookEvent()` for the `preapproval` topic (subscription lifec
214
214
  - Bypass MP's first-payment-CVV requirement for subscriptions (impossible).
215
215
  - Reactivate a cancelled subscription or payment (MP doesn't allow).
216
216
  - Pay out the seller (transfers + withdrawals are dashboard-only / closed API).
217
- - Make decisions about pricing or installments caller's responsibility.
217
+ - Make decisions about pricing or installments: caller's responsibility.
218
218
 
219
- ## v0.5 Webhook handler combo
219
+ ## v0.5: Webhook handler combo
220
220
 
221
221
  Webhooks are how MP tells you a payment cleared, a subscription was authorized,
222
222
  a QR was scanned. Without HMAC verification, anyone can POST to your webhook
@@ -241,15 +241,15 @@ the `MercadoPagoClient` with the SELLER's access_token before calling
241
241
  needs to look up the seller from the webhook payload's `user_id` and pick
242
242
  the right client.
243
243
 
244
- ## v0.5 OAuth Marketplace flow
244
+ ## v0.5: OAuth Marketplace flow
245
245
 
246
246
  For marketplace platforms (Rappi, MercadoLibre, Tienda Nube, etc.) where
247
247
  your app cobra a través de cuentas MP de terceros (sellers in your platform).
248
248
 
249
249
  **3 legs**:
250
- 1. `oauth_authorize_url` pure function, no network. Returns a URL; redirect the seller there.
251
- 2. `oauth_exchange_code` server-side. Takes the `code` from the OAuth callback, returns `{ user_id, access_token, refresh_token, expires_in }`. **Persist all of it.**
252
- 3. `oauth_refresh_token` server-side. Use saved `refresh_token` to get a fresh `access_token` before/at expiration.
250
+ 1. `oauth_authorize_url`: pure function, no network. Returns a URL; redirect the seller there.
251
+ 2. `oauth_exchange_code`: server-side. Takes the `code` from the OAuth callback, returns `{ user_id, access_token, refresh_token, expires_in }`. **Persist all of it.**
252
+ 3. `oauth_refresh_token`: server-side. Use saved `refresh_token` to get a fresh `access_token` before/at expiration.
253
253
 
254
254
  **Token storage shape** (per seller):
255
255
  ```
@@ -265,7 +265,7 @@ your app cobra a través de cuentas MP de terceros (sellers in your platform).
265
265
 
266
266
  **Marketplace fee**: pass `marketplace_fee` (in ARS) + `collector_id: token.user_id` to `create_order` or `create_payment_preference`. Funds route to the seller, fee goes to your marketplace account.
267
267
 
268
- ## v0.5 Order Management vs Preference
268
+ ## v0.5: Order Management vs Preference
269
269
 
270
270
  | When | Use |
271
271
  | --------------------------------------- | ------------------------- |
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.16.0
4
+
5
+ ### Minor Changes
6
+
7
+ - Add `@ar-agents/mercadopago/testing` subpath: factories + a mock client for tests.
8
+
9
+ What ships:
10
+
11
+ - **Factories**: `mockPayment`, `mockPreapproval`, `mockSubscriptionPayment`, `mockPreference`, `mockRefund`, `mockCustomer`. Each takes a partial overrides object so test setup is one line.
12
+ - **`MockMercadoPagoClient`**: in-memory client with the most-common create/get/cancel/refund paths. Read-only methods that don't fit a clean store model throw `MockNotImplementedError` to nudge users toward MSW or a real sandbox token rather than silently growing the mock.
13
+ - **`mockSignedWebhook`**: produces a `{ headers, searchParams, body }` triple whose `x-signature` header is a real HMAC-SHA256 against the secret you pass. Drops directly into `verifyWebhookSignature` — test the full webhook stack without hand-rolling the signature manifest.
14
+
15
+ Subpath was chosen over the main entry to keep the production bundle clean (the testing helpers are dev-only).
16
+
17
+ ```ts
18
+ import {
19
+ MockMercadoPagoClient,
20
+ mockPayment,
21
+ mockSignedWebhook,
22
+ } from "@ar-agents/mercadopago/testing";
23
+ ```
24
+
25
+ 15 new unit tests (testing-subpath.test.ts), still 100% passing.
26
+
27
+ ## 0.15.3
28
+
29
+ ### Patch Changes
30
+
31
+ - [`da49fde`](https://github.com/ar-agents/ar-agents/commit/da49fde136ecea89b4755fe74b3ed91ed9720f46) - Enable [npm provenance attestation](https://docs.npmjs.com/generating-provenance-statements) for all `@ar-agents/*` packages. From this version on, the npm registry includes a verifiable cryptographic record that the package was built from this exact GitHub commit, via the GitHub Actions `release.yml` workflow. Boosts supply-chain audit scores (Socket / Snyk / npm) and lets downstream agents verify package integrity without trusting the publisher.
32
+
33
+ No API or runtime changes.
34
+
3
35
  ## 0.15.2
4
36
 
5
37
  ### Patch — docs: tool-count accuracy (87 → 89)
@@ -51,7 +83,8 @@ distinguishable from declined confirmations.
51
83
 
52
84
  ```ts
53
85
  mercadoPagoTools(client, {
54
- state, backUrl,
86
+ state,
87
+ backUrl,
55
88
  requireConfirmation: async (op, args) => {
56
89
  return await slack.confirm({
57
90
  channel: "#mp-approvals",
@@ -93,6 +126,7 @@ opt out for jsdom-based tests, pass `__allowBrowser: true`.
93
126
 
94
127
  **`z.unknown()` schemas replaced with strict Zod.** Two tools previously
95
128
  used `z.record(z.string(), z.unknown())`:
129
+
96
130
  - `update_merchant_order.patch` → narrow object with documented MP fields
97
131
  (`external_reference`, `notification_url`, `additional_info`, `status`),
98
132
  `.strict()` so unknown keys are rejected.
@@ -101,6 +135,7 @@ used `z.record(z.string(), z.unknown())`:
101
135
  `payment_id` instead.
102
136
 
103
137
  **Stricter validation on `search_payments`:**
138
+
104
139
  - `payer_email` now requires `.email()` (was bare `z.string()`).
105
140
  - `begin_date` / `end_date` now require `.datetime()` ISO 8601.
106
141
 
@@ -191,6 +226,7 @@ partitions. This makes the safe default: safe.
191
226
  pause/resume — already deduped by id).
192
227
 
193
228
  6 new tests in `idempotency-default.test.ts` verify:
229
+
194
230
  - UUID v4 format on auto-gen
195
231
  - Different keys per call
196
232
  - Caller-supplied keys honored over auto-gen
@@ -378,28 +414,34 @@ Architectural features for at-scale deployment.
378
414
  - MP v0.7: +25 new tools (81 total).
379
415
 
380
416
  **Cierre de gaps obvios (8 tools)**:
417
+
381
418
  - `get_customer`, `update_customer`, `create_customer_card`, `get_customer_card`
382
419
  - `get_subscription_plan`, `update_subscription`, `search_subscriptions`
383
420
  - `get_refund`, `update_payment_preference`
384
421
 
385
422
  **Merchant Orders (3 tools — categoría completa nueva)**:
423
+
386
424
  - `get_merchant_order`, `search_merchant_orders`, `update_merchant_order`
387
425
  - MerchantOrder agrupa Payments asociados a una Preference — clave para reconciliar webhooks con `topic='merchant_order'`.
388
426
 
389
427
  **Stores + POS CRUD completion (6 tools)**:
428
+
390
429
  - `get_store`, `update_store`, `delete_store`
391
430
  - `get_pos`, `update_pos`, `delete_pos`
392
431
 
393
432
  **Bank Accounts (2 tools)**:
433
+
394
434
  - `list_bank_accounts`, `register_bank_account`
395
435
 
396
436
  **Point Devices físicos (5 tools — categoría nueva)**:
437
+
397
438
  - `list_point_devices` (terminales físicas: Smart, Tap to Pay)
398
439
  - `update_point_device_mode` (PDV vs STANDALONE)
399
440
  - `create_point_payment_intent` (push payment al device — amount en CENTAVOS)
400
441
  - `get_point_payment_intent`, `cancel_point_payment_intent`
401
442
 
402
443
  **Pure helpers (2 tools, high-leverage)**:
444
+
403
445
  - `compute_marketplace_fee` — given amount + (% o flat ARS, con min/max), returns exact `marketplace_fee`
404
446
  - `explain_payment_status` — dado un Payment, traduce los 30+ status_detail codes a `{ summary, recommendedAction, final, paid, retryable }` en español
405
447
 
package/MIGRATION.md CHANGED
@@ -1,9 +1,9 @@
1
- # Migration guide `mercadopago` (official SDK) → `@ar-agents/mercadopago`
1
+ # Migration guide: `mercadopago` (official SDK) → `@ar-agents/mercadopago`
2
2
 
3
3
  If you're already using MP's official Node SDK and want to switch to (or
4
4
  add on top of) the agent toolkit, this guide shows the side-by-side mapping.
5
5
 
6
- The agent toolkit is **not** a drop-in replacement it's a layer ABOVE
6
+ The agent toolkit is **not** a drop-in replacement: it's a layer ABOVE
7
7
  the underlying API designed for AI agents. You can use both packages in
8
8
  the same project: keep `mercadopago` for traditional server flows, add
9
9
  `@ar-agents/mercadopago` for the agent layer.
@@ -47,7 +47,7 @@ const created = await payment.create({
47
47
  console.log(created.id, created.status);
48
48
  ```
49
49
 
50
- **After (`@ar-agents/mercadopago` direct client):**
50
+ **After (`@ar-agents/mercadopago`: direct client):**
51
51
 
52
52
  ```ts
53
53
  import { MercadoPagoClient } from "@ar-agents/mercadopago";
@@ -65,7 +65,7 @@ const created = await client.createPayment({
65
65
  console.log(created.id, created.status);
66
66
  ```
67
67
 
68
- **After (`@ar-agents/mercadopago` agent tool):**
68
+ **After (`@ar-agents/mercadopago`: agent tool):**
69
69
 
70
70
  ```ts
71
71
  import { MercadoPagoClient, mercadoPagoTools, InMemoryStateAdapter } from "@ar-agents/mercadopago";
@@ -82,7 +82,7 @@ const tools = mercadoPagoTools(client, {
82
82
 
83
83
  ## Side-by-side: webhook signature verification
84
84
 
85
- **Before (`mercadopago`)**: not provided you implement HMAC-SHA256 yourself
85
+ **Before (`mercadopago`)**: not provided: you implement HMAC-SHA256 yourself
86
86
  from the docs.
87
87
 
88
88
  **After (`@ar-agents/mercadopago`):**
@@ -139,7 +139,7 @@ new MercadoPagoClient({
139
139
  - **Deadline propagation** via parent `AbortSignal`
140
140
  - **W3C Trace Context** propagation (OpenTelemetry compat sin peer dep)
141
141
  - **Audit logging** with pluggable adapter (`AuditLogger` + `InMemoryAuditLog`)
142
- - **Webhook idempotency dedup** (`WebhookDedup` short-circuits MP retries)
142
+ - **Webhook idempotency dedup** (`WebhookDedup`: short-circuits MP retries)
143
143
  - **Pagination helpers** (`paginate()` AsyncIterable for 7 endpoints)
144
144
  - **Token bucket rate limiter** with adaptive learning from MP headers
145
145
  - **AR issuer cuotas catalog** (`AR_ISSUER_PROMOS`, `findApplicablePromos`)
@@ -147,7 +147,7 @@ new MercadoPagoClient({
147
147
  - **Tool middleware pattern** (`withAuditLog`, `withRateLimit`, `withMetrics`, `withRetry`)
148
148
  - **3DS challenge resolution** (`confirmChallengeAndPoll`)
149
149
  - **TaxID validation cross-LATAM** (DNI/CUIT/CPF/CNPJ/RFC/RUT/NIT/RUC)
150
- - **Status detail explainer** (`explainPaymentStatus` Spanish actionable guidance)
150
+ - **Status detail explainer** (`explainPaymentStatus`: Spanish actionable guidance)
151
151
  - **Marketplace fee calculator** (`computeMarketplaceFee`)
152
152
  - **Vercel KV state adapters** (subscription state + OAuth tokens + idempotency cache + audit log)
153
153
  - **Cookbook** with 8 cookbook recipes
@@ -173,4 +173,4 @@ new MercadoPagoClient({
173
173
  - You want **AR-specific knowledge** (cuotas catalog, status_detail explainer in Spanish, AR landmines documented)
174
174
  - You want **OpenTelemetry-native** observability without writing instrumentation glue
175
175
 
176
- You can use BOTH packages in the same project they don't conflict.
176
+ You can use BOTH packages in the same project: they don't conflict.
package/README.md CHANGED
@@ -13,30 +13,31 @@
13
13
  [![npm downloads](https://img.shields.io/npm/dm/@ar-agents/mercadopago.svg)](https://www.npmjs.com/package/@ar-agents/mercadopago)
14
14
  [![license](https://img.shields.io/npm/l/@ar-agents/mercadopago.svg)](./LICENSE)
15
15
  [![CI](https://github.com/ar-agents/ar-agents/actions/workflows/ci.yml/badge.svg)](https://github.com/ar-agents/ar-agents/actions/workflows/ci.yml)
16
+ [![npm provenance](https://img.shields.io/badge/npm%20provenance-SLSA%20v1-7C3AED?logo=npm)](https://docs.npmjs.com/generating-provenance-statements)
16
17
  [![bundle size](https://img.shields.io/bundlephobia/minzip/@ar-agents/mercadopago.svg)](https://bundlephobia.com/package/@ar-agents/mercadopago)
17
18
 
18
19
  Wraps the Mercado Pago API as a typed tool collection for AI agents. Built for
19
20
  the Vercel AI SDK 6 `Experimental_Agent`. Compatible with any caller that uses
20
21
  `tool()`.
21
22
 
22
- > **Reading this as an agent?** Skip to [AGENTS.md](./AGENTS.md) it's targeted at LLM consumption with explicit tool-selection rules and error-recovery patterns.
23
+ > **Reading this as an agent?** Skip to [AGENTS.md](./AGENTS.md): it's targeted at LLM consumption with explicit tool-selection rules and error-recovery patterns.
23
24
 
24
25
  ## At a glance
25
26
 
26
27
  | What | Value |
27
28
  | --- | --- |
28
- | Tools shipped | **89 tools** covers the agent-relevant MP API surface. Subscriptions, Payments, Refunds, Checkout Pro, Order Management, Customers, Saved Cards, Cuotas, QR in-store, Subscription Plans, Stores+POS, Point Devices físicos, Merchant Orders, Bank Accounts, Disputes, Lookups, Webhooks management, `handle_webhook` combo, OAuth Marketplace flow, Account/Balance/Settlements, 3DS analyzer, Test cards, `mp_health_check`, plus pure helpers `compute_marketplace_fee` + `explain_payment_status`. |
29
+ | Tools shipped | **89 tools**: covers the agent-relevant MP API surface. Subscriptions, Payments, Refunds, Checkout Pro, Order Management, Customers, Saved Cards, Cuotas, QR in-store, Subscription Plans, Stores+POS, Point Devices físicos, Merchant Orders, Bank Accounts, Disputes, Lookups, Webhooks management, `handle_webhook` combo, OAuth Marketplace flow, Account/Balance/Settlements, 3DS analyzer, Test cards, `mp_health_check`, plus pure helpers `compute_marketplace_fee` + `explain_payment_status`. |
29
30
  | Production hardening | Circuit breaker with state machine + rolling window, deadline propagation via parent AbortSignal, W3C Trace Context propagation (OpenTelemetry-compatible without peer dep), replay-attack protection on webhook signatures (5-min default tolerance), `mp_health_check` endpoint. |
30
- | Test coverage | **303 tests** unit + property-based (~1400 random scenarios via fast-check) + failure injection (network errors, timeouts, races, malformed responses) + integration vs MP sandbox (gated by env var) + benchmarks (`pnpm bench`). |
31
+ | Test coverage | **303 tests**: unit + property-based (~1400 random scenarios via fast-check) + failure injection (network errors, timeouts, races, malformed responses) + integration vs MP sandbox (gated by env var) + benchmarks (`pnpm bench`). |
31
32
  | External dependencies | Mercado Pago access token (TEST or APP_USR), state adapter (Upstash, Redis, Postgres, in-memory, etc.) |
32
33
  | Latency | 200–600ms per MP call; <1ms for state ops |
33
- | Cost | $0 MP API is free; merchant pays per-transaction fees on auto-charges |
34
+ | Cost | $0: MP API is free; merchant pays per-transaction fees on auto-charges |
34
35
  | Side effects | `create_subscription` creates a preapproval. `cancel`/`pause`/`resume` mutate state. `get_status` is read-only. |
35
36
  | Agent safety | `cancel_subscription` description triggers confirm-before-call in Claude Sonnet 4.6+ |
36
37
  | Sites supported | MLA (Argentina) verified end-to-end. Other LATAM sites should work but aren't exercised by tests. |
37
- | Runtime | **Edge Runtime + Node 18+** Web Crypto under the hood, no `node:crypto`. Drops into Vercel Edge Functions, Cloudflare Workers, Deno deploy, or any modern Node. |
38
+ | Runtime | **Edge Runtime + Node 18+**: Web Crypto under the hood, no `node:crypto`. Drops into Vercel Edge Functions, Cloudflare Workers, Deno deploy, or any modern Node. |
38
39
  | Vercel KV adapters | Subpath `@ar-agents/mercadopago/vercel-kv` ships adapters for subscription state, OAuth tokens, idempotency cache, audit log, and rate limiter. |
39
- | Cookbook | 9 recipes shipped in `cookbook/` checkout, subscriptions, webhook handler, marketplace OAuth, QR in-store, 3DS challenge, auth-only Order, recovery patterns, full OpenTelemetry wiring. |
40
+ | Cookbook | 9 recipes shipped in `cookbook/`: checkout, subscriptions, webhook handler, marketplace OAuth, QR in-store, 3DS challenge, auth-only Order, recovery patterns, full OpenTelemetry wiring. |
40
41
 
41
42
  ## Why this exists
42
43
 
@@ -51,7 +52,7 @@ the documented gotchas into typed errors with actionable messages.
51
52
 
52
53
  [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https%3A%2F%2Fgithub.com%2Far-agents%2Far-agents&root-directory=apps%2Fmp-hello&env=MP_ACCESS_TOKEN%2CANTHROPIC_API_KEY%2CUPSTASH_REDIS_REST_URL%2CUPSTASH_REDIS_REST_TOKEN&envDescription=Mercado%20Pago%20access%20token%2C%20Anthropic%20API%20key%2C%20and%20Upstash%20Redis%20credentials%20for%20subscription%20state.&envLink=https%3A%2F%2Fgithub.com%2Far-agents%2Far-agents%2Ftree%2Fmain%2Fapps%2Fmp-hello%23setup&project-name=mp-hello&repository-name=mp-hello)
53
54
 
54
- `apps/mp-hello` ships as a clonable Vercel template Edge Runtime API routes,
55
+ `apps/mp-hello` ships as a clonable Vercel template: Edge Runtime API routes,
55
56
  MP webhook handler with HMAC verify, Upstash-backed subscription state.
56
57
 
57
58
  ## Install
@@ -169,7 +170,7 @@ local development, pass a placeholder valid HTTPS URL like
169
170
 
170
171
  The error message is misleading. The actual cause: the seller account
171
172
  (whose access token authenticates the request) and the buyer email (`payerEmail`)
172
- must be the same MP account "type" both real accounts, or both test users
173
+ must be the same MP account "type": both real accounts, or both test users
173
174
  created via `POST /users/test_user`. Mixing them rejects with this error.
174
175
  Throws `MercadoPagoAccountTypeMismatchError`.
175
176
 
@@ -253,7 +254,7 @@ has history of normal usage, the engine relaxes.
253
254
  ### 11. Failed first payment auto-cancels the entire preapproval
254
255
 
255
256
  When MP's risk engine rejects the first payment of a preapproval, MP
256
- automatically marks the WHOLE preapproval as `status: cancelled` you cannot
257
+ automatically marks the WHOLE preapproval as `status: cancelled`: you cannot
257
258
  retry with another card on the same subscription. Create a fresh preapproval
258
259
  to retry. Throws `MercadoPagoPaymentRejectedError`, which carries the parent
259
260
  `preapprovalId` so the caller knows the parent is dead too.
@@ -293,9 +294,9 @@ selection guidance. Highlights:
293
294
  - **In-store QR + POS** (4 tools): create_qr_payment, cancel_qr_payment, create_store, create_pos
294
295
  - **Cuotas + lookups** (3 tools): calculate_installments, list_payment_methods, list_issuers
295
296
  - **Disputes + Webhooks management** (6 tools): list_payment_disputes, create_webhook, list_webhooks…
296
- - **v0.5 Webhook handler combo** (1 tool): `handle_webhook` verify HMAC + parse + auto-fetch in ONE call
297
- - **v0.5 OAuth Marketplace** (3 tools): `oauth_authorize_url`, `oauth_exchange_code`, `oauth_refresh_token` wire third-party MP accounts to your platform
298
- - **v0.5 Order Management API** (5 tools): `create_order`, `get_order`, `update_order`, `capture_order`, `cancel_order` modern API with auth-only support and marketplace splits
297
+ - **v0.5: Webhook handler combo** (1 tool): `handle_webhook`: verify HMAC + parse + auto-fetch in ONE call
298
+ - **v0.5: OAuth Marketplace** (3 tools): `oauth_authorize_url`, `oauth_exchange_code`, `oauth_refresh_token`: wire third-party MP accounts to your platform
299
+ - **v0.5: Order Management API** (5 tools): `create_order`, `get_order`, `update_order`, `capture_order`, `cancel_order`: modern API with auth-only support and marketplace splits
299
300
 
300
301
  Options:
301
302
 
@@ -309,7 +310,7 @@ mercadoPagoTools(client, {
309
310
  });
310
311
  ```
311
312
 
312
- ### v0.5 Webhook handler combo
313
+ ### v0.5: Webhook handler combo
313
314
 
314
315
  ```ts
315
316
  // In your /api/mercadopago/webhook handler
@@ -324,10 +325,10 @@ if (!result.verified) return new Response("unauthorized", { status: 401 });
324
325
  // Use result.event.topic, result.event.dataId, result.resource (Payment | Preapproval | …)
325
326
  ```
326
327
 
327
- ### v0.5 OAuth Marketplace flow (3 legs)
328
+ ### v0.5: OAuth Marketplace flow (3 legs)
328
329
 
329
330
  ```ts
330
- // 1. Build authorize URL redirect the seller here
331
+ // 1. Build authorize URL: redirect the seller here
331
332
  const { url } = await tools.oauth_authorize_url.execute({
332
333
  redirect_uri: "https://app.test/oauth/callback",
333
334
  state: cryptoRandomToken(), // bind to user's session, verify on redirect
@@ -349,7 +350,7 @@ const { token } = await tools.oauth_refresh_token.execute({
349
350
  const sellerClient = new MercadoPagoClient({ accessToken: token.access_token });
350
351
  ```
351
352
 
352
- ### v0.5 Marketplace split payments
353
+ ### v0.5: Marketplace split payments
353
354
 
354
355
  For two-sided platforms (Rappi-style) where you collect on a seller's behalf
355
356
  and take a fee, pass `marketplace`, `marketplace_fee`, `collector_id` to
@@ -371,20 +372,20 @@ await tools.create_order.execute({
371
372
  All errors extend `MercadoPagoError` which carries `status`, `endpoint`,
372
373
  and `mpResponse` for inspection. Specific subclasses:
373
374
 
374
- - `MercadoPagoAuthError` 401 from MP
375
- - `MercadoPagoBackUrlInvalidError` see gotcha #1
376
- - `MercadoPagoSelfPaymentError` see gotcha #3
377
- - `MercadoPagoAccountTypeMismatchError` see gotcha #2
378
- - `MercadoPagoPaymentRejectedError` see gotchas #10–11; carries `preapprovalId` and `statusDetail`
379
- - `MercadoPagoAuthorizeForbiddenError` see gotcha #6
380
- - `MercadoPagoRateLimitError` 429 from MP
375
+ - `MercadoPagoAuthError`: 401 from MP
376
+ - `MercadoPagoBackUrlInvalidError`: see gotcha #1
377
+ - `MercadoPagoSelfPaymentError`: see gotcha #3
378
+ - `MercadoPagoAccountTypeMismatchError`: see gotcha #2
379
+ - `MercadoPagoPaymentRejectedError`: see gotchas #10–11; carries `preapprovalId` and `statusDetail`
380
+ - `MercadoPagoAuthorizeForbiddenError`: see gotcha #6
381
+ - `MercadoPagoRateLimitError`: 429 from MP
381
382
 
382
383
  ## Production hardening (v0.9+)
383
384
 
384
385
  ### Circuit breaker
385
386
 
386
387
  Protect your app from cascading failures when MP is degraded. The breaker
387
- observes failures over a rolling window after enough, it OPENS and fails
388
+ observes failures over a rolling window: after enough, it OPENS and fails
388
389
  fast (no network round-trip) until cooldown elapses.
389
390
 
390
391
  ```ts
@@ -393,7 +394,7 @@ import { CircuitBreaker, MercadoPagoClient, CircuitOpenError } from "@ar-agents/
393
394
  const breaker = new CircuitBreaker({
394
395
  failureThreshold: 5,
395
396
  resetTimeoutMs: 30_000,
396
- // Don't count 4xx user errors toward circuit opening only upstream failures
397
+ // Don't count 4xx user errors toward circuit opening: only upstream failures
397
398
  isFailure: (err) => err instanceof MercadoPagoError && err.status >= 500,
398
399
  onStateChange: (e) => metrics.gauge(`mp.circuit.${e.to}`, 1),
399
400
  });
@@ -407,7 +408,7 @@ try {
407
408
  await client.getPayment("123");
408
409
  } catch (err) {
409
410
  if (err instanceof CircuitOpenError) {
410
- // MP is down, breaker tripped fast-fail without network
411
+ // MP is down, breaker tripped: fast-fail without network
411
412
  return showFallbackUi(err.retryAfterMs);
412
413
  }
413
414
  throw err;
@@ -415,11 +416,11 @@ try {
415
416
  ```
416
417
 
417
418
  **Multi-tenant marketplace**: pass the same `CircuitBreaker` instance to all
418
- per-seller `MercadoPagoClient`s they share backpressure signal.
419
+ per-seller `MercadoPagoClient`s: they share backpressure signal.
419
420
 
420
421
  ### Deadline propagation
421
422
 
422
- Pass the agent's `AbortSignal` to chain deadlines through to MP when the
423
+ Pass the agent's `AbortSignal` to chain deadlines through to MP: when the
423
424
  agent's budget expires, MP requests cancel cleanly without retrying.
424
425
 
425
426
  ```ts
@@ -467,7 +468,7 @@ Vercel Cron monitoring loops.
467
468
  | Operation | Throughput |
468
469
  |---|---|
469
470
  | `hmacSha256Hex` (typical webhook manifest) | 45,932 ops/sec |
470
- | `sha256Hex` (40-byte input idempotency key) | 92,218 ops/sec |
471
+ | `sha256Hex` (40-byte input: idempotency key) | 92,218 ops/sec |
471
472
  | `timingSafeEqualHex` (64 chars) | 3,099,551 ops/sec |
472
473
  | `computeMarketplaceFee` | 20,662,947 ops/sec |
473
474
  | `explainPaymentStatus` | 21,289,436 ops/sec |
@@ -479,7 +480,7 @@ Run `pnpm bench` to reproduce.
479
480
 
480
481
  The toolkit ships first-class adapters for Vercel infrastructure via the
481
482
  `@ar-agents/mercadopago/vercel-kv` subpath. `@vercel/kv` is an **optional**
482
- peer dep only install it if you use the subpath.
483
+ peer dep: only install it if you use the subpath.
483
484
 
484
485
  ```ts
485
486
  import { mercadoPagoTools, MercadoPagoClient } from "@ar-agents/mercadopago";
@@ -507,7 +508,7 @@ const tools = mercadoPagoTools(
507
508
 
508
509
  The toolkit (including HMAC webhook verification) is fully Edge-Runtime
509
510
  compatible. Add `export const runtime = "edge"` to any Vercel route handler
510
- that uses MP tools sub-100ms global cold starts.
511
+ that uses MP tools: sub-100ms global cold starts.
511
512
 
512
513
  ### Vercel Cron + Blob + Functions
513
514
 
@@ -543,7 +544,7 @@ Each recipe is copy-pasteable into a Next.js route handler.
543
544
 
544
545
  ## License
545
546
 
546
- MIT see [LICENSE](./LICENSE).
547
+ MIT: see [LICENSE](./LICENSE).
547
548
 
548
549
  ## Stability
549
550