@ar-agents/mercadopago 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -507,6 +507,9 @@ var MercadoPagoClient = class {
507
507
  if (params.expires !== void 0) body.expires = params.expires;
508
508
  if (params.expirationDateFrom) body.expiration_date_from = params.expirationDateFrom;
509
509
  if (params.expirationDateTo) body.expiration_date_to = params.expirationDateTo;
510
+ if (params.marketplace) body.marketplace = params.marketplace;
511
+ if (params.marketplaceFee !== void 0) body.marketplace_fee = params.marketplaceFee;
512
+ if (params.collectorId !== void 0) body.collector_id = params.collectorId;
510
513
  return this.request("POST", "/checkout/preferences", body);
511
514
  }
512
515
  async getPreference(id) {
@@ -714,7 +717,693 @@ var MercadoPagoClient = class {
714
717
  `/instore/orders/qr/seller/collectors/${encodeURIComponent(userId)}/pos/${encodeURIComponent(externalPosId)}/qrs`
715
718
  );
716
719
  }
720
+ // ───────────────────────────────────────────────────────────────────────────
721
+ // Subscription Plans (preapproval_plan — reusable plans, v0.4)
722
+ // ───────────────────────────────────────────────────────────────────────────
723
+ /**
724
+ * Create a reusable subscription plan. Customers later subscribe to it via
725
+ * `subscribeToPlan` (which creates a preapproval pointing at the plan).
726
+ *
727
+ * Use this when you have fixed tiers (Básico/Pro/Enterprise). For custom
728
+ * per-customer amounts, skip plans and use `createPreapproval` directly.
729
+ */
730
+ async createSubscriptionPlan(params) {
731
+ const body = {
732
+ reason: params.reason,
733
+ back_url: params.backUrl,
734
+ auto_recurring: {
735
+ frequency: params.frequency,
736
+ frequency_type: params.frequencyType,
737
+ transaction_amount: params.amount,
738
+ currency_id: params.currency,
739
+ ...params.freeTrialFrequency !== void 0 && params.freeTrialFrequencyType !== void 0 ? {
740
+ free_trial: {
741
+ frequency: params.freeTrialFrequency,
742
+ frequency_type: params.freeTrialFrequencyType
743
+ }
744
+ } : {}
745
+ }
746
+ };
747
+ if (params.externalReference) body.external_reference = params.externalReference;
748
+ return this.request("POST", "/preapproval_plan", body);
749
+ }
750
+ async getSubscriptionPlan(id) {
751
+ return this.request("GET", `/preapproval_plan/${id}`);
752
+ }
753
+ async listSubscriptionPlans(params = {}) {
754
+ const query = {
755
+ limit: params.limit ?? 30,
756
+ offset: params.offset ?? 0
757
+ };
758
+ if (params.status) query["status"] = params.status;
759
+ return this.request("GET", "/preapproval_plan/search", void 0, { query });
760
+ }
761
+ async updateSubscriptionPlan(id, patch) {
762
+ const body = {};
763
+ if (patch.reason !== void 0) body.reason = patch.reason;
764
+ if (patch.status !== void 0) body.status = patch.status;
765
+ if (patch.backUrl !== void 0) body.back_url = patch.backUrl;
766
+ if (patch.amount !== void 0) {
767
+ body.auto_recurring = { transaction_amount: patch.amount };
768
+ }
769
+ return this.request("PUT", `/preapproval_plan/${id}`, body);
770
+ }
771
+ /**
772
+ * Subscribe a customer to an existing plan. Returns a Preapproval with
773
+ * `init_point` URL where the buyer completes the first payment.
774
+ */
775
+ async subscribeToPlan(params) {
776
+ const body = {
777
+ preapproval_plan_id: params.planId,
778
+ payer_email: params.payerEmail
779
+ };
780
+ if (params.cardTokenId) body.card_token_id = params.cardTokenId;
781
+ if (params.externalReference) body.external_reference = params.externalReference;
782
+ return this.request("POST", "/preapproval", body, {
783
+ classifyContext: { payerEmail: params.payerEmail }
784
+ });
785
+ }
786
+ /**
787
+ * List the auto-charge attempts (authorized_payments) under a preapproval.
788
+ * Useful for "show me the cobros of the last 6 months for this client".
789
+ */
790
+ async listSubscriptionPayments(preapprovalId, params = {}) {
791
+ const query = {
792
+ preapproval_id: preapprovalId,
793
+ limit: params.limit ?? 30,
794
+ offset: params.offset ?? 0
795
+ };
796
+ return this.request(
797
+ "GET",
798
+ `/authorized_payments/search`,
799
+ void 0,
800
+ { query, classifyContext: { preapprovalId } }
801
+ );
802
+ }
803
+ // ───────────────────────────────────────────────────────────────────────────
804
+ // Stores + POS (for QR payments self-serve setup, v0.4)
805
+ // ───────────────────────────────────────────────────────────────────────────
806
+ /** Create a store for the seller. POSes (for QR) live under stores. */
807
+ async createStore(userId, params) {
808
+ const body = {
809
+ name: params.name,
810
+ external_id: params.externalId
811
+ };
812
+ if (params.location) {
813
+ body.location = {
814
+ ...params.location.addressLine ? { address_line: params.location.addressLine } : {},
815
+ ...params.location.cityName ? { city_name: params.location.cityName } : {},
816
+ ...params.location.stateName ? { state_name: params.location.stateName } : {},
817
+ ...params.location.countryId ? { country_id: params.location.countryId } : {},
818
+ ...params.location.latitude !== void 0 ? { latitude: params.location.latitude } : {},
819
+ ...params.location.longitude !== void 0 ? { longitude: params.location.longitude } : {}
820
+ };
821
+ }
822
+ return this.request("POST", `/users/${encodeURIComponent(userId)}/stores`, body);
823
+ }
824
+ async listStores(userId, params = {}) {
825
+ const query = {
826
+ limit: params.limit ?? 50,
827
+ offset: params.offset ?? 0
828
+ };
829
+ return this.request("GET", `/users/${encodeURIComponent(userId)}/stores/search`, void 0, { query });
830
+ }
831
+ /** Create a POS under a store. The POS's `external_id` is what `createQrPayment` uses. */
832
+ async createPos(params) {
833
+ const body = {
834
+ name: params.name,
835
+ external_id: params.externalId,
836
+ store_id: params.storeId,
837
+ category: params.category ?? 621102
838
+ // "Other Food and Beverage Services" — generic default
839
+ };
840
+ if (params.fixedAmount !== void 0) body.fixed_amount = params.fixedAmount;
841
+ return this.request("POST", "/pos", body);
842
+ }
843
+ async listPos(params = {}) {
844
+ const query = {
845
+ limit: params.limit ?? 50,
846
+ offset: params.offset ?? 0
847
+ };
848
+ if (params.storeId !== void 0) query["store_id"] = String(params.storeId);
849
+ return this.request("GET", "/pos", void 0, { query });
850
+ }
851
+ // ───────────────────────────────────────────────────────────────────────────
852
+ // Disputes (read-only, v0.4)
853
+ // ───────────────────────────────────────────────────────────────────────────
854
+ async listPaymentDisputes(paymentId) {
855
+ return this.request("GET", `/v1/payments/${paymentId}/disputes`, void 0, {
856
+ classifyContext: { paymentId }
857
+ });
858
+ }
859
+ async getDispute(paymentId, disputeId) {
860
+ return this.request(
861
+ "GET",
862
+ `/v1/payments/${paymentId}/disputes/${disputeId}`,
863
+ void 0,
864
+ { classifyContext: { paymentId } }
865
+ );
866
+ }
867
+ // ───────────────────────────────────────────────────────────────────────────
868
+ // Identification Types + Issuers (lookup helpers, v0.4)
869
+ // ───────────────────────────────────────────────────────────────────────────
870
+ /** List valid identification types for the seller's site. AR returns DNI/CI/LE/LC/Otro/Pasaporte/CUIT/CUIL. */
871
+ async listIdentificationTypes() {
872
+ return this.request("GET", "/v1/identification_types");
873
+ }
874
+ /** List card issuers for a payment method. Useful with `bin` for installments. */
875
+ async listIssuers(params) {
876
+ const query = {
877
+ payment_method_id: params.paymentMethodId
878
+ };
879
+ if (params.bin) query["bin"] = params.bin;
880
+ return this.request("GET", "/v1/payment_methods/card_issuers", void 0, { query });
881
+ }
882
+ // ───────────────────────────────────────────────────────────────────────────
883
+ // Webhooks management (v0.4)
884
+ // ───────────────────────────────────────────────────────────────────────────
885
+ /** List configured webhook subscriptions. */
886
+ async listWebhooks() {
887
+ return this.request("GET", "/v1/webhooks");
888
+ }
889
+ /** Create a webhook subscription for a topic. */
890
+ async createWebhook(params) {
891
+ return this.request("POST", "/v1/webhooks", {
892
+ url: params.url,
893
+ topic: params.topic
894
+ });
895
+ }
896
+ async updateWebhook(id, patch) {
897
+ return this.request("PUT", `/v1/webhooks/${id}`, patch);
898
+ }
899
+ async deleteWebhook(id) {
900
+ await this.request("DELETE", `/v1/webhooks/${id}`);
901
+ }
902
+ // ──────────────────────────────────────────────────────────────────────────
903
+ // v0.5 — Order Management API
904
+ //
905
+ // The Order API is MP's newer abstraction for purchases, replacing some
906
+ // Preference flows. Distinct from Preference: Order is a transactional
907
+ // entity with explicit lifecycle (created → processed → captured/canceled),
908
+ // supports manual capture (auth-only, capture later), and can attach
909
+ // multiple payments to a single Order.
910
+ //
911
+ // Use Order when you need:
912
+ // - Auth-only flow (capture later, e.g. ride-share, hotels)
913
+ // - Multi-payment aggregation (one Order = N partial payments)
914
+ // - In-store + online unified status
915
+ //
916
+ // Stick with Preference (Checkout Pro) when you just need a hosted pay-link.
917
+ // ──────────────────────────────────────────────────────────────────────────
918
+ /**
919
+ * Create a new Order. Use `capture_mode: "manual"` for auth-only flows
920
+ * where you want to capture funds later (ride-share, hotels, marketplaces).
921
+ *
922
+ * For marketplace splits, set `marketplace`, `marketplace_fee`,
923
+ * `collector_id` — see `MarketplaceParams`.
924
+ */
925
+ async createOrder(params, options) {
926
+ const body = {
927
+ type: params.type
928
+ };
929
+ if (params.currency_id) body.currency_id = params.currency_id;
930
+ if (params.external_reference) body.external_reference = params.external_reference;
931
+ if (params.items) body.items = params.items;
932
+ if (params.total_amount !== void 0) body.total_amount = params.total_amount;
933
+ if (params.payer) body.payer = params.payer;
934
+ if (params.capture_mode) body.capture_mode = params.capture_mode;
935
+ if (params.notification_url) body.notification_url = params.notification_url;
936
+ if (params.marketplace) body.marketplace = params.marketplace;
937
+ if (params.marketplace_fee !== void 0) body.marketplace_fee = params.marketplace_fee;
938
+ if (params.collector_id !== void 0) body.collector_id = params.collector_id;
939
+ return this.request("POST", "/v1/orders", body, options);
940
+ }
941
+ async getOrder(id) {
942
+ return this.request("GET", `/v1/orders/${id}`);
943
+ }
944
+ async updateOrder(id, patch) {
945
+ return this.request("PUT", `/v1/orders/${id}`, patch);
946
+ }
947
+ /**
948
+ * Capture a previously-authorized Order (only for orders created with
949
+ * `capture_mode: "manual"`). Captures up to the originally-authorized
950
+ * amount; pass `amount` for partial capture.
951
+ */
952
+ async captureOrder(id, amount) {
953
+ const body = amount !== void 0 ? { amount } : {};
954
+ return this.request("POST", `/v1/orders/${id}/capture`, body);
955
+ }
956
+ /**
957
+ * Cancel an Order. Releases any auth-holds; marks the Order as canceled.
958
+ * For orders that have already been captured, use `createRefund` instead.
959
+ */
960
+ async cancelOrder(id) {
961
+ return this.request("POST", `/v1/orders/${id}/cancel`);
962
+ }
717
963
  };
964
+ zod.z.enum(["MLA", "MLB", "MLM", "MCO", "MLC", "MLU"]);
965
+ var CurrencyIdSchema = zod.z.enum(["ARS", "USD", "BRL", "MXN"]);
966
+ var FrequencyTypeSchema = zod.z.enum(["months", "days"]);
967
+ var PreapprovalStatusSchema = zod.z.union([
968
+ zod.z.literal("pending"),
969
+ zod.z.literal("authorized"),
970
+ zod.z.literal("paused"),
971
+ zod.z.literal("cancelled"),
972
+ zod.z.string()
973
+ ]);
974
+ var AutoRecurringSchema = zod.z.object({
975
+ frequency: zod.z.number().int().positive(),
976
+ frequency_type: FrequencyTypeSchema,
977
+ transaction_amount: zod.z.number().positive(),
978
+ currency_id: CurrencyIdSchema,
979
+ start_date: zod.z.string().optional(),
980
+ end_date: zod.z.string().optional()
981
+ });
982
+ zod.z.object({
983
+ id: zod.z.string(),
984
+ status: PreapprovalStatusSchema,
985
+ payer_email: zod.z.string(),
986
+ init_point: zod.z.string().url(),
987
+ external_reference: zod.z.string().optional(),
988
+ date_created: zod.z.string(),
989
+ last_modified: zod.z.string(),
990
+ next_payment_date: zod.z.string().optional(),
991
+ payer_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
992
+ auto_recurring: AutoRecurringSchema
993
+ });
994
+ var WebhookBodySchema = zod.z.object({
995
+ type: zod.z.string().optional(),
996
+ topic: zod.z.string().optional(),
997
+ action: zod.z.string().optional(),
998
+ data: zod.z.object({ id: zod.z.union([zod.z.string(), zod.z.number()]) }).optional(),
999
+ resource: zod.z.string().optional(),
1000
+ user_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1001
+ api_version: zod.z.string().optional(),
1002
+ date_created: zod.z.string().optional(),
1003
+ id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1004
+ live_mode: zod.z.boolean().optional()
1005
+ }).passthrough();
1006
+ var PaymentStatusSchema = zod.z.union([
1007
+ zod.z.literal("pending"),
1008
+ zod.z.literal("approved"),
1009
+ zod.z.literal("authorized"),
1010
+ zod.z.literal("in_process"),
1011
+ zod.z.literal("in_mediation"),
1012
+ zod.z.literal("rejected"),
1013
+ zod.z.literal("cancelled"),
1014
+ zod.z.literal("refunded"),
1015
+ zod.z.literal("charged_back"),
1016
+ zod.z.string()
1017
+ ]);
1018
+ var PaymentSchema = zod.z.object({
1019
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1020
+ status: PaymentStatusSchema,
1021
+ status_detail: zod.z.string().nullable().optional(),
1022
+ date_created: zod.z.string().nullable().optional(),
1023
+ date_approved: zod.z.string().nullable().optional(),
1024
+ date_last_updated: zod.z.string().nullable().optional(),
1025
+ transaction_amount: zod.z.number(),
1026
+ currency_id: zod.z.string(),
1027
+ installments: zod.z.number().int().nullable().optional(),
1028
+ payment_method_id: zod.z.string().nullable().optional(),
1029
+ payment_type_id: zod.z.string().nullable().optional(),
1030
+ external_reference: zod.z.string().nullable().optional(),
1031
+ description: zod.z.string().nullable().optional(),
1032
+ payer: zod.z.object({
1033
+ id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1034
+ email: zod.z.string().nullable().optional(),
1035
+ identification: zod.z.object({
1036
+ type: zod.z.string().nullable().optional(),
1037
+ number: zod.z.string().nullable().optional()
1038
+ }).nullable().optional()
1039
+ }).passthrough().optional(),
1040
+ transaction_details: zod.z.object({
1041
+ net_received_amount: zod.z.number().nullable().optional(),
1042
+ total_paid_amount: zod.z.number().nullable().optional(),
1043
+ installment_amount: zod.z.number().nullable().optional()
1044
+ }).passthrough().optional()
1045
+ }).passthrough();
1046
+ zod.z.object({
1047
+ paging: zod.z.object({
1048
+ total: zod.z.number(),
1049
+ limit: zod.z.number(),
1050
+ offset: zod.z.number()
1051
+ }),
1052
+ results: zod.z.array(PaymentSchema)
1053
+ });
1054
+ zod.z.object({
1055
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1056
+ payment_id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1057
+ amount: zod.z.number(),
1058
+ source: zod.z.object({
1059
+ id: zod.z.string().nullable().optional(),
1060
+ name: zod.z.string().nullable().optional(),
1061
+ type: zod.z.string().nullable().optional()
1062
+ }).nullable().optional(),
1063
+ date_created: zod.z.string().nullable().optional(),
1064
+ status: zod.z.string().nullable().optional()
1065
+ }).passthrough();
1066
+ var PreferenceItemSchema = zod.z.object({
1067
+ id: zod.z.string().optional(),
1068
+ title: zod.z.string(),
1069
+ description: zod.z.string().optional(),
1070
+ picture_url: zod.z.string().url().optional(),
1071
+ category_id: zod.z.string().optional(),
1072
+ quantity: zod.z.number().int().positive(),
1073
+ unit_price: zod.z.number().positive(),
1074
+ currency_id: CurrencyIdSchema.optional()
1075
+ });
1076
+ zod.z.object({
1077
+ id: zod.z.string(),
1078
+ init_point: zod.z.string().url().optional(),
1079
+ sandbox_init_point: zod.z.string().url().optional(),
1080
+ client_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1081
+ collector_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1082
+ items: zod.z.array(PreferenceItemSchema).optional(),
1083
+ external_reference: zod.z.string().nullable().optional(),
1084
+ date_created: zod.z.string().nullable().optional(),
1085
+ expires: zod.z.boolean().optional(),
1086
+ expiration_date_from: zod.z.string().nullable().optional(),
1087
+ expiration_date_to: zod.z.string().nullable().optional()
1088
+ }).passthrough();
1089
+ zod.z.object({
1090
+ id: zod.z.string(),
1091
+ email: zod.z.string(),
1092
+ first_name: zod.z.string().nullable().optional(),
1093
+ last_name: zod.z.string().nullable().optional(),
1094
+ phone: zod.z.object({ area_code: zod.z.string().nullable().optional(), number: zod.z.string().nullable().optional() }).nullable().optional(),
1095
+ identification: zod.z.object({ type: zod.z.string().nullable().optional(), number: zod.z.string().nullable().optional() }).nullable().optional(),
1096
+ date_created: zod.z.string().nullable().optional(),
1097
+ date_last_updated: zod.z.string().nullable().optional(),
1098
+ description: zod.z.string().nullable().optional()
1099
+ }).passthrough();
1100
+ zod.z.object({
1101
+ id: zod.z.string(),
1102
+ customer_id: zod.z.string(),
1103
+ expiration_month: zod.z.number().int().nullable().optional(),
1104
+ expiration_year: zod.z.number().int().nullable().optional(),
1105
+ first_six_digits: zod.z.string().nullable().optional(),
1106
+ last_four_digits: zod.z.string().nullable().optional(),
1107
+ payment_method: zod.z.object({
1108
+ id: zod.z.string().nullable().optional(),
1109
+ name: zod.z.string().nullable().optional(),
1110
+ payment_type_id: zod.z.string().nullable().optional()
1111
+ }).nullable().optional(),
1112
+ date_created: zod.z.string().nullable().optional()
1113
+ }).passthrough();
1114
+ zod.z.object({
1115
+ id: zod.z.string(),
1116
+ name: zod.z.string(),
1117
+ payment_type_id: zod.z.string(),
1118
+ status: zod.z.string(),
1119
+ thumbnail: zod.z.string().nullable().optional(),
1120
+ secure_thumbnail: zod.z.string().nullable().optional(),
1121
+ min_allowed_amount: zod.z.number().nullable().optional(),
1122
+ max_allowed_amount: zod.z.number().nullable().optional()
1123
+ }).passthrough();
1124
+ zod.z.object({
1125
+ payment_method_id: zod.z.string(),
1126
+ payment_type_id: zod.z.string(),
1127
+ issuer: zod.z.object({
1128
+ id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1129
+ name: zod.z.string().nullable().optional()
1130
+ }).nullable().optional(),
1131
+ payer_costs: zod.z.array(
1132
+ zod.z.object({
1133
+ installments: zod.z.number().int(),
1134
+ installment_rate: zod.z.number(),
1135
+ discount_rate: zod.z.number().nullable().optional(),
1136
+ installment_amount: zod.z.number(),
1137
+ total_amount: zod.z.number(),
1138
+ recommended_message: zod.z.string().nullable().optional()
1139
+ }).passthrough()
1140
+ )
1141
+ }).passthrough();
1142
+ zod.z.object({
1143
+ in_store_order_id: zod.z.string(),
1144
+ qr_data: zod.z.string()
1145
+ }).passthrough();
1146
+ zod.z.object({
1147
+ id: zod.z.string(),
1148
+ status: zod.z.string().optional(),
1149
+ date_due: zod.z.string().optional(),
1150
+ card_id: zod.z.string().optional(),
1151
+ cardholder: zod.z.unknown().optional()
1152
+ }).passthrough();
1153
+ zod.z.object({
1154
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1155
+ email: zod.z.string().nullable().optional(),
1156
+ nickname: zod.z.string().nullable().optional(),
1157
+ country_id: zod.z.string().nullable().optional(),
1158
+ site_id: zod.z.string().nullable().optional(),
1159
+ user_type: zod.z.string().nullable().optional(),
1160
+ status: zod.z.object({ user_type: zod.z.string().nullable().optional() }).passthrough().nullable().optional()
1161
+ }).passthrough();
1162
+ zod.z.object({
1163
+ id: zod.z.string(),
1164
+ status: zod.z.string(),
1165
+ reason: zod.z.string(),
1166
+ back_url: zod.z.string().url().optional(),
1167
+ external_reference: zod.z.string().nullable().optional(),
1168
+ date_created: zod.z.string(),
1169
+ last_modified: zod.z.string(),
1170
+ auto_recurring: AutoRecurringSchema
1171
+ }).passthrough();
1172
+ zod.z.object({
1173
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1174
+ name: zod.z.string().optional(),
1175
+ external_id: zod.z.string().optional(),
1176
+ date_creation: zod.z.string().optional(),
1177
+ location: zod.z.object({
1178
+ address_line: zod.z.string().optional(),
1179
+ city_name: zod.z.string().optional(),
1180
+ state_name: zod.z.string().optional(),
1181
+ country_id: zod.z.string().optional(),
1182
+ latitude: zod.z.number().optional(),
1183
+ longitude: zod.z.number().optional()
1184
+ }).passthrough().optional()
1185
+ }).passthrough();
1186
+ zod.z.object({
1187
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1188
+ name: zod.z.string().optional(),
1189
+ external_id: zod.z.string().optional(),
1190
+ store_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1191
+ category: zod.z.number().int().optional(),
1192
+ fixed_amount: zod.z.boolean().optional(),
1193
+ qr: zod.z.object({
1194
+ template_image: zod.z.string().optional(),
1195
+ image: zod.z.string().optional()
1196
+ }).passthrough().optional(),
1197
+ date_creation: zod.z.string().optional()
1198
+ }).passthrough();
1199
+ zod.z.object({
1200
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1201
+ status: zod.z.string(),
1202
+ resource: zod.z.string().optional(),
1203
+ resource_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1204
+ amount: zod.z.number().optional(),
1205
+ date_created: zod.z.string().optional(),
1206
+ reason: zod.z.string().optional(),
1207
+ resolution: zod.z.object({
1208
+ reason: zod.z.string().optional(),
1209
+ result: zod.z.string().optional(),
1210
+ date: zod.z.string().optional()
1211
+ }).passthrough().optional(),
1212
+ /** Documents the buyer / seller submitted as evidence. */
1213
+ documents: zod.z.array(zod.z.unknown()).optional(),
1214
+ /** Buyer's stated complaint. */
1215
+ reason_description: zod.z.string().optional()
1216
+ }).passthrough();
1217
+ zod.z.object({
1218
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1219
+ preapproval_id: zod.z.string().optional(),
1220
+ status: zod.z.string(),
1221
+ payment_id: zod.z.union([zod.z.string(), zod.z.number()]).nullable().optional(),
1222
+ transaction_amount: zod.z.number().optional(),
1223
+ currency_id: zod.z.string().optional(),
1224
+ date_created: zod.z.string().optional(),
1225
+ debit_date: zod.z.string().optional(),
1226
+ next_retry_date: zod.z.string().nullable().optional(),
1227
+ retry_attempt: zod.z.number().optional(),
1228
+ reason: zod.z.string().optional()
1229
+ }).passthrough();
1230
+ zod.z.object({
1231
+ id: zod.z.string(),
1232
+ name: zod.z.string(),
1233
+ type: zod.z.string(),
1234
+ min_length: zod.z.number().optional(),
1235
+ max_length: zod.z.number().optional()
1236
+ }).passthrough();
1237
+ zod.z.object({
1238
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1239
+ name: zod.z.string(),
1240
+ secure_thumbnail: zod.z.string().nullable().optional(),
1241
+ thumbnail: zod.z.string().nullable().optional(),
1242
+ processing_mode: zod.z.string().optional(),
1243
+ status: zod.z.string().optional()
1244
+ }).passthrough();
1245
+ zod.z.enum([
1246
+ "payment",
1247
+ "subscription_authorized_payment",
1248
+ "subscription_preapproval",
1249
+ "merchant_order",
1250
+ "point_integration_wh",
1251
+ "stop_delivery_op_wh"
1252
+ ]);
1253
+ zod.z.object({
1254
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1255
+ url: zod.z.string().url().optional(),
1256
+ status: zod.z.string().optional(),
1257
+ topic: zod.z.string().optional(),
1258
+ date_created: zod.z.string().optional(),
1259
+ date_modified: zod.z.string().optional()
1260
+ }).passthrough();
1261
+ var OAuthTokenSchema = zod.z.object({
1262
+ access_token: zod.z.string(),
1263
+ token_type: zod.z.string().optional(),
1264
+ /** Seconds until access_token expires. Typically 21600 (6h). */
1265
+ expires_in: zod.z.number().optional(),
1266
+ scope: zod.z.string().optional(),
1267
+ /** The MP user_id of the seller who authorized your app. */
1268
+ user_id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1269
+ refresh_token: zod.z.string().optional(),
1270
+ public_key: zod.z.string().optional(),
1271
+ live_mode: zod.z.boolean().optional()
1272
+ }).passthrough();
1273
+ var OrderStatusSchema = zod.z.union([
1274
+ zod.z.literal("created"),
1275
+ zod.z.literal("processed"),
1276
+ zod.z.literal("action_required"),
1277
+ zod.z.literal("canceled"),
1278
+ zod.z.literal("expired"),
1279
+ zod.z.literal("refunded"),
1280
+ zod.z.string()
1281
+ ]);
1282
+ var OrderItemSchema = zod.z.object({
1283
+ title: zod.z.string(),
1284
+ unit_price: zod.z.number(),
1285
+ quantity: zod.z.number(),
1286
+ description: zod.z.string().optional(),
1287
+ id: zod.z.string().optional(),
1288
+ category_id: zod.z.string().optional(),
1289
+ picture_url: zod.z.string().optional()
1290
+ }).passthrough();
1291
+ zod.z.object({
1292
+ id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1293
+ type: zod.z.string().optional(),
1294
+ status: OrderStatusSchema.optional(),
1295
+ status_detail: zod.z.string().optional(),
1296
+ external_reference: zod.z.string().optional(),
1297
+ total_amount: zod.z.union([zod.z.number(), zod.z.string()]).optional(),
1298
+ /** Currency for this Order (e.g. "ARS"). */
1299
+ currency_id: zod.z.string().optional(),
1300
+ date_created: zod.z.string().optional(),
1301
+ date_last_updated: zod.z.string().optional(),
1302
+ items: zod.z.array(OrderItemSchema).optional(),
1303
+ /** Underlying transactions (payments) attached to this Order. */
1304
+ transactions: zod.z.object({
1305
+ payments: zod.z.array(zod.z.unknown()).optional(),
1306
+ refunds: zod.z.array(zod.z.unknown()).optional()
1307
+ }).passthrough().optional(),
1308
+ /** Capture mode: "automatic" (charges immediately) or "manual" (auth-only). */
1309
+ capture_mode: zod.z.string().optional()
1310
+ }).passthrough();
1311
+
1312
+ // src/oauth.ts
1313
+ var DEFAULT_AUTHORIZE_URL = "https://auth.mercadopago.com.ar/authorization";
1314
+ var DEFAULT_TOKEN_URL = "https://api.mercadopago.com/oauth/token";
1315
+ function buildAuthorizeUrl(params) {
1316
+ const url = new URL(params.authorizeUrl ?? DEFAULT_AUTHORIZE_URL);
1317
+ url.searchParams.set("client_id", params.clientId);
1318
+ url.searchParams.set("response_type", "code");
1319
+ url.searchParams.set("platform_id", "mp");
1320
+ url.searchParams.set("redirect_uri", params.redirectUri);
1321
+ if (params.state) url.searchParams.set("state", params.state);
1322
+ return url.toString();
1323
+ }
1324
+ async function exchangeCodeForToken(params) {
1325
+ const url = params.tokenUrl ?? DEFAULT_TOKEN_URL;
1326
+ const fetchFn = params.fetchImpl ?? globalThis.fetch;
1327
+ const res = await fetchFn(url, {
1328
+ method: "POST",
1329
+ headers: {
1330
+ "Content-Type": "application/x-www-form-urlencoded",
1331
+ Accept: "application/json"
1332
+ },
1333
+ body: new URLSearchParams({
1334
+ grant_type: "authorization_code",
1335
+ client_id: params.clientId,
1336
+ client_secret: params.clientSecret,
1337
+ code: params.code,
1338
+ redirect_uri: params.redirectUri
1339
+ }).toString()
1340
+ });
1341
+ return parseTokenResponse(res);
1342
+ }
1343
+ async function refreshAccessToken(params) {
1344
+ const url = params.tokenUrl ?? DEFAULT_TOKEN_URL;
1345
+ const fetchFn = params.fetchImpl ?? globalThis.fetch;
1346
+ const res = await fetchFn(url, {
1347
+ method: "POST",
1348
+ headers: {
1349
+ "Content-Type": "application/x-www-form-urlencoded",
1350
+ Accept: "application/json"
1351
+ },
1352
+ body: new URLSearchParams({
1353
+ grant_type: "refresh_token",
1354
+ client_id: params.clientId,
1355
+ client_secret: params.clientSecret,
1356
+ refresh_token: params.refreshToken
1357
+ }).toString()
1358
+ });
1359
+ return parseTokenResponse(res);
1360
+ }
1361
+ async function parseTokenResponse(res) {
1362
+ const text = await res.text();
1363
+ if (!res.ok) {
1364
+ throw new Error(
1365
+ `MP OAuth ${res.status}: ${text.slice(0, 300)}`
1366
+ );
1367
+ }
1368
+ const json = JSON.parse(text);
1369
+ return OAuthTokenSchema.parse(json);
1370
+ }
1371
+ function expirationTimeMs(issuedAtMs, expiresInSeconds) {
1372
+ return issuedAtMs + (expiresInSeconds ?? 21600) * 1e3;
1373
+ }
1374
+ function isExpiringSoon(expirationMs, skewSeconds = 300) {
1375
+ return Date.now() + skewSeconds * 1e3 >= expirationMs;
1376
+ }
1377
+ function parseWebhookEvent(body, searchParams) {
1378
+ const parseResult = WebhookBodySchema.safeParse(body ?? {});
1379
+ const parsedBody = parseResult.success ? parseResult.data : {};
1380
+ const topic = searchParams?.get("topic") ?? parsedBody.topic ?? parsedBody.type ?? null;
1381
+ const dataId = searchParams?.get("id") ?? (parsedBody.data?.id !== void 0 ? String(parsedBody.data.id) : null) ?? parsedBody.resource ?? null;
1382
+ if (!topic || !dataId) {
1383
+ return null;
1384
+ }
1385
+ return {
1386
+ topic,
1387
+ dataId: String(dataId),
1388
+ action: parsedBody.action ?? null,
1389
+ raw: parsedBody
1390
+ };
1391
+ }
1392
+ function verifyWebhookSignature(params) {
1393
+ if (!params.signatureHeader || !params.requestId) return false;
1394
+ const parts = Object.fromEntries(
1395
+ params.signatureHeader.split(",").map((segment) => segment.trim().split("="))
1396
+ );
1397
+ const ts = parts.ts;
1398
+ const v1 = parts.v1;
1399
+ if (!ts || !v1) return false;
1400
+ const manifest = `id:${params.dataId};request-id:${params.requestId};ts:${ts};`;
1401
+ const expected = crypto.createHmac("sha256", params.secret).update(manifest).digest("hex");
1402
+ if (expected.length !== v1.length) return false;
1403
+ return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
1404
+ }
1405
+
1406
+ // src/tools.ts
718
1407
  function deterministicIdempotencyKey(...parts) {
719
1408
  const payload = parts.filter((p) => p !== void 0 && p !== null).map(String).join("|");
720
1409
  return crypto.createHash("sha256").update(payload).digest("hex").slice(0, 32);
@@ -751,8 +1440,42 @@ var DEFAULT_DESCRIPTIONS = {
751
1440
  // ── Saved-card charging (v0.3) ───────────────────────────────────────────
752
1441
  charge_saved_card: "Charge a previously-saved card for a returning customer. Requires customer_id + card_id (from list_customer_cards) AND a fresh CVV the user provides this session. AR Mercado Pago does NOT support CVV-less charges via the public API \u2014 every charge needs CVV. Idempotent on (card_id, amount, external_reference): retries dedupe automatically. Returns the resulting Payment.",
753
1442
  // ── QR in-store (v0.3) ───────────────────────────────────────────────────
754
- create_qr_payment: "Generate a dynamic in-store QR for a buyer to scan with any AR wallet (Modo, BNA+, Cuenta DNI, Naranja X, Mercado Pago, etc. \u2014 interop is mandated by Transferencias 3.0). Requires a pre-configured POS external_id (one-time setup in MP dashboard). Returns the qr_data string + a base64 PNG data URL ready to display. The QR expires in `expires_in_seconds` (default 600). MP fires `point_integration_wh` then `payment` webhooks when scanned.",
755
- cancel_qr_payment: "Cancel a pending QR order on a POS. Necessary if the buyer never scans \u2014 otherwise the next create_qr_payment on the same POS returns 409."
1443
+ create_qr_payment: "Generate a dynamic in-store QR for a buyer to scan with any AR wallet (Modo, BNA+, Cuenta DNI, Naranja X, Mercado Pago, etc. \u2014 interop is mandated by Transferencias 3.0). Requires a pre-configured POS external_id (use create_pos to set one up first if needed). Returns the qr_data string + a base64 PNG data URL ready to display. The QR expires in `expires_in_seconds` (default 600). MP fires `point_integration_wh` then `payment` webhooks when scanned.",
1444
+ cancel_qr_payment: "Cancel a pending QR order on a POS. Necessary if the buyer never scans \u2014 otherwise the next create_qr_payment on the same POS returns 409.",
1445
+ // ── Subscription Plans (v0.4) ────────────────────────────────────────────
1446
+ create_subscription_plan: "Create a REUSABLE subscription plan (preapproval_plan). Different from create_subscription: a plan defines price + frequency once, then customers subscribe to it via subscribe_to_plan. Use plans for SaaS-style billing (B\xE1sico/Pro/Enterprise tiers). For per-customer custom amounts, use create_subscription directly.",
1447
+ list_subscription_plans: "List all subscription plans defined for this MP account. Useful before create_subscription_plan to check if one already exists, or for surfacing options to a customer.",
1448
+ update_subscription_plan: "Update a subscription plan's reason / amount / status / back_url. Existing customer subscriptions to the plan are NOT automatically updated \u2014 only NEW subscribers get the new pricing.",
1449
+ subscribe_to_plan: "Subscribe a customer to an existing reusable plan. Returns a Preapproval with init_point URL where the customer completes first payment. Cleaner than create_subscription when you have fixed tiers.",
1450
+ list_subscription_payments: "List the auto-charge attempts (authorized_payments) under a subscription. Useful for 'show me the cobros del \xFAltimo mes for this client' or to debug a failing recurring charge.",
1451
+ // ── Stores + POS (v0.4) ──────────────────────────────────────────────────
1452
+ create_store: "Create a store under the seller's MP account. Stores are the parent entity for POSes (which generate QR payments). Required ONE-TIME setup before create_pos. Pass a unique external_id and a display name.",
1453
+ list_stores: "List all stores configured for this MP account. Use this to find an existing store_id before create_pos, or to surface store options to the agent.",
1454
+ create_pos: "Create a POS (Point of Sale) under a store. The POS's external_id is what create_qr_payment uses. Each physical checkout / counter / agent typically has its own POS. Categories are MP-defined (default 621102 = Other Food and Beverage Services).",
1455
+ list_pos: "List all POSes for the seller (or filtered by store_id). Use to find an existing POS before create_qr_payment, or to surface options.",
1456
+ // ── Disputes (v0.4 — read-only) ──────────────────────────────────────────
1457
+ list_payment_disputes: "List all disputes / chargebacks raised against a payment. Read-only \u2014 resolution is dashboard-only. Surface the dashboard URL `https://www.mercadopago.com.ar/disputes/{dispute_id}` to the user when they need to respond.",
1458
+ get_dispute: "Get details of a specific dispute including reason, amount, resolution status. Read-only.",
1459
+ // ── Lookup helpers (v0.4) ────────────────────────────────────────────────
1460
+ list_identification_types: "List valid identification types for the seller's site. AR returns: DNI, CI, LE, LC, Otro, Pasaporte, CUIT, CUIL with their min/max length. Useful to validate an identification before passing to create_payment.",
1461
+ list_issuers: "List card issuers (banks) that support a payment_method_id. Optionally filter by `bin` (first 6 digits of the card) for accurate issuer detection. Useful with calculate_installments \u2014 issuer-specific promos (e.g., Naranja Galicia 6 cuotas sin inter\xE9s) only appear when the issuer is identified.",
1462
+ // ── Webhooks management (v0.4) ───────────────────────────────────────────
1463
+ list_webhooks: "List all webhook subscriptions configured for this MP application. Use to see what topics + URLs are wired before adding new ones.",
1464
+ create_webhook: "Subscribe a webhook URL to a MP topic (payment, subscription_authorized_payment, subscription_preapproval, merchant_order, point_integration_wh). MP will POST to this URL when events of that topic fire.",
1465
+ update_webhook: "Update a webhook's URL or topic. Useful when you change deployment URLs without resubscribing from scratch.",
1466
+ delete_webhook: "Delete a webhook subscription. MP stops POSTing to it immediately.",
1467
+ // ── Webhook handler combo (v0.5) ─────────────────────────────────────────
1468
+ handle_webhook: "Process an incoming MP webhook in ONE call: verify the HMAC-SHA256 signature, parse the event, and (optionally) auto-fetch the underlying resource (Payment, Subscription, Order). Returns the structured event PLUS the full resource. USE THIS in your webhook endpoint INSTEAD of chaining verify_webhook_signature + parse_webhook_event + get_payment manually. Pass the raw request body, x-signature header, x-request-id header, and your MP webhook secret. SAFE: returns { verified: false } when signature mismatches \u2014 caller should respond 401 and stop processing. WHEN auto_fetch is true (default), the resource is fetched as the SAME MP user the client is configured for (so for marketplace integrations, instantiate a per-seller client).",
1469
+ // ── OAuth Marketplace (v0.5) ─────────────────────────────────────────────
1470
+ oauth_authorize_url: "Build the URL the SELLER (third-party MP account) visits to authorize your marketplace app. Pass the seller's redirect uri (must be whitelisted in MP dev panel) and an opaque state token (CSRF protection \u2014 bind it to the user's session). PURE FUNCTION: no network. The seller approves, MP redirects them to your `redirect_uri?code=...&state=...`. Then call oauth_exchange_code with the code.",
1471
+ oauth_exchange_code: "Exchange the authorization code (from the OAuth redirect) for an `OAuthToken`. Returns access_token, refresh_token, user_id, and expires_in. **PERSIST the entire response** \u2014 refresh_token is long-lived and the only way to keep the integration alive past 6h. Use the access_token to instantiate a per-seller MercadoPagoClient for marketplace flows.",
1472
+ oauth_refresh_token: "Refresh a per-seller access_token using the saved refresh_token. Call PROACTIVELY before expires_in elapses, or REACTIVELY on a 401 from a per-seller MercadoPagoClient. Returns a fresh OAuthToken \u2014 persist the new refresh_token (MP often returns the same value, but always replace).",
1473
+ // ── Order Management API (v0.5 — modern Order API) ───────────────────────
1474
+ create_order: "Create a new Order via MP's modern Order Management API. DIFFERENT from create_payment_preference: Order is a transactional entity with explicit lifecycle (created \u2192 processed \u2192 captured/canceled), supports MANUAL CAPTURE (auth-only, capture later \u2014 for ride-share, hotels, marketplaces) and aggregates multiple payments into one Order. Use Preference (Checkout Pro) for simple hosted pay-links; use Order when you need auth-only or multi-payment-per-order semantics. For marketplace splits, set marketplace + marketplace_fee + collector_id (the SELLER's MP user_id from oauth_exchange_code).",
1475
+ get_order: "Fetch an Order by ID. Returns the Order with its lifecycle status and any attached payments/refunds.",
1476
+ update_order: "Patch an existing Order before it's captured/canceled. Common use: update items or external_reference.",
1477
+ 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."
756
1479
  };
757
1480
  function mercadoPagoTools(client, options) {
758
1481
  const desc = (name) => options.descriptions?.[name] ?? DEFAULT_DESCRIPTIONS[name];
@@ -1342,25 +2065,722 @@ function mercadoPagoTools(client, options) {
1342
2065
  width: 512
1343
2066
  });
1344
2067
  return {
1345
- in_store_order_id: qr.in_store_order_id,
1346
- qr_data: qr.qr_data,
1347
- qr_data_url: qrDataUrl,
1348
- expires_at: expiresAt,
1349
- external_pos_id: input.external_pos_id,
1350
- amount: input.amount_ars,
1351
- next_step: "Display the qr_data_url image to the buyer. Wait for the payment webhook (point_integration_wh fires first, then payment topic). If buyer doesn't scan in time, call cancel_qr_payment to free the POS."
2068
+ in_store_order_id: qr.in_store_order_id,
2069
+ qr_data: qr.qr_data,
2070
+ qr_data_url: qrDataUrl,
2071
+ expires_at: expiresAt,
2072
+ external_pos_id: input.external_pos_id,
2073
+ amount: input.amount_ars,
2074
+ next_step: "Display the qr_data_url image to the buyer. Wait for the payment webhook (point_integration_wh fires first, then payment topic). If buyer doesn't scan in time, call cancel_qr_payment to free the POS."
2075
+ };
2076
+ }
2077
+ }),
2078
+ cancel_qr_payment: ai.tool({
2079
+ description: desc("cancel_qr_payment"),
2080
+ inputSchema: zod.z.object({
2081
+ external_pos_id: zod.z.string()
2082
+ }),
2083
+ execute: async ({ external_pos_id }) => {
2084
+ const me = await client.getMe();
2085
+ await client.cancelQrPayment(String(me.id), external_pos_id);
2086
+ return { external_pos_id, cancelled: true };
2087
+ }
2088
+ }),
2089
+ // ─────────────────────────────────────────────────────────────────────────
2090
+ // Subscription Plans (v0.4)
2091
+ // ─────────────────────────────────────────────────────────────────────────
2092
+ create_subscription_plan: ai.tool({
2093
+ description: desc("create_subscription_plan"),
2094
+ inputSchema: zod.z.object({
2095
+ reason: zod.z.string().min(3).max(120).describe("Plan name shown at checkout"),
2096
+ amount_ars: zod.z.number().positive(),
2097
+ frequency_months: zod.z.number().int().min(1).max(12),
2098
+ back_url: zod.z.string().url().describe("HTTPS URL where MP redirects after first payment"),
2099
+ external_reference: zod.z.string().optional(),
2100
+ free_trial_days: zod.z.number().int().min(1).max(60).optional().describe("Free trial period in days before first charge")
2101
+ }),
2102
+ execute: async (input) => {
2103
+ const plan = await client.createSubscriptionPlan({
2104
+ reason: input.reason,
2105
+ amount: input.amount_ars,
2106
+ currency: "ARS",
2107
+ frequency: input.frequency_months,
2108
+ frequencyType: "months",
2109
+ backUrl: input.back_url,
2110
+ ...input.external_reference !== void 0 ? { externalReference: input.external_reference } : {},
2111
+ ...input.free_trial_days !== void 0 ? { freeTrialFrequency: input.free_trial_days, freeTrialFrequencyType: "days" } : {}
2112
+ });
2113
+ return {
2114
+ plan_id: plan.id,
2115
+ status: plan.status,
2116
+ reason: plan.reason,
2117
+ amount: plan.auto_recurring.transaction_amount,
2118
+ currency: plan.auto_recurring.currency_id,
2119
+ frequency: `${plan.auto_recurring.frequency} ${plan.auto_recurring.frequency_type}`,
2120
+ external_reference: plan.external_reference,
2121
+ next_step: "Use subscribe_to_plan to enroll customers in this plan, or share its ID for them to subscribe via your frontend."
2122
+ };
2123
+ }
2124
+ }),
2125
+ list_subscription_plans: ai.tool({
2126
+ description: desc("list_subscription_plans"),
2127
+ inputSchema: zod.z.object({
2128
+ status: zod.z.string().optional(),
2129
+ limit: zod.z.number().int().min(1).max(100).optional()
2130
+ }),
2131
+ execute: async (input) => {
2132
+ const result = await client.listSubscriptionPlans({
2133
+ ...input.status !== void 0 ? { status: input.status } : {},
2134
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2135
+ });
2136
+ return {
2137
+ total: result.paging.total,
2138
+ plans: result.results.map((p) => ({
2139
+ plan_id: p.id,
2140
+ reason: p.reason,
2141
+ status: p.status,
2142
+ amount: p.auto_recurring.transaction_amount,
2143
+ currency: p.auto_recurring.currency_id,
2144
+ frequency: `${p.auto_recurring.frequency} ${p.auto_recurring.frequency_type}`
2145
+ }))
2146
+ };
2147
+ }
2148
+ }),
2149
+ update_subscription_plan: ai.tool({
2150
+ description: desc("update_subscription_plan"),
2151
+ inputSchema: zod.z.object({
2152
+ plan_id: zod.z.string(),
2153
+ reason: zod.z.string().optional(),
2154
+ amount_ars: zod.z.number().positive().optional(),
2155
+ status: zod.z.enum(["active", "cancelled"]).optional(),
2156
+ back_url: zod.z.string().url().optional()
2157
+ }),
2158
+ execute: async (input) => {
2159
+ const updated = await client.updateSubscriptionPlan(input.plan_id, {
2160
+ ...input.reason !== void 0 ? { reason: input.reason } : {},
2161
+ ...input.amount_ars !== void 0 ? { amount: input.amount_ars } : {},
2162
+ ...input.status !== void 0 ? { status: input.status } : {},
2163
+ ...input.back_url !== void 0 ? { backUrl: input.back_url } : {}
2164
+ });
2165
+ return {
2166
+ plan_id: updated.id,
2167
+ status: updated.status,
2168
+ reason: updated.reason,
2169
+ amount: updated.auto_recurring.transaction_amount,
2170
+ message: input.amount_ars !== void 0 ? "Updated. Existing subscribers keep their old amount; only NEW subscribers get the new pricing." : "Plan updated."
2171
+ };
2172
+ }
2173
+ }),
2174
+ subscribe_to_plan: ai.tool({
2175
+ description: desc("subscribe_to_plan"),
2176
+ inputSchema: zod.z.object({
2177
+ plan_id: zod.z.string(),
2178
+ customer_email: zod.z.string().email(),
2179
+ external_reference: zod.z.string().optional()
2180
+ }),
2181
+ execute: async (input) => {
2182
+ const sub = await client.subscribeToPlan({
2183
+ planId: input.plan_id,
2184
+ payerEmail: input.customer_email,
2185
+ ...input.external_reference !== void 0 ? { externalReference: input.external_reference } : {}
2186
+ });
2187
+ return {
2188
+ subscription_id: sub.id,
2189
+ status: sub.status,
2190
+ payer_email: sub.payer_email,
2191
+ init_point_url: sub.init_point,
2192
+ next_step: "Send init_point_url to the customer for first payment with card+CVV."
2193
+ };
2194
+ }
2195
+ }),
2196
+ list_subscription_payments: ai.tool({
2197
+ description: desc("list_subscription_payments"),
2198
+ inputSchema: zod.z.object({
2199
+ subscription_id: zod.z.string(),
2200
+ limit: zod.z.number().int().min(1).max(100).optional()
2201
+ }),
2202
+ execute: async (input) => {
2203
+ const result = await client.listSubscriptionPayments(input.subscription_id, {
2204
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2205
+ });
2206
+ return {
2207
+ subscription_id: input.subscription_id,
2208
+ total: result.paging.total,
2209
+ payments: result.results.map((p) => ({
2210
+ authorized_payment_id: p.id,
2211
+ payment_id: p.payment_id ?? null,
2212
+ status: p.status,
2213
+ amount: p.transaction_amount ?? null,
2214
+ currency: p.currency_id ?? null,
2215
+ debit_date: p.debit_date ?? null,
2216
+ next_retry_date: p.next_retry_date ?? null,
2217
+ retry_attempt: p.retry_attempt ?? 0,
2218
+ reason: p.reason ?? null
2219
+ }))
2220
+ };
2221
+ }
2222
+ }),
2223
+ // ─────────────────────────────────────────────────────────────────────────
2224
+ // Stores + POS (v0.4)
2225
+ // ─────────────────────────────────────────────────────────────────────────
2226
+ create_store: ai.tool({
2227
+ description: desc("create_store"),
2228
+ inputSchema: zod.z.object({
2229
+ name: zod.z.string().min(1).max(80),
2230
+ external_id: zod.z.string().min(1).max(64).describe("Unique within the seller's stores"),
2231
+ address_line: zod.z.string().optional(),
2232
+ city_name: zod.z.string().optional(),
2233
+ state_name: zod.z.string().optional()
2234
+ }),
2235
+ execute: async (input) => {
2236
+ const me = await client.getMe();
2237
+ const store = await client.createStore(String(me.id), {
2238
+ name: input.name,
2239
+ externalId: input.external_id,
2240
+ ...input.address_line || input.city_name || input.state_name ? {
2241
+ location: {
2242
+ ...input.address_line ? { addressLine: input.address_line } : {},
2243
+ ...input.city_name ? { cityName: input.city_name } : {},
2244
+ ...input.state_name ? { stateName: input.state_name } : {},
2245
+ countryId: "AR"
2246
+ }
2247
+ } : {}
2248
+ });
2249
+ return {
2250
+ store_id: store.id,
2251
+ name: store.name,
2252
+ external_id: store.external_id,
2253
+ next_step: "Use create_pos with this store_id to add a Point of Sale where create_qr_payment can issue QRs."
2254
+ };
2255
+ }
2256
+ }),
2257
+ list_stores: ai.tool({
2258
+ description: desc("list_stores"),
2259
+ inputSchema: zod.z.object({
2260
+ limit: zod.z.number().int().min(1).max(100).optional()
2261
+ }),
2262
+ execute: async (input) => {
2263
+ const me = await client.getMe();
2264
+ const result = await client.listStores(String(me.id), {
2265
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2266
+ });
2267
+ return {
2268
+ total: result.paging.total,
2269
+ stores: result.results.map((s) => ({
2270
+ store_id: s.id,
2271
+ name: s.name ?? null,
2272
+ external_id: s.external_id ?? null
2273
+ }))
2274
+ };
2275
+ }
2276
+ }),
2277
+ create_pos: ai.tool({
2278
+ description: desc("create_pos"),
2279
+ inputSchema: zod.z.object({
2280
+ name: zod.z.string().min(1).max(80),
2281
+ external_id: zod.z.string().min(1).max(64).describe("Unique within the store. This is what create_qr_payment uses."),
2282
+ store_id: zod.z.string().describe("From create_store / list_stores"),
2283
+ category: zod.z.number().int().optional().describe("MP category code, default 621102 (other food/beverage)"),
2284
+ fixed_amount: zod.z.boolean().optional().describe("True for static QR with fixed amount; false (default) for dynamic per-order QR")
2285
+ }),
2286
+ execute: async (input) => {
2287
+ const pos = await client.createPos({
2288
+ name: input.name,
2289
+ externalId: input.external_id,
2290
+ storeId: input.store_id,
2291
+ ...input.category !== void 0 ? { category: input.category } : {},
2292
+ ...input.fixed_amount !== void 0 ? { fixedAmount: input.fixed_amount } : {}
2293
+ });
2294
+ return {
2295
+ pos_id: pos.id,
2296
+ external_id: pos.external_id,
2297
+ store_id: pos.store_id,
2298
+ name: pos.name,
2299
+ next_step: "Use create_qr_payment with this external_id to start issuing dynamic QRs from this POS."
2300
+ };
2301
+ }
2302
+ }),
2303
+ list_pos: ai.tool({
2304
+ description: desc("list_pos"),
2305
+ inputSchema: zod.z.object({
2306
+ store_id: zod.z.string().optional(),
2307
+ limit: zod.z.number().int().min(1).max(100).optional()
2308
+ }),
2309
+ execute: async (input) => {
2310
+ const result = await client.listPos({
2311
+ ...input.store_id !== void 0 ? { storeId: input.store_id } : {},
2312
+ ...input.limit !== void 0 ? { limit: input.limit } : {}
2313
+ });
2314
+ return {
2315
+ total: result.paging.total,
2316
+ pos: result.results.map((p) => ({
2317
+ pos_id: p.id,
2318
+ external_id: p.external_id ?? null,
2319
+ store_id: p.store_id ?? null,
2320
+ name: p.name ?? null
2321
+ }))
2322
+ };
2323
+ }
2324
+ }),
2325
+ // ─────────────────────────────────────────────────────────────────────────
2326
+ // Disputes (v0.4 — read-only)
2327
+ // ─────────────────────────────────────────────────────────────────────────
2328
+ list_payment_disputes: ai.tool({
2329
+ description: desc("list_payment_disputes"),
2330
+ inputSchema: zod.z.object({ payment_id: zod.z.string() }),
2331
+ execute: async ({ payment_id }) => {
2332
+ const disputes = await client.listPaymentDisputes(payment_id);
2333
+ return {
2334
+ payment_id,
2335
+ count: disputes.length,
2336
+ disputes: disputes.map((d) => ({
2337
+ dispute_id: d.id,
2338
+ status: d.status,
2339
+ amount: d.amount ?? null,
2340
+ reason: d.reason ?? null,
2341
+ date_created: d.date_created ?? null,
2342
+ dashboard_url: `https://www.mercadopago.com.ar/disputes/${d.id}`
2343
+ }))
2344
+ };
2345
+ }
2346
+ }),
2347
+ get_dispute: ai.tool({
2348
+ description: desc("get_dispute"),
2349
+ inputSchema: zod.z.object({
2350
+ payment_id: zod.z.string(),
2351
+ dispute_id: zod.z.string()
2352
+ }),
2353
+ execute: async ({ payment_id, dispute_id }) => {
2354
+ const d = await client.getDispute(payment_id, dispute_id);
2355
+ return {
2356
+ dispute_id: d.id,
2357
+ status: d.status,
2358
+ amount: d.amount ?? null,
2359
+ reason: d.reason ?? null,
2360
+ reason_description: d.reason_description ?? null,
2361
+ resolution: d.resolution ?? null,
2362
+ date_created: d.date_created ?? null,
2363
+ dashboard_url: `https://www.mercadopago.com.ar/disputes/${d.id}`
2364
+ };
2365
+ }
2366
+ }),
2367
+ // ─────────────────────────────────────────────────────────────────────────
2368
+ // Lookup helpers (v0.4)
2369
+ // ─────────────────────────────────────────────────────────────────────────
2370
+ list_identification_types: ai.tool({
2371
+ description: desc("list_identification_types"),
2372
+ inputSchema: zod.z.object({}),
2373
+ execute: async () => {
2374
+ const types = await client.listIdentificationTypes();
2375
+ return {
2376
+ count: types.length,
2377
+ types: types.map((t) => ({
2378
+ id: t.id,
2379
+ name: t.name,
2380
+ type: t.type,
2381
+ min_length: t.min_length ?? null,
2382
+ max_length: t.max_length ?? null
2383
+ }))
2384
+ };
2385
+ }
2386
+ }),
2387
+ list_issuers: ai.tool({
2388
+ description: desc("list_issuers"),
2389
+ inputSchema: zod.z.object({
2390
+ payment_method_id: zod.z.string().describe("E.g. 'visa', 'master', 'naranja'"),
2391
+ bin: zod.z.string().min(6).max(8).optional().describe("First 6-8 digits of card for precise issuer detection")
2392
+ }),
2393
+ execute: async (input) => {
2394
+ const issuers = await client.listIssuers({
2395
+ paymentMethodId: input.payment_method_id,
2396
+ ...input.bin !== void 0 ? { bin: input.bin } : {}
2397
+ });
2398
+ return {
2399
+ payment_method_id: input.payment_method_id,
2400
+ count: issuers.length,
2401
+ issuers: issuers.map((i) => ({
2402
+ issuer_id: i.id,
2403
+ name: i.name,
2404
+ status: i.status ?? null
2405
+ }))
2406
+ };
2407
+ }
2408
+ }),
2409
+ // ─────────────────────────────────────────────────────────────────────────
2410
+ // Webhooks management (v0.4)
2411
+ // ─────────────────────────────────────────────────────────────────────────
2412
+ list_webhooks: ai.tool({
2413
+ description: desc("list_webhooks"),
2414
+ inputSchema: zod.z.object({}),
2415
+ execute: async () => {
2416
+ const hooks = await client.listWebhooks();
2417
+ return {
2418
+ count: hooks.length,
2419
+ webhooks: hooks.map((h) => ({
2420
+ webhook_id: h.id,
2421
+ url: h.url ?? null,
2422
+ topic: h.topic ?? null,
2423
+ status: h.status ?? null,
2424
+ date_created: h.date_created ?? null
2425
+ }))
2426
+ };
2427
+ }
2428
+ }),
2429
+ create_webhook: ai.tool({
2430
+ description: desc("create_webhook"),
2431
+ inputSchema: zod.z.object({
2432
+ url: zod.z.string().url(),
2433
+ topic: zod.z.string().describe("E.g. 'payment', 'subscription_authorized_payment', 'subscription_preapproval', 'merchant_order', 'point_integration_wh'")
2434
+ }),
2435
+ execute: async ({ url, topic }) => {
2436
+ const hook = await client.createWebhook({ url, topic });
2437
+ return {
2438
+ webhook_id: hook.id,
2439
+ url: hook.url ?? url,
2440
+ topic: hook.topic ?? topic,
2441
+ status: hook.status ?? null
2442
+ };
2443
+ }
2444
+ }),
2445
+ update_webhook: ai.tool({
2446
+ description: desc("update_webhook"),
2447
+ inputSchema: zod.z.object({
2448
+ webhook_id: zod.z.string(),
2449
+ url: zod.z.string().url().optional(),
2450
+ topic: zod.z.string().optional()
2451
+ }),
2452
+ execute: async (input) => {
2453
+ const hook = await client.updateWebhook(input.webhook_id, {
2454
+ ...input.url !== void 0 ? { url: input.url } : {},
2455
+ ...input.topic !== void 0 ? { topic: input.topic } : {}
2456
+ });
2457
+ return {
2458
+ webhook_id: hook.id,
2459
+ url: hook.url ?? null,
2460
+ topic: hook.topic ?? null,
2461
+ status: hook.status ?? null
2462
+ };
2463
+ }
2464
+ }),
2465
+ delete_webhook: ai.tool({
2466
+ description: desc("delete_webhook"),
2467
+ inputSchema: zod.z.object({ webhook_id: zod.z.string() }),
2468
+ execute: async ({ webhook_id }) => {
2469
+ await client.deleteWebhook(webhook_id);
2470
+ return { webhook_id, deleted: true };
2471
+ }
2472
+ }),
2473
+ // ─────────────────────────────────────────────────────────────────────────
2474
+ // v0.5 — Webhook handler combo
2475
+ // ─────────────────────────────────────────────────────────────────────────
2476
+ handle_webhook: ai.tool({
2477
+ description: desc("handle_webhook"),
2478
+ inputSchema: zod.z.object({
2479
+ raw_body: zod.z.string().describe(
2480
+ "The raw JSON body of the webhook request, exactly as received (do NOT re-stringify). Pass `await req.text()` from your handler."
2481
+ ),
2482
+ signature_header: zod.z.string().nullable().describe("Value of the `x-signature` request header."),
2483
+ request_id_header: zod.z.string().nullable().describe("Value of the `x-request-id` request header."),
2484
+ auto_fetch: zod.z.boolean().optional().default(true).describe(
2485
+ "If true (default), fetch the underlying resource (Payment, Subscription, etc.) AS the MP user the client is configured for. Set to false to skip the fetch (faster, useful when you only need the topic+id)."
2486
+ )
2487
+ }),
2488
+ execute: async ({
2489
+ raw_body,
2490
+ signature_header,
2491
+ request_id_header,
2492
+ auto_fetch
2493
+ }) => {
2494
+ if (!options.webhookSecret) {
2495
+ return {
2496
+ verified: false,
2497
+ error: "webhookSecret not configured in mercadoPagoTools options. Pass it from MP dev panel \u2192 Notificaciones \u2192 Webhooks.",
2498
+ event: null,
2499
+ resource: null
2500
+ };
2501
+ }
2502
+ let parsedBody;
2503
+ try {
2504
+ parsedBody = JSON.parse(raw_body);
2505
+ } catch {
2506
+ return {
2507
+ verified: false,
2508
+ error: "raw_body is not valid JSON.",
2509
+ event: null,
2510
+ resource: null
2511
+ };
2512
+ }
2513
+ const event = parseWebhookEvent(parsedBody);
2514
+ if (!event) {
2515
+ return {
2516
+ verified: false,
2517
+ error: "Could not extract topic + dataId from webhook body.",
2518
+ event: null,
2519
+ resource: null
2520
+ };
2521
+ }
2522
+ const verified = verifyWebhookSignature({
2523
+ requestId: request_id_header,
2524
+ dataId: event.dataId,
2525
+ signatureHeader: signature_header,
2526
+ secret: options.webhookSecret
2527
+ });
2528
+ if (!verified) {
2529
+ return {
2530
+ verified: false,
2531
+ error: "HMAC-SHA256 signature mismatch. Reject the webhook (HTTP 401).",
2532
+ event,
2533
+ resource: null
2534
+ };
2535
+ }
2536
+ let resource = null;
2537
+ let resourceError = null;
2538
+ if (auto_fetch) {
2539
+ try {
2540
+ switch (event.topic) {
2541
+ case "payment":
2542
+ case "payment.created":
2543
+ case "payment.updated":
2544
+ resource = await client.getPayment(event.dataId);
2545
+ break;
2546
+ case "preapproval":
2547
+ case "subscription_preapproval":
2548
+ resource = await client.getPreapproval(event.dataId);
2549
+ break;
2550
+ case "subscription_authorized_payment":
2551
+ resource = { id: event.dataId, hint: "Use list_subscription_payments to enumerate parent." };
2552
+ break;
2553
+ default:
2554
+ resource = null;
2555
+ resourceError = `No auto-fetch handler for topic '${event.topic}' yet.`;
2556
+ }
2557
+ } catch (err) {
2558
+ resourceError = err instanceof Error ? err.message : String(err);
2559
+ }
2560
+ }
2561
+ return {
2562
+ verified: true,
2563
+ event,
2564
+ resource,
2565
+ resource_error: resourceError
2566
+ };
2567
+ }
2568
+ }),
2569
+ // ─────────────────────────────────────────────────────────────────────────
2570
+ // v0.5 — OAuth Marketplace flow
2571
+ // ─────────────────────────────────────────────────────────────────────────
2572
+ oauth_authorize_url: ai.tool({
2573
+ description: desc("oauth_authorize_url"),
2574
+ inputSchema: zod.z.object({
2575
+ redirect_uri: zod.z.string().url().describe(
2576
+ "Where MP redirects the seller after approval. MUST be whitelisted in MP dev panel \u2192 Aplicaciones \u2192 tu app \u2192 Redirect URIs."
2577
+ ),
2578
+ state: zod.z.string().min(8).describe(
2579
+ "Opaque CSRF/session token echoed back. Bind to the user's session and verify on redirect."
2580
+ )
2581
+ }),
2582
+ execute: async ({ redirect_uri, state }) => {
2583
+ if (!options.oauth?.clientId) {
2584
+ return {
2585
+ available: false,
2586
+ error: "OAuth not configured. Pass `oauth: { clientId, clientSecret }` to mercadoPagoTools options.",
2587
+ url: null
2588
+ };
2589
+ }
2590
+ const url = buildAuthorizeUrl({
2591
+ clientId: options.oauth.clientId,
2592
+ redirectUri: redirect_uri,
2593
+ state
2594
+ });
2595
+ return {
2596
+ available: true,
2597
+ url,
2598
+ next_step: "Redirect the seller to `url`. After approval MP sends them to redirect_uri?code=...&state=... \u2014 verify state matches, then call oauth_exchange_code with the code."
2599
+ };
2600
+ }
2601
+ }),
2602
+ oauth_exchange_code: ai.tool({
2603
+ description: desc("oauth_exchange_code"),
2604
+ inputSchema: zod.z.object({
2605
+ code: zod.z.string().describe("The `code` query param from the OAuth redirect URL."),
2606
+ redirect_uri: zod.z.string().url().describe(
2607
+ "Must EXACTLY match the redirect_uri used in oauth_authorize_url."
2608
+ )
2609
+ }),
2610
+ execute: async ({ code, redirect_uri }) => {
2611
+ if (!options.oauth?.clientId || !options.oauth?.clientSecret) {
2612
+ return {
2613
+ available: false,
2614
+ error: "OAuth not configured. Pass `oauth: { clientId, clientSecret }` to mercadoPagoTools options.",
2615
+ token: null
2616
+ };
2617
+ }
2618
+ try {
2619
+ const token = await exchangeCodeForToken({
2620
+ clientId: options.oauth.clientId,
2621
+ clientSecret: options.oauth.clientSecret,
2622
+ code,
2623
+ redirectUri: redirect_uri
2624
+ });
2625
+ return {
2626
+ available: true,
2627
+ token,
2628
+ next_step: "PERSIST { user_id, access_token, refresh_token, expires_in } against this seller. Use access_token to instantiate `new MercadoPagoClient({ accessToken })` AS the seller for marketplace API calls."
2629
+ };
2630
+ } catch (err) {
2631
+ return {
2632
+ available: true,
2633
+ error: err instanceof Error ? err.message : String(err),
2634
+ token: null
2635
+ };
2636
+ }
2637
+ }
2638
+ }),
2639
+ oauth_refresh_token: ai.tool({
2640
+ description: desc("oauth_refresh_token"),
2641
+ inputSchema: zod.z.object({
2642
+ refresh_token: zod.z.string().describe("The saved refresh_token for this seller.")
2643
+ }),
2644
+ execute: async ({ refresh_token }) => {
2645
+ if (!options.oauth?.clientId || !options.oauth?.clientSecret) {
2646
+ return {
2647
+ available: false,
2648
+ error: "OAuth not configured. Pass `oauth: { clientId, clientSecret }` to mercadoPagoTools options.",
2649
+ token: null
2650
+ };
2651
+ }
2652
+ try {
2653
+ const token = await refreshAccessToken({
2654
+ clientId: options.oauth.clientId,
2655
+ clientSecret: options.oauth.clientSecret,
2656
+ refreshToken: refresh_token
2657
+ });
2658
+ return {
2659
+ available: true,
2660
+ token,
2661
+ next_step: "Replace the persisted access_token + refresh_token with these new values (refresh_token may have rotated)."
2662
+ };
2663
+ } catch (err) {
2664
+ return {
2665
+ available: true,
2666
+ error: err instanceof Error ? err.message : String(err),
2667
+ token: null
2668
+ };
2669
+ }
2670
+ }
2671
+ }),
2672
+ // ─────────────────────────────────────────────────────────────────────────
2673
+ // v0.5 — Order Management API
2674
+ // ─────────────────────────────────────────────────────────────────────────
2675
+ create_order: ai.tool({
2676
+ description: desc("create_order"),
2677
+ inputSchema: zod.z.object({
2678
+ type: zod.z.enum(["online", "in_store"]).describe("'online' for hosted/checkout flow, 'in_store' for QR/POS"),
2679
+ currency_id: zod.z.string().optional().default("ARS"),
2680
+ external_reference: zod.z.string().optional(),
2681
+ total_amount: zod.z.number().positive().optional(),
2682
+ items: zod.z.array(
2683
+ zod.z.object({
2684
+ title: zod.z.string(),
2685
+ unit_price: zod.z.number(),
2686
+ quantity: zod.z.number(),
2687
+ description: zod.z.string().optional()
2688
+ })
2689
+ ).optional(),
2690
+ payer_email: zod.z.string().email().optional(),
2691
+ capture_mode: zod.z.enum(["automatic", "manual"]).optional().describe(
2692
+ "'automatic' charges immediately; 'manual' authorizes only \u2014 capture later via capture_order."
2693
+ ),
2694
+ notification_url: zod.z.string().url().optional(),
2695
+ marketplace: zod.z.string().optional().describe(
2696
+ "Marketplace identifier (your app's name). Required for split payments."
2697
+ ),
2698
+ marketplace_fee: zod.z.number().optional().describe(
2699
+ "Fee in ARS (NOT %) credited to the marketplace's MP account."
2700
+ ),
2701
+ collector_id: zod.z.union([zod.z.string(), zod.z.number()]).optional().describe(
2702
+ "Seller's MP user_id (from oauth_exchange_code.user_id). Funds route here; marketplace_fee is split off to your account."
2703
+ )
2704
+ }),
2705
+ execute: async (input) => {
2706
+ const params = {
2707
+ type: input.type
2708
+ };
2709
+ if (input.currency_id) params.currency_id = input.currency_id;
2710
+ if (input.external_reference) params.external_reference = input.external_reference;
2711
+ if (input.total_amount !== void 0) params.total_amount = input.total_amount;
2712
+ if (input.items) params.items = input.items;
2713
+ if (input.payer_email) params.payer = { email: input.payer_email };
2714
+ if (input.capture_mode) params.capture_mode = input.capture_mode;
2715
+ if (input.notification_url) params.notification_url = input.notification_url;
2716
+ if (input.marketplace) params.marketplace = input.marketplace;
2717
+ if (input.marketplace_fee !== void 0) params.marketplace_fee = input.marketplace_fee;
2718
+ if (input.collector_id !== void 0) params.collector_id = input.collector_id;
2719
+ const order = await client.createOrder(params, {
2720
+ idempotencyKey: deterministicIdempotencyKey(
2721
+ "create_order",
2722
+ input.external_reference,
2723
+ input.total_amount,
2724
+ input.collector_id
2725
+ )
2726
+ });
2727
+ return {
2728
+ order_id: order.id,
2729
+ status: order.status ?? null,
2730
+ capture_mode: order.capture_mode ?? params.capture_mode ?? "automatic",
2731
+ total_amount: order.total_amount ?? null
1352
2732
  };
1353
2733
  }
1354
2734
  }),
1355
- cancel_qr_payment: ai.tool({
1356
- description: desc("cancel_qr_payment"),
2735
+ get_order: ai.tool({
2736
+ description: desc("get_order"),
2737
+ inputSchema: zod.z.object({ order_id: zod.z.string() }),
2738
+ execute: async ({ order_id }) => {
2739
+ const order = await client.getOrder(order_id);
2740
+ return order;
2741
+ }
2742
+ }),
2743
+ update_order: ai.tool({
2744
+ description: desc("update_order"),
1357
2745
  inputSchema: zod.z.object({
1358
- external_pos_id: zod.z.string()
2746
+ order_id: zod.z.string(),
2747
+ external_reference: zod.z.string().optional(),
2748
+ total_amount: zod.z.number().optional()
1359
2749
  }),
1360
- execute: async ({ external_pos_id }) => {
1361
- const me = await client.getMe();
1362
- await client.cancelQrPayment(String(me.id), external_pos_id);
1363
- return { external_pos_id, cancelled: true };
2750
+ execute: async ({ order_id, external_reference, total_amount }) => {
2751
+ const patch = {};
2752
+ if (external_reference !== void 0) patch.external_reference = external_reference;
2753
+ if (total_amount !== void 0) patch.total_amount = total_amount;
2754
+ const order = await client.updateOrder(order_id, patch);
2755
+ return order;
2756
+ }
2757
+ }),
2758
+ capture_order: ai.tool({
2759
+ description: desc("capture_order"),
2760
+ inputSchema: zod.z.object({
2761
+ order_id: zod.z.string(),
2762
+ amount: zod.z.number().positive().optional().describe(
2763
+ "Optional partial-capture amount. Omit to capture the full authorized amount."
2764
+ )
2765
+ }),
2766
+ execute: async ({ order_id, amount }) => {
2767
+ const order = await client.captureOrder(order_id, amount);
2768
+ return {
2769
+ order_id: order.id,
2770
+ status: order.status ?? null,
2771
+ captured_amount: amount ?? order.total_amount ?? null
2772
+ };
2773
+ }
2774
+ }),
2775
+ cancel_order: ai.tool({
2776
+ description: desc("cancel_order"),
2777
+ inputSchema: zod.z.object({ order_id: zod.z.string() }),
2778
+ execute: async ({ order_id }) => {
2779
+ const order = await client.cancelOrder(order_id);
2780
+ return {
2781
+ order_id: order.id,
2782
+ status: order.status ?? "canceled"
2783
+ };
1364
2784
  }
1365
2785
  })
1366
2786
  };
@@ -1384,234 +2804,6 @@ var InMemoryStateAdapter = class {
1384
2804
  this.store.clear();
1385
2805
  }
1386
2806
  };
1387
- zod.z.enum(["MLA", "MLB", "MLM", "MCO", "MLC", "MLU"]);
1388
- var CurrencyIdSchema = zod.z.enum(["ARS", "USD", "BRL", "MXN"]);
1389
- var FrequencyTypeSchema = zod.z.enum(["months", "days"]);
1390
- var PreapprovalStatusSchema = zod.z.union([
1391
- zod.z.literal("pending"),
1392
- zod.z.literal("authorized"),
1393
- zod.z.literal("paused"),
1394
- zod.z.literal("cancelled"),
1395
- zod.z.string()
1396
- ]);
1397
- var AutoRecurringSchema = zod.z.object({
1398
- frequency: zod.z.number().int().positive(),
1399
- frequency_type: FrequencyTypeSchema,
1400
- transaction_amount: zod.z.number().positive(),
1401
- currency_id: CurrencyIdSchema,
1402
- start_date: zod.z.string().optional(),
1403
- end_date: zod.z.string().optional()
1404
- });
1405
- zod.z.object({
1406
- id: zod.z.string(),
1407
- status: PreapprovalStatusSchema,
1408
- payer_email: zod.z.string(),
1409
- init_point: zod.z.string().url(),
1410
- external_reference: zod.z.string().optional(),
1411
- date_created: zod.z.string(),
1412
- last_modified: zod.z.string(),
1413
- next_payment_date: zod.z.string().optional(),
1414
- payer_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1415
- auto_recurring: AutoRecurringSchema
1416
- });
1417
- var WebhookBodySchema = zod.z.object({
1418
- type: zod.z.string().optional(),
1419
- topic: zod.z.string().optional(),
1420
- action: zod.z.string().optional(),
1421
- data: zod.z.object({ id: zod.z.union([zod.z.string(), zod.z.number()]) }).optional(),
1422
- resource: zod.z.string().optional(),
1423
- user_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1424
- api_version: zod.z.string().optional(),
1425
- date_created: zod.z.string().optional(),
1426
- id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1427
- live_mode: zod.z.boolean().optional()
1428
- }).passthrough();
1429
- var PaymentStatusSchema = zod.z.union([
1430
- zod.z.literal("pending"),
1431
- zod.z.literal("approved"),
1432
- zod.z.literal("authorized"),
1433
- zod.z.literal("in_process"),
1434
- zod.z.literal("in_mediation"),
1435
- zod.z.literal("rejected"),
1436
- zod.z.literal("cancelled"),
1437
- zod.z.literal("refunded"),
1438
- zod.z.literal("charged_back"),
1439
- zod.z.string()
1440
- ]);
1441
- var PaymentSchema = zod.z.object({
1442
- id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1443
- status: PaymentStatusSchema,
1444
- status_detail: zod.z.string().nullable().optional(),
1445
- date_created: zod.z.string().nullable().optional(),
1446
- date_approved: zod.z.string().nullable().optional(),
1447
- date_last_updated: zod.z.string().nullable().optional(),
1448
- transaction_amount: zod.z.number(),
1449
- currency_id: zod.z.string(),
1450
- installments: zod.z.number().int().nullable().optional(),
1451
- payment_method_id: zod.z.string().nullable().optional(),
1452
- payment_type_id: zod.z.string().nullable().optional(),
1453
- external_reference: zod.z.string().nullable().optional(),
1454
- description: zod.z.string().nullable().optional(),
1455
- payer: zod.z.object({
1456
- id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1457
- email: zod.z.string().nullable().optional(),
1458
- identification: zod.z.object({
1459
- type: zod.z.string().nullable().optional(),
1460
- number: zod.z.string().nullable().optional()
1461
- }).nullable().optional()
1462
- }).passthrough().optional(),
1463
- transaction_details: zod.z.object({
1464
- net_received_amount: zod.z.number().nullable().optional(),
1465
- total_paid_amount: zod.z.number().nullable().optional(),
1466
- installment_amount: zod.z.number().nullable().optional()
1467
- }).passthrough().optional()
1468
- }).passthrough();
1469
- zod.z.object({
1470
- paging: zod.z.object({
1471
- total: zod.z.number(),
1472
- limit: zod.z.number(),
1473
- offset: zod.z.number()
1474
- }),
1475
- results: zod.z.array(PaymentSchema)
1476
- });
1477
- zod.z.object({
1478
- id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1479
- payment_id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1480
- amount: zod.z.number(),
1481
- source: zod.z.object({
1482
- id: zod.z.string().nullable().optional(),
1483
- name: zod.z.string().nullable().optional(),
1484
- type: zod.z.string().nullable().optional()
1485
- }).nullable().optional(),
1486
- date_created: zod.z.string().nullable().optional(),
1487
- status: zod.z.string().nullable().optional()
1488
- }).passthrough();
1489
- var PreferenceItemSchema = zod.z.object({
1490
- id: zod.z.string().optional(),
1491
- title: zod.z.string(),
1492
- description: zod.z.string().optional(),
1493
- picture_url: zod.z.string().url().optional(),
1494
- category_id: zod.z.string().optional(),
1495
- quantity: zod.z.number().int().positive(),
1496
- unit_price: zod.z.number().positive(),
1497
- currency_id: CurrencyIdSchema.optional()
1498
- });
1499
- zod.z.object({
1500
- id: zod.z.string(),
1501
- init_point: zod.z.string().url().optional(),
1502
- sandbox_init_point: zod.z.string().url().optional(),
1503
- client_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1504
- collector_id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1505
- items: zod.z.array(PreferenceItemSchema).optional(),
1506
- external_reference: zod.z.string().nullable().optional(),
1507
- date_created: zod.z.string().nullable().optional(),
1508
- expires: zod.z.boolean().optional(),
1509
- expiration_date_from: zod.z.string().nullable().optional(),
1510
- expiration_date_to: zod.z.string().nullable().optional()
1511
- }).passthrough();
1512
- zod.z.object({
1513
- id: zod.z.string(),
1514
- email: zod.z.string(),
1515
- first_name: zod.z.string().nullable().optional(),
1516
- last_name: zod.z.string().nullable().optional(),
1517
- phone: zod.z.object({ area_code: zod.z.string().nullable().optional(), number: zod.z.string().nullable().optional() }).nullable().optional(),
1518
- identification: zod.z.object({ type: zod.z.string().nullable().optional(), number: zod.z.string().nullable().optional() }).nullable().optional(),
1519
- date_created: zod.z.string().nullable().optional(),
1520
- date_last_updated: zod.z.string().nullable().optional(),
1521
- description: zod.z.string().nullable().optional()
1522
- }).passthrough();
1523
- zod.z.object({
1524
- id: zod.z.string(),
1525
- customer_id: zod.z.string(),
1526
- expiration_month: zod.z.number().int().nullable().optional(),
1527
- expiration_year: zod.z.number().int().nullable().optional(),
1528
- first_six_digits: zod.z.string().nullable().optional(),
1529
- last_four_digits: zod.z.string().nullable().optional(),
1530
- payment_method: zod.z.object({
1531
- id: zod.z.string().nullable().optional(),
1532
- name: zod.z.string().nullable().optional(),
1533
- payment_type_id: zod.z.string().nullable().optional()
1534
- }).nullable().optional(),
1535
- date_created: zod.z.string().nullable().optional()
1536
- }).passthrough();
1537
- zod.z.object({
1538
- id: zod.z.string(),
1539
- name: zod.z.string(),
1540
- payment_type_id: zod.z.string(),
1541
- status: zod.z.string(),
1542
- thumbnail: zod.z.string().nullable().optional(),
1543
- secure_thumbnail: zod.z.string().nullable().optional(),
1544
- min_allowed_amount: zod.z.number().nullable().optional(),
1545
- max_allowed_amount: zod.z.number().nullable().optional()
1546
- }).passthrough();
1547
- zod.z.object({
1548
- payment_method_id: zod.z.string(),
1549
- payment_type_id: zod.z.string(),
1550
- issuer: zod.z.object({
1551
- id: zod.z.union([zod.z.string(), zod.z.number()]).optional(),
1552
- name: zod.z.string().nullable().optional()
1553
- }).nullable().optional(),
1554
- payer_costs: zod.z.array(
1555
- zod.z.object({
1556
- installments: zod.z.number().int(),
1557
- installment_rate: zod.z.number(),
1558
- discount_rate: zod.z.number().nullable().optional(),
1559
- installment_amount: zod.z.number(),
1560
- total_amount: zod.z.number(),
1561
- recommended_message: zod.z.string().nullable().optional()
1562
- }).passthrough()
1563
- )
1564
- }).passthrough();
1565
- zod.z.object({
1566
- in_store_order_id: zod.z.string(),
1567
- qr_data: zod.z.string()
1568
- }).passthrough();
1569
- zod.z.object({
1570
- id: zod.z.string(),
1571
- status: zod.z.string().optional(),
1572
- date_due: zod.z.string().optional(),
1573
- card_id: zod.z.string().optional(),
1574
- cardholder: zod.z.unknown().optional()
1575
- }).passthrough();
1576
- zod.z.object({
1577
- id: zod.z.union([zod.z.string(), zod.z.number()]).transform(String),
1578
- email: zod.z.string().nullable().optional(),
1579
- nickname: zod.z.string().nullable().optional(),
1580
- country_id: zod.z.string().nullable().optional(),
1581
- site_id: zod.z.string().nullable().optional(),
1582
- user_type: zod.z.string().nullable().optional(),
1583
- status: zod.z.object({ user_type: zod.z.string().nullable().optional() }).passthrough().nullable().optional()
1584
- }).passthrough();
1585
-
1586
- // src/webhook.ts
1587
- function parseWebhookEvent(body, searchParams) {
1588
- const parseResult = WebhookBodySchema.safeParse(body ?? {});
1589
- const parsedBody = parseResult.success ? parseResult.data : {};
1590
- const topic = searchParams?.get("topic") ?? parsedBody.topic ?? parsedBody.type ?? null;
1591
- const dataId = searchParams?.get("id") ?? (parsedBody.data?.id !== void 0 ? String(parsedBody.data.id) : null) ?? parsedBody.resource ?? null;
1592
- if (!topic || !dataId) {
1593
- return null;
1594
- }
1595
- return {
1596
- topic,
1597
- dataId: String(dataId),
1598
- action: parsedBody.action ?? null,
1599
- raw: parsedBody
1600
- };
1601
- }
1602
- function verifyWebhookSignature(params) {
1603
- if (!params.signatureHeader || !params.requestId) return false;
1604
- const parts = Object.fromEntries(
1605
- params.signatureHeader.split(",").map((segment) => segment.trim().split("="))
1606
- );
1607
- const ts = parts.ts;
1608
- const v1 = parts.v1;
1609
- if (!ts || !v1) return false;
1610
- const manifest = `id:${params.dataId};request-id:${params.requestId};ts:${ts};`;
1611
- const expected = crypto.createHmac("sha256", params.secret).update(manifest).digest("hex");
1612
- if (expected.length !== v1.length) return false;
1613
- return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(v1));
1614
- }
1615
2807
 
1616
2808
  exports.InMemoryStateAdapter = InMemoryStateAdapter;
1617
2809
  exports.MercadoPagoAccountTypeMismatchError = MercadoPagoAccountTypeMismatchError;
@@ -1625,9 +2817,14 @@ exports.MercadoPagoPaymentRejectedError = MercadoPagoPaymentRejectedError;
1625
2817
  exports.MercadoPagoRateLimitError = MercadoPagoRateLimitError;
1626
2818
  exports.MercadoPagoSelfPaymentError = MercadoPagoSelfPaymentError;
1627
2819
  exports.MercadoPagoTimeoutError = MercadoPagoTimeoutError;
2820
+ exports.buildAuthorizeUrl = buildAuthorizeUrl;
1628
2821
  exports.classifyError = classifyError;
2822
+ exports.exchangeCodeForToken = exchangeCodeForToken;
2823
+ exports.expirationTimeMs = expirationTimeMs;
2824
+ exports.isExpiringSoon = isExpiringSoon;
1629
2825
  exports.mercadoPagoTools = mercadoPagoTools;
1630
2826
  exports.parseWebhookEvent = parseWebhookEvent;
2827
+ exports.refreshAccessToken = refreshAccessToken;
1631
2828
  exports.verifyWebhookSignature = verifyWebhookSignature;
1632
2829
  //# sourceMappingURL=index.cjs.map
1633
2830
  //# sourceMappingURL=index.cjs.map