@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 +30 -30
- package/CHANGELOG.md +43 -1
- package/MIGRATION.md +8 -8
- package/README.md +33 -32
- package/README.skeleton.md +21 -21
- package/cookbook/10-cross-package-billing.ts +172 -0
- package/cookbook/11-dunning-sequence.ts +305 -0
- package/cookbook/12-reconciliation-pipeline.ts +277 -0
- package/cookbook/README.md +3 -0
- package/dist/index.d.cts +4 -1084
- package/dist/index.d.ts +4 -1084
- package/dist/testing.cjs +281 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +188 -0
- package/dist/testing.d.ts +188 -0
- package/dist/testing.js +270 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-BaOjfcOt.d.cts +1085 -0
- package/dist/types-BaOjfcOt.d.ts +1085 -0
- package/package.json +30 -16
- package/tools.manifest.json +1 -1
package/AGENTS.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
# @ar-agents/mercadopago
|
|
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
|
|
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
|
|
17
|
-
| **"Cuántas cuotas tiene esta tarjeta para $X?"** | `calculate_installments
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
146
|
-
| `cc_rejected_insufficient_amount` | Not enough funds | "Saldo insuficiente
|
|
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"
|
|
150
|
-
| `pending_waiting_payment` | Ticket created (Rapipago/Pago Fácil) | "Pagá el ticket en cualquier sucursal
|
|
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
|
|
161
|
-
7. **`back_url` MUST be HTTPS
|
|
162
|
-
8. **`payer.identification
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
217
|
+
- Make decisions about pricing or installments: caller's responsibility.
|
|
218
218
|
|
|
219
|
-
## v0.5
|
|
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
|
|
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
|
|
251
|
-
2. `oauth_exchange_code
|
|
252
|
-
3. `oauth_refresh_token
|
|
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
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
176
|
+
You can use BOTH packages in the same project: they don't conflict.
|
package/README.md
CHANGED
|
@@ -13,30 +13,31 @@
|
|
|
13
13
|
[](https://www.npmjs.com/package/@ar-agents/mercadopago)
|
|
14
14
|
[](./LICENSE)
|
|
15
15
|
[](https://github.com/ar-agents/ar-agents/actions/workflows/ci.yml)
|
|
16
|
+
[](https://docs.npmjs.com/generating-provenance-statements)
|
|
16
17
|
[](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)
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
[](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
|
|
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"
|
|
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
|
|
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
|
|
297
|
-
- **v0.5
|
|
298
|
-
- **v0.5
|
|
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
|
|
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
|
|
328
|
+
### v0.5: OAuth Marketplace flow (3 legs)
|
|
328
329
|
|
|
329
330
|
```ts
|
|
330
|
-
// 1. Build authorize URL
|
|
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
|
|
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
|
|
375
|
-
- `MercadoPagoBackUrlInvalidError
|
|
376
|
-
- `MercadoPagoSelfPaymentError
|
|
377
|
-
- `MercadoPagoAccountTypeMismatchError
|
|
378
|
-
- `MercadoPagoPaymentRejectedError
|
|
379
|
-
- `MercadoPagoAuthorizeForbiddenError
|
|
380
|
-
- `MercadoPagoRateLimitError
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
547
|
+
MIT: see [LICENSE](./LICENSE).
|
|
547
548
|
|
|
548
549
|
## Stability
|
|
549
550
|
|