@ar-agents/mercadopago 0.5.0 → 0.7.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 +10 -1
- package/CHANGELOG.md +67 -0
- package/README.md +1 -1
- package/dist/index.cjs +1255 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +533 -2
- package/dist/index.d.ts +533 -2
- package/dist/index.js +1250 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/tools.manifest.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -960,6 +960,280 @@ var MercadoPagoClient = class {
|
|
|
960
960
|
async cancelOrder(id) {
|
|
961
961
|
return this.request("POST", `/v1/orders/${id}/cancel`);
|
|
962
962
|
}
|
|
963
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
964
|
+
// v0.6 — Account Balance + Movements
|
|
965
|
+
//
|
|
966
|
+
// Inspect the seller's MP wallet — what's available to withdraw, what's
|
|
967
|
+
// in retention (pending release), and the movement log.
|
|
968
|
+
//
|
|
969
|
+
// For per-seller marketplace setups, instantiate the client AS THE SELLER
|
|
970
|
+
// (with their OAuth access_token) before calling these — `getAccountBalance`
|
|
971
|
+
// returns the balance of WHOEVER's accessToken is active.
|
|
972
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
973
|
+
/**
|
|
974
|
+
* Get the seller's current MP wallet balance (available + unavailable).
|
|
975
|
+
* - `available_balance`: spendable / withdrawable right now.
|
|
976
|
+
* - `unavailable_balance`: in retention (e.g., 14-21 days for new sellers).
|
|
977
|
+
* - `total_amount` = sum of both.
|
|
978
|
+
*/
|
|
979
|
+
async getAccountBalance() {
|
|
980
|
+
return this.request("GET", "/users/me/mercadopago_account/balance");
|
|
981
|
+
}
|
|
982
|
+
/**
|
|
983
|
+
* List wallet movements (incoming payments, transfers, refunds, holdings).
|
|
984
|
+
* Defaults to most-recent-first, paginated. Filter by date range with
|
|
985
|
+
* `from`/`to` (ISO 8601).
|
|
986
|
+
*/
|
|
987
|
+
async listAccountMovements(params = {}) {
|
|
988
|
+
const query = {};
|
|
989
|
+
if (params.from) query.begin_date = params.from;
|
|
990
|
+
if (params.to) query.end_date = params.to;
|
|
991
|
+
if (params.limit !== void 0) query.limit = params.limit;
|
|
992
|
+
if (params.offset !== void 0) query.offset = params.offset;
|
|
993
|
+
const result = await this.request("GET", "/users/me/mercadopago_account/movements/search", void 0, { query });
|
|
994
|
+
return {
|
|
995
|
+
movements: result.results ?? [],
|
|
996
|
+
paging: result.paging ?? { limit: params.limit ?? 25, offset: params.offset ?? 0, total: 0 }
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1000
|
+
// v0.6 — Settlements (release_money)
|
|
1001
|
+
//
|
|
1002
|
+
// When MP transfers funds from your MP wallet to your registered CBU.
|
|
1003
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1004
|
+
/**
|
|
1005
|
+
* List settlements (transfers from MP wallet to your bank account).
|
|
1006
|
+
* Useful for monthly conciliation reports.
|
|
1007
|
+
*/
|
|
1008
|
+
async listSettlements(params = {}) {
|
|
1009
|
+
const query = {};
|
|
1010
|
+
if (params.from) query.begin_date = params.from;
|
|
1011
|
+
if (params.to) query.end_date = params.to;
|
|
1012
|
+
if (params.status) query.status = params.status;
|
|
1013
|
+
if (params.limit !== void 0) query.limit = params.limit;
|
|
1014
|
+
if (params.offset !== void 0) query.offset = params.offset;
|
|
1015
|
+
const result = await this.request("GET", "/v1/account/release_money/search", void 0, { query });
|
|
1016
|
+
return {
|
|
1017
|
+
settlements: result.results ?? [],
|
|
1018
|
+
paging: result.paging ?? { limit: params.limit ?? 25, offset: params.offset ?? 0, total: 0 }
|
|
1019
|
+
};
|
|
1020
|
+
}
|
|
1021
|
+
/**
|
|
1022
|
+
* Get a single settlement by id. Returns the full Settlement object
|
|
1023
|
+
* including bank_account info (CBU, bank name).
|
|
1024
|
+
*/
|
|
1025
|
+
async getSettlement(id) {
|
|
1026
|
+
return this.request("GET", `/v1/account/release_money/${id}`);
|
|
1027
|
+
}
|
|
1028
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1029
|
+
// v0.7 — Customer + Card extensions (close gaps)
|
|
1030
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1031
|
+
/**
|
|
1032
|
+
* Update a customer's profile (name, last name, address, etc.). MP merges
|
|
1033
|
+
* the patch — fields you don't send remain unchanged.
|
|
1034
|
+
*/
|
|
1035
|
+
async updateCustomer(id, patch) {
|
|
1036
|
+
return this.request("PUT", `/v1/customers/${id}`, patch);
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Add a saved card to a customer using a card token (one-time, get from
|
|
1040
|
+
* MP's frontend Cardform). The card is then chargeable with charge_saved_card.
|
|
1041
|
+
*/
|
|
1042
|
+
async createCustomerCard(customerId, cardToken) {
|
|
1043
|
+
return this.request(
|
|
1044
|
+
"POST",
|
|
1045
|
+
`/v1/customers/${customerId}/cards`,
|
|
1046
|
+
{ token: cardToken }
|
|
1047
|
+
);
|
|
1048
|
+
}
|
|
1049
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1050
|
+
// v0.7 — Subscription extensions
|
|
1051
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1052
|
+
/**
|
|
1053
|
+
* Update an existing subscription. Common patches:
|
|
1054
|
+
* - `transaction_amount` to change the recurring amount
|
|
1055
|
+
* - `card_token_id` to switch payment method (e.g., expired card)
|
|
1056
|
+
* - `status: "cancelled" | "paused"` (alternative to dedicated cancel/pause endpoints)
|
|
1057
|
+
* - `reason` to update the description shown to the buyer
|
|
1058
|
+
*/
|
|
1059
|
+
async updatePreapproval(id, patch) {
|
|
1060
|
+
return this.request("PUT", `/preapproval/${id}`, patch);
|
|
1061
|
+
}
|
|
1062
|
+
/**
|
|
1063
|
+
* Search subscriptions across the seller's account. Common filters:
|
|
1064
|
+
* `status` (pending/authorized/paused/cancelled), `payer_email`,
|
|
1065
|
+
* `external_reference`. Paginated.
|
|
1066
|
+
*/
|
|
1067
|
+
async searchPreapprovals(params = {}) {
|
|
1068
|
+
const query = {};
|
|
1069
|
+
if (params.status) query.status = params.status;
|
|
1070
|
+
if (params.payerEmail) query.payer_email = params.payerEmail;
|
|
1071
|
+
if (params.externalReference) query.external_reference = params.externalReference;
|
|
1072
|
+
if (params.preapproval_plan_id) query.preapproval_plan_id = params.preapproval_plan_id;
|
|
1073
|
+
if (params.limit !== void 0) query.limit = params.limit;
|
|
1074
|
+
if (params.offset !== void 0) query.offset = params.offset;
|
|
1075
|
+
const result = await this.request("GET", "/preapproval/search", void 0, { query });
|
|
1076
|
+
return {
|
|
1077
|
+
results: result.results ?? [],
|
|
1078
|
+
paging: result.paging ?? { limit: params.limit ?? 25, offset: params.offset ?? 0, total: 0 }
|
|
1079
|
+
};
|
|
1080
|
+
}
|
|
1081
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1082
|
+
// v0.7 — Merchant Orders (parent of Payments grouped under a Preference)
|
|
1083
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1084
|
+
/**
|
|
1085
|
+
* Get a merchant_order with all its associated payments + shipments.
|
|
1086
|
+
* Useful for reconciling "which payments belong to which preference"
|
|
1087
|
+
* — typical webhook handler use case.
|
|
1088
|
+
*/
|
|
1089
|
+
async getMerchantOrder(id) {
|
|
1090
|
+
return this.request("GET", `/merchant_orders/${id}`);
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Search merchant_orders by external_reference, preference_id, or status.
|
|
1094
|
+
*/
|
|
1095
|
+
async searchMerchantOrders(params = {}) {
|
|
1096
|
+
const query = {};
|
|
1097
|
+
if (params.preferenceId) query.preference_id = params.preferenceId;
|
|
1098
|
+
if (params.externalReference) query.external_reference = params.externalReference;
|
|
1099
|
+
if (params.status) query.status = params.status;
|
|
1100
|
+
if (params.limit !== void 0) query.limit = params.limit;
|
|
1101
|
+
if (params.offset !== void 0) query.offset = params.offset;
|
|
1102
|
+
const result = await this.request("GET", "/merchant_orders/search", void 0, { query });
|
|
1103
|
+
return {
|
|
1104
|
+
elements: result.elements ?? [],
|
|
1105
|
+
paging: result.paging ?? { limit: params.limit ?? 25, offset: params.offset ?? 0, total: 0 }
|
|
1106
|
+
};
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Update a merchant_order — typically to add items or update shipping.
|
|
1110
|
+
*/
|
|
1111
|
+
async updateMerchantOrder(id, patch) {
|
|
1112
|
+
return this.request("PUT", `/merchant_orders/${id}`, patch);
|
|
1113
|
+
}
|
|
1114
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1115
|
+
// v0.7 — Stores + POS CRUD completion
|
|
1116
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1117
|
+
async getStore(userId, storeId) {
|
|
1118
|
+
return this.request("GET", `/users/${userId}/stores/${storeId}`);
|
|
1119
|
+
}
|
|
1120
|
+
async updateStore(userId, storeId, patch) {
|
|
1121
|
+
return this.request("PUT", `/users/${userId}/stores/${storeId}`, patch);
|
|
1122
|
+
}
|
|
1123
|
+
async deleteStore(userId, storeId) {
|
|
1124
|
+
await this.request("DELETE", `/users/${userId}/stores/${storeId}`);
|
|
1125
|
+
}
|
|
1126
|
+
async getPos(posId) {
|
|
1127
|
+
return this.request("GET", `/pos/${posId}`);
|
|
1128
|
+
}
|
|
1129
|
+
async updatePos(posId, patch) {
|
|
1130
|
+
return this.request("PUT", `/pos/${posId}`, patch);
|
|
1131
|
+
}
|
|
1132
|
+
async deletePos(posId) {
|
|
1133
|
+
await this.request("DELETE", `/pos/${posId}`);
|
|
1134
|
+
}
|
|
1135
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1136
|
+
// v0.7 — Bank Accounts (the CBUs the seller has registered for payouts)
|
|
1137
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1138
|
+
/**
|
|
1139
|
+
* List bank accounts registered by the seller. The default is the one
|
|
1140
|
+
* that receives `release_money` settlements.
|
|
1141
|
+
*/
|
|
1142
|
+
async listBankAccounts() {
|
|
1143
|
+
const result = await this.request(
|
|
1144
|
+
"GET",
|
|
1145
|
+
"/users/me/bank_accounts"
|
|
1146
|
+
);
|
|
1147
|
+
if (Array.isArray(result)) return result;
|
|
1148
|
+
return result.results ?? [];
|
|
1149
|
+
}
|
|
1150
|
+
/**
|
|
1151
|
+
* Register a new bank account (CBU) for the seller. Note: MP usually
|
|
1152
|
+
* requires this through the dashboard for compliance — this endpoint may
|
|
1153
|
+
* not work for all sellers.
|
|
1154
|
+
*/
|
|
1155
|
+
async registerBankAccount(params) {
|
|
1156
|
+
return this.request("POST", "/users/me/bank_accounts", params);
|
|
1157
|
+
}
|
|
1158
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1159
|
+
// v0.7 — Point Devices (physical terminal hardware: Smart, Tap to Pay)
|
|
1160
|
+
//
|
|
1161
|
+
// Distinct from the logical `Pos` entity. PointDevices are the actual
|
|
1162
|
+
// physical terminals you have at brick-and-mortar shops.
|
|
1163
|
+
// ──────────────────────────────────────────────────────────────────────────
|
|
1164
|
+
/**
|
|
1165
|
+
* List the Point devices linked to the seller's MP account. Each device
|
|
1166
|
+
* has an id (the device serial), an operating_mode (PDV vs STANDALONE),
|
|
1167
|
+
* and an optional pos_id (when bound to a logical POS).
|
|
1168
|
+
*/
|
|
1169
|
+
async listPointDevices(params = {}) {
|
|
1170
|
+
const query = {};
|
|
1171
|
+
if (params.posId !== void 0) query["pos.id"] = params.posId;
|
|
1172
|
+
if (params.limit !== void 0) query.limit = params.limit;
|
|
1173
|
+
if (params.offset !== void 0) query.offset = params.offset;
|
|
1174
|
+
const result = await this.request("GET", "/point/integration-api/devices", void 0, { query });
|
|
1175
|
+
return {
|
|
1176
|
+
devices: result.devices ?? [],
|
|
1177
|
+
paging: result.paging ?? { total: 0, limit: params.limit ?? 50, offset: params.offset ?? 0 }
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Switch a Point device's operating mode:
|
|
1182
|
+
* - "PDV": device is bound to a logical Pos and only takes payments
|
|
1183
|
+
* triggered through that Pos (typical for cash-register integrations).
|
|
1184
|
+
* - "STANDALONE": device works independently, accepts any payment.
|
|
1185
|
+
*/
|
|
1186
|
+
async updatePointDeviceOperatingMode(deviceId, operatingMode) {
|
|
1187
|
+
return this.request(
|
|
1188
|
+
"PATCH",
|
|
1189
|
+
`/point/integration-api/devices/${encodeURIComponent(deviceId)}`,
|
|
1190
|
+
{ operating_mode: operatingMode }
|
|
1191
|
+
);
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Create a payment intent on a Point device — the device prompts the buyer
|
|
1195
|
+
* to tap/insert/swipe. Returns immediately with intent id; query state via
|
|
1196
|
+
* `getPointPaymentIntent()` or wait for `point_integration_wh` webhook.
|
|
1197
|
+
*
|
|
1198
|
+
* NOTE: amount is in CENTAVOS (Point API differs from Payments API which
|
|
1199
|
+
* uses pesos). 100 = $1 ARS, 1000 = $10, 10000 = $100, etc.
|
|
1200
|
+
*/
|
|
1201
|
+
async createPointPaymentIntent(deviceId, params) {
|
|
1202
|
+
const body = {
|
|
1203
|
+
amount: params.amount,
|
|
1204
|
+
...params.description ? { description: params.description } : {},
|
|
1205
|
+
...params.externalReference ? { additional_info: { external_reference: params.externalReference } } : {},
|
|
1206
|
+
payment: {
|
|
1207
|
+
installments: params.installments ?? 1,
|
|
1208
|
+
...params.installmentsCost ? { installments_cost: params.installmentsCost } : {},
|
|
1209
|
+
...params.printOnTerminal !== void 0 ? { print_on_terminal: params.printOnTerminal } : {},
|
|
1210
|
+
...params.ticketNumber ? { ticket_number: params.ticketNumber } : {}
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
return this.request(
|
|
1214
|
+
"POST",
|
|
1215
|
+
`/point/integration-api/devices/${encodeURIComponent(deviceId)}/payment-intents`,
|
|
1216
|
+
body
|
|
1217
|
+
);
|
|
1218
|
+
}
|
|
1219
|
+
/** Get the current state of a Point payment intent. */
|
|
1220
|
+
async getPointPaymentIntent(intentId) {
|
|
1221
|
+
return this.request(
|
|
1222
|
+
"GET",
|
|
1223
|
+
`/point/integration-api/payment-intents/${encodeURIComponent(intentId)}`
|
|
1224
|
+
);
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Cancel an OPEN payment intent before the buyer interacts with the device.
|
|
1228
|
+
* Only works while state is "OPEN" — once the buyer taps, you can't cancel.
|
|
1229
|
+
*/
|
|
1230
|
+
async cancelPointPaymentIntent(deviceId, intentId) {
|
|
1231
|
+
await this.request(
|
|
1232
|
+
"DELETE",
|
|
1233
|
+
`/point/integration-api/devices/${encodeURIComponent(deviceId)}/payment-intents/${encodeURIComponent(intentId)}`
|
|
1234
|
+
);
|
|
1235
|
+
return { id: intentId, canceled: true };
|
|
1236
|
+
}
|
|
963
1237
|
};
|
|
964
1238
|
zod.z.enum(["MLA", "MLB", "MLM", "MCO", "MLC", "MLU"]);
|
|
965
1239
|
var CurrencyIdSchema = zod.z.enum(["ARS", "USD", "BRL", "MXN"]);
|
|
@@ -1308,6 +1582,95 @@ zod.z.object({
|
|
|
1308
1582
|
/** Capture mode: "automatic" (charges immediately) or "manual" (auth-only). */
|
|
1309
1583
|
capture_mode: zod.z.string().optional()
|
|
1310
1584
|
}).passthrough();
|
|
1585
|
+
zod.z.object({
|
|
1586
|
+
user_id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String).optional(),
|
|
1587
|
+
available_balance: zod.z.number(),
|
|
1588
|
+
unavailable_balance: zod.z.number(),
|
|
1589
|
+
total_amount: zod.z.number(),
|
|
1590
|
+
currency_id: zod.z.string().default("ARS")
|
|
1591
|
+
}).passthrough();
|
|
1592
|
+
zod.z.object({
|
|
1593
|
+
id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
|
|
1594
|
+
type: zod.z.string(),
|
|
1595
|
+
description: zod.z.string().optional(),
|
|
1596
|
+
amount: zod.z.number(),
|
|
1597
|
+
currency_id: zod.z.string().optional(),
|
|
1598
|
+
status: zod.z.string().optional(),
|
|
1599
|
+
date_created: zod.z.string().optional(),
|
|
1600
|
+
date_released: zod.z.string().optional(),
|
|
1601
|
+
reference_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
|
|
1602
|
+
payment_id: zod.z.union([zod.z.string(), zod.z.number()]).optional()
|
|
1603
|
+
}).passthrough();
|
|
1604
|
+
zod.z.object({
|
|
1605
|
+
id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
|
|
1606
|
+
status: zod.z.string().optional(),
|
|
1607
|
+
amount: zod.z.number().optional(),
|
|
1608
|
+
currency_id: zod.z.string().optional(),
|
|
1609
|
+
date_created: zod.z.string().optional(),
|
|
1610
|
+
date_scheduled: zod.z.string().optional(),
|
|
1611
|
+
date_processed: zod.z.string().optional(),
|
|
1612
|
+
bank_account: zod.z.object({
|
|
1613
|
+
cbu: zod.z.string().optional(),
|
|
1614
|
+
bank_name: zod.z.string().optional()
|
|
1615
|
+
}).passthrough().optional()
|
|
1616
|
+
}).passthrough();
|
|
1617
|
+
zod.z.object({
|
|
1618
|
+
id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
|
|
1619
|
+
status: zod.z.string().optional(),
|
|
1620
|
+
external_reference: zod.z.string().nullable().optional(),
|
|
1621
|
+
preference_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
|
|
1622
|
+
payments: zod.z.array(zod.z.unknown()).optional(),
|
|
1623
|
+
shipments: zod.z.array(zod.z.unknown()).optional(),
|
|
1624
|
+
payer: zod.z.unknown().optional(),
|
|
1625
|
+
collector: zod.z.unknown().optional(),
|
|
1626
|
+
marketplace: zod.z.string().optional(),
|
|
1627
|
+
total_amount: zod.z.number().optional(),
|
|
1628
|
+
paid_amount: zod.z.number().optional(),
|
|
1629
|
+
refunded_amount: zod.z.number().optional(),
|
|
1630
|
+
shipping_cost: zod.z.number().optional(),
|
|
1631
|
+
date_created: zod.z.string().optional(),
|
|
1632
|
+
last_updated: zod.z.string().optional(),
|
|
1633
|
+
site_id: zod.z.string().optional(),
|
|
1634
|
+
order_status: zod.z.string().optional()
|
|
1635
|
+
}).passthrough();
|
|
1636
|
+
zod.z.object({
|
|
1637
|
+
id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
|
|
1638
|
+
cbu: zod.z.string().optional(),
|
|
1639
|
+
alias: zod.z.string().nullable().optional(),
|
|
1640
|
+
bank_name: zod.z.string().optional(),
|
|
1641
|
+
account_type: zod.z.string().optional(),
|
|
1642
|
+
status: zod.z.string().optional(),
|
|
1643
|
+
is_default: zod.z.boolean().optional(),
|
|
1644
|
+
date_created: zod.z.string().optional()
|
|
1645
|
+
}).passthrough();
|
|
1646
|
+
zod.z.object({
|
|
1647
|
+
id: zod.z.string(),
|
|
1648
|
+
pos_id: zod.z.union([zod.z.string(), zod.z.number()]).nullable().optional(),
|
|
1649
|
+
store_id: zod.z.union([zod.z.string(), zod.z.number()]).nullable().optional(),
|
|
1650
|
+
external_pos_id: zod.z.string().nullable().optional(),
|
|
1651
|
+
operating_mode: zod.z.union([zod.z.literal("PDV"), zod.z.literal("STANDALONE"), zod.z.string()]).optional()
|
|
1652
|
+
}).passthrough();
|
|
1653
|
+
zod.z.object({
|
|
1654
|
+
id: zod.z.string(),
|
|
1655
|
+
device_id: zod.z.string().optional(),
|
|
1656
|
+
amount: zod.z.number().optional(),
|
|
1657
|
+
state: zod.z.union([
|
|
1658
|
+
zod.z.literal("OPEN"),
|
|
1659
|
+
zod.z.literal("PROCESSING"),
|
|
1660
|
+
zod.z.literal("FINISHED"),
|
|
1661
|
+
zod.z.literal("CANCELED"),
|
|
1662
|
+
zod.z.literal("ERROR"),
|
|
1663
|
+
zod.z.string()
|
|
1664
|
+
]).optional(),
|
|
1665
|
+
payment: zod.z.object({
|
|
1666
|
+
id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
|
|
1667
|
+
type: zod.z.string().optional(),
|
|
1668
|
+
installments: zod.z.number().optional(),
|
|
1669
|
+
installments_cost: zod.z.string().optional(),
|
|
1670
|
+
print_on_terminal: zod.z.boolean().optional()
|
|
1671
|
+
}).passthrough().optional(),
|
|
1672
|
+
additional_info: zod.z.unknown().optional()
|
|
1673
|
+
}).passthrough();
|
|
1311
1674
|
|
|
1312
1675
|
// src/oauth.ts
|
|
1313
1676
|
var DEFAULT_AUTHORIZE_URL = "https://auth.mercadopago.com.ar/authorization";
|
|
@@ -1374,6 +1737,371 @@ function expirationTimeMs(issuedAtMs, expiresInSeconds) {
|
|
|
1374
1737
|
function isExpiringSoon(expirationMs, skewSeconds = 300) {
|
|
1375
1738
|
return Date.now() + skewSeconds * 1e3 >= expirationMs;
|
|
1376
1739
|
}
|
|
1740
|
+
|
|
1741
|
+
// src/helpers.ts
|
|
1742
|
+
function computeMarketplaceFee(amountArs, rule) {
|
|
1743
|
+
if (amountArs <= 0) return 0;
|
|
1744
|
+
const percentPart = (rule.percent ?? 0) > 0 ? amountArs * (rule.percent / 100) : 0;
|
|
1745
|
+
const flatPart = rule.flatArs ?? 0;
|
|
1746
|
+
let fee = percentPart + flatPart;
|
|
1747
|
+
if (rule.minArs !== void 0) fee = Math.max(fee, rule.minArs);
|
|
1748
|
+
if (rule.maxArs !== void 0) fee = Math.min(fee, rule.maxArs);
|
|
1749
|
+
if (fee > amountArs) fee = amountArs;
|
|
1750
|
+
if (rule.round !== false) fee = Math.round(fee);
|
|
1751
|
+
return fee;
|
|
1752
|
+
}
|
|
1753
|
+
var STATUS_DETAIL_MAP = {
|
|
1754
|
+
// Approved
|
|
1755
|
+
accredited: {
|
|
1756
|
+
summary: "Pago aprobado y acreditado.",
|
|
1757
|
+
recommendedAction: "Confirmar al cliente y continuar con el flujo (env\xEDo, factura).",
|
|
1758
|
+
retryable: false
|
|
1759
|
+
},
|
|
1760
|
+
partially_refunded: {
|
|
1761
|
+
summary: "Pago aprobado con reembolso parcial.",
|
|
1762
|
+
recommendedAction: "Mostrar el monto neto y el reembolso. Verificar inventario si corresponde.",
|
|
1763
|
+
retryable: false
|
|
1764
|
+
},
|
|
1765
|
+
// Pending
|
|
1766
|
+
pending_contingency: {
|
|
1767
|
+
summary: "Pago en proceso por contingencia. MP est\xE1 procesando \u2014 puede demorar minutos a horas.",
|
|
1768
|
+
recommendedAction: "No reintentar todav\xEDa. Esperar webhook de actualizaci\xF3n (puede demorar 24h m\xE1x).",
|
|
1769
|
+
retryable: false
|
|
1770
|
+
},
|
|
1771
|
+
pending_review_manual: {
|
|
1772
|
+
summary: "Pago en revisi\xF3n manual por el equipo de seguridad de MP.",
|
|
1773
|
+
recommendedAction: "No reintentar. MP responder\xE1 con webhook en 24-72h. Avisar al cliente sobre la demora.",
|
|
1774
|
+
retryable: false
|
|
1775
|
+
},
|
|
1776
|
+
pending_waiting_payment: {
|
|
1777
|
+
summary: "Esperando que el comprador complete el pago (t\xEDpico de account_money / boleto / Rapipago).",
|
|
1778
|
+
recommendedAction: "Mostrar instrucciones de pago. MP avisar\xE1 por webhook cuando se complete.",
|
|
1779
|
+
retryable: false
|
|
1780
|
+
},
|
|
1781
|
+
pending_waiting_transfer: {
|
|
1782
|
+
summary: "Esperando confirmaci\xF3n de transferencia bancaria.",
|
|
1783
|
+
recommendedAction: "Esperar webhook. Sin acci\xF3n del agente.",
|
|
1784
|
+
retryable: false
|
|
1785
|
+
},
|
|
1786
|
+
pending_challenge: {
|
|
1787
|
+
summary: "El emisor de la tarjeta requiri\xF3 autenticaci\xF3n 3DS. El comprador debe completar el desaf\xEDo.",
|
|
1788
|
+
recommendedAction: "Redirigir al comprador a `payment.three_ds_info.external_resource_url` (us\xE1 analyze_payment_3ds para obtenerlo).",
|
|
1789
|
+
retryable: false
|
|
1790
|
+
},
|
|
1791
|
+
// Rejected — RETRYABLE (user can fix and try again)
|
|
1792
|
+
cc_rejected_bad_filled_card_number: {
|
|
1793
|
+
summary: "El n\xFAmero de tarjeta es incorrecto.",
|
|
1794
|
+
recommendedAction: "Pedir al cliente que verifique el n\xFAmero. Reintentable.",
|
|
1795
|
+
retryable: true
|
|
1796
|
+
},
|
|
1797
|
+
cc_rejected_bad_filled_security_code: {
|
|
1798
|
+
summary: "El CVV es incorrecto.",
|
|
1799
|
+
recommendedAction: "Pedir el CVV nuevamente. Reintentable.",
|
|
1800
|
+
retryable: true
|
|
1801
|
+
},
|
|
1802
|
+
cc_rejected_bad_filled_date: {
|
|
1803
|
+
summary: "La fecha de vencimiento es incorrecta.",
|
|
1804
|
+
recommendedAction: "Pedir al cliente que verifique mes/a\xF1o. Reintentable.",
|
|
1805
|
+
retryable: true
|
|
1806
|
+
},
|
|
1807
|
+
cc_rejected_bad_filled_other: {
|
|
1808
|
+
summary: "Alg\xFAn dato de la tarjeta es incorrecto.",
|
|
1809
|
+
recommendedAction: "Pedir al cliente que revise todos los datos. Reintentable.",
|
|
1810
|
+
retryable: true
|
|
1811
|
+
},
|
|
1812
|
+
cc_rejected_call_for_authorize: {
|
|
1813
|
+
summary: "El emisor requiere que el cliente autorice el pago llamando al banco.",
|
|
1814
|
+
recommendedAction: "Mostrar el tel\xE9fono del banco emisor (us\xE1 list_issuers para obtenerlo). Reintentable despu\xE9s de la llamada.",
|
|
1815
|
+
retryable: true
|
|
1816
|
+
},
|
|
1817
|
+
cc_rejected_card_disabled: {
|
|
1818
|
+
summary: "La tarjeta est\xE1 inhabilitada por el banco emisor.",
|
|
1819
|
+
recommendedAction: "El cliente debe contactar a su banco. Probar con otra tarjeta. Reintentable con otra tarjeta.",
|
|
1820
|
+
retryable: true
|
|
1821
|
+
},
|
|
1822
|
+
cc_rejected_insufficient_amount: {
|
|
1823
|
+
summary: "Saldo insuficiente en la tarjeta.",
|
|
1824
|
+
recommendedAction: "Sugerir tarjeta alternativa o monto menor. Reintentable.",
|
|
1825
|
+
retryable: true
|
|
1826
|
+
},
|
|
1827
|
+
cc_rejected_invalid_installments: {
|
|
1828
|
+
summary: "El emisor no soporta esa cantidad de cuotas para esta tarjeta.",
|
|
1829
|
+
recommendedAction: "Llamar a calculate_installments para ver opciones v\xE1lidas y sugerir otra. Reintentable.",
|
|
1830
|
+
retryable: true
|
|
1831
|
+
},
|
|
1832
|
+
cc_rejected_other_reason: {
|
|
1833
|
+
summary: "Pago rechazado por raz\xF3n no especificada del emisor.",
|
|
1834
|
+
recommendedAction: "Sugerir otra tarjeta o m\xE9todo de pago. Reintentable con otra tarjeta.",
|
|
1835
|
+
retryable: true
|
|
1836
|
+
},
|
|
1837
|
+
// Rejected — NON-RETRYABLE (don't retry the same card)
|
|
1838
|
+
cc_rejected_blacklist: {
|
|
1839
|
+
summary: "Pago rechazado por blacklist de seguridad de MP. NO REINTENTAR con esta tarjeta.",
|
|
1840
|
+
recommendedAction: "Sugerir un m\xE9todo de pago alternativo (account_money, otra tarjeta de otro titular).",
|
|
1841
|
+
retryable: false
|
|
1842
|
+
},
|
|
1843
|
+
cc_rejected_high_risk: {
|
|
1844
|
+
summary: "Rechazo por an\xE1lisis de riesgo de MP. La tarjeta es v\xE1lida pero MP detect\xF3 fraude potencial.",
|
|
1845
|
+
recommendedAction: "Sugerir otro medio de pago o pedirle al cliente que verifique su identidad en MP.",
|
|
1846
|
+
retryable: false
|
|
1847
|
+
},
|
|
1848
|
+
cc_rejected_max_attempts: {
|
|
1849
|
+
summary: "Excedi\xF3 el n\xFAmero m\xE1ximo de intentos con esta tarjeta.",
|
|
1850
|
+
recommendedAction: "Pedir al cliente que use otra tarjeta. NO REINTENTAR la misma.",
|
|
1851
|
+
retryable: false
|
|
1852
|
+
},
|
|
1853
|
+
cc_rejected_duplicated_payment: {
|
|
1854
|
+
summary: "Ya se proces\xF3 un pago id\xE9ntico en los \xFAltimos minutos (deduplicaci\xF3n de MP).",
|
|
1855
|
+
recommendedAction: "Verificar con search_payments si el pago anterior se acredit\xF3. Sin acci\xF3n adicional necesaria.",
|
|
1856
|
+
retryable: false
|
|
1857
|
+
},
|
|
1858
|
+
// Cancelled / refunded / mediation
|
|
1859
|
+
by_collector: {
|
|
1860
|
+
summary: "El vendedor cancel\xF3 el pago.",
|
|
1861
|
+
recommendedAction: "Sin acci\xF3n. Estado final.",
|
|
1862
|
+
retryable: false
|
|
1863
|
+
},
|
|
1864
|
+
by_payer: {
|
|
1865
|
+
summary: "El comprador cancel\xF3 el pago.",
|
|
1866
|
+
recommendedAction: "Sin acci\xF3n. Estado final.",
|
|
1867
|
+
retryable: false
|
|
1868
|
+
},
|
|
1869
|
+
refunded: {
|
|
1870
|
+
summary: "Pago reembolsado al comprador.",
|
|
1871
|
+
recommendedAction: "Estado final. Reflejar el reembolso en tu sistema.",
|
|
1872
|
+
retryable: false
|
|
1873
|
+
},
|
|
1874
|
+
charged_back: {
|
|
1875
|
+
summary: "Contracargo (chargeback) iniciado por el banco emisor.",
|
|
1876
|
+
recommendedAction: "Revisar list_payment_disputes para responder. Surface al equipo de ops.",
|
|
1877
|
+
retryable: false
|
|
1878
|
+
}
|
|
1879
|
+
};
|
|
1880
|
+
function explainPaymentStatus(payment) {
|
|
1881
|
+
const status = payment.status;
|
|
1882
|
+
const statusDetail = payment.status_detail ?? "";
|
|
1883
|
+
const detail = STATUS_DETAIL_MAP[statusDetail];
|
|
1884
|
+
if (detail) {
|
|
1885
|
+
const isFinal = status === "approved" || status === "rejected" || status === "cancelled" || status === "refunded" || status === "charged_back";
|
|
1886
|
+
return {
|
|
1887
|
+
summary: detail.summary,
|
|
1888
|
+
recommendedAction: detail.recommendedAction,
|
|
1889
|
+
final: isFinal,
|
|
1890
|
+
paid: status === "approved",
|
|
1891
|
+
retryable: detail.retryable
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
switch (status) {
|
|
1895
|
+
case "approved":
|
|
1896
|
+
return {
|
|
1897
|
+
summary: "Pago aprobado.",
|
|
1898
|
+
recommendedAction: "Continuar con el flujo posterior (env\xEDo, factura, notificaci\xF3n).",
|
|
1899
|
+
final: true,
|
|
1900
|
+
paid: true,
|
|
1901
|
+
retryable: false
|
|
1902
|
+
};
|
|
1903
|
+
case "authorized":
|
|
1904
|
+
return {
|
|
1905
|
+
summary: "Pago autorizado pero no capturado (auth-only).",
|
|
1906
|
+
recommendedAction: "Llamar a capture_payment cuando complet\xE9s el servicio. Vence en 7 d\xEDas si no captur\xE1s.",
|
|
1907
|
+
final: false,
|
|
1908
|
+
paid: false,
|
|
1909
|
+
retryable: false
|
|
1910
|
+
};
|
|
1911
|
+
case "in_process":
|
|
1912
|
+
return {
|
|
1913
|
+
summary: "Pago en proceso.",
|
|
1914
|
+
recommendedAction: "Esperar webhook. Sin acci\xF3n inmediata.",
|
|
1915
|
+
final: false,
|
|
1916
|
+
paid: false,
|
|
1917
|
+
retryable: false
|
|
1918
|
+
};
|
|
1919
|
+
case "in_mediation":
|
|
1920
|
+
return {
|
|
1921
|
+
summary: "Pago en mediaci\xF3n con MP por disputa del comprador.",
|
|
1922
|
+
recommendedAction: "Revisar list_payment_disputes y responder via dashboard.",
|
|
1923
|
+
final: false,
|
|
1924
|
+
paid: false,
|
|
1925
|
+
retryable: false
|
|
1926
|
+
};
|
|
1927
|
+
case "pending":
|
|
1928
|
+
return {
|
|
1929
|
+
summary: "Pago pendiente. El comprador no complet\xF3 el pago todav\xEDa o MP est\xE1 procesando.",
|
|
1930
|
+
recommendedAction: "Esperar webhook (puede demorar minutos a 72h seg\xFAn el m\xE9todo).",
|
|
1931
|
+
final: false,
|
|
1932
|
+
paid: false,
|
|
1933
|
+
retryable: false
|
|
1934
|
+
};
|
|
1935
|
+
case "rejected":
|
|
1936
|
+
return {
|
|
1937
|
+
summary: `Pago rechazado (status_detail: ${statusDetail || "no especificado"}).`,
|
|
1938
|
+
recommendedAction: "Verificar status_detail. Considerar otro m\xE9todo de pago.",
|
|
1939
|
+
final: true,
|
|
1940
|
+
paid: false,
|
|
1941
|
+
retryable: true
|
|
1942
|
+
};
|
|
1943
|
+
case "cancelled":
|
|
1944
|
+
return {
|
|
1945
|
+
summary: "Pago cancelado.",
|
|
1946
|
+
recommendedAction: "Estado final. Sin acci\xF3n.",
|
|
1947
|
+
final: true,
|
|
1948
|
+
paid: false,
|
|
1949
|
+
retryable: false
|
|
1950
|
+
};
|
|
1951
|
+
case "refunded":
|
|
1952
|
+
return {
|
|
1953
|
+
summary: "Pago reembolsado.",
|
|
1954
|
+
recommendedAction: "Estado final. Reflejar el reembolso.",
|
|
1955
|
+
final: true,
|
|
1956
|
+
paid: false,
|
|
1957
|
+
retryable: false
|
|
1958
|
+
};
|
|
1959
|
+
case "charged_back":
|
|
1960
|
+
return {
|
|
1961
|
+
summary: "Pago con contracargo del banco.",
|
|
1962
|
+
recommendedAction: "Surfacear a ops. Revisar disputas.",
|
|
1963
|
+
final: true,
|
|
1964
|
+
paid: false,
|
|
1965
|
+
retryable: false
|
|
1966
|
+
};
|
|
1967
|
+
default:
|
|
1968
|
+
return {
|
|
1969
|
+
summary: `Status no reconocido: '${status}'.`,
|
|
1970
|
+
recommendedAction: "Inspeccionar payment.status + payment.status_detail manualmente.",
|
|
1971
|
+
final: false,
|
|
1972
|
+
paid: false,
|
|
1973
|
+
retryable: false
|
|
1974
|
+
};
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
|
|
1978
|
+
// src/test-cards.ts
|
|
1979
|
+
var TEST_CARDS_AR = {
|
|
1980
|
+
VISA_CREDIT: {
|
|
1981
|
+
brand: "Visa (cr\xE9dito)",
|
|
1982
|
+
number: "4509 9535 6623 3704".replace(/\s/g, ""),
|
|
1983
|
+
cvv: "123",
|
|
1984
|
+
exp: "11/30",
|
|
1985
|
+
paymentMethodId: "visa",
|
|
1986
|
+
holderNameToTest: {
|
|
1987
|
+
APRO: "approved",
|
|
1988
|
+
OTHE: "cc_rejected_other_reason",
|
|
1989
|
+
CONT: "pending_contingency",
|
|
1990
|
+
CALL: "cc_rejected_call_for_authorize",
|
|
1991
|
+
FUND: "cc_rejected_insufficient_amount",
|
|
1992
|
+
SECU: "cc_rejected_bad_filled_security_code",
|
|
1993
|
+
EXPI: "cc_rejected_bad_filled_date",
|
|
1994
|
+
FORM: "cc_rejected_bad_filled_other"
|
|
1995
|
+
}
|
|
1996
|
+
},
|
|
1997
|
+
MASTERCARD_CREDIT: {
|
|
1998
|
+
brand: "Mastercard (cr\xE9dito)",
|
|
1999
|
+
number: "5031 7557 3453 0604".replace(/\s/g, ""),
|
|
2000
|
+
cvv: "123",
|
|
2001
|
+
exp: "11/30",
|
|
2002
|
+
paymentMethodId: "master",
|
|
2003
|
+
holderNameToTest: {
|
|
2004
|
+
APRO: "approved",
|
|
2005
|
+
OTHE: "cc_rejected_other_reason",
|
|
2006
|
+
CONT: "pending_contingency",
|
|
2007
|
+
CALL: "cc_rejected_call_for_authorize",
|
|
2008
|
+
FUND: "cc_rejected_insufficient_amount"
|
|
2009
|
+
}
|
|
2010
|
+
},
|
|
2011
|
+
AMEX_CREDIT: {
|
|
2012
|
+
brand: "American Express (cr\xE9dito)",
|
|
2013
|
+
number: "3711 803032 57522".replace(/\s/g, ""),
|
|
2014
|
+
cvv: "1234",
|
|
2015
|
+
exp: "11/30",
|
|
2016
|
+
paymentMethodId: "amex",
|
|
2017
|
+
holderNameToTest: { APRO: "approved", OTHE: "cc_rejected_other_reason" }
|
|
2018
|
+
},
|
|
2019
|
+
VISA_DEBIT: {
|
|
2020
|
+
brand: "Visa (d\xE9bito)",
|
|
2021
|
+
number: "4002 7686 9439 5619".replace(/\s/g, ""),
|
|
2022
|
+
cvv: "123",
|
|
2023
|
+
exp: "11/30",
|
|
2024
|
+
paymentMethodId: "debvisa",
|
|
2025
|
+
holderNameToTest: { APRO: "approved", OTHE: "cc_rejected_other_reason" }
|
|
2026
|
+
},
|
|
2027
|
+
MASTERCARD_DEBIT: {
|
|
2028
|
+
brand: "Mastercard (d\xE9bito)",
|
|
2029
|
+
number: "5287 3383 0125 4634".replace(/\s/g, ""),
|
|
2030
|
+
cvv: "123",
|
|
2031
|
+
exp: "11/30",
|
|
2032
|
+
paymentMethodId: "debmaster",
|
|
2033
|
+
holderNameToTest: { APRO: "approved", OTHE: "cc_rejected_other_reason" }
|
|
2034
|
+
}
|
|
2035
|
+
};
|
|
2036
|
+
var TEST_PAYERS_AR = {
|
|
2037
|
+
approvedBuyer: () => ({
|
|
2038
|
+
email: `test_user_${Date.now()}@testuser.com`,
|
|
2039
|
+
identification: { type: "DNI", number: "12345678" }
|
|
2040
|
+
})
|
|
2041
|
+
};
|
|
2042
|
+
function buildTestCardScenario(cardKey, scenario, amountArs) {
|
|
2043
|
+
const card = TEST_CARDS_AR[cardKey];
|
|
2044
|
+
if (!card) throw new Error(`Unknown test card: ${cardKey}`);
|
|
2045
|
+
if (!card.holderNameToTest[scenario]) {
|
|
2046
|
+
throw new Error(
|
|
2047
|
+
`Card ${cardKey} doesn't define scenario ${scenario}. Available: ${Object.keys(card.holderNameToTest).join(", ")}`
|
|
2048
|
+
);
|
|
2049
|
+
}
|
|
2050
|
+
return {
|
|
2051
|
+
transactionAmount: amountArs,
|
|
2052
|
+
paymentMethodId: card.paymentMethodId,
|
|
2053
|
+
payerEmail: TEST_PAYERS_AR.approvedBuyer().email,
|
|
2054
|
+
description: `TEST ${scenario} via ${cardKey}`,
|
|
2055
|
+
installments: 1,
|
|
2056
|
+
holderName: scenario
|
|
2057
|
+
};
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
// src/three-ds.ts
|
|
2061
|
+
function analyze3DS(payment) {
|
|
2062
|
+
const raw = payment;
|
|
2063
|
+
const mode = raw.three_d_secure_mode ?? null;
|
|
2064
|
+
const statusDetail = payment.status_detail ?? null;
|
|
2065
|
+
if (!mode || mode === "not_supported" || mode === "off") {
|
|
2066
|
+
return {
|
|
2067
|
+
status: "not_required",
|
|
2068
|
+
mode,
|
|
2069
|
+
challengeUrl: null,
|
|
2070
|
+
description: "3DS no fue requerido para este pago (riesgo bajo o emisor sin 3DS habilitado)."
|
|
2071
|
+
};
|
|
2072
|
+
}
|
|
2073
|
+
const threeDsInfo = raw.three_ds_info ?? void 0;
|
|
2074
|
+
if (statusDetail === "pending_challenge" && threeDsInfo?.external_resource_url) {
|
|
2075
|
+
return {
|
|
2076
|
+
status: "challenge_required",
|
|
2077
|
+
mode,
|
|
2078
|
+
challengeUrl: threeDsInfo.external_resource_url,
|
|
2079
|
+
description: "El emisor de la tarjeta requiri\xF3 autenticaci\xF3n 3DS. Redirig\xED al comprador a challengeUrl para completar el desaf\xEDo. El pago queda pending hasta que lo haga."
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
if (payment.status === "approved") {
|
|
2083
|
+
return {
|
|
2084
|
+
status: "frictionless",
|
|
2085
|
+
mode,
|
|
2086
|
+
challengeUrl: null,
|
|
2087
|
+
description: "3DS frictionless: el emisor autoriz\xF3 sin desafiar al comprador."
|
|
2088
|
+
};
|
|
2089
|
+
}
|
|
2090
|
+
if (payment.status === "rejected" && typeof statusDetail === "string" && statusDetail.includes("3ds")) {
|
|
2091
|
+
return {
|
|
2092
|
+
status: "rejected",
|
|
2093
|
+
mode,
|
|
2094
|
+
challengeUrl: null,
|
|
2095
|
+
description: `Autenticaci\xF3n 3DS rechazada (${statusDetail}). El comprador debe usar otra tarjeta o validarla con el emisor.`
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
return {
|
|
2099
|
+
status: "unknown",
|
|
2100
|
+
mode,
|
|
2101
|
+
challengeUrl: threeDsInfo?.external_resource_url ?? null,
|
|
2102
|
+
description: "No se pudo determinar el estado 3DS \u2014 revisar payment.three_d_secure_mode + payment.status_detail manualmente."
|
|
2103
|
+
};
|
|
2104
|
+
}
|
|
1377
2105
|
function parseWebhookEvent(body, searchParams) {
|
|
1378
2106
|
const parseResult = WebhookBodySchema.safeParse(body ?? {});
|
|
1379
2107
|
const parsedBody = parseResult.success ? parseResult.data : {};
|
|
@@ -1475,7 +2203,50 @@ var DEFAULT_DESCRIPTIONS = {
|
|
|
1475
2203
|
get_order: "Fetch an Order by ID. Returns the Order with its lifecycle status and any attached payments/refunds.",
|
|
1476
2204
|
update_order: "Patch an existing Order before it's captured/canceled. Common use: update items or external_reference.",
|
|
1477
2205
|
capture_order: "Capture a previously-authorized Order (only for orders created with capture_mode='manual'). Captures up to the originally-authorized amount; pass amount for partial capture. Common use: ride-share marks ride complete \u2192 capture; hotel checks-out guest \u2192 capture.",
|
|
1478
|
-
cancel_order: "Cancel an Order. Releases any auth-holds and marks the Order as canceled. For orders that have already been CAPTURED, use refund_payment instead \u2014 cancel only works pre-capture."
|
|
2206
|
+
cancel_order: "Cancel an Order. Releases any auth-holds and marks the Order as canceled. For orders that have already been CAPTURED, use refund_payment instead \u2014 cancel only works pre-capture.",
|
|
2207
|
+
// ── Account / Balance / Movements / Settlements (v0.6) ───────────────────
|
|
2208
|
+
get_account_balance: "Get the seller's current MP wallet balance. Returns { available_balance, unavailable_balance, total_amount, currency_id }. The available balance is what the seller can withdraw or pay with right now; unavailable is in retention (typically 14-21 days for new sellers or risk-flagged transactions). For per-seller marketplace setups, instantiate the client AS THE SELLER first.",
|
|
2209
|
+
list_account_movements: "List wallet movements (incoming payments, transfers, refunds, holdings) for the active MP account. Filter by date range with `from`/`to` (ISO 8601). Useful for monthly conciliation or 'show me what came in this month' workflows.",
|
|
2210
|
+
list_settlements: "List settlements (release_money) \u2014 i.e. transfers from the MP wallet to the seller's registered bank account (CBU). USE WHEN the user asks 'cu\xE1ndo me deposita MP' or for monthly bank-conciliation reports. Filter by date range and status.",
|
|
2211
|
+
get_settlement: "Get details of a single settlement: amount, date_scheduled, date_processed, bank_account info (CBU + bank name).",
|
|
2212
|
+
// ── 3DS analyzer (v0.6 — pure) ───────────────────────────────────────────
|
|
2213
|
+
analyze_payment_3ds: "Pure local analyzer for a Payment's 3DS (Strong Customer Authentication) state. Pass a payment_id (string) and the tool fetches the Payment then derives { status: 'not_required'|'frictionless'|'challenge_required'|'rejected'|'unknown', mode, challengeUrl, description }. USE THIS after every create_payment for credit cards: when challengeUrl !== null, you MUST redirect the buyer there before the payment can complete. Without 3DS, payments stay in 'pending' indefinitely if the issuer demanded a challenge.",
|
|
2214
|
+
// ── Test cards (v0.6 — pure) ─────────────────────────────────────────────
|
|
2215
|
+
get_test_cards: "Pure helper that returns the official MP test cards for AR (MLA): VISA/Mastercard/Amex credit + debit, with the 'magic' holder names that route the payment to specific status_detail values (APRO=approved, OTHE=rejected, CONT=pending, FUND=insufficient_amount, etc.). USE WHEN you need to demo a payment flow without a real card, or to script integration tests. Pure data \u2014 no network call.",
|
|
2216
|
+
// ── Customer + Card extensions (v0.7) ────────────────────────────────────
|
|
2217
|
+
get_customer: "Get a customer by id. Returns full Customer object: email, first_name, last_name, identification, address, default_card, registered cards. PURE READ. USE WHEN you have the customer_id from a previous create_customer / find_customer_by_email / payment.payer.id and want the full record.",
|
|
2218
|
+
update_customer: "Update a customer's profile (first_name, last_name, phone, identification, address, default_card). MP merges the patch \u2014 fields you don't send remain unchanged. Use to keep customer records in sync (e.g., shipping address changes) or to set a default card for charge_saved_card.",
|
|
2219
|
+
create_customer_card: "Add a saved card to an existing customer using a card_token (one-time token from MP frontend Cardform \u2014 agents should NEVER take raw card data, that's a PCI violation). Returns the saved CustomerCard with id usable in charge_saved_card. Persists across charges (no need to re-tokenize each time).",
|
|
2220
|
+
get_customer_card: "Get details of a single saved card by (customer_id, card_id). Returns last 4 digits, expiration, brand, issuer. PURE READ \u2014 useful before charge_saved_card to confirm the card is still valid.",
|
|
2221
|
+
// ── Subscription / Plan / Refund / Preference extensions (v0.7) ─────────
|
|
2222
|
+
get_subscription_plan: "Fetch a subscription plan by id. Returns plan config: amount, frequency, status, init_point. Use to inspect a plan before subscribing customers, or to display plan details to the user.",
|
|
2223
|
+
update_subscription: "Update a subscription's amount, status, reason, external_reference, OR card_token_id (to switch payment method when the buyer's card is expired/declined). For card swap: pass card_token_id from a fresh tokenization. CONSTRAINTS: status changes only support 'paused' | 'cancelled' (use authorize via init_point flow to re-activate).",
|
|
2224
|
+
search_subscriptions: "Search subscriptions across the seller's account. Filter by status (pending/authorized/paused/cancelled), payer_email, external_reference, or preapproval_plan_id (to find all subscribers of a plan). Paginated. USE WHEN you need to enumerate active subscribers, audit cancellations, or find a subscription by external reference.",
|
|
2225
|
+
get_refund: "Fetch a single refund by (payment_id, refund_id). Returns the Refund object with amount, status, date_created. PURE READ \u2014 useful to verify a refund processed or to reconcile partial-refund history.",
|
|
2226
|
+
update_payment_preference: "Update a Checkout Pro preference (notification_url, back_urls, items, payer info, payment_methods exclusion list). Only works on preferences NOT yet paid. Common use: regenerate the link with a new notification_url after deployment, or change items if the buyer requested adjustments before paying.",
|
|
2227
|
+
// ── Merchant Orders (v0.7) ────────────────────────────────────────────────
|
|
2228
|
+
get_merchant_order: "Get a merchant_order with all its associated payments + shipments. MerchantOrder is the parent entity for Payments associated with a single Preference \u2014 one Order can have multiple partial Payments (retries, installments). USE THIS in webhooks with topic='merchant_order' to get the aggregate paid_amount, refunded_amount, and shipping status in one call.",
|
|
2229
|
+
search_merchant_orders: "Search merchant_orders by preference_id, external_reference, or status. Paginated. Returns up to 50 per page. USE WHEN you have a preference_id and want all its derived merchant_orders, or when reconciling 'which payments belong to which preference'.",
|
|
2230
|
+
update_merchant_order: "Update a merchant_order \u2014 typically to add items or shipping info. Most agent flows don't need this; use only when integrating with a custom shipping flow that requires updating the MO mid-lifecycle.",
|
|
2231
|
+
// ── Stores + POS CRUD completion (v0.7) ──────────────────────────────────
|
|
2232
|
+
get_store: "Fetch a single store by (user_id, store_id). Returns store details: name, location, business_hours, external_id. PURE READ.",
|
|
2233
|
+
update_store: "Update a store's properties (name, location, business_hours, external_id). MP merges the patch.",
|
|
2234
|
+
delete_store: "Delete a store. IRREVERSIBLE. Confirm with user before calling. Will fail if the store has associated POSes \u2014 delete those first.",
|
|
2235
|
+
get_pos: "Fetch a POS by id. Returns: name, store_id, category, external_id, qr_template (if configured). PURE READ. Use when you need to find the external_id for create_qr_payment.",
|
|
2236
|
+
update_pos: "Update a POS's properties (name, category, external_id). MP merges the patch.",
|
|
2237
|
+
delete_pos: "Delete a POS. IRREVERSIBLE. Cancels any pending QR orders attached to it. Confirm with user before calling.",
|
|
2238
|
+
// ── Bank Accounts (v0.7) ─────────────────────────────────────────────────
|
|
2239
|
+
list_bank_accounts: "List the bank accounts (CBUs) the seller has registered with MP for receiving payouts. Returns an array \u2014 the one with `is_default: true` is where settlements (release_money) go. USE BEFORE list_settlements when the user asks 'a qu\xE9 cuenta me deposita MP'.",
|
|
2240
|
+
register_bank_account: "Register a new bank account (CBU) for the seller. NOTE: MP usually requires this through the dashboard for compliance \u2014 this endpoint may not work for all accounts. If it fails with 403, redirect the user to https://www.mercadopago.com.ar/banking/dashboard.",
|
|
2241
|
+
// ── Point Devices físicos (v0.7) ─────────────────────────────────────────
|
|
2242
|
+
list_point_devices: "List the physical Point devices (Smart, Tap to Pay, etc.) linked to the seller's MP account. Distinct from logical POS \u2014 these are actual terminals at brick-and-mortar shops. Returns each device's id (serial), operating_mode (PDV vs STANDALONE), and pos_id (when bound to a logical POS). Filter by pos_id to find devices for a specific cash register.",
|
|
2243
|
+
update_point_device_mode: "Switch a Point device's operating_mode between 'PDV' (bound to a logical POS, takes payments triggered through that POS) and 'STANDALONE' (works independently, accepts any payment). PDV is for cash-register integrations; STANDALONE is for free-form retail. Affects how payments hit the device.",
|
|
2244
|
+
create_point_payment_intent: "Create a payment intent on a physical Point device \u2014 the device prompts the buyer to tap/insert/swipe their card. Returns immediately with intent_id; query state via get_point_payment_intent or wait for point_integration_wh webhook. **AMOUNT IS IN CENTAVOS**, NOT pesos (Point API differs from Payments API): 100 = $1, 1000 = $10, 10000 = $100.",
|
|
2245
|
+
get_point_payment_intent: "Get the current state of a Point payment intent (OPEN, PROCESSING, FINISHED, CANCELED, ERROR). USE in polling loops if you can't wait for the webhook. When state=FINISHED, the intent.payment.id is the resulting Payment id usable with get_payment.",
|
|
2246
|
+
cancel_point_payment_intent: "Cancel an OPEN point payment intent before the buyer interacts with the device. ONLY WORKS while state='OPEN' \u2014 once the buyer taps, you can't cancel; refund_payment after the fact instead.",
|
|
2247
|
+
// ── Pure helpers (v0.7) ──────────────────────────────────────────────────
|
|
2248
|
+
compute_marketplace_fee: "PURE HELPER (no network) \u2014 given a transaction amount + fee rule (% or flat ARS, with optional min/max floors), returns the exact `marketplace_fee` value in ARS to pass to create_order or create_payment_preference. USE WHEN your platform takes a commission and you need to compute the exact fee per transaction. Examples: { percent: 5, minArs: 50, maxArs: 5000 } for percentage with floor + cap; { flatArs: 200, percent: 2 } for fixed + percentage.",
|
|
2249
|
+
explain_payment_status: "PURE HELPER (no network) \u2014 given a Payment object (from get_payment / create_payment / handle_webhook), returns { summary, recommendedAction, final, paid, retryable } in Spanish. Translates MP's cryptic status_detail codes to plain Spanish + actionable guidance ('reintentar con otra tarjeta' vs 'esperar webhook' vs 'estado final'). USE THIS instead of having to memorize 30+ status_detail codes \u2014 surface summary + recommendedAction directly to the user."
|
|
1479
2250
|
};
|
|
1480
2251
|
function mercadoPagoTools(client, options) {
|
|
1481
2252
|
const desc = (name) => options.descriptions?.[name] ?? DEFAULT_DESCRIPTIONS[name];
|
|
@@ -2782,6 +3553,483 @@ function mercadoPagoTools(client, options) {
|
|
|
2782
3553
|
status: order.status ?? "canceled"
|
|
2783
3554
|
};
|
|
2784
3555
|
}
|
|
3556
|
+
}),
|
|
3557
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3558
|
+
// v0.6 — Account / Balance / Movements / Settlements
|
|
3559
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3560
|
+
get_account_balance: ai.tool({
|
|
3561
|
+
description: desc("get_account_balance"),
|
|
3562
|
+
inputSchema: zod.z.object({}),
|
|
3563
|
+
execute: async () => {
|
|
3564
|
+
const balance = await client.getAccountBalance();
|
|
3565
|
+
return balance;
|
|
3566
|
+
}
|
|
3567
|
+
}),
|
|
3568
|
+
list_account_movements: ai.tool({
|
|
3569
|
+
description: desc("list_account_movements"),
|
|
3570
|
+
inputSchema: zod.z.object({
|
|
3571
|
+
from: zod.z.string().optional().describe("ISO 8601 start date (e.g. 2026-05-01)"),
|
|
3572
|
+
to: zod.z.string().optional().describe("ISO 8601 end date"),
|
|
3573
|
+
limit: zod.z.number().int().min(1).max(100).optional(),
|
|
3574
|
+
offset: zod.z.number().int().min(0).optional()
|
|
3575
|
+
}),
|
|
3576
|
+
execute: async ({ from, to, limit, offset }) => {
|
|
3577
|
+
const params = {};
|
|
3578
|
+
if (from !== void 0) params.from = from;
|
|
3579
|
+
if (to !== void 0) params.to = to;
|
|
3580
|
+
if (limit !== void 0) params.limit = limit;
|
|
3581
|
+
if (offset !== void 0) params.offset = offset;
|
|
3582
|
+
return client.listAccountMovements(params);
|
|
3583
|
+
}
|
|
3584
|
+
}),
|
|
3585
|
+
list_settlements: ai.tool({
|
|
3586
|
+
description: desc("list_settlements"),
|
|
3587
|
+
inputSchema: zod.z.object({
|
|
3588
|
+
from: zod.z.string().optional(),
|
|
3589
|
+
to: zod.z.string().optional(),
|
|
3590
|
+
status: zod.z.string().optional(),
|
|
3591
|
+
limit: zod.z.number().int().min(1).max(100).optional(),
|
|
3592
|
+
offset: zod.z.number().int().min(0).optional()
|
|
3593
|
+
}),
|
|
3594
|
+
execute: async ({ from, to, status, limit, offset }) => {
|
|
3595
|
+
const params = {};
|
|
3596
|
+
if (from !== void 0) params.from = from;
|
|
3597
|
+
if (to !== void 0) params.to = to;
|
|
3598
|
+
if (status !== void 0) params.status = status;
|
|
3599
|
+
if (limit !== void 0) params.limit = limit;
|
|
3600
|
+
if (offset !== void 0) params.offset = offset;
|
|
3601
|
+
return client.listSettlements(params);
|
|
3602
|
+
}
|
|
3603
|
+
}),
|
|
3604
|
+
get_settlement: ai.tool({
|
|
3605
|
+
description: desc("get_settlement"),
|
|
3606
|
+
inputSchema: zod.z.object({ settlement_id: zod.z.string() }),
|
|
3607
|
+
execute: async ({ settlement_id }) => {
|
|
3608
|
+
return client.getSettlement(settlement_id);
|
|
3609
|
+
}
|
|
3610
|
+
}),
|
|
3611
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3612
|
+
// v0.6 — 3DS analyzer (combined: fetch payment + analyze)
|
|
3613
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3614
|
+
analyze_payment_3ds: ai.tool({
|
|
3615
|
+
description: desc("analyze_payment_3ds"),
|
|
3616
|
+
inputSchema: zod.z.object({
|
|
3617
|
+
payment_id: zod.z.string().describe("MP payment id")
|
|
3618
|
+
}),
|
|
3619
|
+
execute: async ({ payment_id }) => {
|
|
3620
|
+
const payment = await client.getPayment(payment_id);
|
|
3621
|
+
const info = analyze3DS(payment);
|
|
3622
|
+
return {
|
|
3623
|
+
payment_id,
|
|
3624
|
+
payment_status: payment.status,
|
|
3625
|
+
payment_status_detail: payment.status_detail ?? null,
|
|
3626
|
+
...info
|
|
3627
|
+
};
|
|
3628
|
+
}
|
|
3629
|
+
}),
|
|
3630
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3631
|
+
// v0.6 — Test cards (pure)
|
|
3632
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3633
|
+
get_test_cards: ai.tool({
|
|
3634
|
+
description: desc("get_test_cards"),
|
|
3635
|
+
inputSchema: zod.z.object({}),
|
|
3636
|
+
execute: async () => {
|
|
3637
|
+
return {
|
|
3638
|
+
site: "MLA",
|
|
3639
|
+
cards: TEST_CARDS_AR,
|
|
3640
|
+
usage: "Pass holderName='APRO' for an approved payment, 'OTHE' for rejected, 'CONT' for pending, 'FUND' for insufficient amount, 'CALL' for call-for-authorize. Use a NEW payer email per call (append a timestamp) to avoid MP idempotency-on-email deduping."
|
|
3641
|
+
};
|
|
3642
|
+
}
|
|
3643
|
+
}),
|
|
3644
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3645
|
+
// v0.7 — Customer + Card extensions
|
|
3646
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3647
|
+
get_customer: ai.tool({
|
|
3648
|
+
description: desc("get_customer"),
|
|
3649
|
+
inputSchema: zod.z.object({ customer_id: zod.z.string() }),
|
|
3650
|
+
execute: async ({ customer_id }) => {
|
|
3651
|
+
return client.getCustomer(customer_id);
|
|
3652
|
+
}
|
|
3653
|
+
}),
|
|
3654
|
+
update_customer: ai.tool({
|
|
3655
|
+
description: desc("update_customer"),
|
|
3656
|
+
inputSchema: zod.z.object({
|
|
3657
|
+
customer_id: zod.z.string(),
|
|
3658
|
+
first_name: zod.z.string().optional(),
|
|
3659
|
+
last_name: zod.z.string().optional(),
|
|
3660
|
+
phone: zod.z.object({ area_code: zod.z.string().optional(), number: zod.z.string().optional() }).optional(),
|
|
3661
|
+
identification: zod.z.object({ type: zod.z.string(), number: zod.z.string() }).optional(),
|
|
3662
|
+
address: zod.z.object({
|
|
3663
|
+
street_name: zod.z.string().optional(),
|
|
3664
|
+
street_number: zod.z.number().optional(),
|
|
3665
|
+
zip_code: zod.z.string().optional()
|
|
3666
|
+
}).optional(),
|
|
3667
|
+
description: zod.z.string().optional(),
|
|
3668
|
+
default_card: zod.z.string().optional()
|
|
3669
|
+
}),
|
|
3670
|
+
execute: async ({ customer_id, ...patch }) => {
|
|
3671
|
+
const cleaned = {};
|
|
3672
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
3673
|
+
if (v !== void 0) cleaned[k] = v;
|
|
3674
|
+
}
|
|
3675
|
+
return client.updateCustomer(customer_id, cleaned);
|
|
3676
|
+
}
|
|
3677
|
+
}),
|
|
3678
|
+
create_customer_card: ai.tool({
|
|
3679
|
+
description: desc("create_customer_card"),
|
|
3680
|
+
inputSchema: zod.z.object({
|
|
3681
|
+
customer_id: zod.z.string(),
|
|
3682
|
+
card_token: zod.z.string().describe("Card token from MP frontend Cardform OR create_card_token.")
|
|
3683
|
+
}),
|
|
3684
|
+
execute: async ({ customer_id, card_token }) => {
|
|
3685
|
+
return client.createCustomerCard(customer_id, card_token);
|
|
3686
|
+
}
|
|
3687
|
+
}),
|
|
3688
|
+
get_customer_card: ai.tool({
|
|
3689
|
+
description: desc("get_customer_card"),
|
|
3690
|
+
inputSchema: zod.z.object({
|
|
3691
|
+
customer_id: zod.z.string(),
|
|
3692
|
+
card_id: zod.z.string()
|
|
3693
|
+
}),
|
|
3694
|
+
execute: async ({ customer_id, card_id }) => {
|
|
3695
|
+
return client.getCustomerCard(customer_id, card_id);
|
|
3696
|
+
}
|
|
3697
|
+
}),
|
|
3698
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3699
|
+
// v0.7 — Subscription / Plan / Refund / Preference extensions
|
|
3700
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3701
|
+
get_subscription_plan: ai.tool({
|
|
3702
|
+
description: desc("get_subscription_plan"),
|
|
3703
|
+
inputSchema: zod.z.object({ plan_id: zod.z.string() }),
|
|
3704
|
+
execute: async ({ plan_id }) => {
|
|
3705
|
+
return client.getSubscriptionPlan(plan_id);
|
|
3706
|
+
}
|
|
3707
|
+
}),
|
|
3708
|
+
update_subscription: ai.tool({
|
|
3709
|
+
description: desc("update_subscription"),
|
|
3710
|
+
inputSchema: zod.z.object({
|
|
3711
|
+
subscription_id: zod.z.string(),
|
|
3712
|
+
transaction_amount: zod.z.number().positive().optional(),
|
|
3713
|
+
card_token_id: zod.z.string().optional(),
|
|
3714
|
+
status: zod.z.enum(["authorized", "paused", "cancelled"]).optional(),
|
|
3715
|
+
reason: zod.z.string().optional(),
|
|
3716
|
+
external_reference: zod.z.string().optional()
|
|
3717
|
+
}),
|
|
3718
|
+
execute: async ({ subscription_id, ...patch }) => {
|
|
3719
|
+
const cleaned = {};
|
|
3720
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
3721
|
+
if (v !== void 0) cleaned[k] = v;
|
|
3722
|
+
}
|
|
3723
|
+
return client.updatePreapproval(subscription_id, cleaned);
|
|
3724
|
+
}
|
|
3725
|
+
}),
|
|
3726
|
+
search_subscriptions: ai.tool({
|
|
3727
|
+
description: desc("search_subscriptions"),
|
|
3728
|
+
inputSchema: zod.z.object({
|
|
3729
|
+
status: zod.z.string().optional(),
|
|
3730
|
+
payer_email: zod.z.string().email().optional(),
|
|
3731
|
+
external_reference: zod.z.string().optional(),
|
|
3732
|
+
plan_id: zod.z.string().optional(),
|
|
3733
|
+
limit: zod.z.number().int().min(1).max(100).optional(),
|
|
3734
|
+
offset: zod.z.number().int().min(0).optional()
|
|
3735
|
+
}),
|
|
3736
|
+
execute: async ({ status, payer_email, external_reference, plan_id, limit, offset }) => {
|
|
3737
|
+
const params = {};
|
|
3738
|
+
if (status !== void 0) params.status = status;
|
|
3739
|
+
if (payer_email !== void 0) params.payerEmail = payer_email;
|
|
3740
|
+
if (external_reference !== void 0) params.externalReference = external_reference;
|
|
3741
|
+
if (plan_id !== void 0) params.preapproval_plan_id = plan_id;
|
|
3742
|
+
if (limit !== void 0) params.limit = limit;
|
|
3743
|
+
if (offset !== void 0) params.offset = offset;
|
|
3744
|
+
return client.searchPreapprovals(params);
|
|
3745
|
+
}
|
|
3746
|
+
}),
|
|
3747
|
+
get_refund: ai.tool({
|
|
3748
|
+
description: desc("get_refund"),
|
|
3749
|
+
inputSchema: zod.z.object({
|
|
3750
|
+
payment_id: zod.z.string(),
|
|
3751
|
+
refund_id: zod.z.string()
|
|
3752
|
+
}),
|
|
3753
|
+
execute: async ({ payment_id, refund_id }) => {
|
|
3754
|
+
return client.getRefund(payment_id, refund_id);
|
|
3755
|
+
}
|
|
3756
|
+
}),
|
|
3757
|
+
update_payment_preference: ai.tool({
|
|
3758
|
+
description: desc("update_payment_preference"),
|
|
3759
|
+
inputSchema: zod.z.object({
|
|
3760
|
+
preference_id: zod.z.string(),
|
|
3761
|
+
notification_url: zod.z.string().url().optional(),
|
|
3762
|
+
external_reference: zod.z.string().optional(),
|
|
3763
|
+
statement_descriptor: zod.z.string().optional()
|
|
3764
|
+
}),
|
|
3765
|
+
execute: async ({ preference_id, ...patch }) => {
|
|
3766
|
+
const cleaned = {};
|
|
3767
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
3768
|
+
if (v !== void 0) cleaned[k] = v;
|
|
3769
|
+
}
|
|
3770
|
+
return client.updatePreference(preference_id, cleaned);
|
|
3771
|
+
}
|
|
3772
|
+
}),
|
|
3773
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3774
|
+
// v0.7 — Merchant Orders
|
|
3775
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3776
|
+
get_merchant_order: ai.tool({
|
|
3777
|
+
description: desc("get_merchant_order"),
|
|
3778
|
+
inputSchema: zod.z.object({ merchant_order_id: zod.z.string() }),
|
|
3779
|
+
execute: async ({ merchant_order_id }) => {
|
|
3780
|
+
return client.getMerchantOrder(merchant_order_id);
|
|
3781
|
+
}
|
|
3782
|
+
}),
|
|
3783
|
+
search_merchant_orders: ai.tool({
|
|
3784
|
+
description: desc("search_merchant_orders"),
|
|
3785
|
+
inputSchema: zod.z.object({
|
|
3786
|
+
preference_id: zod.z.string().optional(),
|
|
3787
|
+
external_reference: zod.z.string().optional(),
|
|
3788
|
+
status: zod.z.string().optional(),
|
|
3789
|
+
limit: zod.z.number().int().min(1).max(100).optional(),
|
|
3790
|
+
offset: zod.z.number().int().min(0).optional()
|
|
3791
|
+
}),
|
|
3792
|
+
execute: async ({ preference_id, external_reference, status, limit, offset }) => {
|
|
3793
|
+
const params = {};
|
|
3794
|
+
if (preference_id !== void 0) params.preferenceId = preference_id;
|
|
3795
|
+
if (external_reference !== void 0) params.externalReference = external_reference;
|
|
3796
|
+
if (status !== void 0) params.status = status;
|
|
3797
|
+
if (limit !== void 0) params.limit = limit;
|
|
3798
|
+
if (offset !== void 0) params.offset = offset;
|
|
3799
|
+
return client.searchMerchantOrders(params);
|
|
3800
|
+
}
|
|
3801
|
+
}),
|
|
3802
|
+
update_merchant_order: ai.tool({
|
|
3803
|
+
description: desc("update_merchant_order"),
|
|
3804
|
+
inputSchema: zod.z.object({
|
|
3805
|
+
merchant_order_id: zod.z.string(),
|
|
3806
|
+
patch: zod.z.record(zod.z.string(), zod.z.unknown())
|
|
3807
|
+
}),
|
|
3808
|
+
execute: async ({ merchant_order_id, patch }) => {
|
|
3809
|
+
return client.updateMerchantOrder(merchant_order_id, patch);
|
|
3810
|
+
}
|
|
3811
|
+
}),
|
|
3812
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3813
|
+
// v0.7 — Stores + POS CRUD completion
|
|
3814
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3815
|
+
get_store: ai.tool({
|
|
3816
|
+
description: desc("get_store"),
|
|
3817
|
+
inputSchema: zod.z.object({
|
|
3818
|
+
user_id: zod.z.string(),
|
|
3819
|
+
store_id: zod.z.string()
|
|
3820
|
+
}),
|
|
3821
|
+
execute: async ({ user_id, store_id }) => {
|
|
3822
|
+
return client.getStore(user_id, store_id);
|
|
3823
|
+
}
|
|
3824
|
+
}),
|
|
3825
|
+
update_store: ai.tool({
|
|
3826
|
+
description: desc("update_store"),
|
|
3827
|
+
inputSchema: zod.z.object({
|
|
3828
|
+
user_id: zod.z.string(),
|
|
3829
|
+
store_id: zod.z.string(),
|
|
3830
|
+
name: zod.z.string().optional(),
|
|
3831
|
+
external_id: zod.z.string().optional()
|
|
3832
|
+
}),
|
|
3833
|
+
execute: async ({ user_id, store_id, ...patch }) => {
|
|
3834
|
+
const cleaned = {};
|
|
3835
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
3836
|
+
if (v !== void 0) cleaned[k] = v;
|
|
3837
|
+
}
|
|
3838
|
+
return client.updateStore(user_id, store_id, cleaned);
|
|
3839
|
+
}
|
|
3840
|
+
}),
|
|
3841
|
+
delete_store: ai.tool({
|
|
3842
|
+
description: desc("delete_store"),
|
|
3843
|
+
inputSchema: zod.z.object({
|
|
3844
|
+
user_id: zod.z.string(),
|
|
3845
|
+
store_id: zod.z.string()
|
|
3846
|
+
}),
|
|
3847
|
+
execute: async ({ user_id, store_id }) => {
|
|
3848
|
+
await client.deleteStore(user_id, store_id);
|
|
3849
|
+
return { user_id, store_id, deleted: true };
|
|
3850
|
+
}
|
|
3851
|
+
}),
|
|
3852
|
+
get_pos: ai.tool({
|
|
3853
|
+
description: desc("get_pos"),
|
|
3854
|
+
inputSchema: zod.z.object({ pos_id: zod.z.string() }),
|
|
3855
|
+
execute: async ({ pos_id }) => {
|
|
3856
|
+
return client.getPos(pos_id);
|
|
3857
|
+
}
|
|
3858
|
+
}),
|
|
3859
|
+
update_pos: ai.tool({
|
|
3860
|
+
description: desc("update_pos"),
|
|
3861
|
+
inputSchema: zod.z.object({
|
|
3862
|
+
pos_id: zod.z.string(),
|
|
3863
|
+
name: zod.z.string().optional(),
|
|
3864
|
+
external_id: zod.z.string().optional(),
|
|
3865
|
+
category: zod.z.number().optional()
|
|
3866
|
+
}),
|
|
3867
|
+
execute: async ({ pos_id, ...patch }) => {
|
|
3868
|
+
const cleaned = {};
|
|
3869
|
+
for (const [k, v] of Object.entries(patch)) {
|
|
3870
|
+
if (v !== void 0) cleaned[k] = v;
|
|
3871
|
+
}
|
|
3872
|
+
return client.updatePos(pos_id, cleaned);
|
|
3873
|
+
}
|
|
3874
|
+
}),
|
|
3875
|
+
delete_pos: ai.tool({
|
|
3876
|
+
description: desc("delete_pos"),
|
|
3877
|
+
inputSchema: zod.z.object({ pos_id: zod.z.string() }),
|
|
3878
|
+
execute: async ({ pos_id }) => {
|
|
3879
|
+
await client.deletePos(pos_id);
|
|
3880
|
+
return { pos_id, deleted: true };
|
|
3881
|
+
}
|
|
3882
|
+
}),
|
|
3883
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3884
|
+
// v0.7 — Bank Accounts
|
|
3885
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3886
|
+
list_bank_accounts: ai.tool({
|
|
3887
|
+
description: desc("list_bank_accounts"),
|
|
3888
|
+
inputSchema: zod.z.object({}),
|
|
3889
|
+
execute: async () => {
|
|
3890
|
+
const accounts = await client.listBankAccounts();
|
|
3891
|
+
return { accounts };
|
|
3892
|
+
}
|
|
3893
|
+
}),
|
|
3894
|
+
register_bank_account: ai.tool({
|
|
3895
|
+
description: desc("register_bank_account"),
|
|
3896
|
+
inputSchema: zod.z.object({
|
|
3897
|
+
cbu: zod.z.string().regex(/^\d{22}$/),
|
|
3898
|
+
alias: zod.z.string().optional()
|
|
3899
|
+
}),
|
|
3900
|
+
execute: async (input) => {
|
|
3901
|
+
const params = {
|
|
3902
|
+
cbu: input.cbu
|
|
3903
|
+
};
|
|
3904
|
+
if (input.alias !== void 0) params.alias = input.alias;
|
|
3905
|
+
return client.registerBankAccount(params);
|
|
3906
|
+
}
|
|
3907
|
+
}),
|
|
3908
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3909
|
+
// v0.7 — Point Devices físicos
|
|
3910
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3911
|
+
list_point_devices: ai.tool({
|
|
3912
|
+
description: desc("list_point_devices"),
|
|
3913
|
+
inputSchema: zod.z.object({
|
|
3914
|
+
pos_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
|
|
3915
|
+
limit: zod.z.number().int().min(1).max(100).optional(),
|
|
3916
|
+
offset: zod.z.number().int().min(0).optional()
|
|
3917
|
+
}),
|
|
3918
|
+
execute: async ({ pos_id, limit, offset }) => {
|
|
3919
|
+
const params = {};
|
|
3920
|
+
if (pos_id !== void 0) params.posId = pos_id;
|
|
3921
|
+
if (limit !== void 0) params.limit = limit;
|
|
3922
|
+
if (offset !== void 0) params.offset = offset;
|
|
3923
|
+
return client.listPointDevices(params);
|
|
3924
|
+
}
|
|
3925
|
+
}),
|
|
3926
|
+
update_point_device_mode: ai.tool({
|
|
3927
|
+
description: desc("update_point_device_mode"),
|
|
3928
|
+
inputSchema: zod.z.object({
|
|
3929
|
+
device_id: zod.z.string(),
|
|
3930
|
+
operating_mode: zod.z.enum(["PDV", "STANDALONE"])
|
|
3931
|
+
}),
|
|
3932
|
+
execute: async ({ device_id, operating_mode }) => {
|
|
3933
|
+
return client.updatePointDeviceOperatingMode(device_id, operating_mode);
|
|
3934
|
+
}
|
|
3935
|
+
}),
|
|
3936
|
+
create_point_payment_intent: ai.tool({
|
|
3937
|
+
description: desc("create_point_payment_intent"),
|
|
3938
|
+
inputSchema: zod.z.object({
|
|
3939
|
+
device_id: zod.z.string(),
|
|
3940
|
+
amount_centavos: zod.z.number().int().positive().describe("Amount in CENTAVOS (NOT pesos). 100 = $1, 1000 = $10, 10000 = $100."),
|
|
3941
|
+
description: zod.z.string().optional(),
|
|
3942
|
+
external_reference: zod.z.string().optional(),
|
|
3943
|
+
installments: zod.z.number().int().min(1).max(24).optional(),
|
|
3944
|
+
installments_cost: zod.z.enum(["seller", "buyer"]).optional(),
|
|
3945
|
+
print_on_terminal: zod.z.boolean().optional(),
|
|
3946
|
+
ticket_number: zod.z.string().optional()
|
|
3947
|
+
}),
|
|
3948
|
+
execute: async (input) => {
|
|
3949
|
+
const params = {
|
|
3950
|
+
amount: input.amount_centavos
|
|
3951
|
+
};
|
|
3952
|
+
if (input.description !== void 0) params.description = input.description;
|
|
3953
|
+
if (input.external_reference !== void 0) params.externalReference = input.external_reference;
|
|
3954
|
+
if (input.installments !== void 0) params.installments = input.installments;
|
|
3955
|
+
if (input.installments_cost !== void 0) params.installmentsCost = input.installments_cost;
|
|
3956
|
+
if (input.print_on_terminal !== void 0) params.printOnTerminal = input.print_on_terminal;
|
|
3957
|
+
if (input.ticket_number !== void 0) params.ticketNumber = input.ticket_number;
|
|
3958
|
+
return client.createPointPaymentIntent(input.device_id, params);
|
|
3959
|
+
}
|
|
3960
|
+
}),
|
|
3961
|
+
get_point_payment_intent: ai.tool({
|
|
3962
|
+
description: desc("get_point_payment_intent"),
|
|
3963
|
+
inputSchema: zod.z.object({ intent_id: zod.z.string() }),
|
|
3964
|
+
execute: async ({ intent_id }) => {
|
|
3965
|
+
return client.getPointPaymentIntent(intent_id);
|
|
3966
|
+
}
|
|
3967
|
+
}),
|
|
3968
|
+
cancel_point_payment_intent: ai.tool({
|
|
3969
|
+
description: desc("cancel_point_payment_intent"),
|
|
3970
|
+
inputSchema: zod.z.object({
|
|
3971
|
+
device_id: zod.z.string(),
|
|
3972
|
+
intent_id: zod.z.string()
|
|
3973
|
+
}),
|
|
3974
|
+
execute: async ({ device_id, intent_id }) => {
|
|
3975
|
+
return client.cancelPointPaymentIntent(device_id, intent_id);
|
|
3976
|
+
}
|
|
3977
|
+
}),
|
|
3978
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3979
|
+
// v0.7 — Pure helpers
|
|
3980
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
3981
|
+
compute_marketplace_fee: ai.tool({
|
|
3982
|
+
description: desc("compute_marketplace_fee"),
|
|
3983
|
+
inputSchema: zod.z.object({
|
|
3984
|
+
amount_ars: zod.z.number().positive(),
|
|
3985
|
+
flat_ars: zod.z.number().nonnegative().optional(),
|
|
3986
|
+
percent: zod.z.number().min(0).max(100).optional(),
|
|
3987
|
+
min_ars: zod.z.number().nonnegative().optional(),
|
|
3988
|
+
max_ars: zod.z.number().nonnegative().optional(),
|
|
3989
|
+
round: zod.z.boolean().optional()
|
|
3990
|
+
}),
|
|
3991
|
+
execute: async (input) => {
|
|
3992
|
+
const rule = {};
|
|
3993
|
+
if (input.flat_ars !== void 0) rule.flatArs = input.flat_ars;
|
|
3994
|
+
if (input.percent !== void 0) rule.percent = input.percent;
|
|
3995
|
+
if (input.min_ars !== void 0) rule.minArs = input.min_ars;
|
|
3996
|
+
if (input.max_ars !== void 0) rule.maxArs = input.max_ars;
|
|
3997
|
+
if (input.round !== void 0) rule.round = input.round;
|
|
3998
|
+
const fee = computeMarketplaceFee(input.amount_ars, rule);
|
|
3999
|
+
return {
|
|
4000
|
+
amount_ars: input.amount_ars,
|
|
4001
|
+
marketplace_fee: fee,
|
|
4002
|
+
seller_receives: input.amount_ars - fee,
|
|
4003
|
+
rule_applied: rule
|
|
4004
|
+
};
|
|
4005
|
+
}
|
|
4006
|
+
}),
|
|
4007
|
+
explain_payment_status: ai.tool({
|
|
4008
|
+
description: desc("explain_payment_status"),
|
|
4009
|
+
inputSchema: zod.z.object({
|
|
4010
|
+
payment_id: zod.z.string().optional().describe("If provided, fetches the Payment first."),
|
|
4011
|
+
payment: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe("Alternatively, pass a Payment object directly (saves a network round-trip).")
|
|
4012
|
+
}),
|
|
4013
|
+
execute: async ({ payment_id, payment }) => {
|
|
4014
|
+
let p;
|
|
4015
|
+
if (payment) {
|
|
4016
|
+
p = payment;
|
|
4017
|
+
} else if (payment_id) {
|
|
4018
|
+
p = await client.getPayment(payment_id);
|
|
4019
|
+
} else {
|
|
4020
|
+
return {
|
|
4021
|
+
ok: false,
|
|
4022
|
+
error: "Pass either payment_id or payment."
|
|
4023
|
+
};
|
|
4024
|
+
}
|
|
4025
|
+
const explanation = explainPaymentStatus(p);
|
|
4026
|
+
return {
|
|
4027
|
+
ok: true,
|
|
4028
|
+
payment_status: p.status,
|
|
4029
|
+
payment_status_detail: p.status_detail ?? null,
|
|
4030
|
+
...explanation
|
|
4031
|
+
};
|
|
4032
|
+
}
|
|
2785
4033
|
})
|
|
2786
4034
|
};
|
|
2787
4035
|
}
|
|
@@ -2817,10 +4065,16 @@ exports.MercadoPagoPaymentRejectedError = MercadoPagoPaymentRejectedError;
|
|
|
2817
4065
|
exports.MercadoPagoRateLimitError = MercadoPagoRateLimitError;
|
|
2818
4066
|
exports.MercadoPagoSelfPaymentError = MercadoPagoSelfPaymentError;
|
|
2819
4067
|
exports.MercadoPagoTimeoutError = MercadoPagoTimeoutError;
|
|
4068
|
+
exports.TEST_CARDS_AR = TEST_CARDS_AR;
|
|
4069
|
+
exports.TEST_PAYERS_AR = TEST_PAYERS_AR;
|
|
4070
|
+
exports.analyze3DS = analyze3DS;
|
|
2820
4071
|
exports.buildAuthorizeUrl = buildAuthorizeUrl;
|
|
4072
|
+
exports.buildTestCardScenario = buildTestCardScenario;
|
|
2821
4073
|
exports.classifyError = classifyError;
|
|
4074
|
+
exports.computeMarketplaceFee = computeMarketplaceFee;
|
|
2822
4075
|
exports.exchangeCodeForToken = exchangeCodeForToken;
|
|
2823
4076
|
exports.expirationTimeMs = expirationTimeMs;
|
|
4077
|
+
exports.explainPaymentStatus = explainPaymentStatus;
|
|
2824
4078
|
exports.isExpiringSoon = isExpiringSoon;
|
|
2825
4079
|
exports.mercadoPagoTools = mercadoPagoTools;
|
|
2826
4080
|
exports.parseWebhookEvent = parseWebhookEvent;
|