Repository: mercadopago/sdk-java Branch: master Commit: 37c6a3be1db5 Files: 485 Total size: 1.1 MB Directory structure: gitextract_2_mobys_/ ├── .code_quality/ │ └── checkstyle_rules.xml ├── .github/ │ ├── ISSUE_TEMPLATE/ │ │ ├── bug_report.yml │ │ ├── config.yml │ │ ├── feature_request.yml │ │ └── question.yml │ └── workflows/ │ ├── main.yml │ ├── maven-publish-release.yml │ └── maven-publish-snapshot.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CODE_OF_CONDUCT.md ├── CODING_GUIDELINES.md ├── CONTRIBUTING.md ├── LICENSE ├── PULL_REQUEST_TEMPLATE.md ├── README.md ├── SUPPORT.md ├── build-gradle.sh ├── maven-central-deploy.sh ├── mp_ref_report.md ├── pom.xml └── src/ ├── main/ │ └── java/ │ └── com/ │ └── mercadopago/ │ ├── MercadoPagoConfig.java │ ├── client/ │ │ ├── MercadoPagoClient.java │ │ ├── cardtoken/ │ │ │ ├── CardTokenClient.java │ │ │ └── CardTokenRequest.java │ │ ├── common/ │ │ │ ├── AddressRequest.java │ │ │ ├── IdentificationRequest.java │ │ │ ├── InvoicePeriod.java │ │ │ ├── PhoneRequest.java │ │ │ ├── SubMerchant.java │ │ │ └── SubscriptionSequence.java │ │ ├── customer/ │ │ │ ├── CustomerAddressRequest.java │ │ │ ├── CustomerCardClient.java │ │ │ ├── CustomerCardCreateRequest.java │ │ │ ├── CustomerClient.java │ │ │ └── CustomerRequest.java │ │ ├── identificationtype/ │ │ │ └── IdentificationTypeClient.java │ │ ├── merchantorder/ │ │ │ ├── MerchantOrderClient.java │ │ │ ├── MerchantOrderCreateRequest.java │ │ │ ├── MerchantOrderItemRequest.java │ │ │ ├── MerchantOrderPayerRequest.java │ │ │ ├── MerchantOrderReceiverAddressCityRequest.java │ │ │ ├── MerchantOrderReceiverAddressCountryRequest.java │ │ │ ├── MerchantOrderReceiverAddressRequest.java │ │ │ ├── MerchantOrderReceiverAddressStateRequest.java │ │ │ ├── MerchantOrderShipmentRequest.java │ │ │ ├── MerchantOrderShippingEstimatedDeliveryRequest.java │ │ │ ├── MerchantOrderShippingOptionRequest.java │ │ │ ├── MerchantOrderShippingSpeedRequest.java │ │ │ └── MerchantOrderUpdateRequest.java │ │ ├── oauth/ │ │ │ ├── CreateOauthCredentialRequest.java │ │ │ ├── OauthClient.java │ │ │ └── RefreshOauthCredentialRequest.java │ │ ├── order/ │ │ │ ├── AdditionalInfoRequest.java │ │ │ ├── OrderAutomaticPaymentsRequest.java │ │ │ ├── OrderClient.java │ │ │ ├── OrderConfigRequest.java │ │ │ ├── OrderCreateRequest.java │ │ │ ├── OrderDifferentialPricing.java │ │ │ ├── OrderInvoicePeriodRequest.java │ │ │ ├── OrderItemRequest.java │ │ │ ├── OrderOnlineConfig.java │ │ │ ├── OrderPayerAddressRequest.java │ │ │ ├── OrderPayerRequest.java │ │ │ ├── OrderPaymentMethodConfig.java │ │ │ ├── OrderPaymentMethodRequest.java │ │ │ ├── OrderPaymentRequest.java │ │ │ ├── OrderPointConfig.java │ │ │ ├── OrderReceiverAddressRequest.java │ │ │ ├── OrderRefundPaymentRequest.java │ │ │ ├── OrderRefundRequest.java │ │ │ ├── OrderRouteRequest.java │ │ │ ├── OrderShipmentRequest.java │ │ │ ├── OrderStoredCredentialRequest.java │ │ │ ├── OrderSubscriptionDataRequest.java │ │ │ ├── OrderSubscriptionSequenceRequest.java │ │ │ ├── OrderTransactionRequest.java │ │ │ ├── OrderTransactionSecurity.java │ │ │ ├── PassengerIdentification.java │ │ │ ├── PayerInfo.java │ │ │ ├── PlatformInfo.java │ │ │ ├── PlatformShipment.java │ │ │ ├── SellerAddress.java │ │ │ ├── SellerIdentification.java │ │ │ ├── SellerInfo.java │ │ │ ├── SellerPhone.java │ │ │ ├── ShipmentInfo.java │ │ │ ├── TrackingInfo.java │ │ │ ├── TravelInfo.java │ │ │ ├── TravelPassengerRequest.java │ │ │ └── TravelRouteRequest.java │ │ ├── payment/ │ │ │ ├── PaymentAdditionalInfoBarcodeRequest.java │ │ │ ├── PaymentAdditionalInfoPayerRequest.java │ │ │ ├── PaymentAdditionalInfoRequest.java │ │ │ ├── PaymentAmountsRequest.java │ │ │ ├── PaymentAuthenticationRequest.java │ │ │ ├── PaymentCancelRequest.java │ │ │ ├── PaymentCaptureRequest.java │ │ │ ├── PaymentCategoryDescriptorRequest.java │ │ │ ├── PaymentClient.java │ │ │ ├── PaymentCounterCurrencyRequest.java │ │ │ ├── PaymentCreateRequest.java │ │ │ ├── PaymentDataRequest.java │ │ │ ├── PaymentDiscountRequest.java │ │ │ ├── PaymentFeeRequest.java │ │ │ ├── PaymentForwardDataRequest.java │ │ │ ├── PaymentInvoicePeriodRequest.java │ │ │ ├── PaymentItemRequest.java │ │ │ ├── PaymentMerchantServicesRequest.java │ │ │ ├── PaymentMethodRequest.java │ │ │ ├── PaymentNetworkTransactionDataRequest.java │ │ │ ├── PaymentOrderRequest.java │ │ │ ├── PaymentPassengerRequest.java │ │ │ ├── PaymentPayerAddressRequest.java │ │ │ ├── PaymentPayerPhoneRequest.java │ │ │ ├── PaymentPayerRequest.java │ │ │ ├── PaymentPaymentReferenceRequest.java │ │ │ ├── PaymentPointOfInteractionRequest.java │ │ │ ├── PaymentReceiverAddressRequest.java │ │ │ ├── PaymentRefundClient.java │ │ │ ├── PaymentRefundCreateRequest.java │ │ │ ├── PaymentRouteRequest.java │ │ │ ├── PaymentRulesRequest.java │ │ │ ├── PaymentShipmentsRequest.java │ │ │ ├── PaymentSubscriptionSequenceRequest.java │ │ │ ├── PaymentTaxRequest.java │ │ │ ├── PaymentTransactionDataRequest.java │ │ │ ├── PaymentTransactionDetailsRequest.java │ │ │ └── PaymentUserAmountRequest.java │ │ ├── paymentmethod/ │ │ │ └── PaymentMethodClient.java │ │ ├── point/ │ │ │ ├── OperatingMode.java │ │ │ ├── PointClient.java │ │ │ ├── PointDeviceOperatingModeRequest.java │ │ │ ├── PointPaymentIntentAdditionalInfoRequest.java │ │ │ ├── PointPaymentIntentListRequest.java │ │ │ ├── PointPaymentIntentPaymentRequest.java │ │ │ └── PointPaymentIntentRequest.java │ │ ├── preapproval/ │ │ │ ├── PreApprovalAutoRecurringCreateRequest.java │ │ │ ├── PreApprovalAutoRecurringUpdateRequest.java │ │ │ ├── PreapprovalClient.java │ │ │ ├── PreapprovalCreateRequest.java │ │ │ └── PreapprovalUpdateRequest.java │ │ ├── preference/ │ │ │ ├── PreferenceAmountsRequest.java │ │ │ ├── PreferenceBackUrlsRequest.java │ │ │ ├── PreferenceCategoryDescriptorRequest.java │ │ │ ├── PreferenceClient.java │ │ │ ├── PreferenceCounterCurrencyRequest.java │ │ │ ├── PreferenceDifferentialPricingRequest.java │ │ │ ├── PreferenceFreeMethodRequest.java │ │ │ ├── PreferenceItemRequest.java │ │ │ ├── PreferencePassengerRequest.java │ │ │ ├── PreferencePayerRequest.java │ │ │ ├── PreferencePaymentMethodRequest.java │ │ │ ├── PreferencePaymentMethodsRequest.java │ │ │ ├── PreferencePaymentTypeRequest.java │ │ │ ├── PreferenceReceiverAddressRequest.java │ │ │ ├── PreferenceRequest.java │ │ │ ├── PreferenceRouteRequest.java │ │ │ ├── PreferenceShipmentsRequest.java │ │ │ ├── PreferenceTaxRequest.java │ │ │ ├── PreferenceTrackRequest.java │ │ │ ├── PreferenceTrackValuesRequest.java │ │ │ └── PreferenceUserAmountRequest.java │ │ └── user/ │ │ └── UserClient.java │ ├── core/ │ │ └── MPRequestOptions.java │ ├── example/ │ │ └── apis/ │ │ ├── order/ │ │ │ ├── CancelOrder.java │ │ │ ├── CaptureOrder.java │ │ │ ├── CreateOrder.java │ │ │ ├── CreateOrderPSE.java │ │ │ ├── CreateOrderWith3DS.java │ │ │ ├── CreateOrderWithIndustryFields.java │ │ │ ├── CreateOrderWithPointConfig.java │ │ │ ├── CreateTransaction.java │ │ │ ├── DeleteTransaction.java │ │ │ ├── GetOrderById.java │ │ │ ├── ProcessOrderById.java │ │ │ ├── RefundPartial.java │ │ │ ├── RefundTotal.java │ │ │ └── UpdateTransaction.java │ │ └── payment/ │ │ └── Main.java │ ├── exceptions/ │ │ ├── MPApiException.java │ │ ├── MPException.java │ │ ├── MPInvalidWebhookSignatureException.java │ │ ├── MPJsonParseException.java │ │ ├── MPMalformedRequestException.java │ │ └── SignatureFailureReason.java │ ├── net/ │ │ ├── Headers.java │ │ ├── HttpMethod.java │ │ ├── HttpStatus.java │ │ ├── KeepAliveStrategy.java │ │ ├── MPDefaultHttpClient.java │ │ ├── MPElementsResourcesPage.java │ │ ├── MPHttpClient.java │ │ ├── MPRequest.java │ │ ├── MPResource.java │ │ ├── MPResourceList.java │ │ ├── MPResponse.java │ │ ├── MPResultsResourcesPage.java │ │ ├── MPSearchRequest.java │ │ └── UrlFormatter.java │ ├── resources/ │ │ ├── CardToken.java │ │ ├── ResultsPaging.java │ │ ├── common/ │ │ │ ├── Address.java │ │ │ ├── Identification.java │ │ │ ├── Phone.java │ │ │ └── Source.java │ │ ├── customer/ │ │ │ ├── Customer.java │ │ │ ├── CustomerAddress.java │ │ │ ├── CustomerAddressCity.java │ │ │ ├── CustomerAddressCountry.java │ │ │ ├── CustomerAddressMunicipality.java │ │ │ ├── CustomerAddressNeighborhood.java │ │ │ ├── CustomerAddressState.java │ │ │ ├── CustomerCard.java │ │ │ ├── CustomerCardCardholder.java │ │ │ ├── CustomerCardCardholderIdentification.java │ │ │ ├── CustomerCardIssuer.java │ │ │ ├── CustomerCardPaymentMethod.java │ │ │ ├── CustomerCardSecurityCode.java │ │ │ ├── CustomerDefaultAddress.java │ │ │ └── Identification.java │ │ ├── identificationtype/ │ │ │ └── IdentificationType.java │ │ ├── merchantorder/ │ │ │ ├── MerchantOrder.java │ │ │ ├── MerchantOrderCollector.java │ │ │ ├── MerchantOrderItem.java │ │ │ ├── MerchantOrderPayer.java │ │ │ ├── MerchantOrderPayment.java │ │ │ ├── MerchantOrderReceiverAddress.java │ │ │ ├── MerchantOrderReceiverAddressCity.java │ │ │ ├── MerchantOrderReceiverAddressCountry.java │ │ │ ├── MerchantOrderReceiverAddressState.java │ │ │ ├── MerchantOrderShipment.java │ │ │ ├── MerchantOrderShippingEstimatedDelivery.java │ │ │ ├── MerchantOrderShippingOption.java │ │ │ └── MerchantOrderShippingSpeed.java │ │ ├── oauth/ │ │ │ ├── CreateOauthCredential.java │ │ │ ├── OauthCredential.java │ │ │ └── RefreshOauthCredential.java │ │ ├── order/ │ │ │ ├── Order.java │ │ │ ├── OrderAttempts.java │ │ │ ├── OrderAutomaticPayments.java │ │ │ ├── OrderCategoryDescriptor.java │ │ │ ├── OrderChargeback.java │ │ │ ├── OrderConfig.java │ │ │ ├── OrderDifferentialPricing.java │ │ │ ├── OrderDiscountPaymentMethod.java │ │ │ ├── OrderDiscounts.java │ │ │ ├── OrderExternalCategory.java │ │ │ ├── OrderInstallments.java │ │ │ ├── OrderInstallmentsAvailable.java │ │ │ ├── OrderInstallmentsInterestFree.java │ │ │ ├── OrderIntegrationData.java │ │ │ ├── OrderInvoicePeriod.java │ │ │ ├── OrderItem.java │ │ │ ├── OrderOnlineConfig.java │ │ │ ├── OrderPaging.java │ │ │ ├── OrderPassenger.java │ │ │ ├── OrderPayer.java │ │ │ ├── OrderPayment.java │ │ │ ├── OrderPaymentDiscount.java │ │ │ ├── OrderPaymentMethod.java │ │ │ ├── OrderPointConfig.java │ │ │ ├── OrderReceiverAddress.java │ │ │ ├── OrderReference.java │ │ │ ├── OrderRefund.java │ │ │ ├── OrderRefundItem.java │ │ │ ├── OrderRoute.java │ │ │ ├── OrderSearchResponse.java │ │ │ ├── OrderShipment.java │ │ │ ├── OrderStoredCredential.java │ │ │ ├── OrderSubscriptionData.java │ │ │ ├── OrderSubscriptionSequence.java │ │ │ ├── OrderTax.java │ │ │ ├── OrderTransaction.java │ │ │ ├── OrderTransactionRefund.java │ │ │ ├── OrderTransactionSecurity.java │ │ │ ├── OrderTypeResponse.java │ │ │ └── UpdateOrderTransaction.java │ │ ├── payment/ │ │ │ ├── Payment.java │ │ │ ├── PaymentAdditionalInfo.java │ │ │ ├── PaymentAdditionalInfoPayer.java │ │ │ ├── PaymentAmounts.java │ │ │ ├── PaymentApplicationData.java │ │ │ ├── PaymentBankInfo.java │ │ │ ├── PaymentBankInfoCollector.java │ │ │ ├── PaymentBankInfoPayer.java │ │ │ ├── PaymentBarcode.java │ │ │ ├── PaymentCard.java │ │ │ ├── PaymentCardholder.java │ │ │ ├── PaymentCounterCurrency.java │ │ │ ├── PaymentData.java │ │ │ ├── PaymentDiscount.java │ │ │ ├── PaymentExpanded.java │ │ │ ├── PaymentFee.java │ │ │ ├── PaymentFeeDetail.java │ │ │ ├── PaymentInvoicePeriod.java │ │ │ ├── PaymentItem.java │ │ │ ├── PaymentMethod.java │ │ │ ├── PaymentOrder.java │ │ │ ├── PaymentPayer.java │ │ │ ├── PaymentPaymentReference.java │ │ │ ├── PaymentPhone.java │ │ │ ├── PaymentPointOfInteraction.java │ │ │ ├── PaymentReceiverAddress.java │ │ │ ├── PaymentRefund.java │ │ │ ├── PaymentRules.java │ │ │ ├── PaymentShipments.java │ │ │ ├── PaymentStatus.java │ │ │ ├── PaymentSubscriptionSequence.java │ │ │ ├── PaymentTax.java │ │ │ ├── PaymentThreeDSInfo.java │ │ │ ├── PaymentTransactionData.java │ │ │ ├── PaymentTransactionDetails.java │ │ │ ├── PaymentUsersAmountCollector.java │ │ │ └── PaymentUsersAmountPayer.java │ │ ├── paymentmethod/ │ │ │ ├── PaymentMethod.java │ │ │ ├── PaymentMethodFinancialInstitutions.java │ │ │ ├── PaymentMethodSettings.java │ │ │ ├── PaymentMethodSettingsBin.java │ │ │ ├── PaymentMethodSettingsCardNumber.java │ │ │ └── PaymentMethodSettingsSecurityCode.java │ │ ├── point/ │ │ │ ├── OperatingMode.java │ │ │ ├── PointCancelPaymentIntent.java │ │ │ ├── PointDevice.java │ │ │ ├── PointDeviceOperatingMode.java │ │ │ ├── PointDevices.java │ │ │ ├── PointPaymentIntent.java │ │ │ ├── PointPaymentIntentAdditionalInfo.java │ │ │ ├── PointPaymentIntentList.java │ │ │ ├── PointPaymentIntentListEvent.java │ │ │ ├── PointPaymentIntentPayment.java │ │ │ ├── PointSearchPaymentIntent.java │ │ │ └── PointStatusPaymentIntent.java │ │ ├── preapproval/ │ │ │ ├── Preapproval.java │ │ │ └── PreapprovalAutoRecurring.java │ │ ├── preference/ │ │ │ ├── Preference.java │ │ │ ├── PreferenceAmounts.java │ │ │ ├── PreferenceBackUrls.java │ │ │ ├── PreferenceCategoryDescriptor.java │ │ │ ├── PreferenceCounterCurrency.java │ │ │ ├── PreferenceDifferentialPricing.java │ │ │ ├── PreferenceFreeMethod.java │ │ │ ├── PreferenceItem.java │ │ │ ├── PreferencePassenger.java │ │ │ ├── PreferencePayer.java │ │ │ ├── PreferencePaymentMethod.java │ │ │ ├── PreferencePaymentMethods.java │ │ │ ├── PreferencePaymentType.java │ │ │ ├── PreferenceReceiverAddress.java │ │ │ ├── PreferenceRoute.java │ │ │ ├── PreferenceSearch.java │ │ │ ├── PreferenceShipments.java │ │ │ ├── PreferenceTax.java │ │ │ ├── PreferenceTrack.java │ │ │ ├── PreferenceTrackValues.java │ │ │ └── PreferenceUserAmount.java │ │ └── user/ │ │ └── User.java │ ├── serialization/ │ │ └── Serializer.java │ └── webhook/ │ └── WebhookSignatureValidator.java └── test/ └── java/ └── com/ └── mercadopago/ ├── BaseClientIT.java ├── BaseClientTest.java ├── client/ │ ├── MercadoPagoClientTest.java │ ├── cardtoken/ │ │ ├── CardTokenCardholderTestCreateRequest.java │ │ ├── CardTokenClientIT.java │ │ ├── CardTokenClientTest.java │ │ ├── CardTokenTestClient.java │ │ └── CardTokenTestCreateRequest.java │ ├── customer/ │ │ ├── CustomerCardClientTest.java │ │ ├── CustomerClientIT.java │ │ └── CustomerClientTest.java │ ├── identificationtype/ │ │ ├── IdentificationTypeClientIT.java │ │ └── IdentificationTypeClientTest.java │ ├── merchantorder/ │ │ ├── MerchantOrderClientIT.java │ │ └── MerchantOrderClientTest.java │ ├── oauth/ │ │ └── OauthClientTest.java │ ├── order/ │ │ ├── OrderClientIT.java │ │ ├── OrderClientTest.java │ │ ├── OrderClientWith3DSTest.java │ │ └── OrderPointConfigTest.java │ ├── payment/ │ │ ├── PaymentClientIT.java │ │ ├── PaymentClientTest.java │ │ ├── PaymentRefundClientIT.java │ │ └── PaymentRefundClientTest.java │ ├── paymentmethod/ │ │ ├── PaymentMethodClientIT.java │ │ └── PaymentMethodClientTest.java │ ├── point/ │ │ ├── PointClientIT.java │ │ └── PointClientTest.java │ ├── preapproval/ │ │ ├── PreapprovalClientIT.java │ │ └── PreapprovalClientTest.java │ ├── preference/ │ │ ├── PreferenceClientIT.java │ │ └── PreferenceClientTest.java │ └── user/ │ ├── UserClientIT.java │ └── UserClientTest.java ├── helper/ │ ├── HttpStatusCode.java │ └── MockHelper.java ├── mock/ │ ├── HttpClientMock.java │ ├── HttpRequestMatcher.java │ └── MPDefaultHttpClientMock.java ├── net/ │ ├── MPDefaultHttpClientTest.java │ └── UrlFormatterTest.java ├── resources/ │ └── mocks/ │ ├── helper/ │ │ └── serializer_iso8601_timestamps.json │ ├── request/ │ │ ├── advancedPayment/ │ │ │ ├── advanced_payment_base.json │ │ │ ├── captured.json │ │ │ ├── money_release_date.json │ │ │ ├── payment_captured.json │ │ │ └── status_cancelled.json │ │ ├── card/ │ │ │ └── card_new.json │ │ ├── customer/ │ │ │ ├── customer_base.json │ │ │ └── customer_first_name.json │ │ ├── merchant/ │ │ │ ├── order_base.json │ │ │ └── order_updated.json │ │ ├── payment/ │ │ │ ├── captured.json │ │ │ ├── payment_3ds.json │ │ │ ├── payment_base.json │ │ │ ├── payment_boleto.json │ │ │ ├── payment_captured.json │ │ │ ├── payment_pix.json │ │ │ ├── payment_pse.json │ │ │ └── status_cancelled.json │ │ ├── point/ │ │ │ ├── devices_operating_mode.json │ │ │ └── payment_intent.json │ │ ├── preapproval/ │ │ │ ├── preapproval_base.json │ │ │ └── preapproval_update.json │ │ ├── preference/ │ │ │ ├── preference_base.json │ │ │ └── preference_updated.json │ │ ├── refund/ │ │ │ ├── refund.json │ │ │ └── refund_partial.json │ │ └── request_generic.json │ └── response/ │ ├── advancedPayment/ │ │ ├── payment_base.json │ │ ├── payment_cancelled.json │ │ ├── payment_captured.json │ │ ├── payment_updated.json │ │ └── refund.json │ ├── card/ │ │ ├── card_all.json │ │ ├── card_new.json │ │ └── card_single.json │ ├── cardtoken/ │ │ └── card_token_base.json │ ├── customer/ │ │ ├── customer_base.json │ │ ├── customer_updated.json │ │ └── search_by_email.json │ ├── identification/ │ │ └── types.json │ ├── merchant/ │ │ ├── order_base.json │ │ ├── order_search.json │ │ └── order_updated.json │ ├── oauth/ │ │ ├── oauth_credential.json │ │ └── oauth_refresh_token.json │ ├── order/ │ │ ├── capture_order_response.json │ │ ├── create_order_response.json │ │ ├── create_refund_partial_response.json │ │ ├── create_refund_total_response.json │ │ ├── create_transaction_response.json │ │ ├── order_search_response.json │ │ └── update_transaction_response.json │ ├── payment/ │ │ ├── by_external_reference.json │ │ ├── payment_3ds.json │ │ ├── payment_base.json │ │ ├── payment_boleto.json │ │ ├── payment_cancelled.json │ │ ├── payment_captured.json │ │ ├── payment_card_token_error.json │ │ ├── payment_pix.json │ │ ├── payment_pse.json │ │ └── payment_search.json │ ├── paymentmethod/ │ │ └── payment_method_base.json │ ├── point/ │ │ ├── devices_list.json │ │ ├── devices_operating_mode.json │ │ ├── payment_intent.json │ │ ├── payment_intent_delete.json │ │ ├── payment_intent_list.json │ │ ├── payment_intent_search.json │ │ └── payment_intent_status.json │ ├── preapproval/ │ │ ├── preapproval_base.json │ │ ├── preapproval_list.json │ │ └── preapproval_update.json │ ├── preference/ │ │ ├── preference_base.json │ │ ├── preference_list.json │ │ └── preference_updated.json │ ├── refund/ │ │ ├── refund_all.json │ │ ├── refund_base.json │ │ ├── refund_list.json │ │ └── refund_partial.json │ ├── response_generic_success.json │ └── user/ │ └── user_base.json ├── serialization/ │ └── SerializerTest.java └── webhook/ └── WebhookSignatureValidatorTest.java ================================================ FILE CONTENTS ================================================ ================================================ FILE: .code_quality/checkstyle_rules.xml ================================================ ================================================ FILE: .github/ISSUE_TEMPLATE/bug_report.yml ================================================ name: 🐛 Bug Report description: Report a bug or unexpected behavior in the SDK title: "[BUG]: " labels: ["bug", "needs-triage"] assignees: ["danielalfarourrea","luismeli10","orojaspardo"] body: - type: markdown attributes: value: | ## 🐛 Thanks for reporting this issue! Please make sure you tested with the latest version of the relevant packages and/or checked existing issues to avoid duplicates. If the bug persists, open the issue with a clear and concise description including screenshots, if applicable. We appreciate your feedback! **Before reporting a bug:** - 🔍 **Search [existing issues](./issues?q=is%3Aissue) to avoid duplicates** - 📚 **Verify you are using the [latest version](../../releases)** - 💡 **Try to reproduce the problem in sandbox environment** - ⚠️ **IMPORTANT: Your bug will be resolved faster if you can share a self-contained example that doesn't rely on internal or private dependencies.** > **🔒 SECURITY WARNING:** Issues without reproduction steps or code examples may be immediately closed as not actionable. Always remember to **REMOVE ALL PII AND PERSONAL INFORMATION** from your examples. **Bugs opened with real data will be immediately reported and closed.** - type: input id: sdk-version attributes: label: 📦 SDK Version description: "Example: 2.1.0" placeholder: "x.y.z" validations: required: true - type: textarea id: environment-details attributes: label: 🖥️ Environment Details description: | System and dependencies information placeholder: | - Operating System: [e.g. Ubuntu 20.04, Windows 11, macOS 13] - Language Version: [e.g. Python 3.9.0, Node.js 18.0.0] - Framework: [e.g. Django 4.0, Express 4.18] - Package Manager: [e.g. pip 21.0, npm 8.0] - Other relevant dependencies: ... validations: required: true - type: dropdown id: country attributes: label: 🌎 Country description: Country where the issue occurs options: - Argentina (MLA) - Brazil (MLB) - Chile (MLC) - Colombia (MCO) - Mexico (MLM) - Peru (MPE) - Uruguay (MLU) - Other validations: required: true - type: textarea id: description attributes: label: 📝 Bug Description description: A clear and concise description of what the bug is placeholder: The SDK fails when I try to... validations: required: true - type: textarea id: expected attributes: label: ✅ Expected Behavior description: A clear description of the behavior you expected from the SDK placeholder: I expected the SDK to... validations: required: true - type: textarea id: actual attributes: label: ❌ Actual Behavior description: A description of what the SDK actually does instead placeholder: Instead, the SDK... validations: required: true - type: textarea id: reproduce attributes: label: 🔄 Steps To Reproduce description: Detailed steps to reproduce the problem placeholder: | 1. Configure the SDK with... 2. Execute the method... 3. Send the following parameters... 4. Observe the error... validations: required: true - type: textarea id: code-sample attributes: label: 💻 Code Example description: | Minimal code that reproduces the problem. **REMOVE ALL CREDENTIALS AND SENSITIVE DATA.** You can provide: - A CodeSandbox (https://codepen.io/pen/) - A link to a GitHub repository - A minimal code example that reproduces the problem - A screenshot of the application if you think it is relevant **Remember to REMOVE ALL SENSITIVE DATA FIRST.** render: python placeholder: | import mercadopago sdk = mercadopago.SDK("YOUR_ACCESS_TOKEN") # ⚠️ DO NOT USE REAL TOKENS # Your code here that reproduces the bug... validations: required: true - type: textarea id: error-logs attributes: label: 📋 Logs and Error Messages description: Copy complete logs, stack traces, or error messages render: shell placeholder: | Error: ... Stack trace: ... - type: checkboxes id: checklist attributes: label: ✅ Checklist options: - label: I have verified that I am using the latest SDK version required: true - label: I have searched existing issues and this bug has not been reported required: true - label: I have included a minimal code example to reproduce the problem required: true - label: I have removed all sensitive information (tokens, credentials, real data) required: true ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: false contact_links: - name: Support Center Mercado Pago - ES url: https://www.mercadopago.com/developers/es/support/center about: Problems with payments, account, or general inquiries - name: Support Center Mercado Pago - PT url: https://www.mercadopago.com/developers/pt/support/center about: Problems with payments, account, or general inquiries ================================================ FILE: .github/ISSUE_TEMPLATE/feature_request.yml ================================================ name: ✨ Feature Request description: Propose a new feature for the Mercado Pago SDK title: "[FEATURE]: " labels: ["enhancement", "needs-triage"] assignees: ["danielalfarourrea","luismeli10","orojaspardo"] body: - type: markdown attributes: value: | ## 💡 Thanks for contributing with ideas! Your feedback is valuable to improve the SDK. Before submitting: - 🔍 **Search [existing issues](./issues?q=is%3Aissue) to avoid duplicates**. - 📚 **Check the [documentation](https://www.mercadopago.com/developers/es/docs) to confirm this isn't already supported**. - type: dropdown id: feature-type attributes: label: ⚙️ Feature Type description: What type of improvement are you proposing? options: - New feature - Enhancement of existing feature - Support for new Mercado Pago product - Better error handling - Documentation improvement - Performance optimization - Other validations: required: true - type: textarea id: problem attributes: label: 🎯 Problem to solve description: Describe the problem or need this feature would solve. placeholder: | As a developer of [application type]... I need [feature]... To be able to [goal]... validations: required: true - type: textarea id: solution attributes: label: 💡 Proposed Solution description: Describe how you would like this new feature to work. placeholder: | I would like the SDK to support... The implementation could be... Usage example: ``` // example code ``` validations: required: true - type: textarea id: alternatives attributes: label: 🔄 Alternatives Considered description: | Have you tried any workarounds? Are there similar features in other SDKs or libraries? placeholder: | - Alternative 1: ... - Alternative 2: ... - In the [language] SDK they do... - type: checkboxes id: checklist attributes: label: ✅ Checklist options: - label: I have searched existing issues and this feature has not been requested before required: true - label: I have clearly described the problem I am trying to solve required: true - label: I have proposed a concrete solution or API design required: true - label: This feature would benefit other users, not just my specific use case required: true - label: I have not included any sensitive information (tokens, credentials, real data) required: true ================================================ FILE: .github/ISSUE_TEMPLATE/question.yml ================================================ name: 💬 Question description: Ask a question about the Mercado Pago SDK title: "[QUESTION]: " labels: ["question", "needs-triage"] assignees: ["danielalfarourrea","luismeli10","orojaspardo"] body: - type: markdown attributes: value: | ## 👋 Thanks for using the Mercado Pago SDK! Before asking your question, please: - 🔍 **Search [existing issues](./issues?q=is%3Aissue) to see if it was already answered** - 📚 **Check the [official documentation](https://www.mercadopago.com/developers/es/docs)** - 💡 **Review the repository examples** - type: input id: sdk-version attributes: label: 📦 SDK Version description: "Example: 2.1.0" placeholder: "x.y.z" validations: required: true - type: dropdown id: country attributes: label: 🌎 Country description: In which country are you operating? options: - Argentina (MLA) - Brazil (MLB) - Chile (MLC) - Colombia (MCO) - Mexico (MLM) - Peru (MPE) - Uruguay (MLU) - Other validations: required: true - type: textarea id: context attributes: label: 🖥️ Environment Details description: | Provide details about your environment to help us understand your setup: - Platform (Web, Mobile, Backend) - Framework used - Relevant error messages - Documentation consulted placeholder: | - Platform: [e.g. Backend, Web, Mobile] - Language Version: [e.g. Python 3.9.0, Node.js 18.0.0] - Framework: [e.g. Django 4.0, Express 4.18] - Other relevant dependencies: ... - type: textarea id: question attributes: label: ❓ Your Question description: Ask your question as clearly and specifically as possible. The more detail you provide, the faster we can help. placeholder: | What are you trying to do? What have you tried so far? What is the result you are getting vs. what you expected? Is there an error message involved? validations: required: true - type: textarea id: code-sample attributes: label: 💻 Code Example (optional) description: If applicable, share a code snippet that illustrates your question. **Remember to remove all sensitive data (tokens, credentials, etc)** render: python placeholder: | import mercadopago sdk = mercadopago.SDK("YOUR_ACCESS_TOKEN") # ⚠️ DO NOT USE REAL TOKENS # Your code here... - type: checkboxes id: checklist attributes: label: ✅ Checklist options: - label: I have searched existing issues required: true - label: I have checked the official documentation required: true - label: I have removed sensitive information (tokens, credentials, etc) required: true ================================================ FILE: .github/workflows/main.yml ================================================ # This workflow will build a Java project with Maven # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven name: Java CI with Maven on: push: branches: [ master, develop ] pull_request: branches: [ master, develop ] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: java-version: '11' distribution: 'temurin' - name: Compile run: mvn compile - name: Run tests run: mvn test env: ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN_V2 }} PUBLIC_KEY: ${{ secrets.PUBLIC_KEY }} # Upload coverage result # - name: Upload Coverage # uses: codecov/codecov-action@v1 # with: # file: ./target/site/jacoco/jacoco.xml ================================================ FILE: .github/workflows/maven-publish-release.yml ================================================ # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path name: Publish package to the Maven Central Repository and GitHub Packages on: release: types: [ released ] jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - uses: actions/checkout@v4 - name: Set up JDK 11 uses: actions/setup-java@v4 with: java-version: '11' distribution: 'temurin' server-id: central server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD gpg-private-key: ${{ secrets.OSSRH_GPG_SECRET_KEY }} gpg-passphrase: MAVEN_GPG_PASSPHRASE - id: publish-to-central name: Publish to Central Repository env: MAVEN_USERNAME: ${{ secrets.CENTRAL_TOKEN_USERNAME }} MAVEN_PASSWORD: ${{ secrets.CENTRAL_TOKEN_PASSWORD }} MAVEN_GPG_PASSPHRASE: ${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} run: | mvn --no-transfer-progress --batch-mode clean deploy ================================================ FILE: .github/workflows/maven-publish-snapshot.yml ================================================ # This workflow will build a package using Maven and then publish it to GitHub packages when a release is created # For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#apache-maven-with-a-settings-path name: Publish SNAPSHOT package on: release: types: [ prereleased ] jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - uses: actions/checkout@v2 - name: Set up JDK 11 uses: actions/setup-java@v2 with: java-version: '11' distribution: 'adopt' server-id: ossrh server-username: MAVEN_USERNAME server-password: MAVEN_PASSWORD - id: install-secret-key name: Install GPG Secret Key run: | cat <(echo -e "${{ secrets.OSSRH_GPG_SECRET_KEY }}") | gpg --batch --import gpg --list-secret-keys --keyid-format LONG - id: publish-to-central name: Publish to Central Repository env: MAVEN_USERNAME: ${{ secrets.OSSRH_USERNAME }} MAVEN_PASSWORD: ${{ secrets.OSSRH_TOKEN }} run: | mvn \ --no-transfer-progress \ --batch-mode \ -Dgpg.passphrase=${{ secrets.OSSRH_GPG_SECRET_KEY_PASSWORD }} \ clean deploy ================================================ FILE: .gitignore ================================================ settings.xml .idea/ .vscode/ out/ *.iml target/ maven-central-deploy.log *.jks *.cer *.pem .DS_Store .classpath .settings .project classes/ ### Gradle ### .gradle gradle/ build.gradle settings.gradle gradlew gradlew.bat # Ignore Gradle GUI config gradle-app.setting # Cache of project .gradletasknamecache ### Gradle Patch ### # Java heap dump *.hprof ### Docs *.html docs/ ================================================ FILE: .pre-commit-config.yaml ================================================ repos: # Websec hook is MANDATORY, DO NOT comment it. - repo: https://github.com/melisource/fury_websec-git-hooks rev: v2.0.0 hooks: - id: pre_commit_hook stages: [commit] - id: post_commit_hook stages: [post-commit] # Datasec hook is MANDATORY, DO NOT comment it. - repo: https://github.com/melisource/fury_datasec-git-hooks rev: 1.2.2 hooks: - id: pre_commit_hook stages: [commit] - id: post_commit_hook stages: [post-commit] ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment of individuals or the company * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct that could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned with this Code of Conduct, as well as temporarily or permanently ban any contributor for other behavior deemed inappropriate, threatening, offensive, or harmful with or without prior notice.. ## Scope This Code of Conduct applies within all project spaces and it also applies when an individual is representing the project or its community in public spaces. Examples of representing a project or community include using an official project email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. This Code of Conduct also applies outside the project spaces when there is a reasonable belief that an individual's behavior may have a negative impact on the project, the company or the community. ## Enforcement Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq ================================================ FILE: CODING_GUIDELINES.md ================================================ # Coding Guidelines The Mercado Pago Java SDK is a collaborative effort from the start. The SDK team thinks that contributions from different developer will enrich its feature set and make it more relevant to the community. However, absorbing all contributions as-is, while expedient, might lead to difficulties in maintenance of the codebase is left unchecked. A collaborative codebase often establish guidelines for contributors to ensure code remains maintainable over time. The effort to maintain the SDK is no different in this regard, so a bit of guidance is in order. The purpose of this guide is to set a baseline for contributions. These guidelines are not intended to limit the tools at your disposal nor to rewire the way you think but rather to encourage good neighbor behavior. ## Language Guidelines We use **english** language. This is to be consistent everywhere, and to be considerate with developers that do not speak our native language. Therefore: source code, comments, documentation, commit messages, review comments, and any other kind of contribution * MUST* use english language. Typos are unavoidable, but try to reduce them by using a spellchecker. Most IDEs can be configured to run one automatically. ## Code Guidelines To contribute to the project you need to have installed in your machine [pre-commit tool](https://pre-commit.com/) to check the code style and formatting. To make pre-commit work you must have installed `Docker` as well. 1. To check if pre-commit is installed, you must run the command below successfully: ``` $ pre-commit --version pre-commit 2.17.0 ``` 2. After pre-commit is installed at your machine, inside the SDK project folder, you must run the command below to set up the git hook scripts of the project: ``` $ pre-commit install ``` After that, git hooks will run automatically before every commit command. Generally speaking, be conscious when contributing and try following the same style that the code in the SDK already has. If you have any doubts, just ask us! This rules will be enforced automatically when making a pull requests, and checks will fail if you do not follow them, resulting in your contribution being automatically rejected until fixed. ## Comment Guidelines Comments in code are a hard thing to write, not because the words are difficult to produce but because it is hard to make relevant comments. Too much of it and people do not read comments (and it obfuscates code reading) and too little of it gives you no recourse but to read large portions of codebase to get insight as to what a feature/codeblock is doing. Both situations are undesirable and efforts should be made at all time to have a please comment reading experience As a general rule you would have to comment on decisions you made while coding that are not part of any specification. In particular, you should always comment any decision that: * Departs from common wisdom or convention (The **why's** are necessary). * Takes a significant amount of time to produce. A good rule of thumb here is that if you spent more than 1 hour thinking on how to produce a fragment of code that took 2 minutes of wrist time to write you should document your thinking to aid reader and allow for validation. * Need to preserve properties of the implementation. This is the case of performance sensitive portions of the codebase, goroutines synchronization, implementations of security primitives, congestion control algorithms, etc. As a general rule of what not to comment you should avoid: * Commenting on structure of programs that is already part of a convention, specified or otherwise. * Having pedantic explanations of behavior that can be found by immediate examination of the surrounding code artifacts. * Commenting on behavior you cannot attest. ### Branching Guidelines Currently `master` is our only long term branch, below a few suggestions of short term branches naming: * `hotfix/something-needs-fix`: Small routine patches in code to feature already there. * `feature/something-new`: A new feature or a change in an existent feature. Beware of breaking changes that would require a major version bump. * `doc/improves-documentation-for-this-feature`: If you add or change documentation with no impact to the source code. ### Git Guidelines All commits **SHOULD** follow the [seven rules of a great Git commit message](https://chris.beams.io/posts/git-commit): 1. Separate subject from body with a blank line. 2. Limit the subject line to 72 characters. 3. Capitalize the subject line. 4. Do not end the subject line with a period. 5. Use the imperative mood in the subject line. 6. Wrap the body at 72 characters. 7. Use the body to explain what and why vs. how. Commits such as "fix tests", "now it's working", and many other common messages we find usually in code **WON'T** be accepted. Ideally we would like to enforce these rules, but we are realistic and understand that it might be a big change for some people. So unless deviating heavily from what was stated we might accept your commits even if not following these rules perfectly. Please avoid taking too much time to deliver code, and always [rebase](https://git-scm.com/docs/git-rebase) your code to avoid reverse merge commits. ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to the Mercado Pago Java SDK Thank you for your interest in contributing to the Mercado Pago Java SDK! ## How to contribute In order to contribute to the Mercado Pago Java SDK effectively we provide guidelines to address common case for contributions. Presently we have guides for the following type of changes. * Request For Change (RFC) / Feature Request: These are suggestions / requests for features the SDK currently does not have. The SDK team evaluates these requests for adequacy / relevance / capacity and overall architectural consistency. * Bug Reports: These are reports of noncompliance behavior with the SDK specification and other blatantly wrong behavior of the Mercado Pago Java SDK. In addition to contributing in the form of Bug Reports and RFCs it is also possible to contribute directly in code with a Pull Request (PR). In the case of a Pull Request you should also indicate the nature of the Pull Request ( Feature/Bug/etc.) to help the team asses the Pull Request. If you are enthusiastic about a particular Feature being added or a bug being fixed, a PR is often the quickest way to promote your change as the team does not have to allocate as many resources to process the contribution. In the case of PRs it is often best to consult with the SDK team before embarking on a PR, specially if it's a beefy one. Spending time on a PR that might later be rejected because major discrepancies with vision or competing contributions is an uncomfortable outcome for all involved people. Remember the SDK team with privilege overall consistency and progress over any one particular contribution. ## Coding Guidance All contributions *MUST* follow the [Coding Guidelines](CODING_GUIDELINES.md). Contributions that fail to follow these guidelines will be disregarded and told to make the required modifications to do so. ## Request For Change / Feature Request Generally speaking an RFC is needed when you want to add a new feature or change an existing one in an incompatible way that might result in a major version bump to the toolkit. Though it seems a little bureaucratic, the process is in place in order to avoid frustration of a potential contributor by making the discussions take place before any code is written. Once the design and direction is fully agreed then the contributor can work peacefully knowing that their change will be committed. As of this moment all you need to do is create an issue and use the [Feature Request Template](.github/ISSUE_TEMPLATE/feature_request.md). Please prepend your issue title with `[RFC]` so that's easier to filter. ## Bug Reports Bugs are a reality in software. We can't fix what we don't know about, so please report liberally. If you're not sure if something is a bug or not, feel free to file it anyway. Before reporting a bug, please search existing issues and pull requests, as it's possible that someone else has already reported your error. In the off case that you find your issue as fixed/closed, please add a reference to it on your new one. Your issue should contain a title and a clear description of the issue. You should also include as much relevant information as possible, and a code sample that demonstrates the issue. The goal of a bug report is to make it easy for yourself - and others - to replicate the bug and develop a fix. Opening an issue is as easy as following [this link](https://github.com/mercadopago/sdk-java/issues/new?assignees=&labels=&template=bug_report.md) and filling out the given template. Bug reports may also be sent in the form of a [pull request](#pull-request) containing a failing test. ## Pull Request First and foremost: Source code, documentation, commit messages, review comments, and any other kind of contribution must *MUST* follow the [Coding Guidelines](CODING_GUIDELINES.md). We use the "fork and pull" model [described here](https://help.github.com/articles/about-collaborative-development-models/), where contributors push changes to their personal fork and create pull requests to bring those changes into the source repository. Your basic steps to get going: * Fork the corresponding toolkit repository and create a branch from master for the issue you are working on. * Commit as you go following our git conventions. * Include tests that cover all non-trivial code. The existing tests should provide a template on how to test the toolkit correctly. * Make sure all test passes. * All code changes are expected to comply with the formatting style. * Push your commits to GitHub and create a pull request against the corresponding toolkit component master branch. If taking too much time to deliver code, **always** [rebase](https://git-scm.com/docs/git-rebase) towards `master` before asking for a review, and avoid reverse merge commits. ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2021 MercadoPago Developers Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: PULL_REQUEST_TEMPLATE.md ================================================ ## Cambios realizados para el feature: * item 1 ## Cambios generales * item 1 ## Issues cerrados * Closes #XX ## Checklist validación PR: - [ ] Título y descripción clara del PR - [ ] Tests de mi funcionalidad - [ ] Documentación de mi funcionalidad - [ ] Tests ejecutados y pasados - [ ] Branch Coverage >= 80% ================================================ FILE: README.md ================================================ # Mercado Pago SDK for Java [![Maven Central](https://img.shields.io/maven-central/v/com.mercadopago/sdk-java.svg)](https://search.maven.org/search?q=g:com.mercadopago%20AND%20a:sdk-java) ![APM](https://img.shields.io/apm/l/vim-mode) The official [Mercado Pago](https://www.mercadopago.com/developers/en/guides) Java client library. ## 💡 Requirements Java 1.8 or later ## 📲 Installation First time using Mercado Pago? Create your [Mercado Pago account](https://www.mercadopago.com), if you don’t have one already. 1. Append MercadoPago dependencies to pom.xml ```xml com.mercadopago sdk-java 3.1.0 ``` 2. Run `mvn install` and that's all, you have Mercado Pago SDK installed. 3. Copy the access_token in the [credentials](https://www.mercadopago.com/developers/panel) section of the page and replace YOUR_ACCESS_TOKEN with it. That's it! Mercado Pago SDK has been successfully installed. ## 🌟 Getting Started Simple usage looks like: ```java import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.order.Order; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class Example { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); OrderClient client = new OrderClient(); OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("10.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("{{CARD_TOKEN}}") .installments(1) .build()) .build(); List payments = new ArrayList<>(); payments.add(payment); OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .totalAmount("10.00") .externalReference("ext_ref") .payer(OrderPayerRequest.builder().email("{{EMAIL}}").build()) .transactions(OrderTransactionRequest.builder() .payments(payments) .build()) .build(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { Order order = client.create(request, requestOptions); System.out.println("Order created: " + order.getId()); } catch (MPApiException | MPException e) { System.out.println("Error creating order: " + e.getMessage()); } } } ``` ### Per-request Configuration All the request methods accept an optional `MPRequestOptions` object. With this you can set a custom access token, custom timeouts or even any custom headers you want, like an idempotency key for example. ```java public class Example { public static void main(String[] args) { OrderClient client = new OrderClient(); Map customHeaders = new HashMap<>(); customHeaders.put("x-idempotency-key", "..."); MPRequestOptions requestOptions = MPRequestOptions.builder() .accessToken("custom_access_token") .connectionRequestTimeout(2000) .connectionTimeout(2000) .socketTimeout(2000) .customHeaders(customHeaders) .build(); OrderCreateRequest createRequest = OrderCreateRequest.builder().build(); try { Order order = client.create(createRequest, requestOptions); System.out.println(order); } catch (MPException | MPApiException ex) { ex.printStackTrace(); } } } ``` ### SDK configurations You can also set some customizations directly at MercadoPagoConfig class, for example set custom timeouts, a custom http client, log configurations, etc... ```java public class Example { public static void main(String[] args) { MercadoPagoConfig.setConnectionRequestTimeout(2000); MercadoPagoConfig.setSocketTimeout(2000); MercadoPagoConfig.setLoggingLevel(Level.FINEST); } } ``` ### Custom Http Client You can use a custom http client instead of using the default `MPDefaultHttpClient` by implementing the `MPHttpClient` interface. ```java public class CustomHttpClient implements MPHttpClient { //... } ``` ## 📚 Documentation See our documentation for more details. - Mercado Pago reference API. [Portuguese](https://www.mercadopago.com/developers/pt/reference) / [English](https://www.mercadopago.com/developers/en/reference) / [Spanish](https://www.mercadopago.com/developers/es/reference) ## 🤝 Contributing All contributions are welcome, ranging from people wanting to triage issues, others wanting to write documentation, to people wanting to contribute code. Please read and follow our [contribution guidelines](CONTRIBUTING.md). Contributions not following these guidelines will be disregarded. The guidelines are in place to make all of our lives easier and make contribution a consistent process for everyone. ### Patches to version 1.x.x Since the release of version 2.0.0, version 1 is deprecated and will not be receiving new features, only bug fixes. If you need to submit PRs for that version, please do so by using `develop-v1` as your base branch. ## ❤️ Support If you require technical support, please contact our support team at our developers site: [English](https://www.mercadopago.com/developers/en/support/center/contact) / [Portuguese](https://www.mercadopago.com/developers/pt/support/center/contact) / [Spanish](https://www.mercadopago.com/developers/es/support/center/contact) ## 🏻 License ``` MIT license. Copyright (c) 2022 - Mercado Pago / Mercado Libre For more information, see the LICENSE file. ``` ================================================ FILE: SUPPORT.md ================================================ # 🆘 Support and Help > **Quick guide:** Have a bug? → [Bug Report](../../issues/new/choose) | Questions? → [Question](../../issues/new/choose) | New idea? → [Feature Request](../../issues/new/choose) --- ## 🎯 Quick Decision Guide | If you need... | Then... | |----------------|---------| | 💬 Question about how to use the SDK | [Create Question](../../issues/new/choose) | | 🐛 Report an error or bug | [Create Bug Report](../../issues/new/choose) | | ✨ Propose new feature | [Create Feature Request](../../issues/new/choose) | | 💳 Problem with your MP account | [Official MP Support - ES ](https://www.mercadopago.com.co/developers/en/support/center)- [Official MP Support - PT ](https://www.mercadopago.com.co/developers/pt/support/center) | --- ## 📚 Before Creating an Issue **Search first, ask later:** 1. **[Official Documentation](https://www.mercadopago.com/developers/es/docs)** - Most questions are answered here 2. **[Closed Issues](../../issues?q=is%3Aissue+is%3Aclosed)** - Your problem may be solved 3. **[Open Issues](../../issues?q=is%3Aissue+is%3Aopen)** - Your problem may be already reported --- ## 💬 How to Report Issues ### 1. For Questions 💬 **When to use?** Doubts about usage, configuration, or best practices. **Steps:** 1. Search in [closed questions](../../issues?q=is%3Aissue+is%3Aclosed+label%3Aquestion) 2. [Create new question](../../issues/new/choose) 3. **Include:** SDK version, country, environment, code example. ### 2. For Bugs 🐛 **When to use?** Errors, unexpected behavior and/or crashes. **Steps:** 1. Verify [latest version](../../releases/latest) 2. Search in [existing bugs](../../issues?q=is%3Aissue+label%3Abug) 3. [Report bug](../../issues/new/choose) 4. **Include:** reproducible steps, logs, environment, SDK version. ### 3. For Features ✨ **When to use?** Propose improvements or new features **Steps:** 1. Search in [feature requests](../../issues?q=is%3Aissue+label%3Afeature%20request) 2. [Propose feature](../../issues/new/choose) 3. **Explain:** problem it solves, use cases, benefit. ### 4. To Contribute 🤝 **Want to help?** Read [CONTRIBUTING.md](./CONTRIBUTING.md) --- ## 🔒 Security ### ⚠️ NEVER Share in Public Issues: - ❌ Access tokens or production credentials - ❌ Client IDs / Client Secrets - ❌ Customer or card data - ❌ Personally Identifiable Information (PII) > **⚠️ IMPORTANT:** Issues with real data will be closed and reported immediately. --- ## 🌎 Official Mercado Pago SDK Support ### ⚡ GitHub Issues Scope **GitHub Issues is ONLY for SDK technical support.** ✅ **Use GitHub for:** - SDK bugs - Questions about SDK usage - SDK features - Code contributions ❌ **DO NOT use GitHub for:** - Problems with your MP account - Specific transactions or payments - Commercial or billing topics - Homologation/certification - Account access or credentials - Webhook configuration in your account ### 🏢 Contact Official MP Support for: [**🔗 Official Mercado Pago Support - ES**](https://www.mercadopago.com.co/developers/es/support/center) [**🔗 Official Mercado Pago Support - PT**](https://www.mercadopago.com.co/developers/pt/support/center) - ✉️ Account problems - 💳 Transactions and payments - 🤝 Commercial topics - 📋 Homologation - 🔐 Account access - 🌐 Webhooks in your account - 📊 Reports and statistics --- ## 🔗 Resources and Contacts ### Documentation - **[Official Documentation](https://www.mercadopago.com/developers/es/docs)** - Complete guides - **[API Reference](https://www.mercadopago.com/developers/en/reference)** - API reference - **[SDKs](https://www.mercadopago.com/developers/en/docs/sdks-library/server-side)** - Other SDKs ### Support - **[GitHub Issues](../../issues/new/choose)** - SDK technical support ### Community channels - **[Discord](https://discord.gg/96nqqpaycN)** - Community channel - **[Newsletter](https://www.mercadopago.com/developers/panel/contact)** - Mercado Pago Newsletter - **[Status Page](https://status.mercadopago.com/)** - Service status --- ## 💡 Tips for Getting Quick Help 1. **🔍 Search first** - Saves everyone time 2. **📝 Be specific** - "Error 400 on POST /payments" vs "It doesn't work" 3. **💻 Reproducible code** - Minimal and complete example 4. **📋 Follow templates** - They're designed to help you 5. **🚫 No sensitive data** - Protect your security 6. **🤝 Be respectful** - We're all part of the community --- 💙 **Thank you for being part of the Mercado Pago developer community!** ================================================ FILE: build-gradle.sh ================================================ #!/bin/sh VERSION="7.6.1" BREW_VERSION=${VERSION:0:1} INSTALL_DIR=gradle CMD=$(which gradle) check_gradle_installed() { echo "Checking if gradle is installed globally..." which gradle > /dev/null 2>&1 return $? } install() { which brew > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "Homebrew detected. Install gradle globally?" echo "[yes/no] default: yes" read brew if [[ "$brew" == "yes" ]] || [[ "$brew" == "" ]]; then echo "brew" install_brew else echo "local" install_locally fi else install_locally fi } install_brew() { echo "Installing version $BREW_VERSION globally with Homebrew..." brew install "gradle@$BREW_VERSION" ln -s /usr/local/opt/gradle@$BREW_VERSION/bin/gradle /usr/local/bin/gradle CMD=$(which gradle) } install_locally() { echo "Installing version $VERSION locally @ ./$INSTALL_DIR/..." ls gradle > /dev/null 2>&1 if [ $? -gt 0 ]; then mkdir gradle fi curl "https://downloads.gradle-dn.com/distributions/gradle-$VERSION-bin.zip" > "gradle/gradle-$VERSION-bin.zip" unzip -d gradle "gradle/gradle-$GRADLE_VERSION-bin.zip" export GRADLE_HOME="gradle/gradle-$VERSION" CMD="$GRADLE_HOME/bin/gradle" } init() { ls settings.gradle > /dev/null 2>&1 if [ $? -gt 0 ]; then echo "Setting up project..." $CMD init <<< "\r\rno\r" fi } build() { which gradle > /dev/null 2>&1 if [ $? -gt 0 ]; then export GRADLE_HOME="gradle/gradle-$VERSION" CMD="$GRADLE_HOME/bin/gradle" fi $CMD build } check_gradle_installed installed=$? if [ $installed -gt 0 ] ; then echo "Gradle not found. Installing..." install fi init build ================================================ FILE: maven-central-deploy.sh ================================================ #!/usr/bin/env bash !/bin/bash # Deploy maven artefact in current directory into Maven central repository # using maven-release-plugin goals read -p "Really deploy to maven central repository (yes/no)? " if ( [ "$REPLY" == "yes" ] ) then ssh-add ~/.ssh/lubos.krnac ssh-add -l mvn release:clean release:prepare release:perform -B -e | tee maven-central-deploy.log ssh-add -D else echo 'Exit without deploy' fi ================================================ FILE: mp_ref_report.md ================================================ # MP API Reference Audit Report — Java SDK _Generado: 2026-04-24_ ## Resumen | Categoria | Cantidad | |-----------|----------| | Total metodos API | 48 | | Con reference URL | 28 (58%) | | Sin reference URL (gaps) | 20 (42%) | | URLs no canonicas (dominio pais) | 16 | | URLs canonicas (.com) | 10 | --- ## URLs no canonicas (dominio por pais) Estas URLs usan dominios por pais (`.com.br`, `.com.ar`) en lugar del canonico `https://www.mercadopago.com/developers/en/reference/...`: | Archivo | URL encontrada | Dominio | |---------|---------------|---------| | PaymentRefundClient.java | `https://www.mercadopago.com.br/developers/en/reference/chargebacks/_payments_id_refunds/post` | .com.br | | PaymentRefundClient.java | `https://www.mercadopago.com.br/developers/en/reference/chargebacks/_payments_id_refunds_refund_id/get` | .com.br | | PaymentRefundClient.java | `https://www.mercadopago.com.br/developers/en/reference/chargebacks/_payments_id_refunds/get` | .com.br | | CustomerClient.java | `https://www.mercadopago.com.br/developers/en/reference/online-payments/checkout-api/customers/search-customer/get` | .com.br | | CustomerCardClient.java | `https://www.mercadopago.com.br/developers/en/reference/cards/_customers_customer_id_cards/get` | .com.br | | IdentificationTypeClient.java | `https://www.mercadopago.com.br/developers/en/reference/identification_types/_identification_types/get` | .com.br | | MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders/post` | .com.br | | MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders_id/get` | .com.br | | MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders_id/put` | .com.br | | MerchantOrderClient.java | `https://www.mercadopago.com.br/developers/en/reference/merchant_orders/_merchant_orders_search/get` | .com.br | | OauthClient.java | `https://www.mercadopago.com.br/developers/en/reference/oauth/_oauth_token/post` | .com.br | | PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences/post` | .com.br | | PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences_id/get` | .com.br | | PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences_id/put` | .com.br | | PreferenceClient.java | `https://www.mercadopago.com.br/developers/en/reference/preferences/_checkout_preferences_search/get` | .com.br | | PaymentMethodClient.java | `https://www.mercadopago.com.br/developers/en/reference/payment_methods/_payment_methods/get` | .com.br | | PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/orders/create-order/post` | .com.ar | | PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/orders/get-order/get` | .com.ar | | PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/orders/cancel-order/post` | .com.ar | | PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/terminals/get-terminals/get` | .com.ar | | PointClient.java | `https://www.mercadopago.com.ar/developers/en/reference/in-person-payments/point/terminals/update-operation-mode/patch` | .com.ar | --- ## Links faltantes (gaps) — 20 metodos sin referencia ### PaymentClient.java (4 gaps de 5 metodos) - [ ] `get(Long id)` — GET /v1/payments/{id} - [ ] `cancel(Long id)` — PUT /v1/payments/{id} (status=cancelled) - [ ] `capture(Long id, BigDecimal amount)` — PUT /v1/payments/{id} (capture=true) - [ ] `search(MPSearchRequest request)` — GET /v1/payments/search ### CustomerCardClient.java (4 gaps de 4 metodos) - [ ] `get(String customerId, String cardId)` — GET /v1/customers/{id}/cards/{cardId} - [ ] `create(String customerId, CustomerCardCreateRequest request)` — POST /v1/customers/{id}/cards - [ ] `delete(String customerId, String cardId)` — DELETE /v1/customers/{id}/cards/{cardId} - [ ] `listAll(String customerId)` — GET /v1/customers/{id}/cards ### CardTokenClient.java (2 gaps de 2 metodos) - [ ] `get(String id)` — GET /v1/card_tokens/{id} - [ ] `create(CardTokenRequest request)` — POST /v1/card_tokens ### OrderClient.java (9 gaps de 10 metodos) - [ ] `get(String id)` — GET /v1/orders/{id} - [ ] `process(String id)` — POST /v1/orders/{id}/process - [ ] `createTransaction(String orderId, OrderTransactionRequest request)` — POST /v1/orders/{id}/transactions - [ ] `updateTransaction(String orderId, String transactionId, OrderPaymentRequest request)` — PUT /v1/orders/{id}/transactions/{transactionId} - [ ] `cancel(String orderId)` — POST /v1/orders/{id}/cancel - [ ] `capture(String orderId)` — POST /v1/orders/{id}/capture - [ ] `deleteTransaction(String orderId, String transactionId)` — DELETE /v1/orders/{id}/transactions/{transactionId} - [ ] `refund(String orderId, OrderRefundRequest request)` — POST /v1/orders/{id}/refund - [ ] `search(MPSearchRequest request)` — GET /v1/orders ### PreapprovalClient.java (4 gaps de 4 metodos) - [ ] `get(String id)` — GET /preapproval/{id} - [ ] `create(PreapprovalCreateRequest request)` — POST /preapproval - [ ] `update(String id, PreapprovalUpdateRequest request)` — PUT /preapproval/{id} - [ ] `search(MPSearchRequest request)` — GET /preapproval/search ### Otros - [ ] `CustomerClient.delete(String customerId)` — DELETE /v1/customers/{id} - [ ] `OauthClient.getAuthorizationURL(...)` — URL builder (no endpoint directo) - [ ] `PointClient.getPaymentIntentStatus(String id)` — GET /point/integration-api/payment-intents/{id}/events - [ ] `UserClient.get()` — GET /users/me --- ## Cobertura por cliente | Cliente | Metodos | Con URL | Sin URL | Cobertura | |---------|---------|---------|---------|-----------| | PaymentClient | 6 | 1 | 5* | 17% | | PaymentRefundClient | 3 | 3 | 0 | 100% | | CustomerClient | 5 | 4 | 1 | 80% | | CustomerCardClient | 4 | 0 | 4 | 0% | | CardTokenClient | 2 | 0 | 2 | 0% | | IdentificationTypeClient | 1 | 1 | 0 | 100% | | MerchantOrderClient | 4 | 4 | 0 | 100% | | OauthClient | 3 | 2 | 1 | 67% | | OrderClient | 10 | 1 | 9 | 10% | | PointClient | 7 | 6 | 1 | 86% | | PreapprovalClient | 4 | 0 | 4 | 0% | | PreferenceClient | 4 | 4 | 0 | 100% | | PaymentMethodClient | 1 | 1 | 0 | 100% | | UserClient | 1 | 0 | 1 | 0% | *PaymentClient: tiene 1 URL a nivel de clase pero solo cubre create() --- ## Lista de revision manual - [ ] PaymentClient.java — 4 metodos sin referencia API - [ ] CustomerCardClient.java — 4 metodos sin referencia API (0% cobertura) - [ ] CardTokenClient.java — 2 metodos sin referencia API (0% cobertura) - [ ] OrderClient.java — 9 metodos sin referencia API (10% cobertura) - [ ] PreapprovalClient.java — 4 metodos sin referencia API (0% cobertura) - [ ] CustomerClient.java — delete() sin referencia API - [ ] OauthClient.java — getAuthorizationURL() sin referencia API - [ ] PointClient.java — getPaymentIntentStatus() sin referencia API - [ ] UserClient.java — get() sin referencia API - [ ] 16 URLs usan dominio por pais (.com.br/.com.ar) en lugar del canonico (.com) ================================================ FILE: pom.xml ================================================ 4.0.0 com.mercadopago sdk-java 3.1.0 jar Mercadopago SDK Mercadopago SDK https://github.com/mercadopago/sdk-java Apache License, Version 2.0 https://www.apache.org/licenses/LICENSE-2.0.txt Mercado Pago mp_sdk@mercadopago.com Mercado Pago https://www.mercadopago.com/developers ${project.artifactId}-${project.version} src/main/java src/test/java org.apache.maven.plugins maven-compiler-plugin 3.8.1 1.8 1.8 maven-clean-plugin 3.1.0 auto-clean initialize clean org.apache.maven.plugins maven-gpg-plugin 3.2.4 sign-artifacts verify sign --pinentry-mode loopback MAVEN_GPG_PASSPHRASE org.apache.maven.plugins maven-surefire-plugin 3.0.0-M5 org.apache.maven.plugins maven-source-plugin 3.3.0 attach-sources jar-no-fork org.apache.maven.plugins maven-javadoc-plugin 3.8.0 1.8 none ${project.build.directory}/delombok ${project.basedir}/docs attach-javadocs jar org.sonatype.central central-publishing-maven-plugin 0.9.0 true central true org.codehaus.mojo cobertura-maven-plugin 2.7 html xml org.jacoco jacoco-maven-plugin 0.8.7 prepare-agent report test report org.projectlombok lombok-maven-plugin 1.18.20.0 ${project.basedir}/src/main/java ${project.build.directory}/delombok false generate-sources delombok https://github.com/mercadopago/sdk-java/tree/master scm:git:git://github.com/mercadopago/sdk-java.git scm:git:ssh://github.com:mercadopago/sdk-java.git HEAD UTF-8 org.apache.httpcomponents httpclient 4.5.14 org.apache.commons commons-collections4 4.4 org.apache.commons commons-compress 1.27.1 org.apache.velocity velocity-engine-core 2.4.1 org.hsqldb hsqldb org.apache.velocity.tools velocity-tools-generic 3.1 commons-collections commons-collections org.apache.commons commons-lang3 3.18.0 org.apache.httpcomponents.client5 httpclient5 5.4.3 com.google.code.gson gson 2.11.0 org.projectlombok lombok 1.18.32 provided org.junit.jupiter junit-jupiter-api 5.8.2 test org.junit.jupiter junit-jupiter-params 5.8.2 test junit junit 4.13.1 test org.mockito mockito-core 5.18.0 test ================================================ FILE: src/main/java/com/mercadopago/MercadoPagoConfig.java ================================================ package com.mercadopago; import com.mercadopago.net.MPDefaultHttpClient; import com.mercadopago.net.MPHttpClient; import java.util.Objects; import java.util.logging.ConsoleHandler; import java.util.logging.Level; import java.util.logging.StreamHandler; import lombok.Getter; import lombok.Setter; import lombok.Synchronized; import org.apache.http.HttpHost; import org.apache.http.client.HttpRequestRetryHandler; /** * Global configuration class for the MercadoPago Java SDK. * *

This class holds all SDK-wide settings such as the OAuth access token, HTTP timeouts, * connection pool limits, proxy configuration, logging behavior, and tracking identifiers. * All fields are static and thread-safe (declared {@code volatile} or synchronized), so a * single configuration applies across the entire application. * *

Per-request overrides (e.g., a different access token or timeout for one call) can be * specified via {@link com.mercadopago.core.MPRequestOptions}; any field left at its * zero/null default in that object will fall back to the values defined here. * *

Usage example: *

{@code
 * MercadoPagoConfig.setAccessToken("APP_USR-...");
 * MercadoPagoConfig.setConnectionTimeout(30000);
 * }
* * @see com.mercadopago.core.MPRequestOptions * @see com.mercadopago.net.MPDefaultHttpClient */ public class MercadoPagoConfig { public static final String CURRENT_VERSION = "3.1.0"; /** Internal MercadoPago product identifier sent in every API request for analytics. */ public static final String PRODUCT_ID = "BC32A7VTRPP001U8NHJ0"; /** * Tracking header value sent with every API request. Encodes the Java runtime version * and SDK version so the MercadoPago platform can identify the client environment. */ public static final String TRACKING_ID = String.format( "platform:%s,type:SDK%s,so;", MercadoPagoConfig.getJavaVersion(), MercadoPagoConfig.CURRENT_VERSION); /** Base URL for all MercadoPago REST API calls. */ public static final String BASE_URL = "https://api.mercadopago.com"; /** Default maximum number of concurrent HTTP connections in the connection pool. Value: 10. */ private static final int DEFAULT_MAX_CONNECTIONS = 10; /** Default timeout in milliseconds for establishing an HTTP connection. Value: 20 000 ms. */ private static final int DEFAULT_CONNECTION_TIMEOUT_MS = 20000; /** Default timeout in milliseconds for obtaining a connection from the pool. Value: 20 000 ms. */ private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT_MS = 20000; /** Default socket (read) timeout in milliseconds for waiting for response data. Value: 20 000 ms. */ private static final int DEFAULT_SOCKET_TIMEOUT_MS = 20000; /** Default scope label used when reporting SDK metrics. Value: {@code "prod"}. */ private static final String DEFAULT_METRICS_SCOPE = "prod"; /** Default logging level for the SDK logger. Value: {@link Level#OFF} (logging disabled). */ private static final Level DEFAULT_LOGGING_LEVEL = Level.OFF; /** OAuth access token used to authenticate API requests when no per-request token is provided. */ @Getter @Setter private static volatile String accessToken; /** Platform identifier header sent with API requests for tracking and analytics. */ @Getter @Setter private static volatile String platformId; /** Corporation identifier header sent with API requests for multi-entity tracking. */ @Getter @Setter private static volatile String corporationId; /** Integrator identifier header sent with API requests to attribute traffic to a specific integrator. */ @Getter @Setter private static volatile String integratorId; /** * Custom {@link StreamHandler} for SDK log output. When {@code null}, a default * {@link ConsoleHandler} is used instead. * * @see #getStreamHandler() */ @Getter @Setter private static volatile StreamHandler loggingHandler; /** Scope label used when reporting SDK metrics. Defaults to {@code "prod"}. */ @Getter @Setter private static volatile String metricsScope = DEFAULT_METRICS_SCOPE; /** * Java {@link Level} controlling the verbosity of SDK log output. Defaults to * {@link Level#OFF} (no logging). */ @Getter @Setter private static volatile Level loggingLevel = DEFAULT_LOGGING_LEVEL; /** Maximum number of concurrent HTTP connections maintained in the connection pool. Defaults to 10. */ @Getter @Setter private static volatile int maxConnections = DEFAULT_MAX_CONNECTIONS; /** Timeout in milliseconds for establishing a new HTTP connection. Defaults to 20 000 ms. */ @Getter @Setter private static volatile int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT_MS; /** Timeout in milliseconds for obtaining a connection from the pool. Defaults to 20 000 ms. */ @Getter @Setter private static volatile int connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT_MS; /** Timeout in milliseconds for waiting for response data on an open socket. Defaults to 20 000 ms. */ @Getter @Setter private static volatile int socketTimeout = DEFAULT_SOCKET_TIMEOUT_MS; /** * HTTP client implementation used for all API calls. Lazily initialized to * {@link MPDefaultHttpClient} on first access via {@link #getHttpClient()}. */ @Setter private static volatile MPHttpClient httpClient; /** * HTTP proxy host through which all API requests are routed. When {@code null}, * requests are made directly without a proxy. */ @Getter(onMethod_ = { @Synchronized }) @Setter(onMethod_ = { @Synchronized }) private static HttpHost proxy; /** * Custom retry handler for HTTP requests. When set, the underlying Apache HTTP client * will delegate retry decisions to this handler instead of using its default strategy. */ @Getter @Setter private static HttpRequestRetryHandler retryHandler; /** * Returns the HTTP client used for API communication, creating a default * {@link MPDefaultHttpClient} instance on first invocation (lazy initialization). * *

The returned client is a singleton shared across all SDK calls. To replace it * with a custom implementation, use {@link #setHttpClient(MPHttpClient)} before making * any API requests. * * @return the current {@link MPHttpClient} instance, never {@code null} * @see MPDefaultHttpClient */ public static synchronized MPHttpClient getHttpClient() { if (Objects.isNull(httpClient)) { httpClient = new MPDefaultHttpClient(); } return httpClient; } /** * Returns the Java runtime version formatted as {@code "major|full"}. * *

For example, on Java 11.0.12+7, this method returns {@code "11|11.0.12+7"}. * The value is used in the {@link #TRACKING_ID} header sent with every API request. * * @return a string in the format {@code "majorVersion|fullVersion"}, or {@code null} * if the {@code java.runtime.version} system property is unavailable */ public static synchronized String getJavaVersion() { String version = System.getProperty("java.runtime.version"); if (Objects.isNull(version)) { return null; } String major = version.replaceAll("^1\\.", ""); int dotIndex = major.indexOf('.'); if (dotIndex != -1) { major = major.substring(0, dotIndex); } return major + "|" + version; } /** * Returns the active {@link StreamHandler} for SDK logging. If a custom handler has been * set via {@link #setLoggingHandler(StreamHandler)}, it is returned; otherwise a new * {@link ConsoleHandler} is created as a fallback. * * @return the configured {@link StreamHandler}, or a default {@link ConsoleHandler} */ public static StreamHandler getStreamHandler() { return Objects.nonNull(loggingHandler) ? loggingHandler : new ConsoleHandler(); } } ================================================ FILE: src/main/java/com/mercadopago/client/MercadoPagoClient.java ================================================ package com.mercadopago.client; import static java.util.Objects.nonNull; import static org.apache.commons.collections4.MapUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.isNotBlank; import com.google.gson.JsonObject; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.Headers; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.net.UrlFormatter; import java.util.HashMap; import java.util.Map; /** * Abstract base client for all MercadoPago API interactions. * *

This class provides the foundation for every specialized API client in the SDK. It handles * HTTP request execution, default and custom header management (including authorization via Bearer * tokens), timeout resolution with a three-level priority (request options, request object, global * config), and automatic idempotency key generation for {@code POST}, {@code PUT}, and * {@code PATCH} requests. * *

Subclasses should use the protected {@code send()}, {@code search()}, and {@code list()} * helper methods to communicate with the MercadoPago REST API. * * @see com.mercadopago.MercadoPagoConfig * @see MPHttpClient * @see MPRequestOptions */ public abstract class MercadoPagoClient { /** Default value for the {@code Accept} HTTP header. */ private static final String ACCEPT_HEADER_VALUE = "application/json"; /** Default value for the {@code Content-Type} HTTP header, including UTF-8 charset. */ private static final String CONTENT_TYPE_HEADER_VALUE = "application/json; charset=UTF-8"; /** Format string used to build the {@code Authorization: Bearer} header value. */ private static final String BEARER = "Bearer %s"; /** Path segment used to detect OAuth token requests and skip the Bearer header. */ private static final String OAUTH_TOKEN = "/oauth/token"; /** HTTP client used to execute every request dispatched by this client instance. */ protected final MPHttpClient httpClient; /** * Default HTTP headers sent with every request. Populated during construction with * {@code Accept}, {@code Content-Type}, {@code User-Agent}, {@code Product-Id}, and * {@code Tracking-Id}. */ protected Map defaultHeaders; /** * Constructs a new {@code MercadoPagoClient} with the given HTTP client. * *

Initialises the default headers map with {@code Accept}, {@code Content-Type}, * {@code User-Agent}, {@code Product-Id}, and {@code Tracking-Id} values taken from * {@link MercadoPagoConfig}. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public MercadoPagoClient(MPHttpClient httpClient) { this.httpClient = httpClient; this.defaultHeaders = new HashMap<>(); defaultHeaders.put(Headers.ACCEPT, ACCEPT_HEADER_VALUE); defaultHeaders.put(Headers.PRODUCT_ID, MercadoPagoConfig.PRODUCT_ID); defaultHeaders.put( Headers.USER_AGENT, String.format("MercadoPago Java SDK/%s", MercadoPagoConfig.CURRENT_VERSION)); defaultHeaders.put(Headers.TRACKING_ID, MercadoPagoConfig.TRACKING_ID); defaultHeaders.put(Headers.CONTENT_TYPE, CONTENT_TYPE_HEADER_VALUE); } /** * Sends an HTTP request using the pre-built {@link MPRequest} object with default configuration. * *

This is a convenience overload that delegates to {@link #send(MPRequest, MPRequestOptions)} * with {@code null} request options, meaning global configuration from * {@link MercadoPagoConfig} is used for timeouts and access tokens. * * @param request the {@link MPRequest} containing URI, HTTP method, payload, and query parameters * @return the {@link MPResponse} with status code, headers, and body returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse send(MPRequest request) throws MPException, MPApiException { return this.send(request, null); } /** * Sends an HTTP request using the pre-built {@link MPRequest} object, applying optional * per-request overrides. * *

This method resolves the final URL (formatting query parameters), selects the access token * (preferring {@code requestOptions} over global config), merges default and custom headers, * and resolves timeouts with a three-level priority: request options > request object > * {@link MercadoPagoConfig} defaults. An idempotency key is automatically generated for * {@code POST}, {@code PUT}, and {@code PATCH} methods unless one is already present. * * @param request the {@link MPRequest} containing URI, HTTP method, payload, and query parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link MPResponse} with status code, headers, and body returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse send(MPRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { String uri = UrlFormatter.format(request.getUri(), request.getQueryParams()); return httpClient.send( MPRequest.builder() .uri(uri) .accessToken(getAccessToken(requestOptions)) .method(request.getMethod()) .headers(addRequestHeaders(request, requestOptions)) .payload(request.getPayload()) .connectionRequestTimeout(addConnectionRequestTimeout(request, requestOptions)) .connectionTimeout(addConnectionTimeout(request, requestOptions)) .socketTimeout(addSocketTimeout(request, requestOptions)) .build()); } /** * Builds and sends an HTTP request from individual components with default configuration. * *

This is a convenience overload that delegates to * {@link #send(String, HttpMethod, JsonObject, Map, MPRequestOptions)} with {@code null} * request options. * * @param path the relative API path (e.g. {@code "/v1/payments"}) * @param method the {@link HttpMethod} to use (GET, POST, PUT, DELETE, PATCH) * @param payload the JSON request body, or {@code null} for body-less requests * @param queryParams a map of query-string parameters, or {@code null} if none * @return the {@link MPResponse} with status code, headers, and body returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse send( String path, HttpMethod method, JsonObject payload, Map queryParams) throws MPException, MPApiException { return this.send(path, method, payload, queryParams, null); } /** * Builds and sends an HTTP request from individual components, applying optional per-request * overrides. * *

Internally constructs an {@link MPRequest} via {@code buildRequest()}, then delegates to * {@link #send(MPRequest)}. This is the most flexible {@code send()} variant and is the * ultimate target of all other convenience overloads. * * @param path the relative API path (e.g. {@code "/v1/payments"}) * @param method the {@link HttpMethod} to use (GET, POST, PUT, DELETE, PATCH) * @param payload the JSON request body, or {@code null} for body-less requests * @param queryParams a map of query-string parameters, or {@code null} if none * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link MPResponse} with status code, headers, and body returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse send( String path, HttpMethod method, JsonObject payload, Map queryParams, MPRequestOptions requestOptions) throws MPException, MPApiException { MPRequest mpRequest = buildRequest(path, method, payload, queryParams, requestOptions); return this.send(mpRequest); } /** * Performs a search request against the given API path using default configuration. * *

Delegates to {@link #search(String, MPSearchRequest, MPRequestOptions)} with {@code null} * request options. * * @param path the relative API path for the search endpoint (e.g. {@code "/v1/payments/search"}) * @param request the {@link MPSearchRequest} containing search/filter/pagination parameters, or * {@code null} for an unfiltered search * @return the {@link MPResponse} with the search results returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse search(String path, MPSearchRequest request) throws MPException, MPApiException { return this.search(path, request, null); } /** * Performs a search request against the given API path, applying optional per-request overrides. * *

Extracts query parameters from the {@link MPSearchRequest} and issues an HTTP {@code GET} * via the underlying {@code send()} method. If {@code searchRequest} is {@code null}, no * query parameters are appended. * * @param path the relative API path for the search endpoint (e.g. {@code "/v1/payments/search"}) * @param searchRequest the {@link MPSearchRequest} containing search/filter/pagination * parameters, or {@code null} for an unfiltered search * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link MPResponse} with the search results returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse search( String path, MPSearchRequest searchRequest, MPRequestOptions requestOptions) throws MPException, MPApiException { Map queryParams = nonNull(searchRequest) ? searchRequest.getParameters() : null; return this.send(path, HttpMethod.GET, null, queryParams, requestOptions); } /** * Performs an HTTP {@code GET} request that returns a list of resources from the given API path. * *

This is a convenience overload that delegates to * {@link #list(String, HttpMethod, JsonObject, Map, MPRequestOptions)} using {@code GET} with * no payload or query parameters. * * @param path the relative API path for the list endpoint * (e.g. {@code "/v1/customers/123/cards"}) * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link MPResponse} containing the list of resources returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse list(String path, MPRequestOptions requestOptions) throws MPException, MPApiException { return this.list(path, HttpMethod.GET, null, null, requestOptions); } /** * Performs an HTTP request that returns a list of resources, with full control over all request * parameters. * *

This method is functionally identical to * {@link #send(String, HttpMethod, JsonObject, Map, MPRequestOptions)} and exists as a * semantic alias to improve readability in subclasses that list resources. * * @param path the relative API path for the list endpoint * @param method the {@link HttpMethod} to use (typically {@code GET}) * @param payload the JSON request body, or {@code null} for body-less requests * @param queryParams a map of query-string parameters, or {@code null} if none * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link MPResponse} containing the list of resources returned by the API * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ protected MPResponse list( String path, HttpMethod method, JsonObject payload, Map queryParams, MPRequestOptions requestOptions) throws MPException, MPApiException { return this.send(path, method, payload, queryParams, requestOptions); } private MPRequest buildRequest( String path, HttpMethod method, JsonObject payload, Map queryParams, MPRequestOptions requestOptions) { return MPRequest.builder() .uri(path) .accessToken(getAccessToken(requestOptions)) .payload(payload) .method(method) .queryParams(queryParams) .headers(addCustomHeaders(path, requestOptions)) .connectionRequestTimeout(addConnectionRequestTimeout(null, requestOptions)) .connectionTimeout(addConnectionTimeout(null, requestOptions)) .socketTimeout(addSocketTimeout(null, requestOptions)) .build(); } private int addSocketTimeout(MPRequest request, MPRequestOptions requestOptions) { if (nonNull(requestOptions) && requestOptions.getSocketTimeout() > 0) { return requestOptions.getSocketTimeout(); } if (nonNull(request) && request.getSocketTimeout() > 0) { return request.getSocketTimeout(); } return MercadoPagoConfig.getSocketTimeout(); } private int addConnectionTimeout(MPRequest request, MPRequestOptions requestOptions) { if (nonNull(requestOptions) && requestOptions.getConnectionTimeout() > 0) { return requestOptions.getConnectionTimeout(); } if (nonNull(request) && request.getConnectionTimeout() > 0) { return request.getConnectionTimeout(); } return MercadoPagoConfig.getConnectionTimeout(); } private int addConnectionRequestTimeout(MPRequest request, MPRequestOptions requestOptions) { if (nonNull(requestOptions) && requestOptions.getConnectionRequestTimeout() > 0) { return requestOptions.getConnectionRequestTimeout(); } if (nonNull(request) && request.getConnectionRequestTimeout() > 0) { return request.getConnectionRequestTimeout(); } return MercadoPagoConfig.getConnectionRequestTimeout(); } private Map addRequestHeaders(MPRequest request, MPRequestOptions requestOptions) { Map headers = nonNull(request.getHeaders()) ? request.getHeaders() : new HashMap<>(); headers.putAll(addDefaultHeaders(request)); if (isNotBlank(MercadoPagoConfig.getCorporationId())) { headers.put(Headers.CORPORATION_ID, MercadoPagoConfig.getCorporationId()); } if (isNotBlank(MercadoPagoConfig.getIntegratorId())) { headers.put(Headers.INTEGRATOR_ID, MercadoPagoConfig.getIntegratorId()); } if (isNotBlank(MercadoPagoConfig.getPlatformId())) { headers.put(Headers.PLATFORM_ID, MercadoPagoConfig.getPlatformId()); } if (nonNull(requestOptions) && isNotEmpty(requestOptions.getCustomHeaders()) ) { for (Map.Entry header : requestOptions.getCustomHeaders().entrySet()) { if (!headers.containsKey(header.getKey()) && !Headers.CONTENT_TYPE.equalsIgnoreCase(header.getKey())) { headers.put(header.getKey().toLowerCase(), header.getValue()); } } } headers.putAll(addCustomHeaders(request.getUri(), requestOptions)); return headers; } private Map addDefaultHeaders(MPRequest request) { Map headers = new HashMap<>(defaultHeaders); if (shouldAddIdempotencyKey(request)) { headers.put(Headers.IDEMPOTENCY_KEY, request.createIdempotencyKey()); } if (nonNull(request) && !request.getUri().contains(OAUTH_TOKEN) && !headers.containsKey(Headers.AUTHORIZATION)) { headers.put(Headers.AUTHORIZATION, String.format(BEARER, chooseAccessToken(request))); } return headers; } private String chooseAccessToken(MPRequest request) { return request.getAccessToken() != null ? request.getAccessToken() : MercadoPagoConfig.getAccessToken(); } private Map addCustomHeaders(String uri, MPRequestOptions requestOptions) { Map headers = new HashMap<>(); if (nonNull(requestOptions) && nonNull(requestOptions.getCustomHeaders())) { for (Map.Entry entry : requestOptions.getCustomHeaders().entrySet()) { headers.put(entry.getKey().toLowerCase(), entry.getValue()); } } if (requestOptions!= null && !uri.contains(OAUTH_TOKEN)) { headers.put(Headers.AUTHORIZATION, String.format(BEARER, getAccessToken(requestOptions))); } return headers; } private boolean shouldAddIdempotencyKey(MPRequest request) { boolean containsIdempotency = false; if (nonNull(request) && nonNull(request.getHeaders())) { containsIdempotency = request.getHeaders().containsKey(Headers.IDEMPOTENCY_KEY.toLowerCase()); } if (containsIdempotency) return false; return request.getMethod() == HttpMethod.POST || request.getMethod() == HttpMethod.PUT || request.getMethod() == HttpMethod.PATCH; } private String getAccessToken(MPRequestOptions requestOptions) { return nonNull(requestOptions) && nonNull(requestOptions.getAccessToken()) && !requestOptions.getAccessToken().isEmpty() ? requestOptions.getAccessToken() : MercadoPagoConfig.getAccessToken(); } } ================================================ FILE: src/main/java/com/mercadopago/client/cardtoken/CardTokenClient.java ================================================ package com.mercadopago.client.cardtoken; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPResponse; import com.mercadopago.resources.CardToken; import com.mercadopago.serialization.Serializer; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Card Tokens API. * *

Provides PCI-compliant card tokenization operations. Tokens represent card data securely * and are used when creating payments or saving cards to a customer profile. * *

Usage example: *

{@code
 * CardTokenClient client = new CardTokenClient();
 * CardToken token = client.create(cardTokenRequest);
 * // Use token.getId() when creating a payment
 * }
* * @see Card Tokens API reference */ public class CardTokenClient extends MercadoPagoClient { /** Class-level logger for card token operations. */ private static final Logger LOGGER = Logger.getLogger(CardTokenClient.class.getName()); /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public CardTokenClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code CardTokenClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public CardTokenClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves a card token by its unique identifier. * * @param id the unique identifier of the card token * @return the requested {@link CardToken} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CardToken get(String id) throws MPException, MPApiException { return this.get(id, null); } /** * Retrieves a card token by its unique identifier with custom request options. * * @param id the unique identifier of the card token * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link CardToken} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CardToken get(String id, MPRequestOptions requestOptions) throws MPException, MPApiException { MPResponse response = send(String.format("/v1/card_tokens/%s", id), HttpMethod.GET, null, null, requestOptions); CardToken cardToken = Serializer.deserializeFromJson(CardToken.class, response.getContent()); cardToken.setResponse(response); return cardToken; } /** * Creates a new card token from card data. * * @param request the {@link CardTokenRequest} with card number, expiration, security code, and * cardholder details * @return the created {@link CardToken} containing the token identifier * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CardToken create(CardTokenRequest request) throws MPException, MPApiException { return this.create(request, null); } /** * Creates a new card token from card data with custom request options. * * @param request the {@link CardTokenRequest} with card number, expiration, security code, and * cardholder details * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link CardToken} containing the token identifier * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CardToken create(CardTokenRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { MPResponse response = send( "/v1/card_tokens", HttpMethod.POST, Serializer.serializeToJson(request), null, requestOptions); CardToken cardToken = Serializer.deserializeFromJson(CardToken.class, response.getContent()); cardToken.setResponse(response); return cardToken; } } ================================================ FILE: src/main/java/com/mercadopago/client/cardtoken/CardTokenRequest.java ================================================ package com.mercadopago.client.cardtoken; import lombok.Builder; import lombok.Getter; /** * Request DTO used to create a card token for secure payment processing. Card tokens allow * sensitive card data to be handled in a PCI-compliant manner by replacing actual card details * with a temporary token that can be used in payment requests. * * @see Card Token API Reference */ @Builder @Getter public class CardTokenRequest { /** Unique identifier of the saved card to be tokenized. */ private final String cardId; /** Unique identifier of the customer who owns the card. */ private final String customerId; /** Security code (CVV/CVC) printed on the card, required for token creation. */ private final String securityCode; } ================================================ FILE: src/main/java/com/mercadopago/client/common/AddressRequest.java ================================================ package com.mercadopago.client.common; import lombok.Getter; import lombok.experimental.SuperBuilder; /** * Request DTO representing a physical address used across multiple Mercado Pago API resources such * as payments, customers, and shipping. Serves as a reusable base for address-related requests. * * @see Mercado Pago API Reference */ @Getter @SuperBuilder public class AddressRequest { /** Postal or ZIP code of the address (e.g., "01310-100"). */ private final String zipCode; /** Name of the street (e.g., "Avenida Paulista"). */ private final String streetName; /** Street number or house number (e.g., "1578"). */ private final String streetNumber; /** Neighborhood or district name. */ private final String neighborhood; /** City name (e.g., "Sao Paulo"). */ private final String city; /** State or province name (e.g., "SP"). */ private final String state; /** Additional address details such as suite or unit number. */ private final String complement; /** Floor number in the building, if applicable. */ private final String floor; } ================================================ FILE: src/main/java/com/mercadopago/client/common/IdentificationRequest.java ================================================ package com.mercadopago.client.common; import lombok.Builder; import lombok.Getter; /** * Request DTO representing a personal identification document used to identify payers, * customers, and cardholders. The type and number vary by country (e.g., CPF in Brazil, * DNI in Argentina, CC in Colombia). * * @see Mercado Pago API Reference */ @Getter @Builder public class IdentificationRequest { /** Type of identification document (e.g., "CPF", "DNI", "CNPJ", "CC"). */ private final String type; /** Identification document number. */ private final String number; } ================================================ FILE: src/main/java/com/mercadopago/client/common/InvoicePeriod.java ================================================ package com.mercadopago.client.common; import lombok.Builder; import lombok.Getter; /** * Request DTO representing the billing period configuration for subscription invoices. Defines * the frequency type and interval at which recurring charges are generated for a subscription plan. * * @see Subscriptions API Reference */ @Getter @Builder public class InvoicePeriod { /** Frequency type of the billing period (e.g., "monthly", "daily"). */ private String type; /** Number of frequency units between each billing cycle (e.g., 1 for every month). */ private Integer period; } ================================================ FILE: src/main/java/com/mercadopago/client/common/PhoneRequest.java ================================================ package com.mercadopago.client.common; import lombok.Builder; import lombok.Getter; /** * Request DTO representing a phone number, split into area code and number. Used across multiple * Mercado Pago API resources such as customers, payers, and shipping contacts. * * @see Mercado Pago API Reference */ @Getter @Builder public class PhoneRequest { /** Telephone area code (e.g., "11" for Sao Paulo, "54" for Argentina). */ private final String areaCode; /** Phone number without the area code. */ private final String number; } ================================================ FILE: src/main/java/com/mercadopago/client/common/SubMerchant.java ================================================ package com.mercadopago.client.common; import lombok.Builder; import lombok.Getter; /** * Request DTO representing sub-merchant information for Payment Facilitator (PF) transactions. * Required by card brands and regulators to identify the actual merchant in payment facilitator * models, including details such as MCC, address, and tax identification. * * @see Mercado Pago API Reference */ @Getter @Builder public class SubMerchant { /** Unique identifier code of the sub-merchant in the facilitator's system. */ private final String subMerchantId; /** Merchant Category Code (MCC) per ABECS standards and/or primary CNAE classification. */ private final String mcc; /** ISO 3166-1 country code where the sub-merchant is located (e.g., "BRA"). */ private final String country; /** Street number of the sub-merchant's address. */ private final Integer addressDoorNumber; /** Postal code (CEP) of the sub-merchant's address. */ private final String zip; /** Tax identification number of the sub-merchant (CPF or CNPJ). */ private final String documentNumber; /** City where the sub-merchant is located. */ private final String city; /** Street name of the sub-merchant's address. */ private final String addressStreet; /** Registered legal name of the sub-merchant. */ private final String legalName; /** ISO code of the state or region where the sub-merchant is located. */ private final String regionCodeIso; /** State or region code of the sub-merchant's address. */ private final String regionCode; /** Type of tax identification document (e.g., "CPF", "CNPJ"). */ private final String documentType; /** Phone number of the sub-merchant. */ private final String phone; /** Website URL of the sub-merchant or payment facilitator. */ private final String url; } ================================================ FILE: src/main/java/com/mercadopago/client/common/SubscriptionSequence.java ================================================ package com.mercadopago.client.common; import lombok.Builder; import lombok.Getter; /** * Request DTO representing the sequence tracking information for a recurring subscription payment. * Indicates the current installment number and the total number of planned installments in the * subscription lifecycle. * * @see Subscriptions API Reference */ @Getter @Builder public class SubscriptionSequence { /** Current sequence number of this payment within the subscription (e.g., 3 of 12). */ private Integer number; /** Total number of planned payments in the subscription series. */ private Integer total; } ================================================ FILE: src/main/java/com/mercadopago/client/customer/CustomerAddressRequest.java ================================================ package com.mercadopago.client.customer; import lombok.Builder; import lombok.Getter; /** * Request DTO representing a customer's default address. Used when creating or updating * a customer to specify their primary address information for shipping or billing purposes. * * @see Customers API Reference */ @Getter @Builder public class CustomerAddressRequest { /** Unique identifier of an existing address to set as default. */ private final String id; /** Postal or ZIP code of the address. */ private final String zipCode; /** Name of the street. */ private final String streetName; /** Street number or house number. */ private final Integer streetNumber; } ================================================ FILE: src/main/java/com/mercadopago/client/customer/CustomerCardClient.java ================================================ package com.mercadopago.client.customer; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import com.google.gson.JsonObject; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResponse; import com.mercadopago.resources.customer.CustomerCard; import com.mercadopago.serialization.Serializer; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Customer Cards API. * *

Provides operations to get, create, delete, and list cards associated with a customer. * Cards are stored securely and can be reused for future payments without requiring the payer * to re-enter card details. * *

This client is typically used internally by {@link CustomerClient}, but can also be * instantiated directly. * * @see CustomerClient * @see * Customer Cards API reference */ public class CustomerCardClient extends MercadoPagoClient { /** Class-level logger for customer card operations. */ private static final Logger LOGGER = Logger.getLogger(CustomerCardClient.class.getName()); /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public CustomerCardClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code CustomerCardClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public CustomerCardClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves a specific card belonging to a customer. * * @param customerId the unique identifier of the customer who owns the card * @param cardId the unique identifier of the card to retrieve * @return the requested {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CustomerCard get(String customerId, String cardId) throws MPException, MPApiException { return this.get(customerId, cardId, null); } /** * Retrieves a specific card belonging to a customer with custom request options. * * @param customerId the unique identifier of the customer who owns the card * @param cardId the unique identifier of the card to retrieve * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CustomerCard get(String customerId, String cardId, MPRequestOptions requestOptions) throws MPException, MPApiException { MPResponse response = send( String.format("/v1/customers/%s/cards/%s", customerId, cardId), HttpMethod.GET, null, null, requestOptions); CustomerCard card = Serializer.deserializeFromJson(CustomerCard.class, response.getContent()); card.setResponse(response); return card; } /** * Creates and associates a new card with a customer. * * @param customerId the unique identifier of the customer * @param request the {@link CustomerCardCreateRequest} with the card token and other details * @return the newly created {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CustomerCard create(String customerId, CustomerCardCreateRequest request) throws MPException, MPApiException { return this.create(customerId, request, null); } /** * Creates and associates a new card with a customer with custom request options. * * @param customerId the unique identifier of the customer * @param request the {@link CustomerCardCreateRequest} with the card token and other details * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the newly created {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CustomerCard create( String customerId, CustomerCardCreateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create customer card request"); JsonObject payload = Serializer.serializeToJson(request); MPRequest mpRequest = MPRequest.buildRequest( String.format("/v1/customers/%s/cards", customerId), HttpMethod.POST, payload, null, requestOptions); MPResponse response = send(mpRequest); CustomerCard card = Serializer.deserializeFromJson(CustomerCard.class, response.getContent()); card.setResponse(response); return card; } /** * Removes a card from a customer. * * @param customerId the unique identifier of the customer * @param cardId the unique identifier of the card to remove * @return the removed {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CustomerCard delete(String customerId, String cardId) throws MPException, MPApiException { return this.delete(customerId, cardId, null); } /** * Removes a card from a customer with custom request options. * * @param customerId the unique identifier of the customer * @param cardId the unique identifier of the card to remove * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the removed {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public CustomerCard delete(String customerId, String cardId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending delete customer card request"); MPResponse response = send( String.format("/v1/customers/%s/cards/%s", customerId, cardId), HttpMethod.DELETE, null, null, requestOptions); CustomerCard card = Serializer.deserializeFromJson(CustomerCard.class, response.getContent()); card.setResponse(response); return card; } /** * Lists all cards belonging to a customer. * * @param customerId the unique identifier of the customer * @return an {@link MPResourceList} of {@link CustomerCard} for the given customer * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResourceList listAll(String customerId) throws MPException, MPApiException { return this.listAll(customerId, null); } /** * Lists all cards belonging to a customer with custom request options. * * @param customerId the unique identifier of the customer * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResourceList} of {@link CustomerCard} for the given customer * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResourceList listAll(String customerId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending list all customer cards request"); MPResponse response = list( String.format("/v1/customers/%s/cards", customerId), HttpMethod.GET, null, null, requestOptions); MPResourceList cards = Serializer.deserializeListFromJson(CustomerCard.class, response.getContent()); cards.setResponse(response); return cards; } } ================================================ FILE: src/main/java/com/mercadopago/client/customer/CustomerCardCreateRequest.java ================================================ package com.mercadopago.client.customer; import com.mercadopago.resources.customer.CustomerCardIssuer; import lombok.Builder; import lombok.Getter; /** * Request DTO used to associate a new card with a customer. The card token is generated on the * frontend using the MercadoPago.js SDK, ensuring that sensitive card data never reaches your * server directly. Once associated, the card can be reused in future payments. * * @see Cards API Reference */ @Getter @Builder public class CustomerCardCreateRequest { /** Temporary card token generated by MercadoPago.js on the frontend. */ private final String token; /** Card issuer information (e.g., issuing bank details). */ private final CustomerCardIssuer issuer; /** Payment method identifier for the card (e.g., "visa", "master", "amex"). */ private final String paymentMethodId; } ================================================ FILE: src/main/java/com/mercadopago/client/customer/CustomerClient.java ================================================ package com.mercadopago.client.customer; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.customer.Customer; import com.mercadopago.resources.customer.CustomerCard; import com.mercadopago.serialization.Serializer; import java.lang.reflect.Type; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Customers API. * *

Provides CRUD operations for customers (create, get, update, delete) and search with * pagination. Card operations (get, create, delete, list) are delegated to an internal * {@link CustomerCardClient} and exposed via convenience methods on this class. * *

Usage example: *

{@code
 * CustomerClient client = new CustomerClient();
 * Customer customer = client.create(customerRequest);
 * MPResourceList cards = client.listCards(customer.getId());
 * }
* * @see CustomerCardClient * @see * Customers API reference */ public class CustomerClient extends MercadoPagoClient { /** Class-level logger for customer operations. */ private static final Logger LOGGER = Logger.getLogger(CustomerClient.class.getName()); /** Internal client used to perform card operations on behalf of this client. */ private final CustomerCardClient cardClient; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public CustomerClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code CustomerClient} with a custom HTTP client. * *

Also initialises the internal {@link CustomerCardClient} with the same HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public CustomerClient(MPHttpClient httpClient) { super(httpClient); cardClient = new CustomerCardClient(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves a customer by its unique identifier. * * @param customerId the unique identifier of the customer * @return the requested {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Customer get(String customerId) throws MPException, MPApiException { return this.get(customerId, null); } /** * Retrieves a customer by its unique identifier with custom request options. * * @param customerId the unique identifier of the customer * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Customer get(String customerId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get customer request"); MPResponse response = send( String.format("/v1/customers/%s", customerId), HttpMethod.GET, null, null, requestOptions); Customer customer = Serializer.deserializeFromJson(Customer.class, response.getContent()); customer.setResponse(response); return customer; } /** * Creates a new customer. * * @param request the {@link CustomerRequest} with customer details (email, identification, etc.) * @return the newly created {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Customer create(CustomerRequest request) throws MPException, MPApiException { return this.create(request, null); } /** * Creates a new customer with custom request options. * * @param request the {@link CustomerRequest} with customer details (email, identification, etc.) * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the newly created {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Customer create(CustomerRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create customer request"); JsonObject payload = Serializer.serializeToJson(request); MPRequest mpRequest = MPRequest.buildRequest("/v1/customers", HttpMethod.POST, payload, null, requestOptions); MPResponse response = send(mpRequest); Customer customer = Serializer.deserializeFromJson(Customer.class, response.getContent()); customer.setResponse(response); return customer; } /** * Updates an existing customer. * * @param customerId the unique identifier of the customer to update * @param request the {@link CustomerRequest} with the updated customer details * @return the updated {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Customer update(String customerId, CustomerRequest request) throws MPException, MPApiException { return this.update(customerId, request, null); } /** * Updates an existing customer with custom request options. * * @param customerId the unique identifier of the customer to update * @param request the {@link CustomerRequest} with the updated customer details * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the updated {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Customer update( String customerId, CustomerRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending update customer request"); JsonObject payload = Serializer.serializeToJson(request); MPRequest mpRequest = MPRequest.buildRequest( String.format("/v1/customers/%s", customerId), HttpMethod.PUT, payload, null, requestOptions); MPResponse response = send(mpRequest); Customer customer = Serializer.deserializeFromJson(Customer.class, response.getContent()); customer.setResponse(response); return customer; } /** * Deletes a customer by its unique identifier. * * @param customerId the unique identifier of the customer to delete * @return the deleted {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Customer delete(String customerId) throws MPException, MPApiException { return this.delete(customerId, null); } /** * Deletes a customer by its unique identifier with custom request options. * * @param customerId the unique identifier of the customer to delete * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the deleted {@link Customer} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Customer delete(String customerId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending delete customer request"); MPRequest mpRequest = MPRequest.buildRequest( String.format("/v1/customers/%s", customerId), HttpMethod.DELETE, null, null, requestOptions); MPResponse response = send(mpRequest); Customer customer = Serializer.deserializeFromJson(Customer.class, response.getContent()); customer.setResponse(response); return customer; } /** * Searches for customers matching the specified criteria. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @return an {@link MPResultsResourcesPage} of {@link Customer} with matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResultsResourcesPage search(MPSearchRequest request) throws MPException, MPApiException { return this.search(request, null); } /** * Searches for customers matching the specified criteria with custom request options. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResultsResourcesPage} of {@link Customer} with matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResultsResourcesPage search( MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending search customer request"); MPResponse response = search("/v1/customers/search", request, requestOptions); Type responseType = new TypeToken>() {}.getType(); MPResultsResourcesPage result = deserializeResultsResourcesPageFromJson(responseType, response.getContent()); result.setResponse(response); return result; } /** * Retrieves a specific card associated with a customer. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @param cardId the unique identifier of the card * @return the requested {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CustomerCard getCard(String customerId, String cardId) throws MPException, MPApiException { return this.getCard(customerId, cardId, null); } /** * Retrieves a specific card associated with a customer with custom request options. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @param cardId the unique identifier of the card * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CustomerCard getCard(String customerId, String cardId, MPRequestOptions requestOptions) throws MPException, MPApiException { return cardClient.get(customerId, cardId, requestOptions); } /** * Associates a new card with a customer. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @param request the {@link CustomerCardCreateRequest} with the card token and other details * @return the newly created {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CustomerCard createCard(String customerId, CustomerCardCreateRequest request) throws MPException, MPApiException { return this.createCard(customerId, request, null); } /** * Associates a new card with a customer with custom request options. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @param request the {@link CustomerCardCreateRequest} with the card token and other details * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the newly created {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CustomerCard createCard( String customerId, CustomerCardCreateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { return cardClient.create(customerId, request, requestOptions); } /** * Removes a card from a customer. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @param cardId the unique identifier of the card to remove * @return the removed {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CustomerCard deleteCard(String customerId, String cardId) throws MPException, MPApiException { return this.deleteCard(customerId, cardId, null); } /** * Removes a card from a customer with custom request options. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @param cardId the unique identifier of the card to remove * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the removed {@link CustomerCard} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CustomerCard deleteCard(String customerId, String cardId, MPRequestOptions requestOptions) throws MPException, MPApiException { return cardClient.delete(customerId, cardId, requestOptions); } /** * Lists all cards associated with a customer. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @return an {@link MPResourceList} of {@link CustomerCard} for the given customer * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList listCards(String customerId) throws MPException, MPApiException { return this.listCards(customerId, null); } /** * Lists all cards associated with a customer with custom request options. * *

Delegates to the internal {@link CustomerCardClient}. * * @param customerId the unique identifier of the customer * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResourceList} of {@link CustomerCard} for the given customer * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList listCards(String customerId, MPRequestOptions requestOptions) throws MPException, MPApiException { return cardClient.listAll(customerId, requestOptions); } } ================================================ FILE: src/main/java/com/mercadopago/client/customer/CustomerRequest.java ================================================ package com.mercadopago.client.customer; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import java.time.OffsetDateTime; import java.util.Map; import lombok.Builder; import lombok.Getter; /** * Request DTO used to create or update a customer in Mercado Pago. Customers can be associated * with saved cards, addresses, and identification documents to streamline recurring payments * and checkout experiences. * * @see Customers API Reference */ @Getter @Builder public class CustomerRequest { /** Customer's email address, used as a unique identifier for the customer. */ private final String email; /** Customer's first name. */ private final String firstName; /** Customer's last name. */ private final String lastName; /** Customer's phone information including area code and number. */ private final PhoneRequest phone; /** Customer's identification document (e.g., CPF, DNI). */ private final IdentificationRequest identification; /** ID of the customer's default address from their address list. */ private final String defaultAddress; /** Customer's address details for registration purposes. */ private final CustomerAddressRequest address; /** ID of the customer's default saved card. */ private final String defaultCard; /** Date when the customer was registered in the merchant's system. */ private final OffsetDateTime dateRegistred; /** Free-text description or notes about the customer. */ private final String description; /** Custom key-value metadata associated with the customer. */ private final Map metadata; } ================================================ FILE: src/main/java/com/mercadopago/client/identificationtype/IdentificationTypeClient.java ================================================ package com.mercadopago.client.identificationtype; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeListFromJson; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResponse; import com.mercadopago.resources.identificationtype.IdentificationType; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Identification Types API. * *

Retrieves the list of identification document types available for the country associated * with the authenticated user's credentials (e.g., CPF for Brazil, DNI for Argentina). * *

Usage example: *

{@code
 * IdentificationTypeClient client = new IdentificationTypeClient();
 * MPResourceList types = client.list();
 * }
* * @see * Identification Types API reference */ public class IdentificationTypeClient extends MercadoPagoClient { /** Class-level logger for identification type operations. */ private static final Logger LOGGER = Logger.getLogger(IdentificationTypeClient.class.getName()); /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public IdentificationTypeClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs an {@code IdentificationTypeClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public IdentificationTypeClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Lists all available identification types for the authenticated user's country. * * @return an {@link MPResourceList} of {@link IdentificationType} (e.g., CPF, DNI, CURP) * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList list() throws MPException, MPApiException { return this.list(null); } /** * Lists all available identification types with custom request options. * * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResourceList} of {@link IdentificationType} (e.g., CPF, DNI, CURP) * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList list(MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending list identification types"); MPResponse response = list("/v1/identification_types", HttpMethod.GET, null, null, requestOptions); MPResourceList identificationTypes = deserializeListFromJson(IdentificationType.class, response.getContent()); identificationTypes.setResponse(response); return identificationTypes; } } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderClient.java ================================================ package com.mercadopago.client.merchantorder; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeElementsResourcesPageFromJson; import static com.mercadopago.serialization.Serializer.deserializeFromJson; import com.google.gson.reflect.TypeToken; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.merchantorder.MerchantOrder; import com.mercadopago.serialization.Serializer; import java.lang.reflect.Type; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Merchant Orders API. * *

Provides operations to create, retrieve, update, and search merchant orders. Merchant orders * group one or more payments and can be associated with preferences, shipments, or external * references. * *

Usage example: *

{@code
 * MerchantOrderClient client = new MerchantOrderClient();
 * MerchantOrder order = client.create(merchantOrderCreateRequest);
 * MerchantOrder retrieved = client.get(order.getId());
 * }
* * @see * Merchant Orders API reference */ public class MerchantOrderClient extends MercadoPagoClient { /** Class-level logger for merchant order operations. */ private static final Logger LOGGER = Logger.getLogger(MerchantOrderClient.class.getName()); /** URL template for single-merchant-order endpoints (e.g. {@code /merchant_orders/{id}}). */ private static final String URL_WITH_ID = "/merchant_orders/%s"; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public MerchantOrderClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code MerchantOrderClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public MerchantOrderClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves a merchant order by its unique identifier. * * @param id the unique identifier of the merchant order * @return the requested {@link MerchantOrder} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MerchantOrder get(Long id) throws MPException, MPApiException { return this.get(id, null); } /** * Retrieves a merchant order by its unique identifier with custom request options. * * @param id the unique identifier of the merchant order * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link MerchantOrder} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MerchantOrder get(Long id, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get merchant order request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(URL_WITH_ID, id.toString())) .method(HttpMethod.GET) .build(); MPResponse response = send(mpRequest, requestOptions); MerchantOrder result = deserializeFromJson(MerchantOrder.class, response.getContent()); result.setResponse(response); return result; } /** * Creates a new merchant order. * * @param request the {@link MerchantOrderCreateRequest} with order details (items, preference * id, etc.) * @return the created {@link MerchantOrder} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MerchantOrder create(MerchantOrderCreateRequest request) throws MPException, MPApiException { return this.create(request, null); } /** * Creates a new merchant order with custom request options. * * @param request the {@link MerchantOrderCreateRequest} with order details (items, preference * id, etc.) * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link MerchantOrder} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MerchantOrder create(MerchantOrderCreateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create merchant order request"); MPRequest mpRequest = MPRequest.builder() .uri("/merchant_orders") .method(HttpMethod.POST) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); MerchantOrder result = deserializeFromJson(MerchantOrder.class, response.getContent()); result.setResponse(response); return result; } /** * Updates an existing merchant order. * * @param id the unique identifier of the merchant order to update * @param request the {@link MerchantOrderUpdateRequest} with the updated attributes * @return the updated {@link MerchantOrder} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MerchantOrder update(Long id, MerchantOrderUpdateRequest request) throws MPException, MPApiException { return this.update(id, request, null); } /** * Updates an existing merchant order with custom request options. * * @param id the unique identifier of the merchant order to update * @param request the {@link MerchantOrderUpdateRequest} with the updated attributes * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the updated {@link MerchantOrder} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MerchantOrder update( Long id, MerchantOrderUpdateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending update merchant order request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(URL_WITH_ID, id.toString())) .method(HttpMethod.PUT) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); MerchantOrder result = deserializeFromJson(MerchantOrder.class, response.getContent()); result.setResponse(response); return result; } /** * Searches for merchant orders matching the specified criteria. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @return an {@link MPElementsResourcesPage} of {@link MerchantOrder} with matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPElementsResourcesPage search(MPSearchRequest request) throws MPException, MPApiException { return this.search(request, null); } /** * Searches for merchant orders matching the specified criteria with custom request options. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPElementsResourcesPage} of {@link MerchantOrder} with matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPElementsResourcesPage search( MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending search merchant order request"); MPResponse response = search("/merchant_orders/search", request, requestOptions); Type responseType = new TypeToken>() {}.getType(); MPElementsResourcesPage result = deserializeElementsResourcesPageFromJson(responseType, response.getContent()); result.setResponse(response); return result; } } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderCreateRequest.java ================================================ package com.mercadopago.client.merchantorder; import java.util.List; import lombok.Builder; import lombok.Getter; /** * Request DTO used to create a new Merchant Order. A merchant order groups one or more payments * for a set of items, enabling the merchant to track fulfillment, shipments, and payment * collection for a complete purchase operation. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderCreateRequest { /** Checkout preference ID that links this order to a payment preference. */ private final String preferenceId; /** Application ID that originated this merchant order. */ private final String applicationId; /** Mercado Libre site ID indicating the country of operation (e.g., "MLA", "MLB"). */ private final String siteId; /** Payer information associated with this order. */ private final MerchantOrderPayerRequest payer; /** Sponsor ID for marketplace or platform integrations. */ private final String sponsorId; /** List of items included in this merchant order. */ private final List items; /** Webhook URL to receive payment and order status notifications. */ private final String notificationUrl; /** Free-text field for additional information about the order. */ private final String additionalInfo; /** External reference ID to correlate this order with the merchant's own system. */ private final String externalReference; /** Marketplace identifier indicating the origin of the payment. */ private final String marketplace; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderItemRequest.java ================================================ package com.mercadopago.client.merchantorder; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request DTO representing an item within a Merchant Order. Each item describes a product or * service being sold, including its price, quantity, and descriptive information. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderItemRequest { /** Unique item code or SKU identifier. */ private final String id; /** Display title or name of the item. */ private final String title; /** Detailed description of the item. */ private final String description; /** URL of the item's image for display purposes. */ private final String pictureUrl; /** Category identifier for the item (e.g., "electronics", "clothing"). */ private final String categoryId; /** Number of units of this item in the order. */ private final int quantity; /** Price per unit of the item. */ private final BigDecimal unitPrice; /** ISO 4217 currency code for the unit price (e.g., "BRL", "ARS", "USD"). */ private final String currencyId; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderPayerRequest.java ================================================ package com.mercadopago.client.merchantorder; import lombok.Builder; import lombok.Getter; /** * Request DTO representing the payer associated with a Merchant Order. Identifies the buyer * who will pay for the items in the order. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderPayerRequest { /** Unique identifier of the payer in Mercado Pago. */ private final Long id; /** Display nickname or username of the payer. */ private final String nickname; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderReceiverAddressCityRequest.java ================================================ package com.mercadopago.client.merchantorder; import lombok.Builder; import lombok.Getter; /** * Request DTO representing city information within a Merchant Order receiver address. Used as * part of the structured address breakdown for shipping destinations. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderReceiverAddressCityRequest { /** Unique identifier of the city. */ private final String id; /** Display name of the city. */ private final String name; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderReceiverAddressCountryRequest.java ================================================ package com.mercadopago.client.merchantorder; import lombok.Builder; import lombok.Getter; /** * Request DTO representing country information within a Merchant Order receiver address. Used as * part of the structured address breakdown for shipping destinations. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderReceiverAddressCountryRequest { /** Unique identifier of the country (e.g., "AR", "BR"). */ private final String id; /** Display name of the country. */ private final String name; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderReceiverAddressRequest.java ================================================ package com.mercadopago.client.merchantorder; import lombok.Builder; import lombok.Getter; /** * Request DTO representing the receiver's shipping address for a Merchant Order shipment. Contains * the full delivery address including geographic coordinates, structured city/state/country * information, and contact details. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderReceiverAddressRequest { /** Unique identifier of the receiver address. */ private final Long id; /** Full address line combining street name and number. */ private final String addressLine; /** Apartment, suite, or unit identifier. */ private final String apartment; /** City information for the delivery address. */ private final MerchantOrderReceiverAddressCityRequest city; /** State or province information for the delivery address. */ private final MerchantOrderReceiverAddressStateRequest state; /** Country information for the delivery address. */ private final MerchantOrderReceiverAddressCountryRequest country; /** Additional delivery instructions or comments for the carrier. */ private final String comment; /** Contact name or reference at the delivery address. */ private final String contact; /** Postal or ZIP code of the delivery address. */ private final String zipCode; /** Street name of the delivery address. */ private final String streetName; /** Street number of the delivery address. */ private final String streetNumber; /** Floor number in the building, if applicable. */ private final String floor; /** Contact phone number at the delivery address. */ private final String phone; /** Geographic latitude coordinate of the delivery address. */ private final String latitude; /** Geographic longitude coordinate of the delivery address. */ private final String longitude; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderReceiverAddressStateRequest.java ================================================ package com.mercadopago.client.merchantorder; import lombok.Builder; import lombok.Getter; /** * Request DTO representing state or province information within a Merchant Order receiver address. * Used as part of the structured address breakdown for shipping destinations. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderReceiverAddressStateRequest { /** Unique identifier of the state or province. */ private final String id; /** Display name of the state or province. */ private final String name; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderShipmentRequest.java ================================================ package com.mercadopago.client.merchantorder; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import lombok.Builder; import lombok.Getter; /** * Request DTO representing a shipment associated with a Merchant Order. Contains all logistics * information including shipping method, status, sender/receiver details, delivery address, * and shipping options. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderShipmentRequest { /** Unique identifier of the shipment. */ private final Long id; /** Type of shipping (e.g., "custom_shipping", "mercado_envios"). */ private final String shippingType; /** Shipping mode indicating the logistics model (e.g., "me1", "me2", "custom"). */ private final String shippingMode; /** Picking type for the shipment (e.g., "seller", "warehouse"). */ private final String pickingType; /** Current status of the shipment (e.g., "pending", "shipped", "delivered"). */ private final String status; /** Detailed sub-status providing additional context about the shipping status. */ private final String shippingSubstatus; /** List of item references included in this shipment, each as a key-value map. */ private final List> items; /** Timestamp when the shipment record was created. */ private final OffsetDateTime dateCreated; /** Timestamp of the last modification to the shipment. */ private final OffsetDateTime lastModified; /** Timestamp when the shipping label was first printed. */ private final OffsetDateTime dateFirstPrinted; /** Identifier of the shipping service or carrier used. */ private final String serviceId; /** Unique identifier of the sender (seller). */ private final Long senderId; /** Unique identifier of the receiver (buyer). */ private final Long receiverId; /** Delivery address where the shipment will be received. */ private final MerchantOrderReceiverAddressRequest receiverAddress; /** Selected shipping option with cost and delivery estimates. */ private final MerchantOrderShippingOptionRequest shippingOption; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderShippingEstimatedDeliveryRequest.java ================================================ package com.mercadopago.client.merchantorder; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Request DTO representing the estimated delivery window for a Merchant Order shipping option. * Provides the expected delivery date along with a time range within that day. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderShippingEstimatedDeliveryRequest { /** Estimated date of delivery. */ private final OffsetDateTime date; /** Start of the estimated delivery time window (e.g., "09:00"). */ private final String timeFrom; /** End of the estimated delivery time window (e.g., "18:00"). */ private final String timeTo; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderShippingOptionRequest.java ================================================ package com.mercadopago.client.merchantorder; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request DTO representing a shipping option for a Merchant Order. Defines the delivery method, * cost, estimated delivery window, and transit speed for shipping the order items. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderShippingOptionRequest { /** Unique identifier of the shipping option. */ private final Long id; /** Net shipping cost charged to the buyer. */ private final BigDecimal cost; /** ISO 4217 currency code for the shipping cost (e.g., "BRL", "ARS"). */ private final String currencyId; /** Estimated delivery date and time window for this shipping option. */ private final MerchantOrderShippingEstimatedDeliveryRequest estimatedDelivery; /** Full list price of shipping before any discounts. */ private final BigDecimal listCost; /** Display name of the shipping option (e.g., "Standard", "Express"). */ private final String name; /** Identifier of the shipping method or carrier service. */ private final Long shippingMethodId; /** Handling and transit speed information for this shipping option. */ private final MerchantOrderShippingSpeedRequest speed; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderShippingSpeedRequest.java ================================================ package com.mercadopago.client.merchantorder; import lombok.Builder; import lombok.Getter; /** * Request DTO representing the shipping speed breakdown for a Merchant Order shipping option. * Separates the total delivery time into handling (preparation) and transit (shipping) durations. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderShippingSpeedRequest { /** Handling time in hours required to prepare the shipment before dispatch. */ private final Long handling; /** Transit time in hours from dispatch to delivery at the destination. */ private final Long shipping; } ================================================ FILE: src/main/java/com/mercadopago/client/merchantorder/MerchantOrderUpdateRequest.java ================================================ package com.mercadopago.client.merchantorder; import java.util.List; import lombok.Builder; import lombok.Getter; /** * Request DTO used to update an existing Merchant Order. Allows modifying order attributes such * as items, shipments, notification settings, and external references after the order has been * created. * * @see Merchant Orders API Reference */ @Getter @Builder public class MerchantOrderUpdateRequest { /** Mercado Libre site ID indicating the country of operation (e.g., "MLA", "MLB"). */ private final String siteId; /** Updated payer information associated with this order. */ private final MerchantOrderPayerRequest payer; /** Sponsor ID for marketplace or platform integrations. */ private final String sponsorId; /** Updated list of items included in this merchant order. */ private final List items; /** List of shipments associated with this merchant order. */ private final List shipments; /** Webhook URL to receive payment and order status notifications. */ private final String notificationUrl; /** Free-text field for additional information about the order. */ private final String additionalInfo; /** External reference ID to correlate this order with the merchant's own system. */ private final String externalReference; /** Marketplace identifier indicating the origin of the payment. */ private final String marketplace; } ================================================ FILE: src/main/java/com/mercadopago/client/oauth/CreateOauthCredentialRequest.java ================================================ package com.mercadopago.client.oauth; import lombok.Builder; import lombok.Getter; /** * Request DTO used to exchange an authorization code for OAuth access and refresh tokens. This * is part of the OAuth 2.0 authorization code flow, which allows your application to act on * behalf of a seller after they grant access through the Mercado Pago authorization URL. * * @see OAuth Guide */ @Getter @Builder public class CreateOauthCredentialRequest { /** * Grant type for the OAuth token request. Fixed as {@code "authorization_code"} for the * authorization code exchange flow. */ private final String grantType = "authorization_code"; /** * Application secret key (client_secret) used to authenticate the token request. Obtained from * the Mercado Pago developer credentials panel. */ private final String clientSecret; /** Application ID (client_id) that uniquely identifies your integration. */ private final String clientId; /** Authorization code received via the redirect URL after the seller grants permission. */ private final String code; /** Redirect URI configured in the application settings, used to validate the token exchange. */ private final String redirectUri; } ================================================ FILE: src/main/java/com/mercadopago/client/oauth/OauthClient.java ================================================ package com.mercadopago.client.oauth; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.client.user.UserClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResponse; import com.mercadopago.net.UrlFormatter; import com.mercadopago.resources.oauth.CreateOauthCredential; import com.mercadopago.resources.oauth.RefreshOauthCredential; import com.mercadopago.resources.user.User; import com.mercadopago.serialization.Serializer; import java.util.HashMap; import java.util.Objects; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago OAuth 2.0 API. * *

Provides operations for the OAuth authorization flow used in marketplace and platform * integrations: generating authorization URLs, creating credentials from authorization codes, * and refreshing expired tokens. * *

Usage example: *

{@code
 * OauthClient client = new OauthClient();
 * String authUrl = client.getAuthorizationURL(appId, redirectUri);
 * // After user authorizes, exchange the code for credentials:
 * CreateOauthCredential credential = client.createCredential(authorizationCode, redirectUri);
 * }
* * @see * OAuth API reference */ public class OauthClient extends MercadoPagoClient { /** Class-level logger for OAuth operations. */ private static final Logger LOGGER = Logger.getLogger(OauthClient.class.getName()); /** Internal client used to retrieve user information for building authorization URLs. */ private final UserClient userClient; /** Base host for MercadoPago OAuth authorization endpoints. */ private final String authHost = "https://auth.mercadopago.com"; /** Relative path for the OAuth token endpoint. */ private final String path = "/oauth/token"; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public OauthClient() { this(MercadoPagoConfig.getHttpClient()); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Constructs an {@code OauthClient} with a custom HTTP client. * *

Also initialises the internal {@link UserClient} with the same HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public OauthClient(MPHttpClient httpClient) { super(httpClient); userClient = new UserClient(httpClient); } /** * Builds the OAuth authorization URL that the seller must visit to grant access. * *

Internally fetches the authenticated user's country to construct the correct * country-specific authorization host. * * @param appId the application ID (client_id) registered in MercadoPago * @param redirectUri the URL to which the user is redirected after authorizing * @return the full authorization URL, or {@code null} if the user's country cannot be determined * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public String getAuthorizationURL(String appId, String redirectUri) throws MPException, MPApiException { return this.getAuthorizationURL(appId, redirectUri, null); } /** * Builds the OAuth authorization URL with custom request options. * *

Internally fetches the authenticated user's country to construct the correct * country-specific authorization host. * * @param appId the application ID (client_id) registered in MercadoPago * @param redirectUri the URL to which the user is redirected after authorizing * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the full authorization URL, or {@code null} if the user's country cannot be determined * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public String getAuthorizationURL( String appId, String redirectUri, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get oauth authorization url request"); User user = userClient.get(requestOptions); if (Objects.isNull(user) || user.getCountryId().isEmpty()) { return null; } HashMap queryParams = new HashMap<>(); queryParams.put("client_id", appId); queryParams.put("response_type", "code"); queryParams.put("platform_id", "mp"); queryParams.put("redirect_uri", redirectUri); return UrlFormatter.format( String.format("%s.%s/authorization", authHost, user.getCountryId().toLowerCase()), queryParams); } /** * Creates OAuth credentials by exchanging an authorization code for access and refresh tokens. * *

Used in the marketplace authorization flow to operate on behalf of a seller. See the * OAuth guide * for more details. * * @param authorizationCode the authorization code received after the seller grants access via the * authorization URL * @param redirectUri the same redirect URI used when generating the authorization URL * @return the {@link CreateOauthCredential} containing access token, refresh token, and * expiration * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CreateOauthCredential createCredential(String authorizationCode, String redirectUri) throws MPException, MPApiException { return this.createCredential(authorizationCode, redirectUri, null); } /** * Creates OAuth credentials with custom request options by exchanging an authorization code. * *

Used in the marketplace authorization flow to operate on behalf of a seller. See the * OAuth guide * for more details. * * @param authorizationCode the authorization code received after the seller grants access via the * authorization URL * @param redirectUri the same redirect URI used when generating the authorization URL * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link CreateOauthCredential} containing access token, refresh token, and * expiration * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public CreateOauthCredential createCredential( String authorizationCode, String redirectUri, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create oauth credential request"); CreateOauthCredentialRequest request = CreateOauthCredentialRequest.builder() .clientSecret(getAccessToken(requestOptions)) .code(authorizationCode) .redirectUri(redirectUri) .build(); MPRequest mpRequest = MPRequest.buildRequest( path, HttpMethod.POST, Serializer.serializeToJson(request), null, requestOptions); MPResponse response = send(mpRequest); CreateOauthCredential credential = Serializer.deserializeFromJson(CreateOauthCredential.class, response.getContent()); credential.setResponse(response); return credential; } /** * Refreshes OAuth credentials using a previously obtained refresh token. * * @param refreshToken the refresh token received during credential creation * @return a new {@link RefreshOauthCredential} containing a fresh access token and refresh token * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public RefreshOauthCredential refreshCredential(String refreshToken) throws MPException, MPApiException { return this.refreshCredential(refreshToken, null); } /** * Refreshes OAuth credentials with custom request options. * * @param refreshToken the refresh token received during credential creation * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return a new {@link RefreshOauthCredential} containing a fresh access token and refresh token * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public RefreshOauthCredential refreshCredential( String refreshToken, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending refresh oauth credential request"); RefreshOauthCredentialRequest request = RefreshOauthCredentialRequest.builder() .clientSecret(getAccessToken(requestOptions)) .refreshToken(refreshToken) .build(); MPRequest mpRequest = MPRequest.buildRequest( path, HttpMethod.POST, Serializer.serializeToJson(request), null, requestOptions); MPResponse response = send(mpRequest); RefreshOauthCredential credential = Serializer.deserializeFromJson(RefreshOauthCredential.class, response.getContent()); credential.setResponse(response); return credential; } private String getAccessToken(MPRequestOptions requestOptions) { return Objects.isNull(requestOptions) ? MercadoPagoConfig.getAccessToken() : requestOptions.getAccessToken(); } } ================================================ FILE: src/main/java/com/mercadopago/client/oauth/RefreshOauthCredentialRequest.java ================================================ package com.mercadopago.client.oauth; import lombok.Builder; import lombok.Getter; /** * Request DTO used to refresh an expired OAuth access token using a previously obtained refresh * token. This avoids requiring the seller to re-authorize the application and ensures * uninterrupted API access. * * @see OAuth Guide */ @Getter @Builder public class RefreshOauthCredentialRequest { /** * Grant type for the OAuth token request. Fixed as {@code "refresh_token"} for the token * refresh flow. */ private final String grantType = "refresh_token"; /** * Application secret key (client_secret) used to authenticate the refresh request. Obtained * from the Mercado Pago developer credentials panel. */ private final String clientSecret; /** * Application ID (client_id) that uniquely identifies your integration in Mercado Pago. */ private final String clientId; /** Refresh token obtained from the initial OAuth authorization code exchange. */ private final String refreshToken; } ================================================ FILE: src/main/java/com/mercadopago/client/order/AdditionalInfoRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Request object containing supplementary information for an order. Provides extra context * about the payer, shipment, platform, and travel details to improve fraud prevention * and payment approval rates. */ @Getter @Builder public class AdditionalInfoRequest { /** Additional payer details such as authentication type and registration date. */ private final PayerInfo payer; /** Additional shipment details such as express shipping and local pickup flags. */ private final ShipmentInfo shipment; /** Platform-level information including seller data and shipment tracking. */ private final PlatformInfo platform; /** Travel-related information including passenger and route details. */ private final TravelInfo travel; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderAutomaticPaymentsRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object for configuring automatic recurring payments within an order. Defines the * payment profile, retry policy, and scheduling dates for automated charge processing. */ @Getter @Builder public class OrderAutomaticPaymentsRequest { /** Identifier of the payment profile used for automatic charges. */ private String paymentProfileId; /** Number of retry attempts if the automatic payment fails. */ private Integer retries; /** Scheduled date for the automatic payment, in ISO 8601 format. */ private String scheduleDate; /** Due date for the payment, in ISO 8601 format. */ private String dueDate; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderClient.java ================================================ package com.mercadopago.client.order; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeFromJson; import com.google.gson.JsonObject; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.order.Order; import com.mercadopago.resources.order.OrderSearchResponse; import com.mercadopago.resources.order.OrderTransaction; import com.mercadopago.resources.order.UpdateOrderTransaction; import com.mercadopago.serialization.Serializer; import java.util.logging.Logger; import java.util.logging.StreamHandler; import org.apache.commons.lang3.StringUtils; /** * Client for the MercadoPago Orders API (v1). * *

Provides the full order lifecycle: creation, retrieval, processing, cancellation, capture, * and refund. Also supports transaction management (create, update, delete) and order search with * pagination. * *

Usage example: *

{@code
 * OrderClient client = new OrderClient();
 * Order order = client.create(orderCreateRequest);
 * Order processed = client.process(order.getId());
 * }
* * @see Orders API * reference */ public class OrderClient extends MercadoPagoClient { /** Class-level logger for order operations. */ private static final Logger LOGGER = Logger.getLogger(OrderClient.class.getName()); /** URL template for single-order endpoints (e.g. {@code /v1/orders/{id}}). */ private static final String URL_WITH_ID = "/v1/orders/%s"; /** URL template for the order processing endpoint. */ private static final String URL_PROCESS = URL_WITH_ID + "/process"; /** URL template for creating transactions within an order. */ private static final String URL_TRANSACTION = URL_WITH_ID + "/transactions"; /** URL template for the order cancellation endpoint. */ private static final String URL_CANCEL = URL_WITH_ID + "/cancel"; /** URL template for the order capture endpoint. */ private static final String URL_CAPTURE = URL_WITH_ID + "/capture"; /** URL template for the order refund endpoint. */ private static final String URL_REFUND = URL_WITH_ID + "/refund"; /** URL template for a specific transaction within an order. */ private static final String URL_TRANSACTION_WITH_ID = URL_WITH_ID + "/transactions/%s"; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public OrderClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs an {@code OrderClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public OrderClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Creates a new order. * * @param request the {@link OrderCreateRequest} with the order details (items, payer, etc.) * @return the created {@link Order} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order create(OrderCreateRequest request) throws MPException, MPApiException { return this.create(request, null); } /** * Creates a new order with custom request options. * * @param request the {@link OrderCreateRequest} with the order details (items, payer, etc.) * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link Order} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order create(OrderCreateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order creation request"); MPRequest mpRequest = MPRequest.builder() .uri("/v1/orders") .method(HttpMethod.POST) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); Order result = deserializeFromJson(Order.class, response.getContent()); result.setResponse(response); return result; } /** * Retrieves an order by its unique identifier. * * @param id the unique identifier of the order * @return the requested {@link Order} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order get(String id) throws MPException, MPApiException { return this.get(id, null); } /** * Retrieves an order by its unique identifier with custom request options. * * @param id the unique identifier of the order * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link Order} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @throws IllegalArgumentException if {@code id} is blank or {@code null} */ public Order get(String id, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order get request"); validateOrderID(id); String url = String.format(URL_WITH_ID, id); MPResponse response = send(url, HttpMethod.GET, null, null, requestOptions); Order result = deserializeFromJson(Order.class, response.getContent()); result.setResponse(response); return result; } /** * Processes an order, triggering payment execution for its transactions. * * @param id the unique identifier of the order to process * @return the processed {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order process(String id) throws MPException, MPApiException { return this.process(id, null); } /** * Processes an order with custom request options, triggering payment execution for its * transactions. * * @param id the unique identifier of the order to process * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the processed {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @throws IllegalArgumentException if {@code id} is blank or {@code null} */ public Order process(String id, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order process request"); validateOrderID(id); String url = String.format(URL_PROCESS, id); MPResponse response = send(url, HttpMethod.POST, null, null, requestOptions); Order result = deserializeFromJson(Order.class, response.getContent()); result.setResponse(response); return result; } /** * Creates a new transaction (payment) within an existing order. * * @param orderId the unique identifier of the order * @param request the {@link OrderTransactionRequest} containing transaction/payment details * @return the created {@link OrderTransaction} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public OrderTransaction createTransaction(String orderId, OrderTransactionRequest request) throws MPException, MPApiException { return this.createTransaction(orderId, request, null); } /** * Creates a new transaction (payment) within an existing order with custom request options. * * @param orderId the unique identifier of the order * @param request the {@link OrderTransactionRequest} containing transaction/payment details * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link OrderTransaction} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public OrderTransaction createTransaction( String orderId, OrderTransactionRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order transaction intent request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(URL_TRANSACTION, orderId)) .method(HttpMethod.POST) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); OrderTransaction result = deserializeFromJson(OrderTransaction.class, response.getContent()); result.setResponse(response); return result; } /** * Updates an existing transaction within an order. * * @param orderId the unique identifier of the order * @param transactionId the unique identifier of the transaction to update * @param request the {@link OrderPaymentRequest} containing the updated transaction details * @return the updated {@link UpdateOrderTransaction} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public UpdateOrderTransaction updateTransaction( String orderId, String transactionId, OrderPaymentRequest request) throws MPException, MPApiException { return this.updateTransaction(orderId, transactionId, request, null); } /** * Updates an existing transaction within an order with custom request options. * * @param orderId the unique identifier of the order * @param transactionId the unique identifier of the transaction to update * @param request the {@link OrderPaymentRequest} containing the updated transaction details * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the updated {@link UpdateOrderTransaction} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @throws IllegalArgumentException if {@code orderId} or {@code transactionId} is blank or * {@code null} */ public UpdateOrderTransaction updateTransaction( String orderId, String transactionId, OrderPaymentRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order transaction update request"); validateOrderID(orderId); validateTransactionID(transactionId); MPRequest mpRequest = MPRequest.builder() .uri(String.format(URL_TRANSACTION_WITH_ID, orderId, transactionId)) .method(HttpMethod.PUT) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); UpdateOrderTransaction result = deserializeFromJson(UpdateOrderTransaction.class, response.getContent()); result.setResponse(response); return result; } /** * Cancels an order by its unique identifier. * * @param orderId the unique identifier of the order to cancel * @return the cancelled {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order cancel(String orderId) throws MPException, MPApiException { return this.cancel(orderId, null); } /** * Cancels an order by its unique identifier with custom request options. * * @param orderId the unique identifier of the order to cancel * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the cancelled {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @throws IllegalArgumentException if {@code orderId} is blank or {@code null} */ public Order cancel(String orderId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order to delete"); validateOrderID(orderId); String url = String.format(URL_CANCEL, orderId); MPResponse response = send(url, HttpMethod.POST, null, null, requestOptions); Order result = deserializeFromJson(Order.class, response.getContent()); result.setResponse(response); return result; } /** * Captures a previously authorized order, settling its payments. * * @param orderId the unique identifier of the order to capture * @return the captured {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order capture(String orderId) throws MPException, MPApiException { return this.capture(orderId, null); } /** * Captures a previously authorized order with custom request options, settling its payments. * * @param orderId the unique identifier of the order to capture * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the captured {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @throws IllegalArgumentException if {@code orderId} is blank or {@code null} */ public Order capture(String orderId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order to capture"); validateOrderID(orderId); String url = String.format(URL_CAPTURE, orderId); MPResponse response = send(url, HttpMethod.POST, null, null, requestOptions); Order result = deserializeFromJson(Order.class, response.getContent()); result.setResponse(response); return result; } /** * Deletes a transaction from an order. * * @param orderId the unique identifier of the order * @param transactionId the unique identifier of the transaction to delete * @return an {@link OrderTransaction} whose response holds the API result * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public OrderTransaction deleteTransaction(String orderId, String transactionId) throws MPException, MPApiException { return this.deleteTransaction(orderId, transactionId, null); } /** * Deletes a transaction from an order with custom request options. * * @param orderId the unique identifier of the order * @param transactionId the unique identifier of the transaction to delete * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link OrderTransaction} whose response holds the API result * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @throws IllegalArgumentException if {@code orderId} or {@code transactionId} is blank or * {@code null} */ public OrderTransaction deleteTransaction( String orderId, String transactionId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order transaction delete request"); validateOrderID(orderId); validateTransactionID(transactionId); String url = String.format(URL_TRANSACTION_WITH_ID, orderId, transactionId); MPResponse response = send(url, HttpMethod.DELETE, null, null, requestOptions); OrderTransaction result = new OrderTransaction(); result.setResponse(response); return result; } /** * Creates a total refund for an order, refunding all transactions. * * @param orderId the unique identifier of the order to refund * @return the refunded {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order refund(String orderId) throws MPException, MPApiException { return this.refund(orderId, null, null); } /** * Creates a total refund for an order with custom request options. * * @param orderId the unique identifier of the order to refund * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the refunded {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order refund(String orderId, MPRequestOptions requestOptions) throws MPException, MPApiException { return this.refund(orderId, null, requestOptions); } /** * Creates a partial refund for an order. * * @param orderId the unique identifier of the order to partially refund * @param request the {@link OrderRefundRequest} containing the refund amount and details * @return the refunded {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Order refund(String orderId, OrderRefundRequest request) throws MPException, MPApiException { return this.refund(orderId, request, null); } /** * Creates a partial or total refund for an order with custom request options. * *

If {@code request} is {@code null}, a total refund is performed. Otherwise the refund * amount and transaction details are taken from the provided {@link OrderRefundRequest}. * * @param orderId the unique identifier of the order to refund * @param request the {@link OrderRefundRequest} containing refund details, or {@code null} for a * total refund * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the refunded {@link Order} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @throws IllegalArgumentException if {@code orderId} is blank or {@code null} */ public Order refund(String orderId, OrderRefundRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order refund request"); validateOrderID(orderId); JsonObject payload = request != null ? Serializer.serializeToJson(request) : null; MPRequest mpRequest = MPRequest.builder() .uri(String.format(URL_REFUND, orderId)) .method(HttpMethod.POST) .payload(payload) .build(); MPResponse response = send(mpRequest, requestOptions); Order result = deserializeFromJson(Order.class, response.getContent()); result.setResponse(response); return result; } /** * Searches for orders matching the specified criteria. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @return an {@link OrderSearchResponse} with the matching orders and pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public OrderSearchResponse search(MPSearchRequest request) throws MPException, MPApiException { return this.search(request, null); } /** * Searches for orders matching the specified criteria with custom request options. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link OrderSearchResponse} with the matching orders and pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public OrderSearchResponse search(MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending order search request"); MPResponse response = search("/v1/orders", request, requestOptions); OrderSearchResponse result = deserializeFromJson(OrderSearchResponse.class, response.getContent()); result.setResponse(response); return result; } /** * Validates that the given order ID is not blank or {@code null}. * * @param id the order identifier to validate * @throws IllegalArgumentException if {@code id} is blank or {@code null} */ void validateOrderID(String id) { if (StringUtils.isBlank(id)) { throw new IllegalArgumentException("Order id cannot be null or empty"); } } /** * Validates that the given transaction ID is not blank or {@code null}. * * @param id the transaction identifier to validate * @throws IllegalArgumentException if {@code id} is blank or {@code null} */ void validateTransactionID(String id) { if (StringUtils.isBlank(id)) { throw new IllegalArgumentException("Transaction id cannot be null or empty"); } } } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderConfigRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object for configuring an order's behavior. Groups payment method restrictions, * online checkout settings (URLs, 3DS, differential pricing), and Point-of-Sale terminal options. */ @Getter @Builder public class OrderConfigRequest { /** Payment method configuration including allowed types, installment limits, and defaults. */ private OrderPaymentMethodConfig paymentMethod; /** Online checkout configuration with callback URLs and security settings. */ private OrderOnlineConfig online; /** Point-of-Sale terminal configuration for in-person payments. */ private OrderPointConfig point; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderCreateRequest.java ================================================ package com.mercadopago.client.order; import com.mercadopago.net.MPResource; import lombok.Builder; import lombok.Getter; import java.util.List; import java.util.Map; // API version: acd67b14-97c4-4a4a-840d-0a018c09654f /** * Request object for creating a new order in the MercadoPago Orders API. Contains all the * information needed to create an order, including payer details, transaction data, items, * shipping, and configuration options. * * @see Orders API */ @Builder @Getter public class OrderCreateRequest extends MPResource { /** Type of the order (e.g. "online", "point"). */ private String type; /** External reference that can be synchronized with your own payment system. */ private String externalReference; /** Transaction information associated with this order, including payments. */ private OrderTransactionRequest transactions; /** Payer information for the order. */ private OrderPayerRequest payer; /** Total amount of the order as a decimal string. */ private String totalAmount; /** Capture mode for the payment (e.g. "automatic", "manual"). */ private String captureMode; /** Processing mode that defines how the payment is processed (e.g. "aggregator", "gateway"). */ private String processingMode; /** Short description of the order. */ private String description; /** Origin of the payment, used in marketplace scenarios. */ private String marketplace; /** Fee collected by a marketplace or MercadoPago application as a decimal string. */ private String marketplaceFee; /** List of items included in the order. */ private List items; /** Configuration options for the order (payment methods, online/point settings). */ private OrderConfigRequest config; /** ISO 8601 date-time when the checkout becomes available. */ private String checkoutAvailableAt; /** ISO 8601 duration or date-time indicating when the order expires. */ private String expirationTime; /** Currency code of the order (e.g. "COP" for Colombia, required for PSE). */ private String currency; /** Additional information about the order such as payer, shipment, platform, and travel data. */ private AdditionalInfoRequest additionalInfo; /** Shipment details for the order, including receiver address and package dimensions. */ private OrderShipmentRequest shipment; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderDifferentialPricing.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Request object for differential pricing configuration in an order. Allows the seller to * offer different payment conditions (e.g. installment plans, discounts) to specific buyer * segments by referencing a pre-configured differential pricing ID. */ @Getter @Builder public class OrderDifferentialPricing { /** Identifier of the differential pricing configuration to apply. */ private Integer id; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderInvoicePeriodRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object representing the invoice period for a subscription payment. Defines the * billing cycle type and duration used to describe the interval covered by each invoice. */ @Getter @Builder public class OrderInvoicePeriodRequest { /** Type of the billing period (e.g. "daily", "monthly", "yearly"). */ private String type; /** Number of periods (e.g. 1 for monthly, 3 for quarterly). */ private Integer period; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderItemRequest.java ================================================ package com.mercadopago.client.order; import lombok.Getter; // API version: acd67b14-97c4-4a4a-840d-0a018c09654f /** * Request object representing an item being purchased within an order. Contains product details * such as title, price, quantity, and optional metadata like category, picture, and warranty. */ @Getter public class OrderItemRequest { /** Display title of the item. */ private String title; /** Unit price of the item as a decimal string. */ private String unitPrice; /** Quantity of this item being purchased. */ private Integer quantity; /** External code used to identify the item in the integrator's system. */ private String externalCode; /** Category identifier for the item. */ private String categoryId; /** Type classification of the item. */ private String type; /** Detailed description of the item. */ private String description; /** URL of the item's picture. */ private String pictureUrl; /** Whether the item includes a warranty. */ private Boolean warranty; /** Date of the event associated with this item, if applicable. */ private String eventDate; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderOnlineConfig.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Configuration for online checkout behavior within an order. Defines redirect URLs for * different payment outcomes, differential pricing rules, and 3D Secure authentication settings. */ @Getter @Builder public class OrderOnlineConfig { /** URL called by MercadoPago to notify the integrator of payment status changes. */ private String callbackUrl; /** URL where the buyer is redirected after a successful payment. */ private String successUrl; /** URL where the buyer is redirected when the payment is pending. */ private String pendingUrl; /** URL where the buyer is redirected when the payment fails. */ private String failureUrl; /** URL for automatic return after payment completion. */ private String autoReturnUrl; /** Differential pricing configuration for offering different conditions to specific buyers. */ private OrderDifferentialPricing differentialPricing; /** Transaction security configuration for 3D Secure (3DS) authentication. */ private OrderTransactionSecurity transactionSecurity; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderPayerAddressRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: acd67b14-97c4-4a4a-840d-0a018c09654f /** * Request object representing the payer's address. Contains street-level address details * used for billing, fraud verification, and delivery purposes. */ @Getter @Builder public class OrderPayerAddressRequest { /** Name of the street. */ private String streetName; /** Street number. */ private String streetNumber; /** Postal or zip code. */ private String zipCode; /** Name of the neighborhood or district. */ private String neighborhood; /** Name of the city. */ private String city; /** Name of the state or province. */ private String state; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderPayerRequest.java ================================================ package com.mercadopago.client.order; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.resources.common.Phone; import lombok.Builder; import lombok.Getter; // API version: acd67b14-97c4-4a4a-840d-0a018c09654f /** * Request object containing the payer's personal information for an order. Includes contact * details such as email and phone, identification documents, and address data. */ @Getter @Builder public class OrderPayerRequest { /** Entity type of the payer (e.g. "individual", "association"). */ private String entityType; /** Email address of the payer. */ private String email; /** First name of the payer. */ private String firstName; /** MercadoPago customer ID associated with the payer. */ private String customerId; /** Last name of the payer. */ private String lastName; /** Payer's identification document (type and number). */ private IdentificationRequest identification; /** Payer's phone number details. */ private Phone phone; /** Payer's address information. */ private OrderPayerAddressRequest address; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderPaymentMethodConfig.java ================================================ package com.mercadopago.client.order; import com.mercadopago.resources.order.OrderInstallments; import lombok.Builder; import lombok.Getter; import java.util.List; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Configuration for payment method restrictions and defaults within an order. Controls which * payment methods are allowed, sets default selections, and defines installment limits and * cost absorption rules for the checkout experience. */ @Builder @Getter public class OrderPaymentMethodConfig { /** List of payment method IDs that are not allowed for this order. */ private List notAllowedIds; /** List of payment method types that are not allowed for this order. */ private List notAllowedTypes; /** Default payment method ID pre-selected in the checkout. */ private String defaultId; /** Maximum number of installments allowed for this order. */ private Integer maxInstallments; /** Default number of installments pre-selected in the checkout. */ private Integer defaultInstallments; /** Default payment method type pre-selected in the checkout. */ private String defaultType; /** Who absorbs the installment cost ("buyer" or "seller"). */ private String installmentsCost; /** Detailed installment configuration options. */ private OrderInstallments installments; /** Minimum number of installments allowed for this order. */ private Integer minInstallments; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderPaymentMethodRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object representing the payment method to be used in an order payment. Includes the * method identifier, type, tokenized card data, installment configuration, and statement * descriptor for the cardholder's bill. */ @Getter @Builder public class OrderPaymentMethodRequest { /** Identifier of the payment method (e.g. "visa", "master", "pix"). */ private String id; /** Type of the payment method (e.g. "credit_card", "debit_card", "bank_transfer"). */ private String type; /** Card token generated by MercadoPago.js for secure card data handling. */ private String token; /** Number of installments selected for the payment. */ private int installments; /** Text that will appear on the cardholder's billing statement (e.g. "MERCADOPAGO"). */ private String statementDescriptor; /** Financial institution code (required for PSE in Colombia, e.g. "1007" Bancolombia). */ private String financialInstitution; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderPaymentRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object representing a single payment within an order transaction. Defines the payment * amount, method, and optional recurring payment settings such as automatic payments, * stored credentials, and subscription data. */ @Getter @Builder public class OrderPaymentRequest { /** Payment amount as a decimal string. */ private String amount; /** ISO 8601 duration or date-time indicating when this payment expires. */ private String expirationTime; /** Payment method details including type, token, and installments. */ private OrderPaymentMethodRequest paymentMethod; /** Configuration for automatic recurring payments. */ private OrderAutomaticPaymentsRequest automaticPayments; /** Stored credential information for card-on-file transactions. */ private OrderStoredCredentialRequest storedCredential; /** Subscription data for recurring billing scenarios. */ private OrderSubscriptionDataRequest subscriptionData; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderPointConfig.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Configuration for Point-of-Sale (POS) terminal integration within an order. Controls terminal * selection, receipt printing behavior, and display timeout for in-person payment scenarios. */ @Getter @Builder public class OrderPointConfig { /** Identifier of the Point terminal device to process the payment. */ private String terminalId; /** Whether to print a receipt on the terminal after payment. */ private String printOnTerminal; /** Duration the payment screen is displayed on the terminal, in ISO 8601 duration format. */ private String screenTime; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderReceiverAddressRequest.java ================================================ package com.mercadopago.client.order; import lombok.Getter; /** * Request object representing the receiver's address for an order shipment. Contains the * full street address, city, state, zip code, and optional floor/apartment details. */ @Getter public class OrderReceiverAddressRequest { /** Name of the street. */ private String streetName; /** Street number. */ private String streetNumber; /** Postal or zip code. */ private String zipCode; /** Name of the city. */ private String cityName; /** Name of the state or province. */ private String stateName; /** Floor number or identifier within the building. */ private String floor; /** Apartment number or identifier. */ private String apartment; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderRefundPaymentRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Request object representing a single payment to be refunded within an order refund operation. * Specifies which payment to refund and the refund amount. */ @Builder @Getter public class OrderRefundPaymentRequest { /** Identifier of the payment to refund. */ private String id; /** Amount to refund as a decimal string. Use {@code null} for a full refund. */ private String amount; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderRefundRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; import java.util.List; /** * Request object for initiating a refund on an order. Contains the list of transaction payments * to be refunded, each specifying the payment ID and the amount to refund. */ @Builder @Getter public class OrderRefundRequest { /** List of payment refund details within the transaction to be refunded. */ private List transactions; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderRouteRequest.java ================================================ package com.mercadopago.client.order; import lombok.Getter; /** * Request object representing a travel route leg within an order. Contains origin and * destination information along with travel times and the carrier company, used for * airline and travel industry payment processing. */ @Getter public class OrderRouteRequest { /** Departure city or airport code. */ private String departure; /** Destination city or airport code. */ private String destination; /** Departure date and time in ISO 8601 format. */ private String departureDateTime; /** Arrival date and time in ISO 8601 format. */ private String arrivalDateTime; /** Name of the carrier or airline company. */ private String company; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderShipmentRequest.java ================================================ package com.mercadopago.client.order; import lombok.Getter; /** * Request object containing shipment details for an order. Includes the receiver's address, * package dimensions, and shipping options such as express delivery and seller pickup. */ @Getter public class OrderShipmentRequest { /** Destination address where the shipment will be delivered. */ private OrderReceiverAddressRequest receiverAddress; /** Width of the package in centimeters. */ private float width; /** Height of the package in centimeters. */ private float height; /** Whether the shipment uses express delivery. */ private Boolean expressShipment; /** Whether the buyer will pick up the order at the seller's location. */ private Boolean pickUpOnSeller; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderStoredCredentialRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object for stored credential (card-on-file) information in an order payment. * Used to indicate whether the payment uses a previously stored card and the context * of the transaction (merchant-initiated vs. cardholder-initiated), as required by * card network regulations. */ @Getter @Builder public class OrderStoredCredentialRequest { /** Who initiated the payment: "cardholder" or "merchant". */ private String paymentInitiator; /** Reason for storing the credential (e.g. "recurring", "installment", "unscheduled"). */ private String reason; /** Whether to store the payment method for future transactions. */ private Boolean storePaymentMethod; /** Whether this is the first payment using this stored credential. */ private Boolean firstPayment; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderSubscriptionDataRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object containing subscription data for recurring payment orders. Provides billing * context such as sequence information, invoice details, and billing dates required for * subscription-based payment processing. */ @Getter @Builder public class OrderSubscriptionDataRequest { /** Sequence information indicating the position of this payment within the subscription. */ private OrderSubscriptionSequenceRequest subscriptionSequence; /** Identifier of the invoice associated with this subscription payment. */ private String invoiceId; /** Period covered by this invoice (type and duration). */ private OrderInvoicePeriodRequest invoicePeriod; /** Date when the billing occurs, in ISO 8601 format. */ private String billingDate; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderSubscriptionSequenceRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object representing the sequence position of a payment within a subscription. * Indicates which payment number this is out of the total number of payments in the * subscription plan. */ @Getter @Builder public class OrderSubscriptionSequenceRequest { /** Current payment number in the subscription sequence (e.g. 3 for the third payment). */ private Integer number; /** Total number of payments in the subscription plan. */ private Integer total; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderTransactionRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; import java.util.List; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Request object representing the transaction data within an order. A transaction groups one or * more payments that are processed together as part of the same order. */ @Builder @Getter public class OrderTransactionRequest{ /** List of payments associated with this transaction. */ private List payments; } ================================================ FILE: src/main/java/com/mercadopago/client/order/OrderTransactionSecurity.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Configuration for 3D Secure (3DS) transaction security in an order. Controls whether 3DS * authentication is required and how liability shift is handled in case of chargebacks. * Used within {@link OrderOnlineConfig} to enforce security policies on online payments. */ @Getter @Builder public class OrderTransactionSecurity { /** Validation mode for 3DS authentication ("always", "on_fraud_risk", or "never"). */ private String validation; /** Liability shift policy for chargebacks ("required" or "preferred"). */ private String liabilityShift; } ================================================ FILE: src/main/java/com/mercadopago/client/order/PassengerIdentification.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Identification document for a travel passenger. Contains the document type and number * used to verify the passenger's identity in travel-related transactions. */ @Getter @Builder public class PassengerIdentification { /** Type of the identification document (e.g. "CPF", "DNI", "passport"). */ private String type; /** Number of the identification document. */ private String number; } ================================================ FILE: src/main/java/com/mercadopago/client/order/PayerInfo.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Additional payer information provided within the {@code additional_info} section of an order. * Contains risk-assessment data such as authentication type, account age, and purchase history * to improve fraud detection and payment approval rates. */ @Getter @Builder public class PayerInfo { /** Type of authentication used by the payer (e.g. "Gmail", "Facebook", "native"). */ private final String authenticationType; /** Date when the payer registered on the platform, in ISO 8601 format. */ private final String registrationDate; /** Whether the payer is a prime or premium user. */ private final Boolean isPrimeUser; /** Whether this is the payer's first online purchase. */ private final Boolean isFirstPurchaseOnline; /** Date of the payer's last purchase, in ISO 8601 format. */ private final String lastPurchase; /** Payer's IP address (required by risk engine for PSE in Colombia). */ private final String ipAddress; } ================================================ FILE: src/main/java/com/mercadopago/client/order/PlatformInfo.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Platform-level information within the additional info section of an order. Groups data about * the marketplace or platform that originated the transaction, including shipment logistics, * seller profile, and authentication context. */ @Getter @Builder public class PlatformInfo { /** Shipment details managed by the platform (delivery promise, tracking, etc.). */ private final PlatformShipment shipment; /** Information about the seller on the platform. */ private final SellerInfo seller; /** Authentication method or token used by the platform. */ private final String authentication; } ================================================ FILE: src/main/java/com/mercadopago/client/order/PlatformShipment.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Shipment information managed by the platform, provided within the additional info section. * Contains logistics details such as delivery promises, drop-shipping flags, safety indicators, * and package tracking data. */ @Getter @Builder public class PlatformShipment { /** Expected delivery promise or estimated delivery date. */ private final String deliveryPromise; /** Drop-shipping indicator or configuration. */ private final String dropShipping; /** Safety level or indicator for the shipment. */ private final String safety; /** Tracking information including code and status. */ private final TrackingInfo tracking; /** Whether the shipment has been withdrawn by the buyer. */ private final Boolean withdrawn; } ================================================ FILE: src/main/java/com/mercadopago/client/order/SellerAddress.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Physical address of the seller, provided within the platform additional info section. * Contains the full postal address used for logistics and compliance verification. */ @Getter @Builder public class SellerAddress { /** Postal or zip code. */ private final String zipCode; /** Name of the street. */ private final String streetName; /** Street number. */ private final String streetNumber; /** Name of the city. */ private final String city; /** Name of the state or province. */ private final String state; /** Address complement (e.g. suite, floor, building). */ private final String complement; /** Country name or ISO country code. */ private final String country; } ================================================ FILE: src/main/java/com/mercadopago/client/order/SellerIdentification.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Identification document of the seller, provided within the platform additional info section. * Contains the document type (e.g. CNPJ, CPF, CUIT) and its number for tax and compliance * verification. */ @Getter @Builder public class SellerIdentification { /** Type of the identification document (e.g. "CNPJ", "CPF", "CUIT"). */ private final String type; /** Number of the identification document. */ private final String number; } ================================================ FILE: src/main/java/com/mercadopago/client/order/SellerInfo.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Seller information within the platform section of additional info. Provides details about the * merchant or seller on the platform, including contact information, business profile, and * registration data used for risk assessment and compliance purposes. */ @Getter @Builder public class SellerInfo { /** Unique identifier of the seller on the platform. */ private final String id; /** Business or display name of the seller. */ private final String name; /** Email address of the seller. */ private final String email; /** Current status of the seller account (e.g. "active", "inactive"). */ private final String status; /** Referral URL associated with the seller. */ private final String referralUrl; /** Date when the seller registered on the platform, in ISO 8601 format. */ private final String registrationDate; /** Plan hired by the seller on the platform. */ private final String hiredPlan; /** Type of business operated by the seller. */ private final String businessType; /** Physical address of the seller. */ private final SellerAddress address; /** Identification document of the seller. */ private final SellerIdentification identification; /** Phone contact information for the seller. */ private final SellerPhone phone; } ================================================ FILE: src/main/java/com/mercadopago/client/order/SellerPhone.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Phone contact information for the seller, provided within the platform additional info * section. Contains the area code and phone number. */ @Getter @Builder public class SellerPhone { /** Telephone area code (e.g. "11", "21"). */ private final String areaCode; /** Phone number without the area code. */ private final String number; } ================================================ FILE: src/main/java/com/mercadopago/client/order/ShipmentInfo.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Shipment information within the additional info section of an order. Provides flags * indicating the type of delivery chosen by the buyer, such as express shipping or * local pickup at the seller's location. */ @Getter @Builder public class ShipmentInfo { /** Whether express shipping was selected for this order. */ private final Boolean express; /** Whether the buyer will pick up the order locally at the seller's location. */ private final Boolean localPickup; } ================================================ FILE: src/main/java/com/mercadopago/client/order/TrackingInfo.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Tracking information for a platform-managed shipment. Contains the tracking code and * current delivery status, used within {@link PlatformShipment} to monitor package logistics. */ @Getter @Builder public class TrackingInfo { /** Carrier-provided tracking code for the shipment. */ private final String code; /** Current status of the tracked shipment (e.g. "in_transit", "delivered"). */ private final String status; } ================================================ FILE: src/main/java/com/mercadopago/client/order/TravelInfo.java ================================================ package com.mercadopago.client.order; import java.util.List; import lombok.Builder; import lombok.Getter; /** * Travel information within the additional info section of an order. Used for airline and travel * industry transactions to provide passenger and route details that improve fraud detection * and chargeback management. */ @Getter @Builder public class TravelInfo { /** List of passengers traveling on this itinerary. */ private final List passengers; /** List of travel routes (legs) in the itinerary. */ private final List routes; } ================================================ FILE: src/main/java/com/mercadopago/client/order/TravelPassengerRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Request object representing a passenger in a travel-related order. Contains the passenger's * name and identification document, used for airline and travel industry fraud prevention. */ @Getter @Builder public class TravelPassengerRequest { /** First name of the passenger. */ private String firstName; /** Last name of the passenger. */ private String lastName; /** Identification document of the passenger. */ private PassengerIdentification identification; } ================================================ FILE: src/main/java/com/mercadopago/client/order/TravelRouteRequest.java ================================================ package com.mercadopago.client.order; import lombok.Builder; import lombok.Getter; /** * Request object representing a single route (leg) in a travel itinerary. Contains departure * and destination cities, travel times, and the carrier company, used for airline and travel * industry fraud prevention. */ @Getter @Builder public class TravelRouteRequest { /** Departure city or airport code. */ private String departure; /** Destination city or airport code. */ private String destination; /** Departure date and time in ISO 8601 format. */ private String departureDateTime; /** Arrival date and time in ISO 8601 format. */ private String arrivalDateTime; /** Name of the carrier or airline company. */ private String company; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentAdditionalInfoBarcodeRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing barcode information included in the additional-info * section of a payment. Describes the encoding type, content, and display * dimensions of a barcode associated with the payment. */ @Getter @Builder public class PaymentAdditionalInfoBarcodeRequest { /** Barcode encoding type (e.g. "Code128", "QR"). */ private final String type; /** Encoded content of the barcode. */ private final String content; /** Display width of the barcode in pixels. */ private final Double width; /** Display height of the barcode in pixels. */ private final Double height; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentAdditionalInfoPayerRequest.java ================================================ package com.mercadopago.client.payment; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Extended payer information included in the additional-info section of a payment request. * Provides enriched buyer data such as registration history and purchase behavior, which * is used by MercadoPago's fraud-prevention engine to improve approval rates. */ @Getter @Builder public class PaymentAdditionalInfoPayerRequest { /** First name of the payer. */ private final String firstName; /** Last name of the payer. */ private final String lastName; /** Payer's phone information. */ private final PhoneRequest phone; /** Payer's address information. */ private final AddressRequest address; /** Date when the payer registered on the merchant's platform. */ private final OffsetDateTime registrationDate; /** Authentication method used by the payer (e.g. "gmail", "facebook", "native"). */ private final String authenticationType; /** Whether the payer is a prime/premium subscriber on the merchant's platform. */ private final boolean isPrimeUser; /** Whether this is the payer's first online purchase on the merchant's platform. */ private final boolean isFirstPurchaseOnline; /** Date and time of the payer's last purchase on the merchant's platform. */ private final OffsetDateTime lastPurchase; /** Personal identification document of the payer (e.g. CPF, DNI). */ private final IdentificationRequest identification; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentAdditionalInfoRequest.java ================================================ package com.mercadopago.client.payment; import java.util.List; import lombok.Builder; import lombok.Getter; /** * Request object containing additional information sent alongside a payment to improve * fraud prevention analysis and increase approval rates. Includes item details, extended * payer information, shipment data, and barcode information. */ @Getter @Builder public class PaymentAdditionalInfoRequest { /** IP address of the device that originated the payment request. */ private final String ipAddress; /** List of items being purchased in this payment. */ private final List items; /** Extended payer information for fraud-prevention analysis. */ private final PaymentAdditionalInfoPayerRequest payer; /** Shipment details for the purchased items. */ private final PaymentShipmentsRequest shipments; /** Barcode information associated with the payment. */ private final PaymentAdditionalInfoBarcodeRequest barcode; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentAmountsRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object defining the payer and collector amounts for a payment. * Used in cross-currency payment scenarios where the payer and the collector * may operate in different currencies. */ @Getter @Builder public class PaymentAmountsRequest { /** Amount details from the payer's perspective, including currency and transaction value. */ private PaymentUserAmountRequest payer; /** Amount details from the collector's perspective, including currency and transaction value. */ private PaymentUserAmountRequest collector; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentAuthenticationRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing 3-D Secure (3DS) authentication data for a payment. * Used when the merchant performs external 3DS authentication and needs to * forward the authentication results to MercadoPago. */ @Getter @Builder public class PaymentAuthenticationRequest { /** Authentication type (e.g. "external_threeds"). */ private final String type; /** Authentication cryptogram generated by the 3DS process. */ private final String cryptogram; /** 3DS Server transaction identifier. */ private final String threeDsServerTransId; /** Electronic Commerce Indicator returned by the 3DS authentication. */ private final String eci; /** Directory Server transaction identifier. */ private final String dsTransId; /** Access Control Server transaction identifier. */ private final String acsTransId; /** Version of the 3-D Secure protocol used (e.g. "2.1.0", "2.2.0"). */ private final String threeDsVersion; /** Authentication status result (e.g. "Y" for authenticated, "N" for not authenticated). */ private final String authenticationStatus; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentCancelRequest.java ================================================ package com.mercadopago.client.payment; import static com.mercadopago.resources.payment.PaymentStatus.CANCELLED; import lombok.Builder; import lombok.Getter; /** * Request object used to cancel an existing payment. * Sets the payment status to {@code cancelled}. Only payments that have * not yet been approved or are in a pending/in-process state can be cancelled. */ @Getter @Builder public class PaymentCancelRequest { /** Payment status, automatically set to {@code cancelled}. */ private final String status = CANCELLED; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentCaptureRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request object used to capture a previously authorized (reserved) payment. * The capture flag is always set to {@code true}. An optional transaction * amount can be specified to perform a partial capture. */ @Getter @Builder public class PaymentCaptureRequest { /** Capture flag, always set to {@code true} to confirm the capture. */ private final boolean capture = true; /** Amount to capture; if {@code null}, the full authorized amount is captured. */ private final BigDecimal transactionAmount; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentCategoryDescriptorRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object providing category-specific descriptors for a purchased item. * Primarily used for travel-related items to include passenger and route * (flight) information that aids in fraud-prevention analysis. */ @Getter @Builder public class PaymentCategoryDescriptorRequest { /** Passenger details associated with the purchased item (e.g. airline ticket). */ private final PaymentPassengerRequest passenger; /** Route or flight details associated with the purchased item. */ private final PaymentRouteRequest route; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentClient.java ================================================ package com.mercadopago.client.payment; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeFromJson; import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; import com.google.gson.reflect.TypeToken; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.payment.Payment; import com.mercadopago.resources.payment.PaymentRefund; import com.mercadopago.serialization.Serializer; import java.lang.reflect.Type; import java.math.BigDecimal; import java.util.HashMap; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Payments API (v1). * *

Supports the full payment lifecycle: creation, retrieval, cancellation, capture (full and * partial amounts), and search with pagination. Refund operations are delegated to an internal * {@link PaymentRefundClient} and exposed via convenience methods on this class. * *

Usage example: *

{@code
 * PaymentClient client = new PaymentClient();
 * Payment payment = client.create(paymentCreateRequest);
 * Payment captured = client.capture(payment.getId());
 * PaymentRefund refund = client.refund(payment.getId());
 * }
* * @see PaymentRefundClient * @see * Payments API reference */ public class PaymentClient extends MercadoPagoClient { /** Class-level logger for payment operations. */ private static final Logger LOGGER = Logger.getLogger(PaymentClient.class.getName()); /** URL template for single-payment endpoints (e.g. {@code /v1/payments/{id}}). */ private static final String URL_WITH_ID = "/v1/payments/%s"; /** Internal client used to perform refund operations on behalf of this client. */ private final PaymentRefundClient refundClient; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public PaymentClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code PaymentClient} with a custom HTTP client. * *

Also initialises the internal {@link PaymentRefundClient} with the same HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public PaymentClient(MPHttpClient httpClient) { super(httpClient); refundClient = new PaymentRefundClient(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves a payment by its unique identifier. * * @param id the unique identifier of the payment * @return the requested {@link Payment} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment get(Long id) throws MPException, MPApiException { return this.get(id, null); } /** * Retrieves a payment by its unique identifier with custom request options. * * @param id the unique identifier of the payment * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link Payment} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment get(Long id, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get payment request"); MPResponse response = send(String.format(URL_WITH_ID, id.toString()), HttpMethod.GET, null, null, requestOptions); Payment result = deserializeFromJson(Payment.class, response.getContent()); result.setResponse(response); return result; } /** * Creates a new payment. * * @param request the {@link PaymentCreateRequest} with payment details (amount, payer, method, * etc.) * @return the created {@link Payment} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment create(PaymentCreateRequest request) throws MPException, MPApiException { return this.create(request, null); } /** * Creates a new payment with custom request options. * * @param request the {@link PaymentCreateRequest} with payment details (amount, payer, method, * etc.) * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link Payment} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment create(PaymentCreateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create payment request"); MPRequest mpRequest = MPRequest.builder() .uri("/v1/payments") .method(HttpMethod.POST) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); Payment result = deserializeFromJson(Payment.class, response.getContent()); result.setResponse(response); return result; } /** * Cancels a pending payment by setting its status to {@code cancelled}. * * @param id the unique identifier of the payment to cancel * @return the cancelled {@link Payment} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment cancel(Long id) throws MPException, MPApiException { return this.cancel(id, null); } /** * Cancels a pending payment with custom request options. * * @param id the unique identifier of the payment to cancel * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the cancelled {@link Payment} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment cancel(Long id, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending cancel payment request"); PaymentCancelRequest payload = new PaymentCancelRequest(); MPResponse response = send( String.format(URL_WITH_ID, id.toString()), HttpMethod.PUT, Serializer.serializeToJson(payload), new HashMap<>(), requestOptions); Payment result = deserializeFromJson(Payment.class, response.getContent()); result.setResponse(response); return result; } /** * Captures a previously authorized payment for its full amount. * * @param id the unique identifier of the payment to capture * @return the captured {@link Payment} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment capture(Long id) throws MPException, MPApiException { return this.capture(id, null, null); } /** * Captures a previously authorized payment for its full amount with custom request options. * * @param id the unique identifier of the payment to capture * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the captured {@link Payment} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment capture(Long id, MPRequestOptions requestOptions) throws MPException, MPApiException { return this.capture(id, null, requestOptions); } /** * Captures a previously authorized payment for the specified amount (partial capture). * * @param id the unique identifier of the payment to capture * @param amount the amount to capture; if {@code null}, the full authorized amount is captured * @return the captured {@link Payment} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment capture(Long id, BigDecimal amount) throws MPException, MPApiException { return this.capture(id, amount, null); } /** * Captures a previously authorized payment for the specified amount with custom request options. * *

If {@code amount} is {@code null}, the full authorized amount is captured (full capture). * Otherwise, a partial capture is performed for the given amount. * * @param id the unique identifier of the payment to capture * @param amount the amount to capture, or {@code null} for the full authorized amount * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the captured {@link Payment} with updated status * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Payment capture(Long id, BigDecimal amount, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending capture payment request"); PaymentCaptureRequest payload = PaymentCaptureRequest.builder().transactionAmount(amount).build(); MPResponse response = send( String.format(URL_WITH_ID, id.toString()), HttpMethod.PUT, Serializer.serializeToJson(payload), new HashMap<>(), requestOptions); Payment result = deserializeFromJson(Payment.class, response.getContent()); result.setResponse(response); return result; } /** * Searches for payments matching the specified criteria. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @return an {@link MPResultsResourcesPage} of {@link Payment} with the matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResultsResourcesPage search(MPSearchRequest request) throws MPException, MPApiException { return this.search(request, null); } /** * Searches for payments matching the specified criteria with custom request options. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResultsResourcesPage} of {@link Payment} with the matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResultsResourcesPage search( MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending search payment request"); MPResponse response = search("/v1/payments/search", request, requestOptions); Type responseType = new TypeToken>() {}.getType(); MPResultsResourcesPage result = deserializeResultsResourcesPageFromJson(responseType, response.getContent()); result.setResponse(response); return result; } /** * Creates a total refund for a payment, returning the full amount to the payer. * *

Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment to refund * @return the {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public PaymentRefund refund(Long paymentId) throws MPException, MPApiException { return this.refund(paymentId, null, null); } /** * Creates a total refund for a payment with custom request options. * *

Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment to refund * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public PaymentRefund refund(Long paymentId, MPRequestOptions requestOptions) throws MPException, MPApiException { return this.refund(paymentId, null, requestOptions); } /** * Creates a partial refund for a payment, returning the specified amount to the payer. * *

Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment to refund * @param amount the amount to refund; if {@code null}, a total refund is performed * @return the {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public PaymentRefund refund(Long paymentId, BigDecimal amount) throws MPException, MPApiException { return this.refund(paymentId, amount, null); } /** * Creates a total or partial refund for a payment with custom request options. * *

If {@code amount} is {@code null}, a total refund is performed. Otherwise, the specified * amount is refunded (partial refund). Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment to refund * @param amount the amount to refund, or {@code null} for a total refund * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public PaymentRefund refund(Long paymentId, BigDecimal amount, MPRequestOptions requestOptions) throws MPException, MPApiException { return refundClient.refund(paymentId, amount, requestOptions); } /** * Retrieves a specific refund associated with a payment. * *

Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment * @param refundId the unique identifier of the refund * @return the {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public PaymentRefund getRefund(Long paymentId, Long refundId) throws MPException, MPApiException { return this.getRefund(paymentId, refundId, null); } /** * Retrieves a specific refund associated with a payment with custom request options. * *

Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment * @param refundId the unique identifier of the refund * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public PaymentRefund getRefund(Long paymentId, Long refundId, MPRequestOptions requestOptions) throws MPException, MPApiException { return refundClient.get(paymentId, refundId, requestOptions); } /** * Lists all refunds associated with a payment. * *

Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment * @return an {@link MPResourceList} of {@link PaymentRefund} for the given payment * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResourceList listRefunds(Long paymentId) throws MPException, MPApiException { return this.listRefunds(paymentId, null); } /** * Lists all refunds associated with a payment with custom request options. * *

Delegates to the internal {@link PaymentRefundClient}. * * @param paymentId the unique identifier of the payment * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResourceList} of {@link PaymentRefund} for the given payment * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResourceList listRefunds(Long paymentId, MPRequestOptions requestOptions) throws MPException, MPApiException { return refundClient.list(paymentId, requestOptions); } } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentCounterCurrencyRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object specifying the counter-currency for cross-border payments. * Indicates the currency in which the collector will receive the funds when * it differs from the payer's currency. */ @Getter @Builder public class PaymentCounterCurrencyRequest { /** Currency identifier in ISO 4217 format (e.g. "USD", "BRL"). */ private String currencyId; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentCreateRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import lombok.Builder; import lombok.Getter; /** * Request object used to create a new payment through the MercadoPago Payments API. * Contains all the parameters needed to describe a payment, including the transaction * amount, payment method, payer details, and additional fraud-prevention information. * * @see Payments API reference */ @Getter @Builder public class PaymentCreateRequest { /** Additional data that improves fraud analysis and conversion rates. */ private final PaymentAdditionalInfoRequest additionalInfo; /** Fee collected by a marketplace or MercadoPago application. */ private final BigDecimal applicationFee; /** When {@code true}, the payment can only be approved or rejected; otherwise an in-process status is possible. */ private final Boolean binaryMode; /** URL where MercadoPago performs the final redirect (used for bank transfers). */ private final String callbackUrl; /** Discount campaign identifier. */ private final Long campaignId; /** Whether the payment should be captured immediately ({@code true}) or only reserved ({@code false}). */ private final Boolean capture; /** Amount of the coupon discount applied to the payment. */ private final BigDecimal couponAmount; /** Discount campaign code. */ private final String couponCode; /** Payment expiration date and time. */ private final OffsetDateTime dateOfExpiration; /** Payment reason or item title shown to the payer. */ private final String description; /** Identifier of the differential pricing scheme for financing-fee absorption. */ private final Long differentialPricingId; /** External reference identifier provided by the merchant in their own system. */ private final String externalReference; /** Number of installments selected by the payer. */ private final Integer installments; /** Identifier of the payment method issuer (e.g. bank or card issuer). */ private final String issuerId; /** Merchant account identifier used in complex payment scenarios. */ private final String merchantAccountId; /** Configuration for merchant anti-fraud services. */ private final PaymentMerchantServicesRequest merchantServices; /** Custom key-value metadata attached to the payment by the merchant. */ private final Map metadata; /** Net amount received by the seller after fees. */ private final BigDecimal netAmount; /** Webhook URL where MercadoPago sends notifications about payment status changes. */ private final String notificationUrl; /** Associated purchase order information. */ private final PaymentOrderRequest order; /** Payer information (email, identification, address, etc.). */ private final PaymentPayerRequest payer; /** Forward data for Payment Facilitator or recurring-payment integrations. */ private final PaymentForwardDataRequest forwardData; /** Identifier of the payment method chosen by the payer (e.g. "visa", "pix"). */ private final String paymentMethodId; /** Payment method option identifier for specific payment flows. */ private final String paymentMethodOptionId; /** Processing mode that determines whether a specific merchant account is used. */ private final String processingMode; /** Tokenized card identifier generated by MercadoPago's card-tokenization flow. */ private final String token; /** Total transaction amount to be charged. */ private final BigDecimal transactionAmount; /** Additional transaction details such as the financial institution. */ private final PaymentTransactionDetailsRequest transactionDetails; /** Point-of-interaction data describing the context of the payment origin. */ private final PaymentPointOfInteractionRequest pointOfInteraction; /** Sponsor (platform) identifier for marketplace payments. */ private final Long sponsorId; /** Description that appears on the payer's card or bank statement (e.g. "MERCADOPAGO"). */ private final String statementDescriptor; /** List of taxes applied to this payment. */ private final List taxes; /** Payment method details including type, rules, and authentication. */ private final PaymentMethodRequest paymentMethod; /** 3-D Secure mode for the payment (e.g. "optional", "mandatory", "not_supported"). */ private final String threeDSecureMode; /** Payer and collector amount details for cross-currency payments. */ private final PaymentAmountsRequest amounts; /** Counter-currency information for cross-border payments. */ private final PaymentCounterCurrencyRequest counterCurrency; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentDataRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing additional data associated with a payment method. * Groups the financial rules (discounts, fines, interest) and 3-D Secure * authentication details for the chosen payment method. */ @Getter @Builder public class PaymentDataRequest { /** Financial rules applied to the payment (discounts, fines, interest). */ private final PaymentRulesRequest rules; /** 3-D Secure authentication data for the payment. */ private final PaymentAuthenticationRequest authentication; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentDiscountRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import java.time.LocalDate; import lombok.Builder; import lombok.Getter; /** * Request object representing a discount rule applied to a payment. * Defines the type, value, and validity date of the discount, typically * used for early-payment incentives on boleto or invoice payments. */ @Getter @Builder public class PaymentDiscountRequest { /** Discount type (e.g. "fixed" or "percentage"). */ private String type; /** Discount value, interpreted as a fixed amount or percentage depending on type. */ private BigDecimal value; /** Last date on which the discount is valid. */ private LocalDate limitDate; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentFeeRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request object representing a fee rule applied to a payment, such as * a late-payment fine or interest charge. Used within {@link PaymentRulesRequest}. */ @Getter @Builder public class PaymentFeeRequest { /** Fee type (e.g. "percentage" or "fixed"). */ private String type; /** Fee value, interpreted as a percentage or fixed amount depending on type. */ private BigDecimal value; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentForwardDataRequest.java ================================================ package com.mercadopago.client.payment; import com.mercadopago.client.common.SubMerchant; import lombok.Builder; import lombok.Getter; /** * Request object carrying forward data for Payment Facilitator integrations. * Contains sub-merchant details required by card networks and network transaction * data used for recurring payments with Visa and Mastercard. */ @Getter @Builder public class PaymentForwardDataRequest { /** Sub-merchant information required for Payment Facilitator integrations. */ private final SubMerchant subMerchant; /** Network transaction data used for recurring payments with Visa and Mastercard. */ private final PaymentNetworkTransactionDataRequest networkTransactionData; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentInvoicePeriodRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object defining the invoice period for a subscription-based payment. * Specifies the billing cycle length and its unit of measurement. */ @Getter @Builder public class PaymentInvoicePeriodRequest { /** Duration of the billing cycle (e.g. 1, 3, 12). */ private int period; /** Unit of the billing cycle (e.g. "monthly", "yearly", "daily"). */ private String type; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentItemRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Request object describing an individual item included in a payment. * Sent inside the additional-info section to provide detailed product data * that supports fraud-prevention analysis and improves the payer experience. */ @Getter @Builder public class PaymentItemRequest { /** Unique item code or SKU in the merchant's catalog. */ private final String id; /** Display name of the item. */ private final String title; /** Type classification of the item (e.g. "electronics", "tickets"). */ private final String type; /** Detailed description of the item. */ private final String description; /** URL of the item's image. */ private final String pictureUrl; /** Category identifier for the item in the merchant's catalog. */ private final String categoryId; /** ISO 4217 currency code for the unit price. */ private final String currencyId; /** Quantity of this item being purchased. */ private final Integer quantity; /** Unit price of the item. */ private final BigDecimal unitPrice; /** Category-specific descriptor with details such as passenger or route information. */ private final PaymentCategoryDescriptorRequest categoryDescriptor; /** Whether the item is purchased with warranty coverage. */ private final boolean warranty; /** Date of the event associated with the item (e.g. concert, flight). */ private final OffsetDateTime eventDate; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentMerchantServicesRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object configuring the merchant's anti-fraud services for a payment. * Controls whether automated fraud scoring and/or manual fraud review are * enabled for the transaction. */ @Getter @Builder public class PaymentMerchantServicesRequest { /** Whether automated fraud-scoring analysis is enabled for this payment. */ private final boolean fraudScoring; /** Whether manual fraud review by a specialist is enabled for this payment. */ private final boolean fraudManualReview; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentMethodRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object specifying the payment method details for a payment. * Wraps the payment method type along with its associated data such as * rules (discounts, fines, interest) and 3-D Secure authentication. */ @Getter @Builder public class PaymentMethodRequest { /** Payment method type (e.g. "credit_card", "debit_card", "bank_transfer"). */ private final String type; /** Data associated with the payment method, including rules and authentication. */ private final PaymentDataRequest data; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentNetworkTransactionDataRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing network transaction data for recurring payments. * Carries the card-brand network transaction identifier used to link * subsequent recurring charges to the original authorization. */ @Getter @Builder public class PaymentNetworkTransactionDataRequest { /** Network transaction identifier assigned by the card brand (Visa/Mastercard). */ private final String networkTransactionId; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentOrderRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object identifying the purchase order associated with a payment. * Links the payment to an existing order in the MercadoPago platform. */ @Getter @Builder public class PaymentOrderRequest { /** Unique identifier of the associated purchase order. */ private final Long id; /** Type of the order (e.g. "mercadolibre"). */ private final String type; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentPassengerRequest.java ================================================ package com.mercadopago.client.payment; import com.mercadopago.client.common.IdentificationRequest; import lombok.Builder; import lombok.Getter; /** * Request object representing a passenger associated with a travel-related item. * Used within the category descriptor to provide passenger identity details * for airline tickets and similar travel purchases. */ @Getter @Builder public class PaymentPassengerRequest { /** First name of the passenger. */ private final String firstName; /** Last name of the passenger. */ private final String lastName; /** Personal identification document of the passenger (e.g. passport, national ID). */ private final IdentificationRequest identification; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentPayerAddressRequest.java ================================================ package com.mercadopago.client.payment; import com.mercadopago.client.common.AddressRequest; import lombok.Getter; import lombok.experimental.SuperBuilder; /** * Request object representing the payer's address in a payment request. * Extends {@link AddressRequest} with a federal-unit field for regions * that require state or province identification. */ @Getter @SuperBuilder public class PaymentPayerAddressRequest extends AddressRequest { /** Federal unit such as state or province (e.g. "SP", "BA"). */ private String federalUnit; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentPayerPhoneRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object representing the payer's phone information in a payment request. * Contains the area code and phone number for contacting the payer. */ @Getter @Builder public class PaymentPayerPhoneRequest { /** Telephone area code (e.g. "11", "21"). */ private String areaCode; /** Telephone number without the area code. */ private String number; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentPayerRequest.java ================================================ package com.mercadopago.client.payment; import com.mercadopago.client.common.IdentificationRequest; import lombok.Builder; import lombok.Getter; import java.util.Date; /** * Request object representing the payer in a payment creation request. * Contains personal data such as name, email, identification document, * address, and phone needed to identify the person making the payment. */ @Getter @Builder public class PaymentPayerRequest { /** Authentication type used by the payer (e.g. "gmail", "facebook", "native"). */ private final String authenticationType; /** Full name of the payer. */ private final String name; /** Payer type identifier; mandatory when the payer is a registered Customer. */ private final String type; /** Unique payer identifier in the MercadoPago platform. */ private final String id; /** Email address of the payer. */ private final String email; /** Personal identification document of the payer (e.g. CPF, DNI). */ private final IdentificationRequest identification; /** First name of the payer. */ private final String firstName; /** Last name of the payer. */ private final String lastName; /** Entity type of the payer, applicable only for bank-transfer payments (e.g. "individual", "association"). */ private final String entityType; /** Payer's address details. */ private PaymentPayerAddressRequest address; /** Payer's phone details. */ private PaymentPayerPhoneRequest phone; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentPaymentReferenceRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing a reference to a previous payment in a subscription series. * Used within transaction data to link the current payment to an earlier authorization. */ @Getter @Builder public class PaymentPaymentReferenceRequest { /** Identifier of the referenced previous payment. */ private String id; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentPointOfInteractionRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object describing the point of interaction where the payment was initiated. * Provides context about the channel, device, or integration from which the * payment originates (e.g. QR code, smart link, subscription). */ @Getter @Builder public class PaymentPointOfInteractionRequest { /** Identifier of the resource this payment is linked to. */ private final String linkedTo; /** Point-of-interaction type (e.g. "PSP_TRANSFER", "CHECKOUT"). */ private final String type; /** Point-of-interaction sub-type for more granular classification. */ private final String subType; /** Transaction data associated with the point of interaction. */ private final PaymentTransactionDataRequest transactionData; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentReceiverAddressRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object representing the receiver's address for a shipment associated with a payment. * Contains the full postal address where purchased goods will be delivered. */ @Getter @Builder public class PaymentReceiverAddressRequest { /** State or province name. */ private final String stateName; /** City name. */ private final String cityName; /** Floor number or identifier within a building. */ private final String floor; /** Apartment or unit number within a building. */ private final String apartment; /** Postal or ZIP code. */ private final String zipCode; /** Street name of the delivery address. */ private final String streetName; /** Street number of the delivery address. */ private final String streetNumber; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentRefundClient.java ================================================ package com.mercadopago.client.payment; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeFromJson; import static com.mercadopago.serialization.Serializer.deserializeListFromJson; import static com.mercadopago.serialization.Serializer.serializeToJson; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResponse; import com.mercadopago.resources.payment.PaymentRefund; import java.math.BigDecimal; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Payment Refunds API. * *

Provides operations to create total or partial refunds for a payment, retrieve a specific * refund by its identifier, and list all refunds associated with a payment. * *

This client is typically used internally by {@link PaymentClient}, but can also be * instantiated directly for standalone refund management. * * @see PaymentClient * @see * Payment Refunds API reference */ public class PaymentRefundClient extends MercadoPagoClient { /** Class-level logger for refund operations. */ private static final Logger LOGGER = Logger.getLogger(PaymentRefundClient.class.getName()); /** URL template for refund endpoints scoped to a payment (e.g. {@code /v1/payments/{id}/refunds}). */ private static final String URL_WITH_PAYMENT_ID = "/v1/payments/%s/refunds"; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public PaymentRefundClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code PaymentRefundClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public PaymentRefundClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Creates a total refund for a payment, returning the full amount to the payer. * * @param paymentId the unique identifier of the payment to refund * @return the created {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PaymentRefund refund(Long paymentId) throws MPException, MPApiException { return this.refund(paymentId, null, null); } /** * Creates a total refund for a payment with custom request options. * * @param paymentId the unique identifier of the payment to refund * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PaymentRefund refund(Long paymentId, MPRequestOptions requestOptions) throws MPException, MPApiException { return this.refund(paymentId, null, requestOptions); } /** * Creates a partial refund for a payment, returning the specified amount to the payer. * * @param paymentId the unique identifier of the payment to refund * @param amount the amount to refund; if {@code null}, a total refund is performed * @return the created {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PaymentRefund refund(Long paymentId, BigDecimal amount) throws MPException, MPApiException { return this.refund(paymentId, amount, null); } /** * Creates a total or partial refund for a payment with custom request options. * *

If {@code amount} is {@code null}, a total refund is performed. Otherwise, the specified * amount is refunded (partial refund). * * @param paymentId the unique identifier of the payment to refund * @param amount the amount to refund, or {@code null} for a total refund * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PaymentRefund refund(Long paymentId, BigDecimal amount, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending refund payment request"); PaymentRefundCreateRequest request = PaymentRefundCreateRequest.builder().amount(amount).build(); MPResponse response = send( String.format(URL_WITH_PAYMENT_ID, paymentId), HttpMethod.POST, serializeToJson(request), null, requestOptions); PaymentRefund result = deserializeFromJson(PaymentRefund.class, response.getContent()); result.setResponse(response); return result; } /** * Retrieves a specific refund by its identifier from a payment. * * @param paymentId the unique identifier of the payment * @param refundId the unique identifier of the refund to retrieve * @return the requested {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PaymentRefund get(Long paymentId, Long refundId) throws MPException, MPApiException { return this.get(paymentId, refundId, null); } /** * Retrieves a specific refund by its identifier from a payment with custom request options. * * @param paymentId the unique identifier of the payment * @param refundId the unique identifier of the refund to retrieve * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link PaymentRefund} with refund details * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PaymentRefund get(Long paymentId, Long refundId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get refund payment request"); MPResponse response = send( String.format("/v1/payments/%s/refunds/%s", paymentId, refundId), HttpMethod.GET, null, null, requestOptions); PaymentRefund result = deserializeFromJson(PaymentRefund.class, response.getContent()); result.setResponse(response); return result; } /** * Lists all refunds associated with a payment. * * @param paymentId the unique identifier of the payment * @return an {@link MPResourceList} of {@link PaymentRefund} for the given payment * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList list(Long paymentId) throws MPException, MPApiException { return this.list(paymentId, null); } /** * Lists all refunds associated with a payment with custom request options. * * @param paymentId the unique identifier of the payment * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResourceList} of {@link PaymentRefund} for the given payment * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList list(Long paymentId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending list refund payment request"); MPResponse response = send( String.format(URL_WITH_PAYMENT_ID, paymentId), HttpMethod.GET, null, null, requestOptions); MPResourceList result = deserializeListFromJson(PaymentRefund.class, response.getContent()); result.setResponse(response); return result; } } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentRefundCreateRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request object used to create a refund for an existing payment. * Allows specifying a partial or full refund amount. When the amount is * {@code null}, a full refund of the original payment is performed. */ @Getter @Builder public class PaymentRefundCreateRequest { /** Amount to be refunded. If {@code null}, the full payment amount is refunded. */ private final BigDecimal amount; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentRouteRequest.java ================================================ package com.mercadopago.client.payment; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Request object describing a travel route associated with a purchased item. * Used within the category descriptor to provide flight or trip details * that support fraud-prevention analysis for travel-related transactions. */ @Getter @Builder public class PaymentRouteRequest { /** Departure location (e.g. airport IATA code or city name). */ private final String departure; /** Destination location (e.g. airport IATA code or city name). */ private final String destination; /** Scheduled departure date and time. */ private final OffsetDateTime departureDateTime; /** Scheduled arrival date and time. */ private final OffsetDateTime arrivalDateTime; /** Name of the transportation company or airline. */ private final String company; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentRulesRequest.java ================================================ package com.mercadopago.client.payment; import java.util.List; import lombok.Builder; import lombok.Getter; /** * Request object defining the financial rules applied to a payment, such as * early-payment discounts, late-payment fines, and interest charges. * Typically used with boleto or other deferred payment methods. */ @Getter @Builder public class PaymentRulesRequest { /** List of discounts applicable to the payment (e.g. early-payment discounts). */ private List discounts; /** Fine configuration applied when the payment is made after the due date. */ private PaymentFeeRequest fine; /** Interest configuration applied when the payment is made after the due date. */ private PaymentFeeRequest interest; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentShipmentsRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing shipment information for a payment. * Provides delivery details such as the receiver's address and shipping * mode, which are used for fraud analysis and logistics processing. */ @Getter @Builder public class PaymentShipmentsRequest { /** Destination address where the shipment will be delivered. */ private final PaymentReceiverAddressRequest receiverAddress; /** Whether the product is picked up at the store instead of being shipped. */ private final boolean localPickup; /** Whether the shipment uses express (expedited) delivery. */ private final boolean expressShipment; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentSubscriptionSequenceRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object representing the sequence position of a subscription payment. * Tracks which payment in the subscription series this is and the total * number of planned payments. */ @Getter @Builder public class PaymentSubscriptionSequenceRequest { /** Current payment number in the subscription sequence (e.g. 3 of 12). */ private int number; /** Total number of payments planned in the subscription. */ private int total; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentTaxRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request object representing a tax applied to a payment. * Each tax has a type, a monetary value, and a flag indicating * whether the value represents a percentage or a fixed amount. */ @Getter @Builder public class PaymentTaxRequest { /** Tax type identifier (e.g. "IVA", "IPI"). */ private final String type; /** Tax value, either a fixed amount or a percentage depending on the {@code percentage} flag. */ private final BigDecimal value; /** Whether the value represents a percentage ({@code true}) or a fixed amount ({@code false}). */ private final Boolean percentage; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentTransactionDataRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing transaction data associated with the point of interaction. * Carries subscription and recurring-payment details such as sequence, billing * period, and payment references. */ @Getter @Builder public class PaymentTransactionDataRequest { /** Whether this is the first use of the payment credential for a subscription. */ private boolean firstTimeUse; /** Subscription sequence tracking the current and total number of payments. */ private PaymentSubscriptionSequenceRequest subscriptionSequence; /** Unique identifier of the subscription this payment belongs to. */ private String subscriptionId; /** Invoice period defining the billing cycle type and duration. */ private PaymentInvoicePeriodRequest invoicePeriod; /** Reference to a previous payment in the subscription series. */ private PaymentPaymentReferenceRequest paymentReference; /** Billing date for the current invoice period (e.g. "2023-01-15"). */ private String billingDate; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentTransactionDetailsRequest.java ================================================ package com.mercadopago.client.payment; import lombok.Builder; import lombok.Getter; /** * Request object containing additional transaction details for a payment. * Used to specify the financial institution involved in bank-transfer * or other institution-dependent payment methods. */ @Getter @Builder public class PaymentTransactionDetailsRequest { /** Identifier of the external financial institution processing the payment. */ private final String financialInstitution; } ================================================ FILE: src/main/java/com/mercadopago/client/payment/PaymentUserAmountRequest.java ================================================ package com.mercadopago.client.payment; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request object representing a user's amount details in a cross-currency payment. * Specifies the currency and transaction value from the perspective of * either the payer or the collector. */ @Getter @Builder public class PaymentUserAmountRequest { /** Currency identifier in ISO 4217 format (e.g. "USD", "BRL", "ARS"). */ private String currencyId; /** Transaction amount in the specified currency. */ private BigDecimal transaction; } ================================================ FILE: src/main/java/com/mercadopago/client/paymentmethod/PaymentMethodClient.java ================================================ package com.mercadopago.client.paymentmethod; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeListFromJson; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResponse; import com.mercadopago.resources.paymentmethod.PaymentMethod; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Payment Methods API. * *

Retrieves the list of payment methods available for the country associated with the * authenticated user's credentials (e.g., credit cards, debit cards, bank transfers, cash). * *

Usage example: *

{@code
 * PaymentMethodClient client = new PaymentMethodClient();
 * MPResourceList methods = client.list();
 * }
* * @see * Payment Methods API reference */ public class PaymentMethodClient extends MercadoPagoClient { /** Class-level logger for payment method operations. */ private static final Logger LOGGER = Logger.getLogger(PaymentMethodClient.class.getName()); /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public PaymentMethodClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code PaymentMethodClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public PaymentMethodClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Lists all available payment methods for the authenticated user's country. * * @return an {@link MPResourceList} of {@link PaymentMethod} (credit, debit, cash, etc.) * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList list() throws MPException, MPApiException { return this.list(null); } /** * Lists all available payment methods with custom request options. * * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResourceList} of {@link PaymentMethod} (credit, debit, cash, etc.) * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPResourceList list(MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending list payment method"); MPResponse response = list("/v1/payment_methods", HttpMethod.GET, null, null, requestOptions); MPResourceList paymentMethods = deserializeListFromJson(PaymentMethod.class, response.getContent()); paymentMethods.setResponse(response); return paymentMethods; } } ================================================ FILE: src/main/java/com/mercadopago/client/point/OperatingMode.java ================================================ package com.mercadopago.client.point; /** * Enum representing the operating modes available for a MercadoPago Point device. * * @see com.mercadopago.client.point.PointDeviceOperatingModeRequest */ public enum OperatingMode { /** Point of Sale mode, where the device is linked to a POS system. */ PDV, /** Standalone mode, where the device operates independently. */ STANDALONE } ================================================ FILE: src/main/java/com/mercadopago/client/point/PointClient.java ================================================ package com.mercadopago.client.point; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeFromJson; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.point.PointCancelPaymentIntent; import com.mercadopago.resources.point.PointDeviceOperatingMode; import com.mercadopago.resources.point.PointDevices; import com.mercadopago.resources.point.PointPaymentIntent; import com.mercadopago.resources.point.PointPaymentIntentList; import com.mercadopago.resources.point.PointSearchPaymentIntent; import com.mercadopago.resources.point.PointStatusPaymentIntent; import com.mercadopago.serialization.Serializer; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Point Integration API. * *

Provides operations for in-person payments via MercadoPago Point card readers, including * creating, searching, cancelling, and tracking payment intents, as well as managing Point * devices and their operating modes. * *

Usage example: *

{@code
 * PointClient client = new PointClient();
 * PointPaymentIntent intent = client.createPaymentIntent(deviceId, paymentIntentRequest);
 * PointStatusPaymentIntent status = client.getPaymentIntentStatus(intent.getId());
 * }
* * @see * Point Integration API reference */ public class PointClient extends MercadoPagoClient { /** Class-level logger for Point operations. */ private static final Logger LOGGER = Logger.getLogger(PointClient.class.getName()); /** URL template for creating payment intents on a specific device. */ private static final String PAYMENT_INTENT_URL = "/point/integration-api/devices/%s/payment-intents"; /** URL for listing payment intents with their final states. */ private static final String PAYMENT_INTENT_LIST_URL = "/point/integration-api/payment-intents/events"; /** URL template for cancelling a specific payment intent on a device. */ private static final String PAYMENT_INTENT_DELETE_URL = "point/integration-api/devices/%s/payment-intents/%s"; /** URL template for searching/retrieving a specific payment intent. */ private static final String PAYMENT_INTENT_SEARCH_URL = "point/integration-api/payment-intents/%s"; /** URL template for retrieving the last status event of a payment intent. */ private static final String PAYMENT_INTENT_STATUS_URL = "point/integration-api/payment-intents/%s/events"; /** URL for listing all Point devices. */ private static final String DEVICES_URL = "point/integration-api/devices"; /** URL template for operating on a specific device by its identifier. */ private static final String DEVICE_WITH_ID_URL = "point/integration-api/devices/%s"; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public PointClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code PointClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public PointClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Creates a payment intent on a specific Point device. * * @param deviceId the unique identifier of the Point device * @param request the {@link PointPaymentIntentRequest} with amount, description, and payment * details * @return the created {@link PointPaymentIntent} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointPaymentIntent createPaymentIntent(String deviceId, PointPaymentIntentRequest request) throws MPException, MPApiException { return this.createPaymentIntent(deviceId, request, null); } /** * Creates a payment intent on a specific Point device with custom request options. * * @param deviceId the unique identifier of the Point device * @param request the {@link PointPaymentIntentRequest} with amount, description, and payment * details * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link PointPaymentIntent} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointPaymentIntent createPaymentIntent( String deviceId, PointPaymentIntentRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create point payment intent request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(PAYMENT_INTENT_URL, deviceId)) .method(HttpMethod.POST) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); PointPaymentIntent result = deserializeFromJson(PointPaymentIntent.class, response.getContent()); result.setResponse(response); return result; } /** * Retrieves a list of payment intents with their final states within a date range. * * @param request the {@link PointPaymentIntentListRequest} with start and end date filters * @return a {@link PointPaymentIntentList} containing payment intents and their states * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointPaymentIntentList getPaymentIntentList(PointPaymentIntentListRequest request) throws MPException, MPApiException { return this.getPaymentIntentList(request, null); } /** * Retrieves a list of payment intents with their final states within a date range with custom * request options. * * @param request the {@link PointPaymentIntentListRequest} with start and end date filters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return a {@link PointPaymentIntentList} containing payment intents and their states * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointPaymentIntentList getPaymentIntentList( PointPaymentIntentListRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get point payment intent list request"); MPRequest mpRequest = MPRequest.builder() .uri(PAYMENT_INTENT_LIST_URL) .method(HttpMethod.GET) .queryParams(request.getParams()) .build(); MPResponse response = send(mpRequest, requestOptions); PointPaymentIntentList result = deserializeFromJson(PointPaymentIntentList.class, response.getContent()); result.setResponse(response); return result; } /** * Cancels a payment intent on a specific Point device. * * @param deviceId the unique identifier of the Point device * @param paymentIntentId the unique identifier of the payment intent to cancel * @return a {@link PointCancelPaymentIntent} containing the cancelled payment intent identifier * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointCancelPaymentIntent cancelPaymentIntent(String deviceId, String paymentIntentId) throws MPException, MPApiException { return this.cancelPaymentIntent(deviceId, paymentIntentId, null); } /** * Cancels a payment intent on a specific Point device with custom request options. * * @param deviceId the unique identifier of the Point device * @param paymentIntentId the unique identifier of the payment intent to cancel * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return a {@link PointCancelPaymentIntent} containing the cancelled payment intent identifier * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointCancelPaymentIntent cancelPaymentIntent( String deviceId, String paymentIntentId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending cancel point payment intent request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(PAYMENT_INTENT_DELETE_URL, deviceId, paymentIntentId)) .method(HttpMethod.DELETE) .build(); MPResponse response = send(mpRequest, requestOptions); PointCancelPaymentIntent result = deserializeFromJson(PointCancelPaymentIntent.class, response.getContent()); result.setResponse(response); return result; } /** * Retrieves a payment intent by its unique identifier. * * @param paymentIntentId the unique identifier of the payment intent * @return the requested {@link PointSearchPaymentIntent} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointSearchPaymentIntent searchPaymentIntent(String paymentIntentId) throws MPException, MPApiException { return this.searchPaymentIntent(paymentIntentId, null); } /** * Retrieves a payment intent by its unique identifier with custom request options. * * @param paymentIntentId the unique identifier of the payment intent * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link PointSearchPaymentIntent} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointSearchPaymentIntent searchPaymentIntent( String paymentIntentId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending search point payment intent request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(PAYMENT_INTENT_SEARCH_URL, paymentIntentId)) .method(HttpMethod.GET) .build(); MPResponse response = send(mpRequest, requestOptions); PointSearchPaymentIntent result = deserializeFromJson(PointSearchPaymentIntent.class, response.getContent()); result.setResponse(response); return result; } /** * Retrieves the last status event for a payment intent. * * @param paymentIntentId the unique identifier of the payment intent * @return the {@link PointStatusPaymentIntent} with the most recent status event * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointStatusPaymentIntent getPaymentIntentStatus(String paymentIntentId) throws MPException, MPApiException { return this.getPaymentIntentStatus(paymentIntentId, null); } /** * Retrieves the last status event for a payment intent with custom request options. * * @param paymentIntentId the unique identifier of the payment intent * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link PointStatusPaymentIntent} with the most recent status event * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointStatusPaymentIntent getPaymentIntentStatus( String paymentIntentId, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get point payment intent status request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(PAYMENT_INTENT_STATUS_URL, paymentIntentId)) .method(HttpMethod.GET) .build(); MPResponse response = send(mpRequest, requestOptions); PointStatusPaymentIntent result = deserializeFromJson(PointStatusPaymentIntent.class, response.getContent()); result.setResponse(response); return result; } /** * Retrieves Point devices, optionally filtered by POS and/or store. * * @param request the {@link MPSearchRequest} with optional POS or store filter parameters * @return the {@link PointDevices} containing the list of devices * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointDevices getDevices(MPSearchRequest request) throws MPException, MPApiException { return this.getDevices(request, null); } /** * Retrieves Point devices with custom request options, optionally filtered by POS and/or store. * * @param request the {@link MPSearchRequest} with optional POS or store filter parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the {@link PointDevices} containing the list of devices * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointDevices getDevices(MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get point devices request"); MPRequest mpRequest = MPRequest.builder() .uri(DEVICES_URL) .method(HttpMethod.GET) .queryParams(request.getParameters()) .build(); MPResponse response = send(mpRequest, requestOptions); PointDevices result = deserializeFromJson(PointDevices.class, response.getContent()); result.setResponse(response); return result; } /** * Changes the operating mode of a Point device (e.g., PDV or standalone). * * @param deviceId the unique identifier of the Point device * @param request the {@link PointDeviceOperatingModeRequest} with the desired operating mode * @return the updated {@link PointDeviceOperatingMode} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointDeviceOperatingMode changeDeviceOperatingMode( String deviceId, PointDeviceOperatingModeRequest request) throws MPException, MPApiException { return this.changeDeviceOperatingMode(deviceId, request, null); } /** * Changes the operating mode of a Point device with custom request options. * * @param deviceId the unique identifier of the Point device * @param request the {@link PointDeviceOperatingModeRequest} with the desired operating mode * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the updated {@link PointDeviceOperatingMode} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public PointDeviceOperatingMode changeDeviceOperatingMode( String deviceId, PointDeviceOperatingModeRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending change point device operating mode request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(DEVICE_WITH_ID_URL, deviceId)) .method(HttpMethod.PATCH) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); PointDeviceOperatingMode result = deserializeFromJson(PointDeviceOperatingMode.class, response.getContent()); result.setResponse(response); return result; } } ================================================ FILE: src/main/java/com/mercadopago/client/point/PointDeviceOperatingModeRequest.java ================================================ package com.mercadopago.client.point; import lombok.Builder; import lombok.Getter; /** * Request object to change the operating mode of a MercadoPago Point device. * * @see com.mercadopago.client.point.OperatingMode * @see com.mercadopago.client.point.PointClient */ @Getter @Builder public class PointDeviceOperatingModeRequest { /** Operating mode to set on the device (PDV or STANDALONE). */ private final OperatingMode operatingMode; } ================================================ FILE: src/main/java/com/mercadopago/client/point/PointPaymentIntentAdditionalInfoRequest.java ================================================ package com.mercadopago.client.point; import lombok.Builder; import lombok.Getter; /** * Additional information for a Point payment intent, including external references and printing * options. * * @see com.mercadopago.client.point.PointPaymentIntentRequest */ @Getter @Builder public class PointPaymentIntentAdditionalInfoRequest { /** Alphanumeric identifier from your application, returned in the Webhook notification. */ private final String externalReference; /** Whether to print the ticket on the Point device. */ private final Boolean printOnTerminal; /** Alphanumeric invoice or ticket number, printed on the device ticket. */ private final String ticketNumber; } ================================================ FILE: src/main/java/com/mercadopago/client/point/PointPaymentIntentListRequest.java ================================================ package com.mercadopago.client.point; import java.time.LocalDate; import java.util.HashMap; import java.util.Map; import lombok.Builder; import lombok.Getter; /** * Request object to filter the list of Point payment intents by date range. * * @see com.mercadopago.client.point.PointClient */ @Getter @Builder public class PointPaymentIntentListRequest { /** Start date for filtering payment intents. */ private final LocalDate startDate; /** End date for filtering payment intents. */ private final LocalDate endDate; /** * Method responsible for mapping data range. * * @return map with data range. */ public Map getParams() { Map params = new HashMap<>(); params.put("startDate", this.startDate); params.put("endDate", this.endDate); return params; } } ================================================ FILE: src/main/java/com/mercadopago/client/point/PointPaymentIntentPaymentRequest.java ================================================ package com.mercadopago.client.point; import lombok.Builder; import lombok.Getter; /** * Payment configuration for a Point payment intent, defining the payment type, installments and * cost allocation. * * @see com.mercadopago.client.point.PointPaymentIntentRequest */ @Getter @Builder public class PointPaymentIntentPaymentRequest { /** Number of installments (1-72). Only applicable when type is {@code credit_card}. */ private final Integer installments; /** Payment type: {@code credit_card}, {@code debit_card}, or {@code voucher_card}. */ private final String type; /** Who pays the installment cost ({@code seller} or {@code buyer}). Only for credit cards. */ private final String installmentsCost; /** Voucher brand ({@code sodexo} or {@code alelo}). Only when type is {@code voucher_card}. */ private final String voucherType; } ================================================ FILE: src/main/java/com/mercadopago/client/point/PointPaymentIntentRequest.java ================================================ package com.mercadopago.client.point; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Request object to create a payment intent on a MercadoPago Point device. * * @see com.mercadopago.client.point.PointPaymentIntentPaymentRequest * @see com.mercadopago.client.point.PointPaymentIntentAdditionalInfoRequest * @see com.mercadopago.client.point.PointClient */ @Getter @Builder public class PointPaymentIntentRequest { /** Positive amount to charge for this payment intent. */ private final BigDecimal amount; /** Description displayed for this payment intent. */ private final String description; /** Payment configuration including type and installments. */ private final PointPaymentIntentPaymentRequest payment; /** Additional information such as external references and printing options. */ private final PointPaymentIntentAdditionalInfoRequest additionalInfo; } ================================================ FILE: src/main/java/com/mercadopago/client/preapproval/PreApprovalAutoRecurringCreateRequest.java ================================================ package com.mercadopago.client.preapproval; import java.math.BigDecimal; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Auto-recurring billing configuration used when creating a preapproval (subscription). Defines * the currency, amount, frequency, and date range for recurring charges. * * @see com.mercadopago.client.preapproval.PreapprovalCreateRequest */ @Getter @Builder public class PreApprovalAutoRecurringCreateRequest { /** Currency identifier (e.g., ARS, BRL, MXN). */ private final String currencyId; /** Amount charged on each recurring cycle. */ private final BigDecimal transactionAmount; /** Number of time units between each charge. */ private final Integer frequency; /** Time unit for the frequency ({@code days} or {@code months}). */ private final String frequencyType; /** Date when the recurring billing starts. */ private final OffsetDateTime startDate; /** Date when the recurring billing ends. */ private final OffsetDateTime endDate; } ================================================ FILE: src/main/java/com/mercadopago/client/preapproval/PreApprovalAutoRecurringUpdateRequest.java ================================================ package com.mercadopago.client.preapproval; import java.math.BigDecimal; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Auto-recurring billing configuration used when updating an existing preapproval (subscription). * Allows modification of the amount and date range for recurring charges. * * @see com.mercadopago.client.preapproval.PreapprovalUpdateRequest */ @Getter @Builder public class PreApprovalAutoRecurringUpdateRequest { /** Updated amount charged on each recurring cycle. */ private final BigDecimal transactionAmount; /** Updated date when the recurring billing starts. */ private final OffsetDateTime startDate; /** Updated date when the recurring billing ends. */ private final OffsetDateTime endDate; } ================================================ FILE: src/main/java/com/mercadopago/client/preapproval/PreapprovalClient.java ================================================ package com.mercadopago.client.preapproval; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeFromJson; import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; import static com.mercadopago.serialization.Serializer.serializeToJson; import com.google.gson.reflect.TypeToken; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.preapproval.Preapproval; import java.lang.reflect.Type; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Subscriptions (Preapproval) API. * *

Provides operations to create, retrieve, update, and search preapprovals (subscriptions). * A preapproval authorises recurring charges against a payer's payment method over a defined * billing period. * *

Usage example: *

{@code
 * PreapprovalClient client = new PreapprovalClient();
 * Preapproval subscription = client.create(preapprovalCreateRequest);
 * Preapproval updated = client.update(subscription.getId(), preapprovalUpdateRequest);
 * }
* * @see * Subscriptions API reference */ public class PreapprovalClient extends MercadoPagoClient { /** Class-level logger for preapproval/subscription operations. */ private static final Logger LOGGER = Logger.getLogger(PreapprovalClient.class.getName()); /** URL template for single-preapproval endpoints (e.g. {@code /preapproval/{id}}). */ private static final String URL_WITH_ID = "/preapproval/%s"; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public PreapprovalClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code PreapprovalClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public PreapprovalClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves a preapproval (subscription) by its unique identifier. * * @param id the unique identifier of the preapproval * @return the requested {@link Preapproval} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Preapproval get(String id) throws MPException, MPApiException { return this.get(id, null); } /** * Retrieves a preapproval (subscription) by its unique identifier with custom request options. * * @param id the unique identifier of the preapproval * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link Preapproval} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Preapproval get(String id, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get preapproval request"); MPResponse response = send(String.format(URL_WITH_ID, id), HttpMethod.GET, null, null, requestOptions); Preapproval result = deserializeFromJson(Preapproval.class, response.getContent()); result.setResponse(response); return result; } /** * Creates a new preapproval (subscription). * * @param request the {@link PreapprovalCreateRequest} with subscription details (reason, amount, * frequency, etc.) * @return the created {@link Preapproval} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Preapproval create(PreapprovalCreateRequest request) throws MPException, MPApiException { return this.create(request, null); } /** * Creates a new preapproval (subscription) with custom request options. * * @param request the {@link PreapprovalCreateRequest} with subscription details (reason, amount, * frequency, etc.) * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link Preapproval} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Preapproval create(PreapprovalCreateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create preapproval request"); MPResponse response = send("/preapproval", HttpMethod.POST, serializeToJson(request), null, requestOptions); Preapproval result = deserializeFromJson(Preapproval.class, response.getContent()); result.setResponse(response); return result; } /** * Updates an existing preapproval (subscription). * * @param id the unique identifier of the preapproval to update * @param request the {@link PreapprovalUpdateRequest} with the updated subscription attributes * @return the updated {@link Preapproval} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Preapproval update(String id, PreapprovalUpdateRequest request) throws MPException, MPApiException { return this.update(id, request, null); } /** * Updates an existing preapproval (subscription) with custom request options. * * @param id the unique identifier of the preapproval to update * @param request the {@link PreapprovalUpdateRequest} with the updated subscription attributes * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the updated {@link Preapproval} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public Preapproval update( String id, PreapprovalUpdateRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending update preapproval request"); MPResponse response = send( String.format(URL_WITH_ID, id), HttpMethod.PUT, serializeToJson(request), null, requestOptions); Preapproval result = deserializeFromJson(Preapproval.class, response.getContent()); result.setResponse(response); return result; } /** * Searches for preapprovals (subscriptions) matching the specified criteria. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @return an {@link MPResultsResourcesPage} of {@link Preapproval} with matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResultsResourcesPage search(MPSearchRequest request) throws MPException, MPApiException { return this.search(request, null); } /** * Searches for preapprovals (subscriptions) matching the specified criteria with custom request * options. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPResultsResourcesPage} of {@link Preapproval} with matching results and * pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public MPResultsResourcesPage search( MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending search preapproval request"); MPResponse response = search("/preapproval/search", request, requestOptions); Type responseType = new TypeToken>() {}.getType(); MPResultsResourcesPage result = deserializeResultsResourcesPageFromJson(responseType, response.getContent()); result.setResponse(response); return result; } } ================================================ FILE: src/main/java/com/mercadopago/client/preapproval/PreapprovalCreateRequest.java ================================================ package com.mercadopago.client.preapproval; import lombok.Builder; import lombok.Getter; /** * Request object to create a new preapproval (subscription) in MercadoPago. Contains payer * details, seller information, and auto-recurring billing configuration. * * @see com.mercadopago.client.preapproval.PreApprovalAutoRecurringCreateRequest * @see com.mercadopago.client.preapproval.PreapprovalClient */ @Getter @Builder public class PreapprovalCreateRequest { /** Email address of the payer (subscriber). */ private final String payerEmail; /** URL to redirect the user after the preapproval flow. */ private final String backUrl; /** Unique identifier of the seller (collector). */ private final String collectorId; /** Title or reason describing the subscription. */ private final String reason; /** External reference to synchronize with your system. */ private final String externalReference; /** Initial status of the preapproval. */ private final String status; /** Auto-recurring billing configuration for the subscription. */ private final PreApprovalAutoRecurringCreateRequest autoRecurring; } ================================================ FILE: src/main/java/com/mercadopago/client/preapproval/PreapprovalUpdateRequest.java ================================================ package com.mercadopago.client.preapproval; import lombok.Builder; import lombok.Getter; /** * Request object to update an existing preapproval (subscription) in MercadoPago. Allows * modification of the return URL, reason, status, and recurring billing configuration. * * @see com.mercadopago.client.preapproval.PreApprovalAutoRecurringUpdateRequest * @see com.mercadopago.client.preapproval.PreapprovalClient */ @Getter @Builder public class PreapprovalUpdateRequest { /** Updated URL to redirect the user after the preapproval flow. */ private final String backUrl; /** Updated title or reason describing the subscription. */ private final String reason; /** Updated external reference to synchronize with your system. */ private final String externalReference; /** Updated status of the preapproval. */ private final String status; /** Updated auto-recurring billing configuration for the subscription. */ private final PreApprovalAutoRecurringUpdateRequest autoRecurring; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceAmountsRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Amount breakdown for a checkout preference, specifying payer and collector amounts along with * optional counter-currency details. * * @see com.mercadopago.client.preference.PreferenceRequest */ @Getter @Builder public class PreferenceAmountsRequest { /** Counter-currency conversion details. */ private PreferenceCounterCurrencyRequest counterCurrency; /** Amount information from the payer's perspective. */ private PreferenceUserAmountRequest payer; /** Amount information from the collector's perspective. */ private PreferenceUserAmountRequest collector; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceBackUrlsRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Callback URLs that the buyer is redirected to after the checkout flow, depending on the payment * outcome. * * @see com.mercadopago.client.preference.PreferenceRequest */ @Getter @Builder public class PreferenceBackUrlsRequest { /** URL to redirect the buyer to when the payment succeeds. */ private final String success; /** URL to redirect the buyer to when the payment is pending. */ private final String pending; /** URL to redirect the buyer to when the payment fails. */ private final String failure; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceCategoryDescriptorRequest.java ================================================ package com.mercadopago.client.preference; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Category-specific descriptor for a preference item, providing additional details such as * passenger data, route information, and event dates (e.g., for travel or event tickets). * * @see com.mercadopago.client.preference.PreferenceItemRequest */ @Getter @Builder public class PreferenceCategoryDescriptorRequest { /** Passenger details associated with the item. */ private final PreferencePassengerRequest passenger; /** Route or flight details associated with the item. */ private final PreferenceRouteRequest route; /** Date of the event related to the item. */ private final OffsetDateTime eventDate; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceClient.java ================================================ package com.mercadopago.client.preference; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.serialization.Serializer.deserializeElementsResourcesPageFromJson; import static com.mercadopago.serialization.Serializer.deserializeFromJson; import com.google.gson.reflect.TypeToken; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.preference.Preference; import com.mercadopago.resources.preference.PreferenceSearch; import com.mercadopago.serialization.Serializer; import java.lang.reflect.Type; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Checkout Preferences API. * *

Provides operations to create, retrieve, update, and search checkout preferences. A * preference defines the payment experience for the buyer, including items, payment methods, * redirect URLs, and expiration settings. * *

Usage example: *

{@code
 * PreferenceClient client = new PreferenceClient();
 * Preference preference = client.create(preferenceRequest);
 * String initPoint = preference.getInitPoint();
 * }
* * @see * Checkout Preferences API reference */ public class PreferenceClient extends MercadoPagoClient { /** Class-level logger for preference operations. */ private static final Logger LOGGER = Logger.getLogger(PreferenceClient.class.getName()); /** URL template for single-preference endpoints (e.g. {@code /checkout/preferences/{id}}). */ private static final String URL_WITH_ID = "/checkout/preferences/%s"; /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public PreferenceClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code PreferenceClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public PreferenceClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves a checkout preference by its unique identifier. * * @param id the unique identifier of the preference * @return the requested {@link Preference} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Preference get(String id) throws MPException, MPApiException { return this.get(id, null); } /** * Retrieves a checkout preference by its unique identifier with custom request options. * * @param id the unique identifier of the preference * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the requested {@link Preference} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Preference get(String id, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get preference request"); MPResponse response = send(String.format(URL_WITH_ID, id), HttpMethod.GET, null, null, requestOptions); Preference result = deserializeFromJson(Preference.class, response.getContent()); result.setResponse(response); return result; } /** * Creates a new checkout preference. * * @param request the {@link PreferenceRequest} with items, payer info, payment methods, and * other preference attributes * @return the created {@link Preference} including its {@code initPoint} URL * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Preference create(PreferenceRequest request) throws MPException, MPApiException { return this.create(request, null); } /** * Creates a new checkout preference with custom request options. * * @param request the {@link PreferenceRequest} with items, payer info, payment methods, and * other preference attributes * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the created {@link Preference} including its {@code initPoint} URL * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Preference create(PreferenceRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending create preference request"); MPRequest mpRequest = MPRequest.builder() .uri("/checkout/preferences") .method(HttpMethod.POST) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); Preference result = deserializeFromJson(Preference.class, response.getContent()); result.setResponse(response); return result; } /** * Updates an existing checkout preference. * * @param id the unique identifier of the preference to update * @param request the {@link PreferenceRequest} with the updated preference attributes * @return the updated {@link Preference} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Preference update(String id, PreferenceRequest request) throws MPException, MPApiException { return this.update(id, request, null); } /** * Updates an existing checkout preference with custom request options. * * @param id the unique identifier of the preference to update * @param request the {@link PreferenceRequest} with the updated preference attributes * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the updated {@link Preference} * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public Preference update(String id, PreferenceRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending update preference request"); MPRequest mpRequest = MPRequest.builder() .uri(String.format(URL_WITH_ID, id)) .method(HttpMethod.PUT) .payload(Serializer.serializeToJson(request)) .build(); MPResponse response = send(mpRequest, requestOptions); Preference result = deserializeFromJson(Preference.class, response.getContent()); result.setResponse(response); return result; } /** * Searches for checkout preferences matching the specified criteria. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @return an {@link MPElementsResourcesPage} of {@link PreferenceSearch} with matching results * and pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPElementsResourcesPage search(MPSearchRequest request) throws MPException, MPApiException { return this.search(request, null); } /** * Searches for checkout preferences matching the specified criteria with custom request options. * * @param request the {@link MPSearchRequest} containing search filters and pagination parameters * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return an {@link MPElementsResourcesPage} of {@link PreferenceSearch} with matching results * and pagination metadata * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code * @see api * docs */ public MPElementsResourcesPage search( MPSearchRequest request, MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending search preference request"); MPResponse response = search("/checkout/preferences/search", request, requestOptions); Type responseType = new TypeToken>() {}.getType(); MPElementsResourcesPage result = deserializeElementsResourcesPageFromJson(responseType, response.getContent()); result.setResponse(response); return result; } } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceCounterCurrencyRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Counter-currency configuration for a checkout preference, used for cross-currency transactions. * * @see com.mercadopago.client.preference.PreferenceRequest */ @Getter @Builder public class PreferenceCounterCurrencyRequest { /** Currency identifier in ISO 4217 format (e.g., USD, BRL). */ private String currencyId; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceDifferentialPricingRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Differential pricing configuration for a checkout preference, allowing specific pricing rules * per buyer segment. * * @see com.mercadopago.client.preference.PreferenceRequest */ @Getter @Builder public class PreferenceDifferentialPricingRequest { /** Identifier of the differential pricing rule to apply. */ private final Long id; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceFreeMethodRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Shipping method offered as free shipping within a checkout preference (applicable in * {@code me2} mode only). * * @see com.mercadopago.client.preference.PreferenceShipmentsRequest */ @Getter @Builder public class PreferenceFreeMethodRequest { /** Identifier of the shipping method to offer for free. */ private final Long id; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceItemRequest.java ================================================ package com.mercadopago.client.preference; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Represents an item to be purchased within a checkout preference. Each item includes pricing, * quantity, and optional category and warranty details. * * @see com.mercadopago.client.preference.PreferenceRequest * @see com.mercadopago.client.preference.PreferenceCategoryDescriptorRequest */ @Getter @Builder public class PreferenceItemRequest { /** Unique item identifier or code in your system. */ private final String id; /** Display name of the item. */ private final String title; /** Type classification of the item. */ private final String type; /** Detailed description of the item. */ private final String description; /** URL of the item's image. */ private final String pictureUrl; /** Category identifier for the item. */ private final String categoryId; /** Currency identifier in ISO 4217 format (e.g., ARS, BRL). */ private final String currencyId; /** Number of units of this item. */ private final Integer quantity; /** Price per unit of the item. */ private final BigDecimal unitPrice; /** Category-specific descriptor with additional item metadata. */ private final PreferenceCategoryDescriptorRequest categoryDescriptor; /** Whether the item includes a warranty. */ private final boolean warranty; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferencePassengerRequest.java ================================================ package com.mercadopago.client.preference; import com.mercadopago.client.common.IdentificationRequest; import lombok.Builder; import lombok.Getter; /** * Passenger information associated with a travel-related preference item, including name and * identification details. * * @see com.mercadopago.client.preference.PreferenceCategoryDescriptorRequest */ @Getter @Builder public class PreferencePassengerRequest { /** Passenger's first name. */ private final String firstName; /** Passenger's last name. */ private final String lastName; /** Passenger's identification document details. */ private final IdentificationRequest identification; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferencePayerRequest.java ================================================ package com.mercadopago.client.preference; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import java.time.OffsetDateTime; import java.util.Date; import lombok.Builder; import lombok.Getter; /** * Payer (buyer) information for a checkout preference, including personal details, contact * information, and purchase history indicators used for fraud prevention. * * @see com.mercadopago.client.preference.PreferenceRequest */ @Getter @Builder public class PreferencePayerRequest { /** Payer's first name. */ private final String name; /** Payer's last name. */ private final String surname; /** Payer's email address. */ private final String email; /** Payer's phone contact information. */ private final PhoneRequest phone; /** Payer's identification document details. */ private final IdentificationRequest identification; /** Payer's address information. */ private final AddressRequest address; /** Date when the payer's account was created. */ private final OffsetDateTime dateCreated; /** Authentication type used by the payer (e.g., Gmail, Facebook, native). */ private final String authenticationType; /** Whether the payer has a prime/loyalty membership. */ private final boolean isPrimeUser; /** Whether this is the payer's first online purchase. */ private final boolean isFirstPurchaseOnline; /** Date when the payer registered on the platform. */ private final OffsetDateTime registrationDate; /** Date of the payer's most recent purchase. */ private final OffsetDateTime lastPurchase; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferencePaymentMethodRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Identifies a specific payment method to include or exclude from the checkout preference. * * @see com.mercadopago.client.preference.PreferencePaymentMethodsRequest */ @Getter @Builder public class PreferencePaymentMethodRequest { /** Unique identifier of the payment method (e.g., visa, master, amex). */ private final String id; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferencePaymentMethodsRequest.java ================================================ package com.mercadopago.client.preference; import java.util.List; import lombok.Builder; import lombok.Getter; /** * Configuration of allowed and excluded payment methods and types for a checkout preference, * including installment settings. * * @see com.mercadopago.client.preference.PreferenceRequest * @see com.mercadopago.client.preference.PreferencePaymentMethodRequest * @see com.mercadopago.client.preference.PreferencePaymentTypeRequest */ @Getter @Builder public class PreferencePaymentMethodsRequest { /** Payment methods excluded from the checkout (except account_money). */ private final List excludedPaymentMethods; /** Payment types excluded from the checkout. */ private final List excludedPaymentTypes; /** Identifier of the payment method to pre-select in the checkout. */ private final String defaultPaymentMethodId; /** Maximum number of credit card installments allowed. */ private final Integer installments; /** Default number of credit card installments pre-selected. */ private final Integer defaultInstallments; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferencePaymentTypeRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Identifies a specific payment type to include or exclude from the checkout preference. * * @see com.mercadopago.client.preference.PreferencePaymentMethodsRequest */ @Getter @Builder public class PreferencePaymentTypeRequest { /** Unique identifier of the payment type (e.g., credit_card, ticket, bank_transfer). */ private final String id; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceReceiverAddressRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Receiver's shipping address for a checkout preference, used to specify where the purchased items * should be delivered. * * @see com.mercadopago.client.preference.PreferenceShipmentsRequest */ @Getter @Builder public class PreferenceReceiverAddressRequest { /** Postal or ZIP code of the address. */ private final String zipCode; /** Street name of the address. */ private final String streetName; /** Street number of the address. */ private final String streetNumber; /** Country name of the address. */ private final String countryName; /** State or province name. */ private final String stateName; /** Floor number or identifier. */ private final String floor; /** Apartment number or identifier. */ private final String apartment; /** City name of the address. */ private final String cityName; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceRequest.java ================================================ package com.mercadopago.client.preference; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import lombok.Builder; import lombok.Getter; /** * Main request object to create or update a MercadoPago checkout preference. Aggregates all * checkout configuration including items, payer details, payment methods, shipping, tracking, * and expiration settings. * * @see com.mercadopago.client.preference.PreferenceClient * @see com.mercadopago.client.preference.PreferenceItemRequest * @see com.mercadopago.client.preference.PreferencePayerRequest */ @Getter @Builder public class PreferenceRequest { /** Free-text additional information attached to the preference. */ private final String additionalInfo; /** Auto-return mode that redirects buyers back to your site after completing the purchase. */ private final String autoReturn; /** Callback URLs for success, pending, and failure payment outcomes. */ private final PreferenceBackUrlsRequest backUrls; /** When true, payments can only be approved or rejected (no in_process status). */ private final Boolean binaryMode; /** Expiration date for cash-based payment methods. */ private final OffsetDateTime dateOfExpiration; /** Differential pricing rule applied to this preference. */ private final PreferenceDifferentialPricingRequest differentialPricing; /** Date from which the preference becomes active. */ private final OffsetDateTime expirationDateFrom; /** Date when the preference expires and is no longer usable. */ private final OffsetDateTime expirationDateTo; /** Whether this preference has an expiration date. */ private final Boolean expires; /** External reference to synchronize with your payment system. */ private final String externalReference; /** List of items included in the checkout. */ private final List items; /** Origin of the payment. Defaults to NONE. */ private final String marketplace; /** Fee charged by the marketplace application owner. */ private final BigDecimal marketplaceFee; /** Custom key-value metadata attached to the preference for merchant use. */ private final Map metadata; /** URL to receive payment status webhook notifications. */ private final String notificationUrl; /** Type of operation for this preference. */ private final String operationType; /** Buyer (payer) information for the checkout. */ private final PreferencePayerRequest payer; /** Payment method configuration including exclusions and installment settings. */ private final PreferencePaymentMethodsRequest paymentMethods; /** Processing modes to use (e.g., aggregator, gateway). */ private final List processingModes; /** Purpose of the preference (e.g., wallet_purchase). */ private final String purpose; /** Shipping configuration for the checkout. */ private final PreferenceShipmentsRequest shipments; /** Text that appears on the buyer's credit card statement. */ private final String statementDescriptor; /** Tax items applied to this preference. */ private final List taxes; /** Tracking tags executed during the buyer's checkout interaction. */ private final List tracks; /** Amount breakdown with payer and collector details. */ private final PreferenceAmountsRequest amounts; /** Counter-currency configuration for cross-currency transactions. */ private final PreferenceCounterCurrencyRequest counterCurrency; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceRouteRequest.java ================================================ package com.mercadopago.client.preference; import java.time.OffsetDateTime; import lombok.Builder; import lombok.Getter; /** * Flight or route information associated with a travel-related preference item, including origin, * destination, schedule, and carrier details. * * @see com.mercadopago.client.preference.PreferenceCategoryDescriptorRequest */ @Getter @Builder public class PreferenceRouteRequest { /** Departure location (airport code or city). */ private final String departure; /** Destination location (airport code or city). */ private final String destination; /** Scheduled departure date and time. */ private final OffsetDateTime departureDateTime; /** Scheduled arrival date and time. */ private final OffsetDateTime arrivalDateTime; /** Name of the airline or transport company. */ private final String company; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceShipmentsRequest.java ================================================ package com.mercadopago.client.preference; import java.math.BigDecimal; import java.util.List; import lombok.Builder; import lombok.Getter; /** * Shipping configuration for a checkout preference, supporting MercadoEnvios ({@code me2}), * custom, and express shipment modes. * * @see com.mercadopago.client.preference.PreferenceRequest * @see com.mercadopago.client.preference.PreferenceReceiverAddressRequest */ @Getter @Builder public class PreferenceShipmentsRequest { /** Shipment mode (e.g., {@code custom}, {@code me2}, {@code not_specified}). */ private final String mode; /** Whether the buyer can pick up the shipment at the seller's store ({@code me2} mode only). */ private final Boolean localPickup; /** Package dimensions in format {@code cm x cm x cm, gr} ({@code me2} mode only). */ private final String dimensions; /** Default shipping method pre-selected in checkout ({@code me2} mode only). */ private final String defaultShippingMethod; /** Shipping methods offered for free ({@code me2} mode only). */ private final List freeMethods; /** Fixed shipment cost ({@code custom} mode only). */ private final BigDecimal cost; /** Whether shipping is free ({@code custom} mode only). */ private final Boolean freeShipping; /** Receiver's delivery address. */ private final PreferenceReceiverAddressRequest receiverAddress; /** Whether to use express shipment. */ private final Boolean expressShipment; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceTaxRequest.java ================================================ package com.mercadopago.client.preference; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Tax item applied to a checkout preference, specifying the tax type and its monetary value. * * @see com.mercadopago.client.preference.PreferenceRequest */ @Getter @Builder public class PreferenceTaxRequest { /** Type of tax (e.g., IVA, INC). */ private final String type; /** Monetary value of the tax. */ private final BigDecimal value; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceTrackRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Advertising or analytics tracking tag to execute during the buyer's interaction in the * checkout flow. * * @see com.mercadopago.client.preference.PreferenceRequest * @see com.mercadopago.client.preference.PreferenceTrackValuesRequest */ @Getter @Builder public class PreferenceTrackRequest { /** Track type ({@code google_ad} or {@code facebook_ad}). */ private final String type; /** Tracking parameter values specific to the track type. */ private final PreferenceTrackValuesRequest values; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceTrackValuesRequest.java ================================================ package com.mercadopago.client.preference; import lombok.Builder; import lombok.Getter; /** * Tracking parameter values for advertising conversion tags used during the checkout flow. * Supports Google Ads and Facebook Pixel identifiers. * * @see com.mercadopago.client.preference.PreferenceTrackRequest */ @Getter @Builder public class PreferenceTrackValuesRequest { /** Conversion ID for Google Ads (GTM) conversion tracking. */ private final String conversionId; /** Conversion label for Google Ads (GTM) conversion tracking. */ private final String conversionLabel; /** Pixel ID for Facebook Pixel tracking. */ private final String pixelId; } ================================================ FILE: src/main/java/com/mercadopago/client/preference/PreferenceUserAmountRequest.java ================================================ package com.mercadopago.client.preference; import java.math.BigDecimal; import lombok.Builder; import lombok.Getter; /** * Amount details for a specific user (payer or collector) in a checkout preference, including * the currency and transaction value. * * @see com.mercadopago.client.preference.PreferenceAmountsRequest */ @Getter @Builder public class PreferenceUserAmountRequest { /** Currency identifier in ISO 4217 format (e.g., ARS, BRL). */ private String currencyId; /** Transaction amount for this user. */ private BigDecimal transaction; } ================================================ FILE: src/main/java/com/mercadopago/client/user/UserClient.java ================================================ package com.mercadopago.client.user; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPResponse; import com.mercadopago.resources.user.User; import com.mercadopago.serialization.Serializer; import java.util.logging.Logger; import java.util.logging.StreamHandler; /** * Client for the MercadoPago Users API. * *

Retrieves information about the authenticated MercadoPago user, including country, site, * and account details. This client is used internally by {@link * com.mercadopago.client.oauth.OauthClient} to build country-specific authorization URLs. * *

Usage example: *

{@code
 * UserClient client = new UserClient();
 * User user = client.get();
 * String country = user.getCountryId();
 * }
*/ public class UserClient extends MercadoPagoClient { /** Class-level logger for user operations. */ private static final Logger LOGGER = Logger.getLogger(UserClient.class.getName()); /** * Default constructor. Uses the default HTTP client provided by {@link MercadoPagoConfig}. */ public UserClient() { this(MercadoPagoConfig.getHttpClient()); } /** * Constructs a {@code UserClient} with a custom HTTP client. * * @param httpClient the {@link MPHttpClient} implementation used to execute HTTP requests */ public UserClient(MPHttpClient httpClient) { super(httpClient); StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); } /** * Retrieves information about the currently authenticated user. * * @return the authenticated {@link User} with account details and country information * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public User get() throws MPException, MPApiException { return this.get(null); } /** * Retrieves information about the currently authenticated user with custom request options. * * @param requestOptions optional {@link MPRequestOptions} to override access token, headers, or * timeouts for this single request; may be {@code null} * @return the authenticated {@link User} with account details and country information * @throws MPException if a transport-level or SDK-internal error occurs * @throws MPApiException if the API returns a non-successful HTTP status code */ public User get(MPRequestOptions requestOptions) throws MPException, MPApiException { LOGGER.info("Sending get user request"); MPResponse response = send("/users/me", HttpMethod.GET, null, null, requestOptions); User user = Serializer.deserializeFromJson(User.class, response.getContent()); user.setResponse(response); return user; } } ================================================ FILE: src/main/java/com/mercadopago/core/MPRequestOptions.java ================================================ package com.mercadopago.core; import java.util.Map; import lombok.Builder; import lombok.Data; /** * Per-request configuration overrides for MercadoPago API calls. * *

Instances of this class allow callers to override global settings defined in * {@link com.mercadopago.MercadoPagoConfig} on a request-by-request basis. Any field * left at its default value ({@code null} for objects, {@code 0} for primitives) will * fall back to the corresponding global configuration value at execution time. * *

Use the Lombok-generated builder for fluent construction: *

{@code
 * MPRequestOptions options = MPRequestOptions.builder()
 *     .accessToken("APP_USR-...")
 *     .connectionTimeout(5000)
 *     .customHeaders(Map.of("X-Idempotency-Key", uuid))
 *     .build();
 * }
* * @see com.mercadopago.MercadoPagoConfig */ @Data @Builder public class MPRequestOptions { /** OAuth access token for this specific request, overriding the global token when set. */ private String accessToken; /** HTTP connection timeout in milliseconds for this request. A value of {@code 0} uses the global default. */ private int connectionTimeout; /** Timeout in milliseconds for obtaining a connection from the pool. A value of {@code 0} uses the global default. */ private int connectionRequestTimeout; /** Socket (read) timeout in milliseconds for this request. A value of {@code 0} uses the global default. */ private int socketTimeout; /** Additional HTTP headers to include in this request (e.g., idempotency keys, custom tracing headers). */ private Map customHeaders; /** * Creates a default {@link MPRequestOptions} with all fields at their zero/null defaults, * meaning every setting will fall back to the global {@link com.mercadopago.MercadoPagoConfig}. * * @return a new {@link MPRequestOptions} instance with no overrides */ public static MPRequestOptions createDefault() { return MPRequestOptions.builder().build(); } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CancelOrder.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.OrderClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.order.Order; import java.util.HashMap; import java.util.Map; /** * Mercado Pago Cancel Order. * * @see Documentation. */ public class CancelOrder { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN"); OrderClient client = new OrderClient(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { Order order = client.cancel("{{ORDER_ID}}", requestOptions); System.out.println("Canceled order: " + order.getId()); System.out.println("Status: " + order.getStatus()); } catch (MPException | MPApiException e) { System.out.println("Error canceling order: " + e.getMessage()); System.out.println("Cause: " + e.getCause()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CaptureOrder.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.resources.order.Order; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Mercado Pago Capture Order. * * @see Documentation */ public class CaptureOrder { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); System.out.println("Initializing OrderClient..."); OrderClient client = new OrderClient(); System.out.println("Creating OrderPaymentRequest..."); OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("1000.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("{{CARD_TOKEN}}") .installments(1) .statementDescriptor("statement") .build()) .build(); List payments = new ArrayList<>(); payments.add(payment); OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .processingMode("automatic") .captureMode("automatic_async") .totalAmount("1000.00") .externalReference("ext_ref") .payer(OrderPayerRequest.builder().email("{{PAYER_EMAIL}}").build()) .transactions(OrderTransactionRequest.builder() .payments(payments) .build()) .build(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { Order order = client.create(request, requestOptions); System.out.println("Order created: " + order.getId()); System.out.println("Order status: " + order.getStatus()); System.out.println("Order status detail: " + order.getStatusDetail()); // Capture Order Order capturedOrder = client.capture(order.getId(), requestOptions); System.out.println("Captured order: " + capturedOrder.getId()); System.out.println("Captured order status: " + capturedOrder.getStatus()); System.out.println("Captured order status detail: " + capturedOrder.getStatusDetail()); } catch (Exception e) { System.out.println("Error creating order: " + e.getMessage()); System.out.println("Cause: " + e.getCause()); System.out.println("Stack Trace: " + e.getStackTrace()); System.out.println("Error cause: " + e.getCause()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CreateOrder.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.resources.order.Order; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Mercado Pago Create Order transaction. * * @see Documentation. */ public class CreateOrder { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); System.out.println("Initializing OrderClient..."); OrderClient client = new OrderClient(); System.out.println("Creating OrderPaymentRequest..."); OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("{{card_token}}") .installments(1) .statementDescriptor("statement") .build()) .build(); System.out.println("Adding payment details:"); System.out.println("Payment Amount: " + payment.getAmount()); System.out.println("Payment Method ID: " + payment.getPaymentMethod().getId()); List payments = new ArrayList<>(); payments.add(payment); System.out.println("Creating OrderCreateRequest..."); OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .processingMode("automatic") .totalAmount("100.00") .externalReference("ref_12345") .payer(OrderPayerRequest.builder().email("{{PAYER_EMAIL}}").build()) .transactions(OrderTransactionRequest.builder() .payments(payments) .build()) .build(); System.out.println("Total amount: " + request.getTotalAmount()); System.out.println("External reference: " + request.getExternalReference()); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { System.out.println("Attempting to create order..."); Order order = client.create(request, requestOptions); System.out.println("Order created: " + order.getId()); System.out.println("Order status: " + order.getStatus()); } catch (MPApiException mpApiException) { System.out.println("Error creating order: " + mpApiException.getMessage()); System.out.println("Status Code: " + mpApiException.getStatusCode()); System.out.println("Error Code: " + mpApiException.getApiResponse()); System.out.println("Error Details: " + mpApiException.getCause()); } catch (Exception e) { e.printStackTrace(); System.out.println("Error creating order: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CreateOrderPSE.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.resources.order.Order; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Mercado Pago — Create Order with PSE (Pagos Seguros en Línea — Colombia). * *

PSE is Colombia's standard online bank-transfer payment method. The integrator initiates * the transaction with {@code payment_method.id = "pse"} and {@code type = "bank_transfer"}, * and must specify the buyer's bank via {@code financial_institution}. * *

Required PSE-specific fields: *

    *
  • {@code payment_method.id} = "pse" (fixed)
  • *
  • {@code payment_method.type} = "bank_transfer" (fixed)
  • *
  • {@code payment_method.financial_institution} = PSE bank code (see table below)
  • *
  • {@code currency} = "COP" (Colombia only)
  • *
  • {@code payer.entity_type} = "individual" or "association"
  • *
  • {@code payer.identification.type} = "CC", "NIT", etc. (Colombian doc type)
  • *
  • {@code additional_info.payer.ip_address} (required by risk engine)
  • *
  • {@code config.online.callback_url} (URL to redirect the buyer after auth)
  • *
* *

Most-used PSE bank codes (full catalog via MP API): *

 *   Bancolombia ........... 1007
 *   Davivienda ............ 1051
 *   Banco de Bogotá ....... 1001
 *   BBVA Colombia ......... 1013
 *   Banco Popular ......... 1002
 *   Scotiabank Colpatria .. 1019
 * 
* * @see Documentación oficial PSE */ public class CreateOrderPSE { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); OrderClient client = new OrderClient(); // PSE payment: id="pse", type="bank_transfer", financial_institution = bank code. OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("50000.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("pse") .type("bank_transfer") .financialInstitution("1007") // Bancolombia .build()) .build(); List payments = new ArrayList<>(); payments.add(payment); // Payer: entity_type + Colombian identification (CC/NIT) are required for PSE. OrderPayerRequest payer = OrderPayerRequest.builder() .email("{{PAYER_EMAIL}}") .firstName("{{FIRST_NAME}}") .lastName("{{LAST_NAME}}") .entityType("individual") .identification(IdentificationRequest.builder() .type("CC") .number("{{PAYER_DOC_NUMBER}}") .build()) .build(); // additional_info.payer.ip_address — required by MP's risk engine for PSE. AdditionalInfoRequest additionalInfo = AdditionalInfoRequest.builder() .payer(PayerInfo.builder() .ipAddress("{{CLIENT_IP}}") .build()) .build(); // callback_url — where the bank redirects the buyer after authorization. OrderConfigRequest config = OrderConfigRequest.builder() .online(OrderOnlineConfig.builder() .callbackUrl("{{CALLBACK_URL}}") .build()) .build(); OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .processingMode("automatic") .totalAmount("50000.00") .currency("COP") .externalReference("ref_pse_12345") .payer(payer) .transactions(OrderTransactionRequest.builder() .payments(payments) .build()) .additionalInfo(additionalInfo) .config(config) .build(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { Order order = client.create(request, requestOptions); System.out.println("Order created: " + order.getId()); System.out.println("Order status: " + order.getStatus()); } catch (MPApiException mpApiException) { System.out.println("Error creating order: " + mpApiException.getMessage()); System.out.println("Status Code: " + mpApiException.getStatusCode()); System.out.println("Error Code: " + mpApiException.getApiResponse()); } catch (Exception e) { e.printStackTrace(); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CreateOrderWith3DS.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.order.Order; import com.mercadopago.resources.order.OrderPayment; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; /** * Example of creating an Order with 3DS (3D Secure) authentication. * This example demonstrates how to configure transaction security for enhanced payment security. */ public class CreateOrderWith3DS { /** * Creates an order with 3DS authentication enabled. * * @param accessToken Your MercadoPago access token * @param cardToken Token representing the credit card * @param payerEmail Payer's email address * @param identificationType Payer's identification type (e.g., "CPF", "DNI") * @param identificationNumber Payer's identification number * @return Created Order with 3DS configuration * @throws MPException if there's an error in the request * @throws MPApiException if the API returns an error */ public static Order createOrderWith3DS( String accessToken, String cardToken, String payerEmail, String identificationType, String identificationNumber) throws MPException, MPApiException { // Set your access token MercadoPagoConfig.setAccessToken(accessToken); // Create the order client OrderClient client = new OrderClient(); // Configure 3DS transaction security OrderTransactionSecurity transactionSecurity = OrderTransactionSecurity.builder() .validation("on_fraud_risk") // Recommended: validate based on fraud risk .liabilityShift("required") // Required for liability shift to card brand .build(); // Configure online settings with 3DS OrderOnlineConfig onlineConfig = OrderOnlineConfig.builder() .transactionSecurity(transactionSecurity) .build(); // Configure order settings OrderConfigRequest config = OrderConfigRequest.builder() .online(onlineConfig) .build(); // Configure payment method OrderPaymentMethodRequest paymentMethod = OrderPaymentMethodRequest.builder() .id("master") // Card brand (master, visa, etc.) .type("credit_card") // Payment type .token(cardToken) // Card token from MercadoPago SDK JS .installments(1) // Number of installments .build(); // Configure payment List payments = new ArrayList<>(); payments.add(OrderPaymentRequest.builder() .amount("150.00") .paymentMethod(paymentMethod) .build()); // Configure transactions OrderTransactionRequest transactions = OrderTransactionRequest.builder() .payments(payments) .build(); // Configure payer information OrderPayerRequest payer = OrderPayerRequest.builder() .email(payerEmail) .build(); // Create the order request OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .externalReference("3ds_test_" + System.currentTimeMillis()) .processingMode("automatic") .totalAmount("150.00") .config(config) .payer(payer) .transactions(transactions) .build(); // Create the order Order order = client.create(request); return order; } /** * Main method to demonstrate the usage. */ public static void main(String[] args) { try { // Replace with your actual values String accessToken = "YOUR_ACCESS_TOKEN"; String cardToken = "YOUR_CARD_TOKEN"; // Generated using MercadoPago SDK JS String payerEmail = "test_user@example.com"; String identificationType = "CPF"; String identificationNumber = "12345678901"; Order order = createOrderWith3DS( accessToken, cardToken, payerEmail, identificationType, identificationNumber ); System.out.println("Order created successfully!"); System.out.println("Order ID: " + order.getId()); System.out.println("Status: " + order.getStatus()); System.out.println("Status Detail: " + order.getStatusDetail()); // Check if 3DS challenge is required if ("action_required".equals(order.getStatus()) && "pending_challenge".equals(order.getStatusDetail())) { // Get the challenge URL from the payment method if (order.getTransactions() != null && order.getTransactions().getPayments() != null && !order.getTransactions().getPayments().isEmpty()) { OrderPayment payment = order.getTransactions().getPayments().get(0); if (payment.getPaymentMethod() != null && payment.getPaymentMethod().getTransactionSecurity() != null) { String challengeUrl = payment.getPaymentMethod() .getTransactionSecurity().getUrl(); System.out.println("3DS Challenge required!"); System.out.println("Challenge URL: " + challengeUrl); System.out.println("Display this URL in an iframe for the user to complete the challenge."); } } } else if ("processed".equals(order.getStatus())) { System.out.println("Payment processed successfully without 3DS challenge."); } } catch (MPException | MPApiException e) { System.err.println("Error creating order: " + e.getMessage()); e.printStackTrace(); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CreateOrderWithIndustryFields.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.resources.order.Order; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Arrays; /** * Mercado Pago Create Order with industry fields. * * @see Documentation. */ public class CreateOrderWithIndustryFields { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); System.out.println("Initializing OrderClient..."); OrderClient client = new OrderClient(); System.out.println("Creating OrderPaymentRequest..."); OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("{{CARD_TOKEN}}") .installments(1) .statementDescriptor("statement") .build()) .build(); System.out.println("Adding payment details:"); System.out.println("Payment Amount: " + payment.getAmount()); System.out.println("Payment Method ID: " + payment.getPaymentMethod().getId()); List payments = new ArrayList<>(); payments.add(payment); System.out.println("Creating OrderCreateRequest..."); AdditionalInfoRequest additionalInfo = AdditionalInfoRequest.builder() .payer(PayerInfo.builder() .authenticationType("MOBILE") .registrationDate("2022-01-01T00:00:00Z") .isPrimeUser(true) .isFirstPurchaseOnline(false) .lastPurchase("2024-12-01T12:00:00Z") .build()) .shipment(ShipmentInfo.builder() .express(true) .localPickup(false) .build()) .platform(PlatformInfo.builder() .authentication("2FA") .shipment(PlatformShipment.builder() .deliveryPromise("delivery_promise") .dropShipping("drop_shipping") .safety("safety") .tracking(TrackingInfo.builder() .code("TRACK123") .status("status") .build()) .withdrawn(false) .build()) .seller(SellerInfo.builder() .id("123456") .name("Seller name") .email("seller@example.com") .status("active") .referralUrl("https://example.com") .registrationDate("2020-05-01T00:00:00Z") .hiredPlan("Premium") .businessType("E-commerce") .address(SellerAddress.builder() .zipCode("01310000") .streetName("Av. Paulista") .streetNumber("100") .city("São Paulo") .state("SP") .complement("101") .country("Brasil") .build()) .identification(SellerIdentification.builder() .type("CNPJ") .number("12.345.678/0001-99") .build()) .phone(SellerPhone.builder() .areaCode("11") .number("999999999") .build()) .build()) .build()) .travel(TravelInfo.builder() .passengers(Arrays.asList( TravelPassengerRequest.builder() .firstName("John") .lastName("Doe") .identification(PassengerIdentification.builder() .type("CPF") .number("12345678900") .build()) .build())) .routes(Arrays.asList( TravelRouteRequest.builder() .departure("GRU") .destination("CWB") .departureDateTime("2024-12-01T12:00:00Z") .arrivalDateTime("2024-12-01T14:00:00Z") .company("LATAM") .build())) .build()) .build(); OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .processingMode("automatic") .totalAmount("100.00") .externalReference("ref_12345") .payer(OrderPayerRequest.builder().email("{{PAYER_EMAIL}}").build()) .transactions(OrderTransactionRequest.builder() .payments(payments) .build()) .additionalInfo(additionalInfo) .build(); System.out.println("Total amount: " + request.getTotalAmount()); System.out.println("External reference: " + request.getExternalReference()); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { System.out.println("Attempting to create order..."); Order order = client.create(request, requestOptions); System.out.println("Order created: " + order.getId()); System.out.println("Order status: " + order.getStatus()); } catch (MPApiException mpApiException) { System.out.println("Error creating order: " + mpApiException.getMessage()); System.out.println("Status Code: " + mpApiException.getStatusCode()); System.out.println("Error Code: " + mpApiException.getApiResponse()); System.out.println("Error Details: " + mpApiException.getCause()); } catch (Exception e) { e.printStackTrace(); System.out.println("Error creating order: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CreateOrderWithPointConfig.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.order.Order; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** Example: Create Order with Point Configuration */ public class CreateOrderWithPointConfig { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); OrderClient client = new OrderClient(); System.out.println("Creating OrderCreateRequest with Point configuration..."); // Configure Point settings OrderPointConfig pointConfig = OrderPointConfig.builder() .terminalId("") .printOnTerminal("seller_ticket") .screenTime("") .build(); // Configure Order config with Point OrderConfigRequest config = OrderConfigRequest.builder() .point(pointConfig) .build(); // Create payment request OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("debit_card") .type("debit_card") .installments(1) .build()) .build(); List payments = new ArrayList<>(); payments.add(payment); // Create order request OrderCreateRequest request = OrderCreateRequest.builder() .type("point") .processingMode("automatic") .totalAmount("100.00") .externalReference("ext_ref_point_1234") .description("Example Point - Payment") .config(config) .payer(OrderPayerRequest.builder().email("{{PAYER_EMAIL}}").build()) .transactions(OrderTransactionRequest.builder() .payments(payments) .build()) .build(); System.out.println("Point Terminal ID: " + pointConfig.getTerminalId()); System.out.println("Print on Terminal: " + pointConfig.getPrintOnTerminal()); System.out.println("Screen Time: " + pointConfig.getScreenTime()); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { System.out.println("Attempting to create Point order..."); Order order = client.create(request, requestOptions); System.out.println("Point Order created: " + order.getId()); System.out.println("Order type: " + order.getType()); System.out.println("Order status: " + order.getStatus()); if (order.getConfig() != null && order.getConfig().getPoint() != null) { System.out.println("Terminal ID configured: " + order.getConfig().getPoint().getTerminalId()); } } catch (MPApiException mpApiException) { System.out.println("Error creating Point order: " + mpApiException.getMessage()); System.out.println("Status Code: " + mpApiException.getStatusCode()); System.out.println("Error Details: " + mpApiException.getApiResponse()); } catch (Exception e) { e.printStackTrace(); System.out.println("Error creating Point order: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/CreateTransaction.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.OrderClient; import com.mercadopago.client.order.OrderPaymentMethodRequest; import com.mercadopago.client.order.OrderPaymentRequest; import com.mercadopago.client.order.OrderTransactionRequest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.net.MPResponse; import java.util.*; /** * Mercado Pago Create Order transaction. * * @see Documentation */ public class CreateTransaction{ public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); String orderId = "{{Order_id}}"; OrderClient client = new OrderClient(); OrderPaymentMethodRequest paymentMethodRequest = OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("{{card_token}}") .installments(1) .statementDescriptor("statement") .build(); OrderPaymentRequest paymentRequest = OrderPaymentRequest.builder() .amount("500.00") .paymentMethod(paymentMethodRequest) .build(); List payments = new ArrayList<>(); payments.add(paymentRequest); OrderTransactionRequest transactionRequest = OrderTransactionRequest.builder() .payments(payments) .build(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{idempotency_key}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try{ MPResponse response = client.createTransaction(orderId, transactionRequest, requestOptions).getResponse(); System.out.println("Status Code: " + response.getStatusCode()); System.out.println("Order transaction created: " + response.getContent()); } catch (Exception e) { System.out.println("Error creating order transaction: " + e.getMessage()); System.out.println("Status: " + e.getCause()); System.out.println("Cause: " + Arrays.toString(e.getStackTrace())); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/DeleteTransaction.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.OrderClient; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; /** * Mercado Pago Delete Order transaction. * * @see Documentation */ public class DeleteTransaction { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); String orderId = "{{order_id}}"; String transactionId = "{{transaction_id}}"; OrderClient client = new OrderClient(); try { client.deleteTransaction(orderId, transactionId); System.out.println("Transaction successfully deleted."); } catch (MPApiException e) { System.out.println("API error while deleting transaction: " + e.getMessage()); System.out.println("Status: " + e.getApiResponse().getContent()); } catch (MPException e) { System.out.println("Error while deleting transaction: " + e.getMessage()); } catch (Exception e) { System.out.println("Unexpected error: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/GetOrderById.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.OrderClient; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResponse; /** * Mercado Pago Get Order. * * @see Documentation */ public class GetOrderById { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); OrderClient client = new OrderClient(); try { MPResponse order = client.get("{{order_id}}").getResponse(); System.out.println("Getting order: " + order.getContent()); } catch (MPException | MPApiException e) { System.out.println("Error getting order: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/ProcessOrderById.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.OrderClient; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.order.Order; /** * Mercado Pago Process Order. * * @see Documentation */ public class ProcessOrderById { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); OrderClient client = new OrderClient(); try { Order order = client.process("{{order_id}}"); System.out.println("Process order: " + order.getId()); System.out.println("Status: " + order.getStatus()); System.out.println("Status Detail: " + order.getStatusDetail()); } catch (MPException | MPApiException e) { System.out.println("Error getting order: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/RefundPartial.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.*; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResponse; import java.util.*; /** * Mercado Pago Partial Refund Order. * * @see Documentation */ public class RefundPartial { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); String orderId = "{{order_id}}"; OrderClient client = new OrderClient(); OrderRefundPaymentRequest refundRequest = OrderRefundPaymentRequest.builder() .id("{{transaction_id}}") .amount("10.00") .build(); List orderRefundTransactionRequests = new ArrayList<>(); orderRefundTransactionRequests.add(refundRequest); OrderRefundRequest orderRequest = OrderRefundRequest.builder() .transactions(orderRefundTransactionRequests) .build(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{idempotency_key}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { MPResponse response = client.refund(orderId, orderRequest, requestOptions).getResponse(); System.out.println("Updated transaction: " + response.getContent()); } catch (MPException e) { System.out.println("Error refund order transaction: " + e.getMessage()); System.out.println("Status: " + e.getCause()); } catch (Exception e) { System.out.println("Error refund order transaction: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/RefundTotal.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.OrderClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.resources.order.Order; import java.util.HashMap; import java.util.Map; /** * Mercado Pago Total Refund Order. * * @see Documentation */ public class RefundTotal { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); String orderId = "{{order_id}}"; OrderClient client = new OrderClient(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{idempotency_key}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { Order order = client.refund(orderId, requestOptions); System.out.println("Order successfully refunded."); System.out.println("Status: " + order.getStatus()); System.out.println("Status Detail: " + order.getStatusDetail()); } catch (Exception e) { System.out.println("Error while refunding order: " + e.getMessage()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/order/UpdateTransaction.java ================================================ package com.mercadopago.example.apis.order; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.order.OrderClient; import com.mercadopago.client.order.OrderPaymentMethodRequest; import com.mercadopago.client.order.OrderPaymentRequest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.resources.order.UpdateOrderTransaction; import java.util.HashMap; import java.util.Map; /** * Mercado Pago Update Order transaction. * * @see Documentation */ public class UpdateTransaction { public static void main(String[] args) { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); String orderId = "{{order_id}}"; String transactionId = "{{transaction_id}}"; OrderClient client = new OrderClient(); OrderPaymentRequest paymentRequest = OrderPaymentRequest.builder() .paymentMethod(OrderPaymentMethodRequest.builder() .type("credit_card") .installments(8) .statementDescriptor("statement") .build()) .build(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", "{{IDEMPOTENCY_KEY}}"); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(headers) .build(); try { UpdateOrderTransaction updatedTransaction = client.updateTransaction(orderId, transactionId, paymentRequest, requestOptions); System.out.println("Updated transaction: " + updatedTransaction.getResponse().getContent()); } catch (Exception e) { System.out.println("Error updating order transaction: " + e.getMessage()); System.out.println("Status: " + e.getCause()); } } } ================================================ FILE: src/main/java/com/mercadopago/example/apis/payment/Main.java ================================================ package com.mercadopago.example.apis.payment; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.client.common.SubMerchant; import com.mercadopago.client.payment.*; import com.mercadopago.resources.payment.Payment; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.*; public class Main { public static void main(String[] args) throws MPException, MPApiException { MercadoPagoConfig.setAccessToken("{{ACCESS_TOKEN}}"); PaymentClient client = new PaymentClient(); IdentificationRequest payeridentification = IdentificationRequest.builder() .type("CPF") .number("{{DOC_NUMBER}}") .build(); PaymentPayerAddressRequest payeraddress = PaymentPayerAddressRequest.builder() .zipCode("{{CODE}}") .streetName("Rua AAAAA") .streetNumber("123") .build(); PhoneRequest payerphone = PhoneRequest.builder() .areaCode("{{CODE}}") .number("{{PHONE_NUMBER}}") .build(); PaymentPassengerRequest passenger = PaymentPassengerRequest.builder() .identification(payeridentification) .firstName("First Name") .lastName("Last Name") .build(); PaymentRouteRequest route = PaymentRouteRequest.builder() .departure("São Paulo") .destination("Rio de Janeiro") .departureDateTime(OffsetDateTime.parse("2020-08-06T09:25:04.000-03:00")) .arrivalDateTime(OffsetDateTime.parse("2020-08-06T09:25:04.000-03:00")) .company("Company") .build(); PaymentCategoryDescriptorRequest categoryDescriptor = PaymentCategoryDescriptorRequest.builder() .passenger(passenger) .route(route) .build(); PaymentAdditionalInfoPayerRequest additionalInfoPayerRequest = PaymentAdditionalInfoPayerRequest.builder() .firstName("First Name") .lastName("Last Name") .phone(payerphone) .address(payeraddress) .registrationDate(OffsetDateTime.parse("2020-08-06T09:25:04.000-03:00")) .isPrimeUser(true) .isFirstPurchaseOnline(true) .authenticationType("Gmail") .lastPurchase(OffsetDateTime.parse("2020-08-06T09:25:04.000-03:00")) .build(); PaymentPayerRequest payer = PaymentPayerRequest.builder() .firstName("First Name") .lastName("Last Name") .email("{{PAYER_EMAIL}}") .identification(payeridentification) .address(payeraddress) .build(); List itemsList = new ArrayList<>(); PaymentItemRequest item = PaymentItemRequest.builder() .id("1941") .title("title") .description("description") .pictureUrl("pictureUrl") .categoryId("categoryId") .quantity(1) .unitPrice(new BigDecimal("100")) .eventDate(OffsetDateTime.parse("2020-08-06T09:25:04.000-03:00")) .type("type") .warranty(true) .categoryDescriptor(categoryDescriptor) .build(); itemsList.add(item); PaymentReceiverAddressRequest receiverAddress = PaymentReceiverAddressRequest.builder() .zipCode("{{CODE}}") .streetName("Street Name") .streetNumber("1234") .floor("5") .apartment("12345") .stateName("DF") .cityName("Bogota") .build(); PaymentShipmentsRequest shipments = PaymentShipmentsRequest.builder() .localPickup(true) .expressShipment(true) .receiverAddress(receiverAddress) .build(); PaymentAdditionalInfoRequest additional = PaymentAdditionalInfoRequest.builder() .items(itemsList) .payer(additionalInfoPayerRequest) .shipments(shipments) .build(); SubMerchant subMerchant = SubMerchant.builder() .subMerchantId("12345") .mcc("1234") .country("BRA") .addressDoorNumber(123) .zip("{{CODE}}") .documentNumber("{{DOC_NUMBER}}") .city("SÃO PAULO") .addressStreet("RUA A") .legalName("{{NAME}}") .regionCodeIso("BR-MG") .regionCode("BR") .documentType("CNPJ") .phone("{{PHONE_NUMBER}}") .url("{{URL}}") .build(); PaymentForwardDataRequest forwardData = PaymentForwardDataRequest.builder() .subMerchant(subMerchant) .build(); PaymentCreateRequest createRequest = PaymentCreateRequest.builder() .transactionAmount(new BigDecimal("1000")) .description("Title") .paymentMethodId("pix") .binaryMode(true) .capture(true) .externalReference("external_reference") .statementDescriptor("Store 123") .notificationUrl("{{URL}}") .payer(payer) .additionalInfo(additional) .forwardData(forwardData) .build(); try { Payment payment = client.create(createRequest); System.out.println(payment.getId()); } catch (MPApiException ex) { System.out.printf( "MercadoPago Error. Status: %s, Content: %s%n", ex.getApiResponse().getStatusCode(), ex.getApiResponse().getContent()); } catch (MPException ex) { ex.printStackTrace(); } } } ================================================ FILE: src/main/java/com/mercadopago/exceptions/MPApiException.java ================================================ package com.mercadopago.exceptions; import com.mercadopago.net.MPResponse; import lombok.Getter; /** * Exception thrown when the MercadoPago API returns an error response (HTTP 4xx/5xx). * *

Unlike {@link MPException}, which covers client-side failures (network errors, * serialization issues), this exception specifically represents a successfully received * API response that indicates a business or validation error. It carries the HTTP status * code and the full {@link MPResponse} so callers can inspect headers, body, and status * for error-handling logic. * *

Usage example: *

{@code
 * try {
 *     Payment payment = client.create(request);
 * } catch (MPApiException e) {
 *     System.out.println("Status: " + e.getStatusCode());
 *     System.out.println("Response: " + e.getApiResponse().getContent());
 * }
 * }
* * @see MPException * @see com.mercadopago.net.MPResponse */ @Getter public class MPApiException extends Exception { /** HTTP status code returned by the MercadoPago API (e.g., 400, 401, 404, 500). */ private final int statusCode; /** Full API response including headers, status code, and body content. */ private final MPResponse apiResponse; /** * Constructs a new API exception with the specified message and response. * * @param message a human-readable description of the API error * @param response the full {@link MPResponse} received from the API */ public MPApiException(String message, MPResponse response) { this(message, null, response); } /** * Constructs a new API exception with the specified message, underlying cause, and response. * * @param message a human-readable description of the API error * @param cause the underlying throwable that triggered this exception, or {@code null} * @param response the full {@link MPResponse} received from the API */ public MPApiException(String message, Throwable cause, MPResponse response) { super(message, cause); this.apiResponse = response; this.statusCode = response.getStatusCode(); } } ================================================ FILE: src/main/java/com/mercadopago/exceptions/MPException.java ================================================ package com.mercadopago.exceptions; import lombok.Getter; /** * Base checked exception for SDK-side errors in the MercadoPago Java SDK. * *

This exception represents failures that occur on the client side before or after * an API call, such as network errors, serialization failures, or invalid request * construction. It is not used for API-level error responses (HTTP 4xx/5xx); * those are represented by {@link MPApiException}. * *

Concrete subclasses provide more specific error categories: *

    *
  • {@link MPJsonParseException} – JSON serialization/deserialization failures
  • *
  • {@link MPMalformedRequestException} – invalid request construction errors
  • *
* * @see MPApiException * @see MPJsonParseException * @see MPMalformedRequestException */ @Getter public class MPException extends Exception { /** * Constructs a new SDK exception with the specified detail message. * * @param message a human-readable description of the error */ public MPException(String message) { super(message); } /** * Constructs a new SDK exception with the specified detail message and underlying cause. * * @param message a human-readable description of the error * @param cause the underlying throwable that triggered this exception */ public MPException(String message, Throwable cause) { super(message, cause); } /** * Constructs a new SDK exception wrapping an underlying cause. * * @param cause the underlying throwable that triggered this exception */ public MPException(Throwable cause) { super(cause); } } ================================================ FILE: src/main/java/com/mercadopago/exceptions/MPInvalidWebhookSignatureException.java ================================================ package com.mercadopago.exceptions; import lombok.Getter; /** * Exception thrown by {@link com.mercadopago.webhook.WebhookSignatureValidator} * when a webhook notification cannot be confirmed as originating from MercadoPago. * *

The exception carries enough context to support structured logging without * exposing internal details in the HTTP response. The {@link #getReason()} * indicates why validation failed, while {@link #getRequestId()} and * {@link #getTimestamp()} echo the inputs that were available at the point of * failure (when applicable) to correlate against MercadoPago's notifications * dashboard. */ @Getter public class MPInvalidWebhookSignatureException extends MPException { private static final long serialVersionUID = 1L; private final SignatureFailureReason reason; private final String requestId; private final String timestamp; /** * Creates a new {@code MPInvalidWebhookSignatureException}. * * @param reason the specific failure mode that triggered the exception * @param requestId the {@code x-request-id} header value, when available; may be {@code null} * @param timestamp the {@code ts} value extracted from the signature header, when * parsing reached that point; may be {@code null} */ public MPInvalidWebhookSignatureException( SignatureFailureReason reason, String requestId, String timestamp) { super("Invalid webhook signature: " + reason); this.reason = reason; this.requestId = requestId; this.timestamp = timestamp; } } ================================================ FILE: src/main/java/com/mercadopago/exceptions/MPJsonParseException.java ================================================ package com.mercadopago.exceptions; /** * Exception thrown when JSON serialization or deserialization fails within the SDK. * *

This exception is raised by {@link com.mercadopago.serialization.Serializer} when a * JSON string cannot be parsed into the expected resource type, or when an object cannot * be converted to its JSON representation. Common causes include malformed JSON, unexpected * field types, or missing required properties. * * @see MPException * @see com.mercadopago.serialization.Serializer */ public class MPJsonParseException extends MPException { /** * Constructs a new JSON parse exception with the specified detail message. * * @param message a human-readable description of the parsing error */ public MPJsonParseException(String message) { super(message); } /** * Constructs a new JSON parse exception with the specified detail message and underlying cause. * * @param message a human-readable description of the parsing error * @param throwable the underlying throwable (e.g., a Gson or IO exception) that caused the failure */ public MPJsonParseException(String message, Throwable throwable) { super(message, throwable); } } ================================================ FILE: src/main/java/com/mercadopago/exceptions/MPMalformedRequestException.java ================================================ package com.mercadopago.exceptions; /** * Exception thrown when an API request cannot be constructed due to invalid or * incomplete input. * *

This exception is raised before any network call is made, indicating that * the request object is structurally invalid (e.g., missing required fields, malformed * URLs, or encoding failures). It signals a programming error on the caller's side * rather than an API-level or network-level failure. * * @see MPException * @see MPApiException */ public class MPMalformedRequestException extends MPException { /** * Constructs a new malformed request exception with the specified detail message. * * @param message a human-readable description of the request construction error */ public MPMalformedRequestException(String message) { super(message); } /** * Constructs a new malformed request exception wrapping an underlying cause. * * @param cause the underlying throwable that prevented request construction */ public MPMalformedRequestException(Throwable cause) { super(cause); } } ================================================ FILE: src/main/java/com/mercadopago/exceptions/SignatureFailureReason.java ================================================ package com.mercadopago.exceptions; /** * Enumerates the reasons why * {@link com.mercadopago.webhook.WebhookSignatureValidator} may reject a * MercadoPago webhook notification. * *

Integrators are encouraged to log this value alongside the {@code x-request-id} * for correlation against the MercadoPago notifications dashboard. */ public enum SignatureFailureReason { /** The {@code x-signature} header was missing, empty, or whitespace. */ MISSING_SIGNATURE_HEADER, /** The header did not match the expected {@code ts=...,vN=...} format. */ MALFORMED_SIGNATURE_HEADER, /** The header parsed correctly but no {@code ts=} component was present. */ MISSING_TIMESTAMP, /** * No hash was found in the header for any of the supported versions. Typically * indicates MercadoPago has migrated to a new signature version and the SDK * needs to be upgraded. */ MISSING_HASH, /** * The computed HMAC did not match the value in the header. Most often caused by * an incorrect secret signature or a forged request. */ SIGNATURE_MISMATCH, /** * The header timestamp fell outside the configured tolerance window against the * current clock. May indicate clock drift on the integrator's server or a replay * attack. */ TIMESTAMP_OUT_OF_TOLERANCE, } ================================================ FILE: src/main/java/com/mercadopago/net/Headers.java ================================================ package com.mercadopago.net; /** * Defines standard HTTP header name constants used throughout the MercadoPago SDK. * *

This class contains both standard HTTP headers (such as {@code Authorization} and * {@code Content-Type}) and MercadoPago-specific custom headers (prefixed with {@code X-}) used * for request identification, idempotency, and partner tracking. * *

These constants are used by {@link MPRequest} and {@link MPDefaultHttpClient} when * constructing and sending HTTP requests to the MercadoPago API. * * @see MPRequest * @see MPDefaultHttpClient */ public class Headers { /** * Standard HTTP {@code Authorization} header, used to carry the OAuth access token * (Bearer token) for authenticating requests against the MercadoPago API. */ public static final String AUTHORIZATION = "Authorization"; /** * Standard HTTP {@code Content-Type} header, indicating the media type of the request body. * Typically set to {@code application/json} for MercadoPago API requests. */ public static final String CONTENT_TYPE = "Content-Type"; /** * Standard HTTP {@code Accept} header, indicating the media types the client is willing to * receive in the response. Typically set to {@code application/json}. */ public static final String ACCEPT = "Accept"; /** * Standard HTTP {@code User-Agent} header, identifying the client software originating the * request. The SDK sets this to a value containing the SDK version and Java runtime information. */ public static final String USER_AGENT = "User-Agent"; /** * MercadoPago custom header {@code X-Idempotency-Key}, used to ensure that POST requests are * idempotent. Sending the same idempotency key on repeated requests prevents duplicate resource * creation on the server side. * * @see MPRequest#createIdempotencyKey() */ public static final String IDEMPOTENCY_KEY = "X-Idempotency-Key"; /** * MercadoPago custom header {@code X-Product-Id}, used internally to identify the SDK product. * The value is set from {@link com.mercadopago.MercadoPagoConfig#PRODUCT_ID}. */ public static final String PRODUCT_ID = "X-Product-Id"; /** * MercadoPago custom header {@code X-Tracking-Id}, used internally for request tracking and * telemetry. Contains platform and SDK version metadata. * * @see com.mercadopago.MercadoPagoConfig#TRACKING_ID */ public static final String TRACKING_ID = "X-Tracking-Id"; /** * MercadoPago custom header {@code X-Corporation-Id}, used to identify the corporation * associated with the API request. Set via * {@link com.mercadopago.MercadoPagoConfig#setCorporationId(String)}. */ public static final String CORPORATION_ID = "X-Corporation-Id"; /** * MercadoPago custom header {@code X-Integrator-Id}, used to identify the integrator (partner) * making the API request. Set via * {@link com.mercadopago.MercadoPagoConfig#setIntegratorId(String)}. */ public static final String INTEGRATOR_ID = "X-Integrator-Id"; /** * MercadoPago custom header {@code X-Platform-Id}, used to identify the e-commerce platform * through which the API request originates. Set via * {@link com.mercadopago.MercadoPagoConfig#setPlatformId(String)}. */ public static final String PLATFORM_ID = "X-Platform-Id"; } ================================================ FILE: src/main/java/com/mercadopago/net/HttpMethod.java ================================================ package com.mercadopago.net; /** * Enumerates the HTTP methods supported by the MercadoPago SDK for communicating with the * MercadoPago API. * *

Each constant corresponds to a standard HTTP verb. The SDK uses this enum in {@link MPRequest} * to indicate which HTTP method should be used when sending a request through * {@link MPHttpClient#send(MPRequest)}. * * @see MPRequest * @see MPDefaultHttpClient */ public enum HttpMethod { /** HTTP GET method, used to retrieve resources without side effects. */ GET, /** HTTP POST method, used to create new resources. */ POST, /** HTTP PUT method, used to fully replace an existing resource. */ PUT, /** HTTP PATCH method, used to partially update an existing resource. */ PATCH, /** HTTP DELETE method, used to remove an existing resource. */ DELETE } ================================================ FILE: src/main/java/com/mercadopago/net/HttpStatus.java ================================================ package com.mercadopago.net; /** * Defines commonly used HTTP status code constants for the MercadoPago SDK. * *

These constants are used internally by {@link MPDefaultHttpClient} to evaluate API responses * and to map low-level HTTP exceptions (such as protocol or SSL errors) to appropriate status * codes. * * @see MPDefaultHttpClient * @see MPResponse */ public class HttpStatus { /** * HTTP 200 OK. Indicates that the request has succeeded and the response body contains the * requested resource. */ public static final int OK = 200; /** * HTTP 201 Created. Indicates that a new resource has been successfully created as a result of * the request (typically returned for POST operations). */ public static final int CREATED = 201; /** * HTTP 204 No Content. Indicates that the request has succeeded but the response body is empty * (typically returned for DELETE or update operations that produce no content). */ public static final int NO_CONTENT = 204; /** * HTTP 400 Bad Request. Indicates that the server could not understand the request due to * invalid syntax or malformed parameters. Also used internally when a * {@link org.apache.http.client.ClientProtocolException} occurs. */ public static final int BAD_REQUEST = 400; /** * HTTP 403 Forbidden. Indicates that the server understood the request but refuses to * authorize it. Also used internally when an * {@link javax.net.ssl.SSLPeerUnverifiedException} occurs during TLS verification. */ public static final int FORBIDDEN = 403; /** * HTTP 500 Internal Server Error. Indicates an unexpected condition on the server side. Also * used internally when a generic {@link java.io.IOException} occurs during request execution. */ public static final int INTERNAL_SERVER_ERROR = 500; } ================================================ FILE: src/main/java/com/mercadopago/net/KeepAliveStrategy.java ================================================ package com.mercadopago.net; import org.apache.http.HeaderElement; import org.apache.http.HeaderElementIterator; import org.apache.http.HttpResponse; import org.apache.http.conn.ConnectionKeepAliveStrategy; import org.apache.http.message.BasicHeaderElementIterator; import org.apache.http.protocol.HTTP; import org.apache.http.protocol.HttpContext; /** * Custom connection keep-alive strategy for the MercadoPago SDK's HTTP client. * *

Implements Apache HttpClient's {@link ConnectionKeepAliveStrategy} to determine how long * idle connections should be kept alive in the connection pool. The strategy works as follows: *

    *
  1. Parses the server's {@code Keep-Alive} response header looking for the {@code timeout} * parameter.
  2. *
  3. If a valid timeout value is found, it is converted from seconds to milliseconds and * returned.
  4. *
  5. If the header is absent or does not contain a {@code timeout} parameter, a default of * {@value #DEFAULT_KEEP_ALIVE_TIMEOUT_MS} milliseconds (10 seconds) is used.
  6. *
* * @see MPDefaultHttpClient */ public class KeepAliveStrategy implements ConnectionKeepAliveStrategy { /** * Default keep-alive timeout in milliseconds used when the server does not specify a * {@code Keep-Alive} header with a {@code timeout} parameter. Value: {@value} ms (10 seconds). */ private static final int DEFAULT_KEEP_ALIVE_TIMEOUT_MS = 10000; /** The name of the parameter to look for in the {@code Keep-Alive} header. */ private static final String KEEP_ALIVE_TIMEOUT_PARAM_NAME = "timeout"; /** * Determines how long a connection may remain idle before being closed. * *

Inspects the {@code Keep-Alive} response header for a {@code timeout} parameter. If * found, the value (in seconds) is converted to milliseconds. Otherwise, the default timeout * of {@value #DEFAULT_KEEP_ALIVE_TIMEOUT_MS} ms is returned. * * @param response the HTTP response from which the {@code Keep-Alive} header is read * @param context the HTTP execution context (unused by this implementation) * @return the keep-alive duration in milliseconds */ @Override public long getKeepAliveDuration(HttpResponse response, HttpContext context) { HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE)); while (it.hasNext()) { HeaderElement he = it.nextElement(); String param = he.getName(); String value = he.getValue(); if (value != null && param.equalsIgnoreCase(KEEP_ALIVE_TIMEOUT_PARAM_NAME)) { return Long.parseLong(value) * 1000; } } return DEFAULT_KEEP_ALIVE_TIMEOUT_MS; } } ================================================ FILE: src/main/java/com/mercadopago/net/MPDefaultHttpClient.java ================================================ package com.mercadopago.net; import static com.mercadopago.MercadoPagoConfig.getStreamHandler; import static com.mercadopago.net.HttpStatus.BAD_REQUEST; import static com.mercadopago.net.HttpStatus.FORBIDDEN; import static com.mercadopago.net.HttpStatus.INTERNAL_SERVER_ERROR; import com.google.gson.JsonObject; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.exceptions.MPMalformedRequestException; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.logging.Logger; import java.util.logging.StreamHandler; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLPeerUnverifiedException; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.methods.HttpDelete; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPatch; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.config.Registry; import org.apache.http.config.RegistryBuilder; import org.apache.http.conn.socket.ConnectionSocketFactory; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.entity.StringEntity; import org.apache.http.impl.client.DefaultHttpRequestRetryHandler; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.message.BasicHeader; import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicStatusLine; import org.apache.http.ssl.SSLContexts; import org.apache.http.util.EntityUtils; /** * Default {@link MPHttpClient} implementation backed by Apache HttpClient 4.x. * *

This client is configured with the following defaults: *

    *
  • TLS 1.2 -- only TLSv1.2 is enabled for HTTPS connections.
  • *
  • Connection pooling -- uses a * {@link PoolingHttpClientConnectionManager} whose maximum total and per-route connections * are governed by {@link MercadoPagoConfig#getMaxConnections()}.
  • *
  • Keep-alive -- the {@link KeepAliveStrategy} parses the server's * {@code Keep-Alive} header and defaults to 10 seconds.
  • *
  • Automatic retries -- failed requests are retried up to * {@value #DEFAULT_RETRIES} times (non-idempotent requests are not retried) * unless a custom {@link org.apache.http.client.HttpRequestRetryHandler} is configured via * {@link MercadoPagoConfig#setRetryHandler(org.apache.http.client.HttpRequestRetryHandler)}.
  • *
  • Proxy support -- an HTTP proxy can be configured via * {@link MercadoPagoConfig#setProxy(org.apache.http.HttpHost)}.
  • *
  • Connection validation -- stale connections are validated after * {@value #VALIDATE_INACTIVITY_INTERVAL_MS} ms of inactivity.
  • *
* *

Cookies and automatic redirects are disabled. * * @see MPHttpClient * @see KeepAliveStrategy * @see MercadoPagoConfig */ public class MPDefaultHttpClient implements MPHttpClient { /** * Interval in milliseconds after which idle connections are validated before reuse. * Value: {@value} ms. */ private static final int VALIDATE_INACTIVITY_INTERVAL_MS = 30000; /** * Default number of automatic retries for failed HTTP requests. * Value: {@value}. */ private static final int DEFAULT_RETRIES = 3; /** Character encoding used for request and response bodies. */ private static final String UTF_8 = "UTF-8"; /** Error message returned when a payload is attached to a GET or DELETE request. */ private static final String PAYLOAD_NOT_SUPPORTED_MESSAGE = "Payload not supported for this method."; /** Log format pattern for HTTP header key-value pairs. */ private static final String HEADER_LOG_FORMAT = "%s: %s%s"; /** Logger instance for this class. */ private static final Logger LOGGER = Logger.getLogger(MPDefaultHttpClient.class.getName()); /** The underlying Apache {@link HttpClient} used to execute HTTP requests. */ private final HttpClient httpClient; /** * Constructs a new {@code MPDefaultHttpClient} with default settings. * *

Internally creates an Apache {@link HttpClient} configured with TLS 1.2, connection * pooling, keep-alive strategy, retry handling, and optional proxy support as described in the * class-level documentation. */ public MPDefaultHttpClient() { this(null); } /** * Constructs an {@code MPDefaultHttpClient} using the provided Apache {@link HttpClient}. * *

This constructor is intended for testing purposes. If the given {@code httpClient} is * {@code null}, a default client is created via {@link #createHttpClient()}. * * @param httpClient the Apache {@link HttpClient} to use, or {@code null} to create a default * client */ protected MPDefaultHttpClient(HttpClient httpClient) { StreamHandler streamHandler = getStreamHandler(); streamHandler.setLevel(MercadoPagoConfig.getLoggingLevel()); LOGGER.addHandler(streamHandler); LOGGER.setLevel(MercadoPagoConfig.getLoggingLevel()); if (Objects.isNull(httpClient)) { this.httpClient = createHttpClient(); } else { this.httpClient = httpClient; } } private HttpClient createHttpClient() { SSLContext sslContext = SSLContexts.createDefault(); SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory( sslContext, new String[] {"TLSv1.2"}, null, SSLConnectionSocketFactory.getDefaultHostnameVerifier()); Registry registry = RegistryBuilder.create() .register("https", sslConnectionSocketFactory) .build(); PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(registry); connectionManager.setMaxTotal(MercadoPagoConfig.getMaxConnections()); connectionManager.setDefaultMaxPerRoute(MercadoPagoConfig.getMaxConnections()); connectionManager.setValidateAfterInactivity(VALIDATE_INACTIVITY_INTERVAL_MS); HttpClientBuilder httpClientBuilder = HttpClients.custom() .setConnectionManager(connectionManager) .setKeepAliveStrategy(new KeepAliveStrategy()) .disableCookieManagement() .disableRedirectHandling(); if (Objects.nonNull(MercadoPagoConfig.getProxy())) { httpClientBuilder.setProxy(MercadoPagoConfig.getProxy()); } if (Objects.nonNull(MercadoPagoConfig.getRetryHandler())) { httpClientBuilder.setRetryHandler(MercadoPagoConfig.getRetryHandler()); } else { DefaultHttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(DEFAULT_RETRIES, false); httpClientBuilder.setRetryHandler(retryHandler); } return httpClientBuilder.build(); } /** * {@inheritDoc} * *

Translates the given {@link MPRequest} into an Apache {@link HttpRequestBase}, executes it, * and converts the raw response into an {@link MPResponse}. If the response status code is * greater than 299, an {@link MPApiException} is thrown containing the full response details. * *

Transport-level exceptions are mapped as follows: *

    *
  • {@link org.apache.http.client.ClientProtocolException} returns status * {@link HttpStatus#BAD_REQUEST 400}
  • *
  • {@link javax.net.ssl.SSLPeerUnverifiedException} returns status * {@link HttpStatus#FORBIDDEN 403}
  • *
  • {@link java.io.IOException} returns status * {@link HttpStatus#INTERNAL_SERVER_ERROR 500}
  • *
* * @param mpRequest the {@link MPRequest} to send * @return an {@link MPResponse} with status code, headers, and body * @throws MPException if an unexpected transport-level error occurs * @throws MPApiException if the API returns a non-success status code (greater than 299) */ @Override public MPResponse send(MPRequest mpRequest) throws MPException, MPApiException { try { HttpRequestBase completeRequest = createHttpRequest(mpRequest); HttpClientContext context = HttpClientContext.create(); HttpResponse response = executeHttpRequest(mpRequest, completeRequest, context); String responseBody = ""; if (Objects.nonNull(response.getEntity())) { responseBody = EntityUtils.toString(response.getEntity(), UTF_8); } Map> headers = getHeaders(response); int statusCode = response.getStatusLine().getStatusCode(); MPResponse mpResponse = new MPResponse(statusCode, headers, responseBody); if (statusCode > 299) { throw new MPApiException("Api error. Check response for details", mpResponse); } StringBuilder responseHeaders = new StringBuilder(String.format("Response headers:%s", System.lineSeparator())); for (Header header : response.getAllHeaders()) { responseHeaders.append( String.format( HEADER_LOG_FORMAT, header.getName(), header.getValue(), System.lineSeparator())); } LOGGER.fine(responseHeaders.toString()); LOGGER.fine( String.format("Response status code: %s", response.getStatusLine().getStatusCode())); LOGGER.fine(String.format("Response body: %s", responseBody)); return mpResponse; } catch (MPMalformedRequestException | MPApiException ex) { throw ex; } catch (Exception ex) { throw new MPException(ex); } } private HttpRequestBase createHttpRequest(MPRequest mpRequest) throws MPMalformedRequestException { HttpEntity entity = normalizePayload(mpRequest.getPayload()); HttpRequestBase request = getRequestBase(mpRequest.getMethod(), mpRequest.getUri(), entity); Map headers = new HashMap<>(mpRequest.getHeaders()); for (Map.Entry header : headers.entrySet()) { request.addHeader(new BasicHeader(header.getKey(), header.getValue())); } int socketTimeout = mpRequest.getSocketTimeout() != 0 ? mpRequest.getSocketTimeout() : MercadoPagoConfig.getSocketTimeout(); int connectionTimeout = mpRequest.getConnectionTimeout() != 0 ? mpRequest.getConnectionTimeout() : MercadoPagoConfig.getConnectionTimeout(); int connectionRequestTimeout = mpRequest.getConnectionRequestTimeout() != 0 ? mpRequest.getConnectionRequestTimeout() : MercadoPagoConfig.getConnectionRequestTimeout(); RequestConfig.Builder requestConfigBuilder = RequestConfig.custom() .setSocketTimeout(socketTimeout) .setConnectTimeout(connectionTimeout) .setConnectionRequestTimeout(connectionRequestTimeout); request.setConfig(requestConfigBuilder.build()); return request; } private HttpResponse executeHttpRequest( MPRequest mpRequest, HttpRequestBase completeRequest, HttpClientContext context) { try { if (Objects.nonNull(mpRequest.getPayload())) { LOGGER.fine(String.format("Request body: %s", mpRequest.getPayload().toString())); } StringBuilder headersMessage = new StringBuilder(String.format("Request Headers:%s", System.lineSeparator())); for (Map.Entry entry : mpRequest.getHeaders().entrySet()) { headersMessage.append( String.format( HEADER_LOG_FORMAT, entry.getKey(), entry.getValue(), System.lineSeparator())); } LOGGER.fine(headersMessage.toString()); return httpClient.execute(completeRequest, context); } catch (ClientProtocolException e) { LOGGER.fine(String.format("ClientProtocolException: %s", e.getMessage())); return new BasicHttpResponse( new BasicStatusLine(completeRequest.getProtocolVersion(), BAD_REQUEST, null)); } catch (SSLPeerUnverifiedException e) { LOGGER.fine(String.format("SSLException: %s", e.getMessage())); return new BasicHttpResponse( new BasicStatusLine(completeRequest.getProtocolVersion(), FORBIDDEN, null)); } catch (IOException e) { LOGGER.fine(String.format("IOException: %s", e.getMessage())); return new BasicHttpResponse( new BasicStatusLine(completeRequest.getProtocolVersion(), INTERNAL_SERVER_ERROR, null)); } } private Map> getHeaders(HttpResponse response) { Map> headers = new HashMap<>(); for (Header header : response.getAllHeaders()) { if (!headers.containsKey(header.getName())) { headers.put(header.getName(), new ArrayList<>()); } headers.get(header.getName()).add(header.getValue()); } return headers; } private HttpRequestBase getRequestBase(HttpMethod method, String uri, HttpEntity entity) throws MPMalformedRequestException { if (Objects.isNull(method)) { throw new MPMalformedRequestException( "HttpMethod must be either \"GET\", \"POST\", \"PUT\", \"PATCH\" or \"DELETE\"."); } if (StringUtils.isEmpty(uri)) { throw new MPMalformedRequestException("Uri can not be an empty String."); } if ((method.equals(HttpMethod.GET) || method.equals(HttpMethod.DELETE)) && Objects.nonNull(entity)) { throw new MPMalformedRequestException(PAYLOAD_NOT_SUPPORTED_MESSAGE); } return getHttpRequestBase(method, uri, entity); } private HttpRequestBase getHttpRequestBase(HttpMethod method, String uri, HttpEntity entity) { if (method.equals(HttpMethod.GET)) { return new HttpGet(uri); } if (method.equals(HttpMethod.POST)) { HttpPost post = new HttpPost(uri); post.setEntity(entity); return post; } if (method.equals(HttpMethod.PUT)) { HttpPut put = new HttpPut(uri); put.setEntity(entity); return put; } if (method.equals(HttpMethod.PATCH)) { HttpPatch patch = new HttpPatch(uri); patch.setEntity(entity); return patch; } if (method.equals(HttpMethod.DELETE)) { return new HttpDelete(uri); } return null; } private HttpEntity normalizePayload(JsonObject payload) throws MPMalformedRequestException { if (payload != null && payload.size() != 0) { try { return new StringEntity(payload.toString(), UTF_8); } catch (Exception ex) { throw new MPMalformedRequestException(ex); } } return null; } } ================================================ FILE: src/main/java/com/mercadopago/net/MPElementsResourcesPage.java ================================================ package com.mercadopago.net; import java.util.List; import lombok.Getter; /** * Represents a paginated API response whose JSON structure follows the * {@code {"total": N, "next_offset": M, "elements": [...]}} convention. * *

Some MercadoPago endpoints use this envelope instead of the * {@link MPResultsResourcesPage} format. The {@link #total} field indicates the overall number * of matching items, {@link #nextOffset} provides the offset for retrieving the next page, and * {@link #elements} contains the deserialized resource objects for the current page. * *

To fetch subsequent pages, create a new request with an offset equal to * {@link #nextOffset} until all items have been retrieved. * * @param the type of each resource element in the elements list * @see MPResultsResourcesPage * @see MPResource */ @Getter public class MPElementsResourcesPage extends MPResource { /** * The total number of items across all pages that match the search criteria. This value * remains constant across pages. */ private int total; /** * The offset value to use when requesting the next page of results. When all items have been * fetched, this value will typically equal or exceed {@link #total}. */ private int nextOffset; /** The list of deserialized resource objects for the current page. */ private List elements; } ================================================ FILE: src/main/java/com/mercadopago/net/MPHttpClient.java ================================================ package com.mercadopago.net; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; /** * Contract for executing HTTP requests against the MercadoPago API. * *

Implementations of this interface are responsible for the full HTTP lifecycle: building the * underlying HTTP request from an {@link MPRequest}, executing it, and wrapping the raw response * into an {@link MPResponse}. * *

The default implementation is {@link MPDefaultHttpClient}. A custom implementation can be * provided via {@link com.mercadopago.MercadoPagoConfig#setHttpClient(MPHttpClient)}. * * @see MPDefaultHttpClient * @see MPRequest * @see MPResponse */ public interface MPHttpClient { /** * Sends the given HTTP request to the MercadoPago API and returns the response. * *

If the API responds with a status code greater than 299, the implementation should throw * an {@link MPApiException} containing the full {@link MPResponse} for inspection. * * @param request the {@link MPRequest} describing the URI, HTTP method, headers, payload, and * timeout configuration for the request * @return an {@link MPResponse} containing the status code, response headers, and body content * @throws MPException if a transport-level error occurs (e.g., I/O failure, connection * timeout) preventing the request from completing * @throws MPApiException if the API returns a non-success HTTP status code (greater than 299) */ MPResponse send(MPRequest request) throws MPException, MPApiException; } ================================================ FILE: src/main/java/com/mercadopago/net/MPRequest.java ================================================ package com.mercadopago.net; import com.google.gson.JsonObject; import com.mercadopago.core.MPRequestOptions; import java.util.Map; import java.util.Objects; import java.util.UUID; import lombok.Builder; import lombok.Getter; /** * Immutable value object representing an HTTP request to be sent to the MercadoPago API. * *

Instances are created via the Lombok-generated builder or through the * {@link #buildRequest(String, HttpMethod, JsonObject, Map, MPRequestOptions)} factory method, * which merges per-request options (custom headers, access token, timeouts) from * {@link MPRequestOptions} into the request. * *

When a timeout value is {@code 0} (the default), the corresponding global timeout from * {@link com.mercadopago.MercadoPagoConfig} is used at execution time. * * @see MPRequestOptions * @see MPHttpClient#send(MPRequest) * @see MPDefaultHttpClient */ @Getter @Builder public class MPRequest { /** The fully-qualified URI (or relative path) for the API endpoint. */ private final String uri; /** The HTTP method to use for this request. */ private final HttpMethod method; /** Custom HTTP headers to include in this request, keyed by header name. */ private final Map headers; /** * The JSON request body. May be {@code null} for methods that do not carry a payload * (e.g., GET, DELETE). */ private final JsonObject payload; /** Query parameters to append to the URI, keyed by parameter name. */ private final Map queryParams; /** * The OAuth access token for this specific request. When set, it overrides the global token * from {@link com.mercadopago.MercadoPagoConfig#getAccessToken()}. */ private final String accessToken; /** * Connection timeout in milliseconds for this request. A value of {@code 0} means the global * default from {@link com.mercadopago.MercadoPagoConfig#getConnectionTimeout()} is used. */ private final int connectionTimeout; /** * Timeout in milliseconds for obtaining a connection from the connection pool. A value of * {@code 0} means the global default from * {@link com.mercadopago.MercadoPagoConfig#getConnectionRequestTimeout()} is used. */ private final int connectionRequestTimeout; /** * Socket (read) timeout in milliseconds for this request. A value of {@code 0} means the * global default from {@link com.mercadopago.MercadoPagoConfig#getSocketTimeout()} is used. */ private final int socketTimeout; /** * Factory method that builds an {@link MPRequest} from the given path, method, payload, query * parameters, and optional per-request options. * *

When {@code requestOptions} is not {@code null}, its custom headers, access token, and * timeout values are applied to the resulting request. When {@code requestOptions} is * {@code null}, only the path, method, and payload are set. * * @param path the API endpoint path (relative or absolute URL) * @param method the {@link HttpMethod} to use * @param payload the JSON body for the request, or {@code null} if none * @param queryParams a map of query parameter names to values, or {@code null} if none * @param requestOptions per-request options including custom headers, access token, and * timeouts; may be {@code null} for defaults * @return a fully constructed {@link MPRequest} ready to be sent via * {@link MPHttpClient#send(MPRequest)} */ public static MPRequest buildRequest( String path, HttpMethod method, JsonObject payload, Map queryParams, MPRequestOptions requestOptions) { MPRequest mpRequest; if (Objects.nonNull(requestOptions)) { mpRequest = MPRequest.builder() .uri(path) .method(method) .headers(requestOptions.getCustomHeaders()) .payload(payload) .queryParams(queryParams) .accessToken(requestOptions.getAccessToken()) .connectionRequestTimeout(requestOptions.getConnectionRequestTimeout()) .connectionTimeout(requestOptions.getConnectionTimeout()) .socketTimeout(requestOptions.getSocketTimeout()) .build(); } else { mpRequest = MPRequest.builder().uri(path).method(method).payload(payload).build(); } return mpRequest; } /** * Generates a new, random idempotency key based on a version-4 UUID. * *

The returned value is suitable for use as the {@link Headers#IDEMPOTENCY_KEY} header to * ensure that a POST request can be safely retried without creating duplicate resources. * * @return a random UUID string to be used as an idempotency key * @see Headers#IDEMPOTENCY_KEY */ public String createIdempotencyKey() { return UUID.randomUUID().toString(); } } ================================================ FILE: src/main/java/com/mercadopago/net/MPResource.java ================================================ package com.mercadopago.net; import lombok.Data; /** * Base class for all MercadoPago API resource objects. * *

Every domain model returned by the SDK (e.g., Payment, Preference, Customer) extends this * class. It carries a reference to the raw {@link MPResponse} from which the resource was * deserialized, allowing callers to access the original HTTP status code, response headers, and * body content when needed. * *

Subclasses are typically populated via Gson deserialization and have their {@code response} * field set by the SDK's internal request pipeline. * * @see MPResponse * @see MPResourceList * @see MPResultsResourcesPage * @see MPElementsResourcesPage */ @Data public class MPResource { /** * The raw HTTP response from which this resource was deserialized. Provides access to the * status code, headers, and body content of the original API response. */ private MPResponse response; } ================================================ FILE: src/main/java/com/mercadopago/net/MPResourceList.java ================================================ package com.mercadopago.net; import java.util.List; import lombok.Getter; import lombok.Setter; /** * Represents a list-style response from the MercadoPago API where the JSON body is a flat array * of resources (i.e., not wrapped in a pagination envelope). * *

Use this class for endpoints that return a simple JSON array such as * {@code [{"id": 1, ...}, {"id": 2, ...}]}. For paginated responses that include metadata * (total, limit, offset), use {@link MPResultsResourcesPage} or * {@link MPElementsResourcesPage} instead. * * @param the type of each resource element in the list * @see MPResource * @see MPResultsResourcesPage * @see MPElementsResourcesPage */ @Getter @Setter public class MPResourceList extends MPResource { /** The list of deserialized resource objects returned by the API. */ private List results; } ================================================ FILE: src/main/java/com/mercadopago/net/MPResponse.java ================================================ package com.mercadopago.net; import java.util.List; import java.util.Map; import lombok.AllArgsConstructor; import lombok.Getter; /** * Immutable value object representing an HTTP response returned by the MercadoPago API. * *

Instances are created by {@link MPDefaultHttpClient} after executing a request. The response * carries the HTTP status code, all response headers (with multi-value support), and the raw * response body as a string. * *

This object is also attached to {@link MPResource} subclasses so that callers can inspect * the underlying HTTP response metadata even after deserialization. * * @see MPHttpClient#send(MPRequest) * @see MPResource#getResponse() */ @Getter @AllArgsConstructor public class MPResponse { /** * The HTTP status code of the response (e.g., 200, 201, 400). * * @see HttpStatus */ private final Integer statusCode; /** * A map of response header names to their values. Each header name may map to multiple values * because HTTP allows repeated headers with the same name. */ private final Map> headers; /** * The raw response body as a UTF-8 string. May be empty for responses with no content * (e.g., HTTP 204 No Content). */ private final String content; } ================================================ FILE: src/main/java/com/mercadopago/net/MPResultsResourcesPage.java ================================================ package com.mercadopago.net; import com.mercadopago.resources.ResultsPaging; import java.util.List; import lombok.Data; import lombok.EqualsAndHashCode; /** * Represents a paginated API response whose JSON structure follows the * {@code {"paging": {...}, "results": [...]}} convention. * *

Many MercadoPago search/list endpoints return results wrapped in this envelope. The * {@link #paging} field carries pagination metadata (total count, limit, and offset), while the * {@link #results} field contains the deserialized resource objects for the current page. * *

For endpoints that use the alternative {@code {"total", "next_offset", "elements"}} structure, * see {@link MPElementsResourcesPage}. * * @param the type of each resource element in the results list * @see ResultsPaging * @see MPElementsResourcesPage * @see MPResource */ @Data @EqualsAndHashCode(callSuper = true) public class MPResultsResourcesPage extends MPResource { /** * Pagination metadata including total number of matching items, page size limit, and current * offset. */ private ResultsPaging paging; /** The list of deserialized resource objects for the current page. */ private List results; } ================================================ FILE: src/main/java/com/mercadopago/net/MPSearchRequest.java ================================================ package com.mercadopago.net; import java.util.HashMap; import java.util.Map; import java.util.Objects; import lombok.Builder; import lombok.Getter; /** * Encapsulates search and pagination parameters for MercadoPago API list/search endpoints. * *

Instances are created via the Lombok-generated builder: *

{@code
 * MPSearchRequest searchRequest = MPSearchRequest.builder()
 *     .limit(10)
 *     .offset(0)
 *     .filters(Map.of("status", "approved"))
 *     .build();
 * }
* *

The {@link #getParameters()} method merges the pagination fields ({@code limit}, * {@code offset}) with any custom filters into a single map of query parameters. If a filter * already defines a {@code limit} or {@code offset} key, the explicit filter value takes * precedence over the dedicated fields. * * @see MPRequest */ @Getter @Builder public class MPSearchRequest { /** Query parameter name used for the page size limit. */ private final String limitParam = "limit"; /** Query parameter name used for the page offset. */ private final String offsetParam = "offset"; /** * Maximum number of results to return per page. Passed as the {@code limit} query parameter * unless the {@link #filters} map already contains a {@code limit} key. */ private final Integer limit; /** * Zero-based offset indicating the starting position within the full result set. Passed as * the {@code offset} query parameter unless the {@link #filters} map already contains an * {@code offset} key. */ private final Integer offset; /** * Additional search filters to include as query parameters. Each entry's key is the parameter * name and its value is the parameter value. */ private final Map filters; /** * Merges the pagination fields ({@code limit} and {@code offset}) with the custom * {@link #filters} into a single query-parameter map. * *

If the filters already contain a key named {@code "limit"} or {@code "offset"}, the * value from the filters map is preserved (i.e., it is not overwritten by the dedicated * {@link #limit} or {@link #offset} fields). * * @return a new mutable {@link Map} containing all query parameters ready to be appended to * the request URL */ public Map getParameters() { HashMap parameters = Objects.nonNull(filters) ? new HashMap<>(filters) : new HashMap<>(); if (!parameters.containsKey(limitParam)) { parameters.put(limitParam, limit); } if (!parameters.containsKey(offsetParam)) { parameters.put(offsetParam, offset); } return parameters; } } ================================================ FILE: src/main/java/com/mercadopago/net/UrlFormatter.java ================================================ package com.mercadopago.net; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.exceptions.MPException; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.ArrayList; import java.util.Map; import java.util.Objects; /** * Utility class for building fully-qualified API request URLs for the MercadoPago SDK. * *

Handles two key responsibilities: *

    *
  • Base URL prepending -- relative paths (those not starting with * {@code "https"}) are automatically prefixed with * {@link com.mercadopago.MercadoPagoConfig#BASE_URL}.
  • *
  • Query parameter encoding -- key-value pairs from the query parameter * map are URL-encoded (UTF-8) and appended to the URL.
  • *
* * @see MPRequest * @see com.mercadopago.MercadoPagoConfig#BASE_URL */ public class UrlFormatter { /** * Formats a request URL by prepending the MercadoPago base URL (when the path is relative) * and appending URL-encoded query parameters. * *

If the path already starts with {@code "https"}, it is treated as an absolute URL and the * base URL is not prepended. Query parameters are only appended if the resulting URL does not * already contain a query string. * * @param path the API endpoint path (e.g., {@code "/v1/payments"}) or a fully-qualified * URL * @param queryParams a map of query parameter names to values to append, or {@code null} if * no parameters are needed * @return the fully-formatted URL string with base URL and encoded query parameters * @throws MPException if the URL is malformed or if UTF-8 encoding is not supported */ public static String format(String path, Map queryParams) throws MPException { StringBuilder builder = new StringBuilder(); builder.append(generateFullPath(path)); try { URL url = new URL(builder.toString()); if (Objects.isNull(url.getQuery()) && Objects.nonNull(queryParams)) { builder.append("?"); ArrayList> entries = new ArrayList<>(queryParams.entrySet()); for (int i = 0; i < entries.size(); i++) { String queryFormat = i == 0 ? "%s=%s" : "&%s=%s"; builder.append( String.format( queryFormat, URLEncoder.encode(entries.get(i).getKey(), "UTF-8"), URLEncoder.encode(entries.get(i).getValue().toString(), "UTF-8"))); } } } catch (UnsupportedEncodingException | MalformedURLException e) { throw new MPException( String.format("Error while trying to add query string to path: %s", e.getMessage())); } return builder.toString(); } private static String generateFullPath(String path) { String formatPattern = path.startsWith("/") ? "%s%s" : "%s/%s"; return !path.startsWith("https") ? String.format(formatPattern, MercadoPagoConfig.BASE_URL, path) : path; } } ================================================ FILE: src/main/java/com/mercadopago/resources/CardToken.java ================================================ package com.mercadopago.resources; import com.mercadopago.net.MPResource; import com.mercadopago.resources.customer.CustomerCardCardholder; import java.time.OffsetDateTime; import lombok.EqualsAndHashCode; import lombok.Getter; /** * Represents a tokenized card used to process secure payment transactions in the MercadoPago API. * *

Card tokens are generated by sending card data to the MercadoPago server, which returns a * token that can be used to complete payment transactions without exposing sensitive card details. * This resource is intended for testing purposes in sandbox environments. * * @see * Card Token API Reference */ @Getter @EqualsAndHashCode(callSuper = true) public class CardToken extends MPResource { /** Unique identifier of the card token. */ private String id; /** Identifier of the associated card. */ private String cardId; /** First six digits of the card number (BIN). */ private String firstSixDigits; /** Expiration month of the card (1-12). */ private Integer expirationMonth; /** Expiration year of the card (four-digit format). */ private Integer expirationYear; /** Last four digits of the card number. */ private String lastFourDigits; /** Information about the cardholder (name and identification). */ private CustomerCardCardholder cardholder; /** Current status of the card token (e.g., active). */ private String status; /** Date and time when the card token was created. */ private OffsetDateTime dateCreated; /** Date and time when the card token was last updated. */ private OffsetDateTime dateLastUpdated; /** Date and time when the card token expires. */ private OffsetDateTime dateDue; /** Whether the Luhn algorithm validation is applied to the card number. */ private Boolean luhnValidation; /** Whether the token was created in production (live) mode. */ private Boolean liveMode; /** Whether the token requires ESC (Electronic Security Code). */ private Boolean requireEsc; /** Total length of the card number. */ private Integer cardNumberLength; /** Length of the card's security code (CVV). */ private Integer securityCodeLength; } ================================================ FILE: src/main/java/com/mercadopago/resources/ResultsPaging.java ================================================ package com.mercadopago.resources; import lombok.Getter; /** * Pagination metadata returned by MercadoPago API endpoints that use the * {@code {"paging": {"total": N, "limit": M, "offset": O}, "results": [...]}} response envelope. * *

This class is deserialized from the {@code paging} object within an * {@link com.mercadopago.net.MPResultsResourcesPage} and provides the information needed to * iterate through pages of results: *

    *
  • {@link #total} -- the total number of items matching the query across all pages.
  • *
  • {@link #limit} -- the maximum number of items returned per page.
  • *
  • {@link #offset} -- the zero-based starting position of the current page within the full * result set.
  • *
* * @see com.mercadopago.net.MPResultsResourcesPage * @see com.mercadopago.net.MPSearchRequest */ @Getter public class ResultsPaging { /** * The total number of items that match the search criteria across all pages. This value * remains constant regardless of the current page. */ private int total; /** * The maximum number of items returned in a single page of results. Corresponds to the * {@code limit} query parameter sent in the original request. */ private int limit; /** * The zero-based offset of the first item in the current page within the full result set. * Corresponds to the {@code offset} query parameter sent in the original request. */ private int offset; } ================================================ FILE: src/main/java/com/mercadopago/resources/common/Address.java ================================================ package com.mercadopago.resources.common; import lombok.Getter; /** * Represents a generic physical address used across the MercadoPago API. * *

Contains basic address information such as street name, street number, and zip code. This * class is used as a shared component in resources like payments, preferences, and customers. * * @see MercadoPago API Reference */ @Getter public class Address { /** Street name of the address. */ private String streetName; /** Street number of the address. */ private String streetNumber; /** Postal zip code of the address. */ private String zipCode; } ================================================ FILE: src/main/java/com/mercadopago/resources/common/Identification.java ================================================ package com.mercadopago.resources.common; import lombok.Getter; /** * Represents an identification document used across the MercadoPago API. * *

This base type holds document data such as type (e.g., CPF, DNI, CNPJ) and document number. * It is commonly used in payer, customer, and cardholder contexts to identify individuals. * * @see MercadoPago API Reference */ @Getter public class Identification { /** Type of identification document (e.g., CPF, DNI, CNPJ). */ private String type; /** Unique number of the identification document. */ private String number; } ================================================ FILE: src/main/java/com/mercadopago/resources/common/Phone.java ================================================ package com.mercadopago.resources.common; import lombok.Getter; /** * Represents a phone number used across the MercadoPago API. * *

Holds the area code and the phone number, typically associated with payers, customers, or * other contact information within the MercadoPago ecosystem. * * @see MercadoPago API Reference */ @Getter public class Phone { /** Area code of the phone number (e.g., country or region prefix). */ private String areaCode; /** Phone number without the area code. */ private String number; } ================================================ FILE: src/main/java/com/mercadopago/resources/common/Source.java ================================================ package com.mercadopago.resources.common; import lombok.Getter; /** * Represents the source or origin of an action in the MercadoPago API. * *

Identifies the entity that initiated an operation, such as a refund or chargeback. It * includes the source identifier, name, and type to trace the originating party. * * @see MercadoPago API Reference */ @Getter public class Source { /** Unique identifier of the source. */ public String id; /** Name of the source entity. */ public String name; /** Type of the source (e.g., collector, operator). */ public String type; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/Customer.java ================================================ package com.mercadopago.resources.customer; import com.mercadopago.resources.common.Identification; import com.mercadopago.resources.common.Phone; import com.mercadopago.net.MPResource; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import lombok.Getter; /** * Represents a customer resource in the MercadoPago API. * *

Stores customer data such as email, name, phone, identification, addresses, and saved cards * to improve the shopping experience. When used with the Cards resource, customers can complete * purchases faster without re-entering payment information. * * @see * Customer API Reference */ @Getter public class Customer extends MPResource { /** Unique identifier of the customer. */ private String id; /** Email address of the customer. */ private String email; /** First name of the customer. */ private String firstName; /** Last name of the customer. */ private String lastName; /** Phone information of the customer. */ private Phone phone; /** Identification document information of the customer. */ private Identification identification; /** Identifier of the customer's default address. */ private String defaultAddress; /** Default address details of the customer. */ private CustomerDefaultAddress address; /** Date when the customer registered on the merchant's site. */ private OffsetDateTime dateRegistered; /** Free-text description or notes about the customer. */ private String description; /** Date and time when the customer record was created in MercadoPago. */ private OffsetDateTime dateCreated; /** Date and time when the customer record was last updated. */ private OffsetDateTime dateLastUpdated; /** Custom metadata as key-value pairs associated with the customer. */ private Map metadata; /** Identifier of the customer's default card. */ private String defaultCard; /** List of saved cards associated with the customer. */ private List cards; /** List of addresses registered for the customer. */ private List addresses; /** Whether the customer was created in production (live) mode. */ private Boolean liveMode; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerAddress.java ================================================ package com.mercadopago.resources.customer; import java.time.OffsetDateTime; import lombok.Getter; /** * Represents a detailed address associated with a customer in the MercadoPago API. * *

Contains full address information including street, apartment, floor, city, state, country, * neighborhood, and municipality. A customer may have multiple addresses on file. * * @see Customer * @see * Customer API Reference */ @Getter public class CustomerAddress { /** Unique identifier of the address. */ private String id; /** Contact phone number associated with this address. */ private String phone; /** Descriptive name or label for this address (e.g., "Home", "Work"). */ private String name; /** Floor number within the building. */ private String floor; /** Apartment or unit number. */ private String apartment; /** Street name of the address. */ private String streetName; /** Street number of the address. */ private String streetNumber; /** Postal or zip code of the address. */ private String zipCode; /** City information of the address. */ private CustomerAddressCity city; /** State or province information of the address. */ private CustomerAddressState state; /** Country information of the address. */ private CustomerAddressCountry country; /** Neighborhood information of the address. */ private CustomerAddressNeighborhood neighborhood; /** Municipality information of the address. */ private CustomerAddressMunicipality municipality; /** Additional comments or instructions about the address. */ private String comments; /** Date and time when the address was created. */ private OffsetDateTime dateCreated; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerAddressCity.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents city information within a customer's address in the MercadoPago API. * *

Contains the city identifier and name as part of the geographic breakdown of a customer * address. * * @see CustomerAddress */ @Getter public class CustomerAddressCity { /** Unique identifier of the city. */ private String id; /** Name of the city. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerAddressCountry.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents country information within a customer's address in the MercadoPago API. * *

Contains the country identifier and name as part of the geographic breakdown of a customer * address. * * @see CustomerAddress */ @Getter public class CustomerAddressCountry { /** Unique identifier of the country. */ private String id; /** Name of the country. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerAddressMunicipality.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents municipality information within a customer's address in the MercadoPago API. * *

Contains the municipality identifier and name as part of the geographic breakdown of a * customer address. Applicable in countries where municipalities are an administrative division. * * @see CustomerAddress */ @Getter public class CustomerAddressMunicipality { /** Unique identifier of the municipality. */ private String id; /** Name of the municipality. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerAddressNeighborhood.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents neighborhood information within a customer's address in the MercadoPago API. * *

Contains the neighborhood identifier and name as part of the geographic breakdown of a * customer address. * * @see CustomerAddress */ @Getter public class CustomerAddressNeighborhood { /** Unique identifier of the neighborhood. */ private String id; /** Name of the neighborhood. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerAddressState.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents state or province information within a customer's address in the MercadoPago API. * *

Contains the state identifier and name as part of the geographic breakdown of a customer * address. * * @see CustomerAddress */ @Getter public class CustomerAddressState { /** Unique identifier of the state or province. */ private String id; /** Name of the state or province. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerCard.java ================================================ package com.mercadopago.resources.customer; import com.mercadopago.net.MPResource; import java.time.OffsetDateTime; import lombok.EqualsAndHashCode; import lombok.Getter; /** * Represents a saved card associated with a customer in the MercadoPago API. * *

Contains card details such as expiration date, first/last digits, payment method, issuer, * cardholder information, and security code metadata. Saved cards enable returning customers to * complete payments without re-entering their card data. * * @see Customer * @see * Customer Cards API Reference */ @Getter @EqualsAndHashCode(callSuper = true) public class CustomerCard extends MPResource { /** Unique identifier of the card. */ private String id; /** Identifier of the customer who owns this card. */ private String customerId; /** Expiration month of the card (1-12). */ private Integer expirationMonth; /** Expiration year of the card (four-digit format). */ private Integer expirationYear; /** First six digits of the card number (BIN). */ private String firstSixDigits; /** Last four digits of the card number. */ private String lastFourDigits; /** Payment method information associated with this card. */ private CustomerCardPaymentMethod paymentMethod; /** Security code metadata of the card (length and location). */ private CustomerCardSecurityCode securityCode; /** Issuer (financial institution) of the card. */ private CustomerCardIssuer issuer; /** Cardholder information including name and identification. */ private CustomerCardCardholder cardholder; /** Date and time when the card record was created. */ private OffsetDateTime dateCreated; /** Date and time when the card record was last updated. */ private OffsetDateTime dateLastUpdated; /** Identifier of the user associated with this card. */ private String userId; /** Whether this card was saved in production (live) mode. */ private boolean liveMode; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerCardCardholder.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents the cardholder information for a saved customer card in the MercadoPago API. * *

Contains the cardholder's name and identification document, which are used to validate card * ownership during payment processing. * * @see CustomerCard */ @Getter public class CustomerCardCardholder { /** Full name of the cardholder as printed on the card. */ private String name; /** Identification document of the cardholder. */ private CustomerCardCardholderIdentification identification; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerCardCardholderIdentification.java ================================================ package com.mercadopago.resources.customer; import com.mercadopago.resources.common.Identification; import lombok.EqualsAndHashCode; import lombok.Getter; /** * Represents the identification document of a cardholder in the MercadoPago API. * *

Extends the common {@link Identification} class to provide document type and number for * cardholder verification purposes. Inherits fields such as type (e.g., CPF, DNI) and number. * * @see Identification * @see CustomerCardCardholder */ @Getter @EqualsAndHashCode(callSuper = true) public class CustomerCardCardholderIdentification extends Identification {} ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerCardIssuer.java ================================================ package com.mercadopago.resources.customer; import lombok.Builder; import lombok.Getter; /** * Represents the issuer (financial institution) of a customer's saved card in the MercadoPago API. * *

Contains the issuer identifier and name, which identify the bank or financial institution * that issued the card. * * @see CustomerCard */ @Getter @Builder public class CustomerCardIssuer { /** Unique identifier of the card issuer. */ private final String id; /** Name of the card issuer (e.g., bank name). */ private final String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerCardPaymentMethod.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents the payment method associated with a customer's saved card in the MercadoPago API. * *

Contains details about the payment method type, name, and thumbnail images that correspond * to the card brand (e.g., Visa, Mastercard). * * @see CustomerCard */ @Getter public class CustomerCardPaymentMethod { /** Unique identifier of the payment method. */ private String id; /** Display name of the payment method (e.g., Visa, Mastercard). */ private String name; /** Type identifier of the payment method (e.g., credit_card, debit_card). */ private String paymentTypeId; /** URL of the payment method thumbnail image. */ private String thumbnail; /** URL of the payment method thumbnail image served over HTTPS. */ private String secureThumbnail; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerCardSecurityCode.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents security code (CVV) metadata for a customer's saved card in the MercadoPago API. * *

Describes the expected length of the security code and its physical location on the card * (e.g., front or back), used for validation and UI rendering purposes. * * @see CustomerCard */ @Getter public class CustomerCardSecurityCode { /** Expected length of the security code (e.g., 3 or 4 digits). */ private Integer length; /** Physical location of the security code on the card (e.g., "back", "front"). */ private String cardLocation; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/CustomerDefaultAddress.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents the default address of a customer in the MercadoPago API. * *

Contains a simplified set of address fields (zip code, street name, and street number) used * as the customer's primary address for shipping and billing purposes. * * @see Customer */ @Getter public class CustomerDefaultAddress { /** Unique identifier of the default address. */ private String id; /** Postal or zip code of the address. */ private String zipCode; /** Street name of the address. */ private String streetName; /** Street number of the address. */ private Integer streetNumber; } ================================================ FILE: src/main/java/com/mercadopago/resources/customer/Identification.java ================================================ package com.mercadopago.resources.customer; import lombok.Getter; /** * Represents a customer's identification document in the MercadoPago API. * *

Holds the document type (e.g., CPF, DNI, CNPJ) and the document number, used for identity * verification in customer-related operations. * * @see Customer */ @Getter public class Identification { /** Type of identification document (e.g., CPF, DNI, CNPJ). */ private String type; /** Number of the identification document. */ private String number; } ================================================ FILE: src/main/java/com/mercadopago/resources/identificationtype/IdentificationType.java ================================================ package com.mercadopago.resources.identificationtype; import com.mercadopago.net.MPResource; import lombok.Getter; /** * Represents a type of identification document available in the MercadoPago API. * *

Describes the accepted identification document types for a given country (e.g., CPF, DNI, * CNPJ), including validation constraints such as minimum and maximum character lengths. * * @see * Identification Types API Reference */ @Getter public class IdentificationType extends MPResource { /** Unique identifier of the identification type. */ private String id; /** Display name of the identification type (e.g., CPF, DNI). */ private String name; /** Data type of the identification number (e.g., "number", "string"). */ private String type; /** Minimum allowed length for the identification number. */ private Integer minLength; /** Maximum allowed length for the identification number. */ private Integer maxLength; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrder.java ================================================ package com.mercadopago.resources.merchantorder; import com.mercadopago.net.MPResource; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.List; import lombok.Getter; /** * Represents a merchant order resource in the MercadoPago API. * *

A merchant order groups one or more payments, items, and shipments into a single commercial * transaction. It tracks the overall status, amounts, and logistics of an order placed through * MercadoPago payment preferences. * * @see * Merchant Order API Reference */ @Getter public class MerchantOrder extends MPResource { /** Unique identifier of the merchant order. */ private Long id; /** Payment preference identifier associated with this merchant order. */ private String preferenceId; /** Application identifier that created the order. */ private String applicationId; /** Current status of the merchant order (e.g., opened, closed). */ private String status; /** Country site identifier where the merchant order was created (e.g., MLA, MLB). */ private String siteId; /** Payer (buyer) information for this order. */ private MerchantOrderPayer payer; /** Collector (seller) information for this order. */ private MerchantOrderCollector collector; /** Identifier of the sponsor associated with the order. */ private String sponsorId; /** List of payments associated with this merchant order. */ private List payments; /** Total amount already paid for this order. */ private BigDecimal paidAmount; /** Total amount refunded for this order. */ private BigDecimal refundedAmount; /** Shipping cost of the order. */ private BigDecimal shippingCost; /** Date and time when the order was created. */ private OffsetDateTime dateCreated; /** Whether the order has been cancelled. */ private boolean cancelled; /** List of items included in this order. */ private List items; /** List of shipments associated with this order. */ private List shipments; /** URL to receive payment notification webhooks. */ private String notificationUrl; /** Additional information about the order. */ private String additionalInfo; /** External reference to synchronize with the merchant's own system. */ private String externalReference; /** Marketplace origin of the payment. */ private String marketplace; /** Total amount of the order including all items. */ private BigDecimal totalAmount; /** Computed order status based on the aggregate status of its payments. */ private String orderStatus; /** Date and time when the order was last updated. */ private OffsetDateTime lastUpdated; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderCollector.java ================================================ package com.mercadopago.resources.merchantorder; import lombok.Getter; /** * Represents the collector (seller) of a merchant order in the MercadoPago API. * *

Contains the seller's identifier and nickname, identifying the merchant who will receive * the payment for the order. * * @see MerchantOrder */ @Getter public class MerchantOrderCollector { /** Unique identifier of the collector (seller). */ private Long id; /** Display nickname of the collector (seller). */ private String nickname; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderItem.java ================================================ package com.mercadopago.resources.merchantorder; import java.math.BigDecimal; import lombok.Getter; /** * Represents an item within a merchant order in the MercadoPago API. * *

Contains product information such as title, description, image, category, quantity, and * unit price. A merchant order may contain one or more items. * * @see MerchantOrder */ @Getter public class MerchantOrderItem { /** Unique identifier (code) of the item. */ private String id; /** Title or name of the item. */ private String title; /** Detailed description of the item. */ private String description; /** URL of the item's image. */ private String pictureUrl; /** Category identifier for the item. */ private String categoryId; /** Quantity of this item in the order. */ private int quantity; /** Unit price of the item. */ private BigDecimal unitPrice; /** Currency identifier in ISO 4217 format (e.g., BRL, ARS, USD). */ private String currencyId; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderPayer.java ================================================ package com.mercadopago.resources.merchantorder; import lombok.Getter; /** * Represents the payer (buyer) of a merchant order in the MercadoPago API. * *

Contains the buyer's identifier and nickname, identifying the customer who placed the order. * * @see MerchantOrder */ @Getter public class MerchantOrderPayer { /** Unique identifier of the payer (buyer). */ private Long id; /** Display nickname of the payer (buyer). */ private String nickname; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderPayment.java ================================================ package com.mercadopago.resources.merchantorder; import java.math.BigDecimal; import java.time.OffsetDateTime; import lombok.Getter; /** * Represents a payment associated with a merchant order in the MercadoPago API. * *

Contains payment details such as transaction amount, status, currency, approval date, and * refund information. A merchant order may have multiple payments. * * @see MerchantOrder */ @Getter public class MerchantOrderPayment { /** Unique identifier of the payment. */ private Long id; /** Transaction amount (product cost) of the payment. */ private BigDecimal transactionAmount; /** Total amount paid including shipping and other charges. */ private BigDecimal totalPaidAmount; /** Shipping cost included in the payment. */ private BigDecimal shippingCost; /** Currency identifier in ISO 4217 format (e.g., BRL, ARS, USD). */ private String currencyId; /** Current status of the payment (e.g., approved, pending, rejected). */ private String status; /** Detailed information about the payment status or rejection cause. */ private String statusDetails; /** Type of operation (e.g., regular_payment, money_transfer). */ private String operationType; /** Date and time when the payment was approved. */ private OffsetDateTime dateApproved; /** Date and time when the payment was created. */ private OffsetDateTime dateCreated; /** Date and time when the payment was last modified. */ private OffsetDateTime lastModified; /** Total amount refunded from this payment. */ private BigDecimal amountRefunded; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderReceiverAddress.java ================================================ package com.mercadopago.resources.merchantorder; import lombok.Getter; /** * Represents the receiver's shipping address for a merchant order in the MercadoPago API. * *

Contains the full destination address for shipment delivery, including street details, * apartment, floor, geographic coordinates, and hierarchical geographic data (city, state, * country). * * @see MerchantOrderShipment */ @Getter public class MerchantOrderReceiverAddress { /** Unique identifier of the receiver address. */ private Long id; /** Full address line (street name and number combined). */ private String addressLine; /** Apartment or unit number. */ private String apartment; /** City information of the receiver address. */ private MerchantOrderReceiverAddressCity city; /** State or province information of the receiver address. */ private MerchantOrderReceiverAddressState state; /** Country information of the receiver address. */ private MerchantOrderReceiverAddressCountry country; /** Additional comments or delivery instructions. */ private String comment; /** Contact name or information for the receiver. */ private String contact; /** Postal or zip code of the receiver address. */ private String zipCode; /** Street name of the receiver address. */ private String streetName; /** Street number of the receiver address. */ private String streetNumber; /** Floor number within the building. */ private String floor; /** Contact phone number at the receiver address. */ private String phone; /** Geographic latitude coordinate of the address. */ private String latitude; /** Geographic longitude coordinate of the address. */ private String longitude; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderReceiverAddressCity.java ================================================ package com.mercadopago.resources.merchantorder; import lombok.Getter; /** * Represents city information within a merchant order receiver address in the MercadoPago API. * *

Contains the city identifier and name as part of the shipping destination address. * * @see MerchantOrderReceiverAddress */ @Getter public class MerchantOrderReceiverAddressCity { /** Unique identifier of the city. */ private String id; /** Name of the city. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderReceiverAddressCountry.java ================================================ package com.mercadopago.resources.merchantorder; import lombok.Getter; /** * Represents country information within a merchant order receiver address in the MercadoPago API. * *

Contains the country identifier and name as part of the shipping destination address. * * @see MerchantOrderReceiverAddress */ @Getter public class MerchantOrderReceiverAddressCountry { /** Unique identifier of the country. */ private String id; /** Name of the country. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderReceiverAddressState.java ================================================ package com.mercadopago.resources.merchantorder; import lombok.Getter; /** * Represents state or province information within a merchant order receiver address in the * MercadoPago API. * *

Contains the state identifier and name as part of the shipping destination address. * * @see MerchantOrderReceiverAddress */ @Getter public class MerchantOrderReceiverAddressState { /** Unique identifier of the state or province. */ private String id; /** Name of the state or province. */ private String name; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderShipment.java ================================================ package com.mercadopago.resources.merchantorder; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import lombok.Getter; /** * Represents a shipment associated with a merchant order in the MercadoPago API. * *

Contains shipping logistics information including type, mode, status, items being shipped, * sender/receiver details, delivery address, and selected shipping option. * * @see MerchantOrder */ @Getter public class MerchantOrderShipment { /** Unique identifier of the shipment. */ private Long id; /** Type of shipping (e.g., custom, mercadoenvios). */ private String shippingType; /** Shipping mode (e.g., me1, me2, not_specified). */ private String shippingMode; /** Picking type for the shipment (e.g., fulfillment, cross_docking). */ private String pickingType; /** Current status of the shipment (e.g., pending, shipped, delivered). */ private String status; /** Sub-status providing additional detail about the shipment status. */ private String shippingSubstatus; /** List of items included in this shipment as key-value maps. */ private List> items; /** Date and time when the shipment was created. */ private OffsetDateTime dateCreated; /** Date and time when the shipment was last modified. */ private OffsetDateTime lastModified; /** Date and time when the shipping label was first printed. */ private OffsetDateTime dateFirstPrinted; /** Identifier of the shipping service used. */ private String serviceId; /** Identifier of the sender (seller). */ private Long senderId; /** Identifier of the receiver (buyer). */ private Long receiverId; /** Destination address for the shipment. */ private MerchantOrderReceiverAddress receiverAddress; /** Selected shipping option with cost and delivery details. */ private MerchantOrderShippingOption shippingOption; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderShippingEstimatedDelivery.java ================================================ package com.mercadopago.resources.merchantorder; import java.time.OffsetDateTime; import lombok.Getter; /** * Represents estimated delivery information for a shipping option in the MercadoPago API. * *

Provides the estimated delivery date and a time window (from/to) within which the shipment * is expected to arrive. * * @see MerchantOrderShippingOption */ @Getter public class MerchantOrderShippingEstimatedDelivery { /** Estimated date of delivery. */ private OffsetDateTime date; /** Start of the estimated delivery time window. */ private String timeFrom; /** End of the estimated delivery time window. */ private String timeTo; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderShippingOption.java ================================================ package com.mercadopago.resources.merchantorder; import java.math.BigDecimal; import lombok.Getter; /** * Represents a shipping option available for a merchant order shipment in the MercadoPago API. * *

Contains cost, currency, estimated delivery, shipping method, and speed information for a * specific shipping option that can be selected for order fulfillment. * * @see MerchantOrderShipment */ @Getter public class MerchantOrderShippingOption { /** Unique identifier of the shipping option. */ private Long id; /** Net cost absorbed by the receiver (buyer). */ private BigDecimal cost; /** Currency identifier in ISO 4217 format (e.g., BRL, ARS, USD). */ private String currencyId; /** Estimated delivery date and time window. */ private MerchantOrderShippingEstimatedDelivery estimatedDelivery; /** Listed (original) cost of the shipping before discounts. */ private BigDecimal listCost; /** Display name of the shipping option. */ private String name; /** Identifier of the shipping method. */ private Long shippingMethodId; /** Speed details including handling and shipping times. */ private MerchantOrderShippingSpeed speed; } ================================================ FILE: src/main/java/com/mercadopago/resources/merchantorder/MerchantOrderShippingSpeed.java ================================================ package com.mercadopago.resources.merchantorder; import lombok.Getter; /** * Represents shipping speed details for a shipping option in the MercadoPago API. * *

Contains the handling time (preparation before dispatch) and shipping time (transit duration) * in hours, used to calculate total estimated delivery time. * * @see MerchantOrderShippingOption */ @Getter public class MerchantOrderShippingSpeed { /** Handling time in hours before the package is dispatched. */ private Long handling; /** Transit time in hours from dispatch to delivery. */ private Long shipping; } ================================================ FILE: src/main/java/com/mercadopago/resources/oauth/CreateOauthCredential.java ================================================ package com.mercadopago.resources.oauth; import lombok.EqualsAndHashCode; import lombok.Getter; /** * Resource representing the credential returned when creating a new OAuth authorization. * Extends {@link OauthCredential} with additional fields that indicate the public key * associated with the application and whether the credential operates in live (production) mode. * * @see OauthCredential */ @Getter @EqualsAndHashCode(callSuper = true) public class CreateOauthCredential extends OauthCredential { /** Public key associated with the MercadoPago application for this credential. */ private String publicKey; /** Whether this credential is configured for live (production) mode rather than sandbox. */ private boolean liveMode; } ================================================ FILE: src/main/java/com/mercadopago/resources/oauth/OauthCredential.java ================================================ package com.mercadopago.resources.oauth; import com.mercadopago.net.MPResource; import lombok.Getter; /** * Base resource representing credential information obtained from an OAuth authorization flow. * Contains the access token, its type and expiration, the granted scope, and a refresh token * that can be used to renew the credential without repeating the authorization process. * * @see OAuth API reference */ @Getter public class OauthCredential extends MPResource { /** OAuth access token used to authenticate API requests on behalf of the user. */ private String accessToken; /** Token type indicating the authentication scheme, typically "Bearer". */ private String tokenType; /** Number of seconds until the access token expires. */ private Long expiresIn; /** OAuth scope that defines the permissions granted by this credential. */ private String scope; /** Refresh token used to obtain a new access token when the current one expires. */ private String refreshToken; } ================================================ FILE: src/main/java/com/mercadopago/resources/oauth/RefreshOauthCredential.java ================================================ package com.mercadopago.resources.oauth; import lombok.EqualsAndHashCode; import lombok.Getter; /** * Resource representing the credential returned when refreshing an existing OAuth token. * Inherits all fields from {@link OauthCredential} including the new access token, * its expiration, scope, and a potentially rotated refresh token. * * @see OauthCredential */ @Getter @EqualsAndHashCode(callSuper = true) public class RefreshOauthCredential extends OauthCredential {} ================================================ FILE: src/main/java/com/mercadopago/resources/order/Order.java ================================================ package com.mercadopago.resources.order; import com.mercadopago.net.MPResource; import lombok.Getter; import java.util.List; import java.util.Map; /* API version: acd67b14-97c4-4a4a-840d-0a018c09654f */ /** * Resource representing a MercadoPago Order. * An Order is the top-level entity that groups one or more payment transactions, line items, * payer information, and configuration options for online or point-of-sale checkout flows. * * @see Order API reference */ @Getter public class Order extends MPResource { /** Unique identifier of the order. */ private String id; /** Type of the order (e.g., "online", "point"). */ private String type; /** External reference used to correlate this order with an identifier in the integrator's system. */ private String externalReference; /** Total amount of the order expressed as a decimal string. */ private String totalAmount; /** Total amount already paid on this order expressed as a decimal string. */ private String totalPaidAmount; /** Country code of the site to which the MercadoPago application that created the order belongs. */ private String countryCode; /** Identifier of the user (seller) who will receive the payment for this order. */ private String userId; /** Current status of the order (e.g., "created", "processed", "expired"). */ private String status; /** Detailed sub-status providing additional context about the current order status. */ private String statusDetail; /** Capture mode for the order's payments (e.g., "automatic", "manual"). */ private String captureMode; /** ISO 8601 date-time when the order was created. */ private String createdDate; /** ISO 8601 date-time when the order was last updated. */ private String lastUpdatedDate; /** Integration data containing identifiers for correlating the order with external systems. */ private OrderIntegrationData integrationData; /** Processing mode that controls how payments are executed (e.g., "aggregator", "gateway"). */ private String processingMode; /** Free-text description of the order visible to the payer. */ private String description; /** Marketplace identifier indicating the origin of the order. */ private String marketplace; /** Fee collected by the marketplace or MercadoPago application, expressed as a decimal string. */ private String marketplaceFee; /** Transaction details including payments, refunds, and chargebacks associated with this order. */ private OrderTransaction transactions; /** ISO 8601 date-time from which the checkout becomes available for the payer. */ private String checkoutAvailableAt; /** ISO 8601 date-time when the order expires if not completed. */ private String expirationTime; /** Unique client token that identifies the integrator's credentials for this order. */ private String clientToken; /** List of line items included in this order. */ private List items; /** Configuration settings for payment methods, online checkout, and point-of-sale behavior. */ private OrderConfig config; /** Information about the payer associated with this order. */ private OrderPayer payer; /** Additional key-value metadata attached to the order for integration purposes. */ private Map additionalInfo; /** ISO 4217 currency code for the order (e.g., "BRL", "ARS", "MXN"). */ private String currency; /** List of taxes applied to the order. */ private List taxes; /** Discount information applied to the order by payment method. */ private OrderDiscounts discounts; /** Type-specific response data such as QR codes for in-store payments. */ private OrderTypeResponse typeResponse; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderAttempts.java ================================================ package com.mercadopago.resources.order; import com.mercadopago.resources.paymentmethod.PaymentMethod; import lombok.Getter; // API version: d0494f1c-8d81-4c76-ae1d-0c65bb8ef6de /** * Resource representing a payment attempt within a MercadoPago Order payment. * Records the outcome of an individual attempt to process a payment, including * its status and the payment method used. */ @Getter public class OrderAttempts { /** Unique identifier of this payment attempt. */ private String id; /** Status of this payment attempt (e.g., "approved", "rejected"). */ private String status; /** Detailed sub-status providing the reason for the attempt outcome. */ private String statusDetail; /** Payment method used in this attempt. */ private PaymentMethod paymentMethod; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderAutomaticPayments.java ================================================ package com.mercadopago.resources.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing automatic (recurring) payment configuration for a MercadoPago Order. * Defines the payment profile, retry policy, and scheduling dates for automated billing cycles. */ @Getter @Builder public class OrderAutomaticPayments { /** Identifier of the payment profile used for automatic charges. */ private String paymentProfileId; /** Number of retry attempts allowed if the automatic payment fails. */ private Integer retries; /** ISO 8601 date-time when the automatic payment is scheduled to be processed. */ private String scheduleDate; /** ISO 8601 date-time by which the automatic payment must be completed. */ private String dueDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderCategoryDescriptor.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing category-specific descriptors for a MercadoPago Order item. * Used for travel and event categories to provide additional details such as * event dates, passenger identity, and route information. */ @Getter public class OrderCategoryDescriptor { /** ISO 8601 date of the event associated with this item. */ private String eventDate; /** Passenger details for travel-related order items. */ private OrderPassenger passenger; /** Route details including departure, destination, and travel dates. */ private OrderRoute route; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderChargeback.java ================================================ package com.mercadopago.resources.order; import java.util.List; import lombok.Getter; /** * Resource representing a chargeback raised against a payment within a MercadoPago Order. * Contains identifiers for the chargeback case, the disputed transaction, and the * current dispute status. */ @Getter public class OrderChargeback { /** Unique identifier of this chargeback. */ private String id; /** Identifier of the original transaction that is being disputed. */ private String transactionId; /** Identifier of the dispute case opened by the card issuer or payment network. */ private String caseId; /** Current status of the chargeback dispute (e.g., "open", "closed"). */ private String status; /** List of reference identifiers associated with this chargeback. */ private List references; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderConfig.java ================================================ package com.mercadopago.resources.order; import com.mercadopago.client.order.OrderOnlineConfig; import com.mercadopago.client.order.OrderPaymentMethodConfig; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing the configuration of a MercadoPago Order. * Groups together payment method restrictions, online checkout settings, * and point-of-sale terminal configuration. */ @Getter public class OrderConfig { /** Payment method configuration defining accepted methods and installment rules. */ private OrderPaymentMethodConfig paymentMethod; /** Online checkout configuration including redirect URLs and 3DS settings. */ private OrderOnlineConfig online; /** Point-of-sale terminal configuration for in-store payments. */ private OrderPointConfig point; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderDifferentialPricing.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing differential pricing configuration for a MercadoPago Order. * Allows applying different prices to buyers based on predefined pricing groups * configured in the seller's MercadoPago account. */ @Getter public class OrderDifferentialPricing { /** Identifier of the differential pricing group to apply. */ private Integer id; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderDiscountPaymentMethod.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing a discount tied to a specific payment method type in a MercadoPago Order. * Indicates the adjusted total amount the payer would pay when using this payment method. */ @Getter public class OrderDiscountPaymentMethod { /** Payment method type that qualifies for this discount (e.g., "credit_card", "debit_card"). */ private String type; /** Adjusted total order amount after applying the discount, expressed as a decimal string. */ private String newTotalAmount; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderDiscounts.java ================================================ package com.mercadopago.resources.order; import java.util.List; import lombok.Getter; /** * Resource representing discount information applied to a MercadoPago Order. * Contains discounts organized by payment method, each specifying the adjusted * total amount when that payment method is selected. */ @Getter public class OrderDiscounts { /** List of payment-method-specific discounts available for this order. */ private List paymentMethods; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderExternalCategory.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing an external category classification for a MercadoPago Order item. * Used to map items to category taxonomies defined outside of MercadoPago. */ @Getter public class OrderExternalCategory { /** Identifier of the external category in the integrator's classification system. */ private String id; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderInstallments.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing installment configuration for a MercadoPago Order payment method. * Defines both interest-free installment options and the general availability rules * for installment plans. */ @Getter public class OrderInstallments { /** Interest-free installment options offered to the payer. */ private OrderInstallmentsInterestFree interestFree; /** Configuration defining which installment plans are available. */ private OrderInstallmentsAvailable available; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderInstallmentsAvailable.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing the availability configuration for installment plans * on a MercadoPago Order payment method. */ @Getter public class OrderInstallmentsAvailable { /** Type of installment availability rule (e.g., "all", "specific"). */ private String type; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderInstallmentsInterestFree.java ================================================ package com.mercadopago.resources.order; import java.util.List; import lombok.Getter; /** * Resource representing interest-free installment options for a MercadoPago Order payment method. * Specifies how interest-free installments are determined and the allowed installment counts. */ @Getter public class OrderInstallmentsInterestFree { /** Type of interest-free rule (e.g., "specific_values"). */ private String type; /** List of installment counts offered without interest (e.g., [3, 6, 12]). */ private List values; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderIntegrationData.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing integration metadata for a MercadoPago Order. * Contains identifiers used to correlate the order with the integrator's * MercadoPago application. */ @Getter public class OrderIntegrationData { /** Identifier of the MercadoPago application that created this order. */ private String applicationId; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderInvoicePeriod.java ================================================ package com.mercadopago.resources.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing the billing period for a subscription invoice * within a MercadoPago Order. Defines the recurrence type and interval * between charges. */ @Getter @Builder public class OrderInvoicePeriod { /** Type of billing period (e.g., "daily", "monthly", "yearly"). */ private String type; /** Number of intervals between billing cycles (e.g., 1 for every month, 2 for bimonthly). */ private Integer period; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderItem.java ================================================ package com.mercadopago.resources.order; import java.util.List; import lombok.Getter; // API version: acd67b14-97c4-4a4a-840d-0a018c09654f /** * Resource representing a line item within a MercadoPago Order. * Each item describes a product or service being purchased, including its * price, quantity, category, and optional metadata such as picture URL and warranty. */ @Getter public class OrderItem { /** Display title of the item shown to the payer. */ private String title; /** Unit price of the item expressed as a decimal string. */ private String unitPrice; /** Number of units of this item included in the order. */ private Integer quantity; /** Unique identifier of the item. */ private String id; /** MercadoPago category identifier for the item. */ private String categoryId; /** Type classification of the item. */ private String type; /** Detailed description of the item. */ private String description; /** URL of the item's picture for display in checkout. */ private String pictureUrl; /** External code used to identify this item in the integrator's catalog. */ private String externalCode; /** Whether the item includes a warranty. */ private Boolean warranty; /** ISO 8601 date associated with the event for event-type items. */ private String eventDate; /** Unit of measure for the item (e.g., "unit", "kg"). */ private String unitMeasure; /** List of external category classifications for this item. */ private List externalCategories; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderOnlineConfig.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing the online checkout configuration of a MercadoPago Order. * Defines redirect URLs for each payment outcome, differential pricing rules, * and 3DS transaction security settings for card payments. */ @Getter public class OrderOnlineConfig { /** URL called by MercadoPago to notify the integrator about payment status changes. */ private String callbackUrl; /** URL where the payer is redirected after a successful payment. */ private String successUrl; /** URL where the payer is redirected when the payment is pending approval. */ private String pendingUrl; /** URL where the payer is redirected after a failed payment. */ private String failureUrl; /** URL for automatic redirection after the checkout process completes. */ private String autoReturnUrl; /** Differential pricing configuration for applying custom pricing rules. */ private OrderDifferentialPricing differentialPricing; /** Transaction security configuration for 3DS authentication on online payments. */ private OrderTransactionSecurity transactionSecurity; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderPaging.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing pagination metadata for order search results. * Provides total count, page information, and the current offset and limit * used to navigate through paginated responses. */ @Getter public class OrderPaging { /** Total number of orders matching the search criteria. */ private Integer total; /** Total number of pages available based on the current limit. */ private Integer totalPages; /** Zero-based offset of the first result in the current page. */ private Integer offset; /** Maximum number of results returned per page. */ private Integer limit; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderPassenger.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing passenger information for travel-related MercadoPago Order items. * Contains the traveler's personal identification data required by airlines and * travel operators for anti-fraud and regulatory compliance. */ @Getter public class OrderPassenger { /** First name of the passenger as it appears on the travel document. */ private String firstName; /** Last name of the passenger as it appears on the travel document. */ private String lastName; /** Type of identification document (e.g., "CPF", "DNI", "passport"). */ private String identificationType; /** Identification document number of the passenger. */ private String identificationNumber; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderPayer.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; // API version: d0494f1c-8d81-4c76-ae1d-0c65bb8ef6de /** * Resource representing the payer associated with a MercadoPago Order. * Contains identifying information about the person or entity making the payment. */ @Getter public class OrderPayer { /** MercadoPago customer identifier for the payer. */ private String customerId; /** Entity type of the payer (e.g., "individual", "association"). */ private String entityType; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderPayment.java ================================================ package com.mercadopago.resources.order; import java.util.List; import lombok.Getter; // API version: d0494f1c-8d81-4c76-ae1d-0c65bb8ef6de /** * Resource representing a single payment within a MercadoPago Order transaction. * Contains the payment amount, method details, lifecycle status, and related data * such as attempts, automatic payment configuration, and applied discounts. */ @Getter public class OrderPayment { /** Payment amount expressed as a decimal string. */ private String amount; /** Payment method details including type, card, installments, and ticket information. */ private OrderPaymentMethod paymentMethod; /** Unique identifier of this payment. */ private String id; /** Reference identifier linking this payment to an external system. */ private String referenceId; /** Current status of the payment (e.g., "approved", "pending", "rejected"). */ private String status; /** Detailed sub-status providing additional context about the payment status. */ private String statusDetail; /** ISO 8601 date-time when the payment expires if not completed. */ private String dateOfExpiration; /** Duration in ISO 8601 format after which the payment expires. */ private String expirationTime; /** Amount already paid on this payment, expressed as a decimal string. */ private String paidAmount; /** Sequential number of the current payment attempt. */ private Integer attemptNumber; /** Details of previous payment attempts made for this payment. */ private OrderAttempts attempts; /** Configuration for automatic recurring payments. */ private OrderAutomaticPayments automaticPayments; /** Stored credential information for card-on-file transactions. */ private OrderStoredCredential storedCredential; /** Subscription data when this payment is part of a recurring billing cycle. */ private OrderSubscriptionData subscriptionData; /** Total amount that has been refunded on this payment, expressed as a decimal string. */ private String refundedAmount; /** Payment provider or acquirer that processed this payment. */ private String provider; /** List of discounts applied to this payment. */ private List discounts; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderPaymentDiscount.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing a discount applied to a specific payment within a MercadoPago Order. * Indicates the type of discount that was applied to reduce the payment amount. */ @Getter public class OrderPaymentDiscount { /** Type of discount applied to the payment (e.g., "campaign", "coupon"). */ private String type; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderPaymentMethod.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing the payment method used in an order payment. * Includes details such as the method type, card or token references, installment * configuration, barcode/QR data for offline methods, and 3DS transaction security. */ @Getter public class OrderPaymentMethod { /** Identifier of the payment method (e.g., "visa", "pix", "bolbradesco"). */ private String id; /** Identifier of the saved card used for this payment. */ private String cardId; /** Type of payment method (e.g., "credit_card", "debit_card", "ticket", "bank_transfer"). */ private String type; /** Tokenized card data generated by the MercadoPago SDK for secure card transactions. */ private String token; /** Number of installments selected for this payment. */ private Integer installments; /** Text that appears on the payer's card statement (e.g., "MERCADOPAGO"). */ private String statementDescriptor; /** Barcode content for offline payment methods such as boleto. */ private String barcodeContent; /** Reference code for identifying the payment at the financial institution. */ private String reference; /** Verification code associated with the payment method. */ private String verificationCode; /** Financial institution responsible for processing the payment. */ private String financialInstitution; /** QR code string for QR-based payment methods such as Pix. */ private String qrCode; /** Base64-encoded QR code image for rendering in the client application. */ private String qrCodeBase64; /** Digitable line for boleto or similar offline payment methods. */ private String digitableLine; /** URL where the payer can view or download the payment ticket or voucher. */ private String ticketUrl; /** Transaction security configuration for 3DS authentication flows. */ private OrderTransactionSecurity transactionSecurity; /** End-to-end identifier for tracking the payment across systems (e.g., Pix e2eId). */ private String e2eId; /** URL to redirect the payer for completing the payment in an external flow. */ private String redirectUrl; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderPointConfig.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing the Point-of-Sale (POS) terminal configuration for a MercadoPago Order. * Defines how the order is presented and processed on a physical MercadoPago Point device. */ @Getter public class OrderPointConfig { /** Identifier of the MercadoPago Point terminal device assigned to this order. */ private String terminalId; /** Whether to print a receipt on the terminal after payment completion. */ private String printOnTerminal; /** Duration the order is displayed on the terminal screen, in ISO 8601 duration format. */ private String screenTime; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderReceiverAddress.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing the delivery address for a MercadoPago Order shipment. * Contains the full postal address where the purchased items will be delivered. */ @Getter public class OrderReceiverAddress { /** Name of the street for the delivery address. */ private String streetName; /** Street number of the delivery address. */ private String streetNumber; /** Postal or ZIP code of the delivery address. */ private String zipCode; /** City name of the delivery address. */ private String cityName; /** State or province name of the delivery address. */ private String stateName; /** Floor number within the building, if applicable. */ private String floor; /** Apartment or unit number within the building, if applicable. */ private String apartment; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderReference.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing a reference entry associated with a MercadoPago Order. * Provides traceability by linking the order to identifiers from external sources. */ @Getter public class OrderReference { /** Unique identifier of this order reference. */ private String id; /** Source system or origin from which this reference was generated. */ private String source; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderRefund.java ================================================ package com.mercadopago.resources.order; import com.mercadopago.net.MPResource; import lombok.Getter; // API version: d0494f1c-8d81-4c76-ae1d-0c65bb8ef6de /** * Resource representing a refund issued against a payment within a MercadoPago Order. * Contains the refund amount, its current processing status, and references to * the originating transaction and associated items. */ @Getter public class OrderRefund extends MPResource { /** Unique identifier of this refund. */ private String id; /** Identifier of the original transaction that was refunded. */ private String transactionId; /** External reference identifier for correlating this refund with the integrator's system. */ private String referenceId; /** Refund amount expressed as a decimal string. */ private String amount; /** Current processing status of the refund (e.g., "approved", "pending"). */ private String status; /** Detailed sub-status providing additional context about the refund status. */ private String statusDetail; /** Items associated with this refund. */ private OrderItem items; /** End-to-end identifier for tracking the refund across payment systems. */ private String e2eId; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderRefundItem.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing an individual refund line item within a MercadoPago Order transaction refund. * Contains details about a single refund entry including its amount, status, and * references to the originating transaction. */ @Getter public class OrderRefundItem { /** Unique identifier of this refund item. */ private String id; /** Identifier of the original transaction being refunded. */ private String transactionId; /** External reference identifier for correlating this refund with the integrator's system. */ private String referenceId; /** Refund amount expressed as a decimal string. */ private String amount; /** Current processing status of this refund item (e.g., "approved", "pending"). */ private String status; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderRoute.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing travel route information for a MercadoPago Order item. * Used in travel-related transactions to describe the itinerary, including * departure and arrival locations, times, and the carrier company. */ @Getter public class OrderRoute { /** Name of the departure city or airport code. */ private String departure; /** Name of the destination city or airport code. */ private String destination; /** ISO 8601 date-time of the scheduled departure. */ private String departureDateTime; /** ISO 8601 date-time of the scheduled arrival. */ private String arrivalDateTime; /** Name of the transport company or airline operating this route. */ private String company; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderSearchResponse.java ================================================ package com.mercadopago.resources.order; import com.mercadopago.net.MPResource; import java.util.List; import lombok.Getter; /** * Resource representing a paginated search response for MercadoPago Orders. * Contains the list of orders matching the search criteria and pagination metadata. */ @Getter public class OrderSearchResponse extends MPResource { /** List of orders returned by the search query. */ private List data; /** Pagination metadata including total results, offset, and limit. */ private OrderPaging paging; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderShipment.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing shipment information associated with a MercadoPago Order. * Contains the delivery address, package dimensions, and shipping preferences * such as express delivery or seller pickup. */ @Getter public class OrderShipment { /** Delivery address where the shipment will be received. */ private OrderReceiverAddress receiverAddress; /** Width of the package in the seller's configured unit of measurement. */ private float width; /** Height of the package in the seller's configured unit of measurement. */ private float height; /** Whether the shipment uses express delivery. */ private Boolean expressShipment; /** Whether the buyer will pick up the order at the seller's location. */ private Boolean pickUpOnSeller; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderStoredCredential.java ================================================ package com.mercadopago.resources.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing stored credential (card-on-file) information for a MercadoPago Order payment. * Used for recurring or merchant-initiated transactions where the payer's card data * has been previously stored with consent. */ @Getter @Builder public class OrderStoredCredential { /** Entity that initiated the payment: "cardholder" or "merchant". */ private String paymentInitiator; /** Reason for using stored credentials (e.g., "recurring", "installment", "unscheduled"). */ private String reason; /** Whether to store the payment method for future transactions. */ private Boolean storePaymentMethod; /** Whether this is the first payment in a series using stored credentials. */ private Boolean firstPayment; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderSubscriptionData.java ================================================ package com.mercadopago.resources.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing subscription billing data for a recurring MercadoPago Order payment. * Contains the subscription sequence position, invoice details, billing period, * and the scheduled billing date. */ @Getter @Builder public class OrderSubscriptionData { /** Sequence information indicating the position of this payment in the subscription cycle. */ private OrderSubscriptionSequence subscriptionSequence; /** Unique identifier of the invoice associated with this billing cycle. */ private String invoiceId; /** Billing period configuration defining the recurrence interval. */ private OrderInvoicePeriod invoicePeriod; /** ISO 8601 date when this subscription payment is billed. */ private String billingDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderSubscriptionSequence.java ================================================ package com.mercadopago.resources.order; import lombok.Builder; import lombok.Getter; // API version: 1ff4822a-2dfd-4393-800e-a562edb3fe32 /** * Resource representing the sequence position of a payment within a subscription cycle. * Tracks the current payment number relative to the total number of planned payments. */ @Getter @Builder public class OrderSubscriptionSequence { /** Current sequence number of this payment in the subscription (1-based). */ private Integer number; /** Total number of planned payments in the subscription cycle. */ private Integer total; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderTax.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing a tax applied to a MercadoPago Order. * Contains the tax type, rate or amount, and the fiscal condition of the payer * that determines the applicable tax. */ @Getter public class OrderTax { /** Fiscal condition of the payer that determines the tax applicability. */ private String payerCondition; /** Type of tax applied (e.g., "IVA", "IIBB"). */ private String type; /** Tax value expressed as a decimal string representing a rate or fixed amount. */ private String value; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderTransaction.java ================================================ package com.mercadopago.resources.order; import com.mercadopago.net.MPResource; import lombok.Getter; import java.util.List; // API version: d0494f1c-8d81-4c76-ae1d-0c65bb8ef6de /** * Resource representing the transaction details of a MercadoPago Order. * Groups together all financial operations associated with an order, including * payments, refunds, and chargebacks. */ @Getter public class OrderTransaction extends MPResource{ /** List of payments associated with this order transaction. */ private List payments; /** List of refunds issued against payments in this order transaction. */ private List refunds; /** List of chargebacks raised against payments in this order transaction. */ private List chargebacks; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderTransactionRefund.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; import java.util.List; /** * Resource representing the refund result of an order transaction operation. * Contains the list of individual refund items generated when a transaction-level * refund is processed on a MercadoPago Order. */ @Getter public class OrderTransactionRefund { /** List of individual refund items resulting from the transaction refund. */ private List refunds; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderTransactionSecurity.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing 3D Secure (3DS) transaction security configuration and response * for a MercadoPago Order payment. Contains the authentication mode, challenge URL * for cardholder verification, and liability shift preference. */ @Getter public class OrderTransactionSecurity { /** Unique identifier of this transaction security entry. */ private String id; /** * Challenge URL for 3DS cardholder authentication. * Should be displayed in an iframe when status is "action_required" * and status_detail is "pending_challenge". */ private String url; /** * Validation mode controlling when 3DS authentication is triggered. * Possible values: "always", "on_fraud_risk", "never". */ private String validation; /** * Liability shift preference indicating whether 3DS authentication * is mandatory or best-effort. Possible values: "required", "preferred". */ private String liabilityShift; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/OrderTypeResponse.java ================================================ package com.mercadopago.resources.order; import lombok.Getter; /** * Resource representing type-specific response data for a MercadoPago Order. * Contains output generated based on the order type, such as QR code data * for in-store (Point) payments. */ @Getter public class OrderTypeResponse { /** QR code payload data for rendering the payment QR code in Point integrations. */ private String qrData; } ================================================ FILE: src/main/java/com/mercadopago/resources/order/UpdateOrderTransaction.java ================================================ package com.mercadopago.resources.order; import com.mercadopago.net.MPResource; import lombok.Getter; /** * Resource representing the response returned when updating a transaction * on an existing MercadoPago Order. Contains the updated payment method details. */ @Getter public class UpdateOrderTransaction extends MPResource { /** Updated payment method details for the order transaction. */ private OrderPaymentMethod paymentMethod; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/Payment.java ================================================ package com.mercadopago.resources.payment; import com.google.gson.annotations.SerializedName; import com.mercadopago.net.MPResource; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import lombok.EqualsAndHashCode; import lombok.Getter; /** * Resource that represents a MercadoPago payment. * *

This is the core resource of the Payments API. It contains all information related to a * payment transaction, including the payer, the amount, the payment method, status, fees, * refunds, and metadata. Payments can be created, searched, captured, cancelled, and refunded * through the {@link com.mercadopago.client.payment.PaymentClient}. * * @see Payments API reference */ @Getter @EqualsAndHashCode(callSuper = true) public class Payment extends MPResource { /** Unique payment identifier assigned by MercadoPago. */ private Long id; /** Date and time when the payment was created. */ private OffsetDateTime dateCreated; /** Date and time when the payment was approved. */ private OffsetDateTime dateApproved; /** Date and time of the last status change. */ private OffsetDateTime dateLastUpdated; /** Expiration date for the payment, after which it can no longer be approved. */ private OffsetDateTime dateOfExpiration; /** Date and time when the funds become available to the collector. */ private OffsetDateTime moneyReleaseDate; /** Schema that defines how and when the funds are released to the collector. */ private String moneyReleaseSchema; /** Type of operation, such as regular_payment, money_transfer, or recurring_payment. */ private String operationType; /** Identifier of the issuer of the payment method (e.g. a specific bank). */ private String issuerId; /** Identifier of the payment method chosen to process the payment (e.g. visa, master, pix). */ private String paymentMethodId; /** Type of the payment method (e.g. credit_card, debit_card, ticket, bank_transfer). */ private String paymentTypeId; /** Current status of the payment (e.g. approved, pending, rejected, cancelled). */ private String status; /** Detailed explanation of the current payment status or rejection cause. */ private String statusDetail; /** Currency identifier using ISO 4217 code (e.g. BRL, ARS, MXN). */ private String currencyId; /** Short description of the payment reason, typically the item or service title. */ private String description; /** Whether the payment was created in production mode ({@code true}) or sandbox mode ({@code false}). */ private boolean liveMode; /** Identifier of the sponsor that originated the payment through the MercadoPago platform. */ private Long sponsorId; /** Authorization code returned by the card issuer. */ private String authorizationCode; /** Identifier of the integrator who processes the payment through the platform. */ private String integratorId; /** Identifier of the platform that originated the payment. */ private String platformId; /** Identifier of the corporation associated with the payment. */ private String corporationId; /** Identifier of the collector (seller) who receives the payment. */ private Long collectorId; /** Information about the payer who is making the payment. */ private PaymentPayer payer; /** * Custom key-value metadata attached to the payment to record additional merchant-defined * attributes. */ private Map metadata; /** * Additional information that can improve fraud analysis and conversion rates. Includes item * details, payer information, and shipping data. */ private PaymentAdditionalInfo additionalInfo; /** Order associated with this payment, linking it to a purchase order. */ private PaymentOrder order; /** External reference identifier provided by the merchant in their own system. */ private String externalReference; /** Total amount to be paid by the buyer. */ private BigDecimal transactionAmount; /** Total amount that has been refunded for this payment. */ private BigDecimal transactionAmountRefunded; /** Discount coupon amount applied to the payment. */ private BigDecimal couponAmount; /** Identifier of the differential pricing scheme used for financing fee absorption. */ private String differentialPricingId; /** Number of installments selected by the buyer for the payment. */ private int installments; /** Detailed transaction information including net received amount, total paid, and references. */ private PaymentTransactionDetails transactionDetails; /** Breakdown of the fees charged for this payment (e.g. MercadoPago fee, financing fee). */ private List feeDetails; /** Whether the payment amount has been captured ({@code true}) or only reserved/authorized ({@code false}). */ private boolean captured; /** * When {@code true}, the payment can only be approved or rejected immediately. When * {@code false}, the in_process status is also possible. */ private boolean binaryMode; /** Identifier for the call-for-authorize flow, providing details on state or rejection cause. */ private String callForAuthorizeId; /** Description that will appear on the payer's card or account statement. */ private String statementDescriptor; /** Card information used to process the payment, including last four digits and cardholder data. */ private PaymentCard card; /** * URL where MercadoPago will send webhook notifications when the payment status changes. */ private String notificationUrl; /** URL where MercadoPago redirects the user after completing a bank transfer payment. */ private String callbackUrl; /** Processing mode that determines whether a specific merchant ID should be used (e.g. gateway or aggregator). */ private String processingMode; /** Merchant account identifier used in complex payment scenarios with multiple sub-merchants. */ private String merchantAccountId; /** Merchant number associated with a discount campaign. */ private String merchantNumber; /** Coupon code entered by the buyer to apply a discount campaign. */ private String couponCode; /** Net amount received by the collector after deducting fees. */ private BigDecimal netAmount; /** Identifier for the selected payment method option when multiple options exist. */ private String paymentMethodOptionId; /** List of taxes applied to this payment (e.g. IVA, ICMS). */ private List taxes; /** Total amount of taxes applied to the payment. */ private BigDecimal taxesAmount; /** Counter-currency conversion details when the payment currency differs from the collector's currency. */ private PaymentCounterCurrency counterCurrency; /** Shipping cost amount included in the payment. */ private BigDecimal shippingAmount; /** Identifier of the Point of Sale device where the payment was originated. */ private String posId; /** Identifier of the physical store where the payment was originated. */ private String storeId; /** Schema that defines how deductions are applied to the payment. */ private String deductionSchema; /** List of refunds that have been applied to this payment. */ private List refunds; /** Information about the point of interaction where the payment was initiated (e.g. QR, deep link). */ private PaymentPointOfInteraction pointOfInteraction; /** Payment method details including rules, references, and external resource URLs. */ private PaymentMethod paymentMethod; /** 3D Secure authentication information associated with the payment. */ @SerializedName("three_ds_info") private PaymentThreeDSInfo threeDSInfo; /** * Internal key-value metadata used for recording additional merchant-specific attributes * that are not exposed publicly. */ private Map internalMetadata; /** Expanded response data returned when using the {@code X-Expand-Response-Nodes} header. */ private PaymentExpanded expanded; /** Breakdown of amounts for both payer and collector in their respective currencies. */ private PaymentAmounts amounts; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentAdditionalInfo.java ================================================ package com.mercadopago.resources.payment; import java.util.List; import lombok.Getter; /** * Resource that holds additional information attached to a MercadoPago payment. * *

Provides supplementary data that can improve fraud analysis and increase conversion rates. * Includes item details, extended payer information, shipping data, and the origin IP address. * Sending as much information as possible is recommended. * * @see Payment#getAdditionalInfo() */ @Getter public class PaymentAdditionalInfo { /** IP address from which the payment request originated (required for bank transfer payments). */ private String ipAddress; /** List of items being purchased in this payment. */ private List items; /** Extended payer information including name, phone, address, and registration date. */ private PaymentAdditionalInfoPayer payer; /** Shipping details including the receiver's address. */ private PaymentShipments shipments; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentAdditionalInfoPayer.java ================================================ package com.mercadopago.resources.payment; import com.mercadopago.resources.common.Address; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource that holds extended payer information within the additional info of a MercadoPago payment. * *

Provides the payer's name, phone, address, and registration date on the merchant's platform. * This data supplements the primary {@link PaymentPayer} and helps improve fraud detection. * * @see PaymentAdditionalInfo#getPayer() */ @Getter public class PaymentAdditionalInfoPayer { /** First name of the payer as registered on the merchant's platform. */ private String firstName; /** Last name of the payer as registered on the merchant's platform. */ private String lastName; /** Phone contact information of the payer. */ private PaymentPhone phone; /** Residential or billing address of the payer. */ private Address address; /** Date and time when the payer registered on the merchant's site. */ private OffsetDateTime registrationDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentAmounts.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that holds the amount breakdown for both the payer and collector in a MercadoPago payment. * *

Provides currency-specific transaction and net amounts from the perspective of each party * involved in the payment, useful for cross-currency and marketplace scenarios. * * @see Payment#getAmounts() */ @Getter public class PaymentAmounts { /** Amount details from the payer's perspective, including total paid and currency. */ private PaymentUsersAmountPayer payer; /** Amount details from the collector's perspective, including net received and currency. */ private PaymentUsersAmountCollector collector; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentApplicationData.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that identifies the application that originated a MercadoPago payment. * *

Contains the name and version of the client application used at the point of * interaction to create the payment. * * @see PaymentPointOfInteraction#getApplicationData() */ @Getter public class PaymentApplicationData { /** Name of the application that created the payment. */ private String name; /** Version of the application that created the payment. */ private String version; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentBankInfo.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that holds banking information for both parties involved in a MercadoPago payment. * *

Contains the bank account details of the payer and the collector (seller), and indicates * whether both accounts belong to the same owner. Used primarily for bank transfer and * Pix payment methods. * * @see PaymentTransactionData#getBankInfo() */ @Getter public class PaymentBankInfo { /** Bank account information of the payer. */ private PaymentBankInfoPayer payer; /** Bank account information of the collector (seller). */ private PaymentBankInfoCollector collector; /** Indicates whether the payer and collector share the same bank account owner. */ private String isSameBankAccountOwner; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentBankInfoCollector.java ================================================ package com.mercadopago.resources.payment; import java.math.BigInteger; import lombok.Getter; /** * Resource that holds the bank account information of the collector (seller) in a MercadoPago payment. * *

Identifies the collector's bank account used to receive funds from bank transfer or * Pix-based payments. * * @see PaymentBankInfo#getCollector() */ @Getter public class PaymentBankInfoCollector { /** Unique identifier of the collector's bank account. */ private BigInteger accountId; /** Full display name of the collector's bank account. */ private String longName; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentBankInfoPayer.java ================================================ package com.mercadopago.resources.payment; import java.math.BigInteger; import lombok.Getter; /** * Resource that holds the bank account information of the payer in a MercadoPago payment. * *

Identifies the payer's bank account used to send funds via bank transfer or Pix. * Includes the email associated with the account for notification purposes. * * @see PaymentBankInfo#getPayer() */ @Getter public class PaymentBankInfoPayer { /** Email address associated with the payer's bank account. */ private String email; /** Unique identifier of the payer's bank account. */ private BigInteger accountId; /** Full display name of the payer's bank account. */ private String longName; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentBarcode.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that represents barcode data for a ticket or boleto-based MercadoPago payment. * *

Contains the raw barcode content that can be used to generate a scannable barcode * image for offline payment methods. * * @see PaymentTransactionDetails#getBarcode() */ @Getter public class PaymentBarcode { /** Raw barcode string content used to generate the scannable barcode. */ private String content; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentCard.java ================================================ package com.mercadopago.resources.payment; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource that represents the card used to process a MercadoPago payment. * *

Contains masked card details (first six and last four digits), expiration information, * and the cardholder data. Full card numbers are never stored or returned for security * compliance. * * @see Payment * @see PaymentCardholder */ @Getter public class PaymentCard { /** Unique identifier of the stored card in MercadoPago's vault. */ private String id; /** Last four digits of the card number for display purposes. */ private String lastFourDigits; /** First six digits (BIN) of the card number, used to identify the issuer and card type. */ private String firstSixDigits; /** Year in which the card expires. */ private int expirationYear; /** Month in which the card expires (1-12). */ private int expirationMonth; /** Date and time when the card was first registered. */ private OffsetDateTime dateCreated; /** Date and time of the most recent update to the card data. */ private OffsetDateTime dateLastUpdated; /** Information about the cardholder (name and identification). */ private PaymentCardholder cardholder; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentCardholder.java ================================================ package com.mercadopago.resources.payment; import com.mercadopago.resources.common.Identification; import lombok.Getter; /** * Resource that represents the holder of the card used in a MercadoPago payment. * *

Contains the name printed on the card and the cardholder's identification document, * which may be required for certain payment methods or regions. * * @see PaymentCard */ @Getter public class PaymentCardholder { /** Full name of the cardholder as printed on the card. */ private String name; /** Identification document of the cardholder (e.g. CPF, DNI). */ private Identification identification; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentCounterCurrency.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that holds counter-currency conversion details for a MercadoPago payment. * *

When the payment currency differs from the collector's settlement currency, this resource * provides the exchange rate, converted amount, and any refunded amount in the counter currency. * * @see Payment#getCounterCurrency() */ @Getter public class PaymentCounterCurrency { /** ISO 4217 currency code of the counter currency (e.g. USD, EUR). */ private String currencyId; /** Exchange rate applied to convert from the payment currency to the counter currency. */ private BigDecimal rate; /** Payment amount expressed in the counter currency. */ private BigDecimal amount; /** Refunded amount expressed in the counter currency. */ private BigDecimal amountRefunded; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentData.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that holds payment method data including rules, references, and external resource URLs. * *

Contains the configuration rules (discounts, fines, interest) applicable to the * payment method, along with internal and external reference identifiers. * * @see PaymentMethod#getData() */ @Getter public class PaymentData { /** Rules defining discounts, fines, and interest for this payment method. */ private PaymentRules rules; /** Internal reference identifier for the payment data. */ private String referenceId; /** External reference identifier linking to the merchant's system. */ private String externalReferenceId; /** URL of the external resource associated with the payment method (e.g. ticket page). */ private String externalResourceUrl; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentDiscount.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import java.time.LocalDate; import lombok.Getter; /** * Resource that represents a discount applied to a MercadoPago payment method. * *

Defines the type of discount, its monetary value, and an optional limit date * after which the discount is no longer applicable. * * @see PaymentRules#getDiscounts() */ @Getter public class PaymentDiscount { /** Type of discount (e.g. fixed, percentage). */ private String type; /** Monetary value of the discount. */ private BigDecimal value; /** Date after which this discount is no longer valid. */ private LocalDate limitDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentExpanded.java ================================================ package com.mercadopago.resources.payment; import com.mercadopago.client.payment.PaymentNetworkTransactionDataRequest; import lombok.Getter; /** * Resource that holds expanded response data for a MercadoPago payment. * *

Returned only when the {@code X-Expand-Response-Nodes} header is used in the API request. * Contains gateway-level details such as network transaction references, which are useful * for reconciliation and advanced payment processing scenarios. * * @see Payment#getExpanded() */ @Getter public class PaymentExpanded { /** Gateway-level expanded information including network transaction references. */ private Gateway gateway; /** * Inner resource representing gateway-specific expanded data. * *

Contains the network transaction reference returned by the payment gateway. */ @Getter public static class Gateway { /** Network transaction data reference from the payment gateway. */ private PaymentNetworkTransactionDataRequest reference; } } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentFee.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that represents a fee or financial charge rule applied to a MercadoPago payment. * *

Used within {@link PaymentRules} to define fines and interest charges associated * with late or deferred payments. * * @see PaymentRules#getFine() * @see PaymentRules#getInterest() */ @Getter public class PaymentFee { /** Type of the fee (e.g. percentage, fixed). */ private String type; /** Monetary or percentage value of the fee. */ private BigDecimal value; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentFeeDetail.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that represents a single fee charged on a MercadoPago payment. * *

Each payment may have multiple fee details, such as the MercadoPago marketplace fee, * financing costs, or shipping fees. This resource identifies the type, who absorbs the * cost, and the monetary amount of each fee. * * @see Payment#getFeeDetails() */ @Getter public class PaymentFeeDetail { /** Type of fee (e.g. mercadopago_fee, coupon_fee, financing_fee). */ private String type; /** Party that absorbs this fee cost (e.g. collector, payer). */ private String feePayer; /** Monetary amount of the fee. */ private BigDecimal amount; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentInvoicePeriod.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that represents the invoice period for a subscription-based MercadoPago payment. * *

Defines the billing cycle length and type for recurring or subscription payments, * indicating how frequently invoices are generated. * * @see PaymentTransactionData#getInvoicePeriod() */ @Getter public class PaymentInvoicePeriod { /** Number representing the billing cycle length (e.g. 1, 3, 12). */ private int period; /** Unit of the billing period (e.g. monthly, yearly, daily). */ private String type; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentItem.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that represents a single item being purchased in a MercadoPago payment. * *

Contains details about the product or service such as title, description, quantity, * unit price, and category. Item information is included in the additional info and helps * with fraud prevention and purchase tracking. * * @see PaymentAdditionalInfo#getItems() */ @Getter public class PaymentItem { /** Unique item code or SKU provided by the merchant. */ private String id; /** Display name of the item. */ private String title; /** Type classification of the item. */ private String type; /** Detailed description of the item. */ private String description; /** URL of the item's image for display purposes. */ private String pictureUrl; /** Category identifier that classifies the item (e.g. electronics, clothing). */ private String categoryId; /** ISO 4217 currency code of the unit price. */ private String currencyId; /** Number of units of this item being purchased. */ private Integer quantity; /** Price per unit of the item. */ private BigDecimal unitPrice; /** Whether the item includes a warranty ({@code true}) or not ({@code false}). */ private boolean warranty; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentMethod.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that represents the payment method details associated with a MercadoPago payment. * *

Contains the data structure that holds payment rules, reference identifiers, and * external resource URLs specific to the payment method used in the transaction. * * @see Payment * @see PaymentData */ @Getter public class PaymentMethod { /** Data containing rules, references, and external resource URLs for this payment method. */ private PaymentData data; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentOrder.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that represents the purchase order associated with a MercadoPago payment. * *

Links the payment to an order in the MercadoPago or MercadoLibre ecosystem, * allowing tracking and reconciliation between payments and orders. * * @see Payment#getOrder() */ @Getter public class PaymentOrder { /** Unique identifier of the associated purchase order. */ private Long id; /** Type of the order (e.g. mercadolibre, mercadopago). */ private String type; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentPayer.java ================================================ package com.mercadopago.resources.payment; import com.mercadopago.resources.common.Identification; import lombok.Getter; import java.time.OffsetDateTime; import java.util.Date; /** * Resource that represents the payer associated with a MercadoPago payment. * *

Contains personal information about the buyer including identification, contact details, * authentication type, and registration data. This information is used for fraud prevention * and to process the payment correctly. * * @see Payment */ @Getter public class PaymentPayer { /** Payer type, mandatory when the payer is a registered Customer (e.g. customer, guest). */ private String type; /** Unique identifier of the payer in the MercadoPago platform. */ private String id; /** Email address of the payer. */ private String email; /** Personal identification document of the payer (e.g. CPF, DNI, CURP). */ private Identification identification; /** First name of the payer. */ private String firstName; /** Last name of the payer. */ private String lastName; /** Entity type of the payer, applicable only for bank transfer payments (e.g. individual, association). */ private String entityType; /** Authentication type used to verify the payer's identity. */ private String authenticationType; /** Whether the payer is a MercadoLibre Loyalty (prime/level 6) subscriber. */ private boolean isPrimeUser; /** Whether this is the payer's first online purchase. */ private boolean isFirstPurchaseOnline; /** Date and time when the payer registered on the merchant's platform. */ private OffsetDateTime registrationDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentPaymentReference.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that holds a reference to a related MercadoPago payment. * *

Used in recurring or linked payment contexts to point back to the original or * previous payment in a sequence. * * @see PaymentTransactionData#getPaymentReference() */ @Getter public class PaymentPaymentReference { /** Unique identifier of the referenced payment. */ private String id; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentPhone.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that represents a phone number associated with a MercadoPago payment payer. * *

Contains the area code and phone number, used for contact and fraud prevention purposes. * * @see PaymentAdditionalInfoPayer#getPhone() */ @Getter public class PaymentPhone { /** Area code of the phone number (e.g. 11, 21, 55). */ private String areaCode; /** Phone number without the area code. */ private String number; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentPointOfInteraction.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that describes the point of interaction where a MercadoPago payment was initiated. * *

Identifies how and where the payment originated, such as through a QR code, deep link, * IVR system, or checkout flow. Includes the application that created the payment and * the transaction data associated with the interaction channel. * * @see Payment#getPointOfInteraction() */ @Getter public class PaymentPointOfInteraction { /** Type of the point of interaction (e.g. QR, DEEP_LINK, IVR). */ private String type; /** Sub-type further specifying the interaction channel. */ private String subType; /** Identifier indicating the entity or flow this interaction is linked to. */ private String linkedTo; /** Information about the application that originated the payment. */ private PaymentApplicationData applicationData; /** Transaction-level data from the interaction channel (e.g. QR code, ticket URL). */ private PaymentTransactionData transactionData; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentReceiverAddress.java ================================================ package com.mercadopago.resources.payment; import com.mercadopago.resources.common.Address; import lombok.EqualsAndHashCode; import lombok.Getter; /** * Resource that represents the shipping receiver's address for a MercadoPago payment. * *

Extends the base {@link Address} with additional fields for state, city, floor, and * apartment details, providing a complete delivery address. * * @see PaymentShipments#getReceiverAddress() */ @EqualsAndHashCode(callSuper = true) @Getter public class PaymentReceiverAddress extends Address { /** Name of the state or province. */ private String stateName; /** Name of the city. */ private String cityName; /** Floor number or identifier within the building. */ private String floor; /** Apartment or unit number within the floor. */ private String apartment; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentRefund.java ================================================ package com.mercadopago.resources.payment; import com.mercadopago.resources.common.Source; import com.mercadopago.net.MPResource; import java.math.BigDecimal; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource that represents a refund applied to a MercadoPago payment. * *

A refund can be total or partial, allowing the merchant to return funds to the payer. * Each refund is linked to the original payment and tracks its own status, amount, and * creation date. * * @see Payment * @see Refunds API reference */ @Getter public class PaymentRefund extends MPResource { /** Unique identifier of this refund. */ private Long id; /** Identifier of the original payment that was refunded. */ private Long paymentId; /** Amount that was refunded to the payer. */ private BigDecimal amount; /** Adjustment amount applied to the refund (e.g. rounding differences). */ private BigDecimal adjustmentAmount; /** Current status of the refund (e.g. approved, in_process). */ private String status; /** Mode of the refund indicating how it was processed. */ private String refundMode; /** Date and time when the refund was created. */ private OffsetDateTime dateCreated; /** Reason provided by the merchant for issuing this refund. */ private String reason; /** Unique sequence number that identifies this refund transaction. */ private String uniqueSequenceNumber; /** Source that originated the refund (e.g. collector, admin). */ private Source source; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentRules.java ================================================ package com.mercadopago.resources.payment; import java.util.List; import lombok.Getter; /** * Resource that defines the financial rules applied to a MercadoPago payment method. * *

Contains discount, fine, and interest configurations that affect the final payment * amount. These rules are typically set by the collector and applied at payment creation. * * @see PaymentData#getRules() */ @Getter public class PaymentRules { /** List of discounts applicable to the payment (e.g. early payment discounts). */ private List discounts; /** Fine charged for late payments. */ private PaymentFee fine; /** Interest charged for deferred or late payments. */ private PaymentFee interest; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentShipments.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that holds shipping information for a MercadoPago payment. * *

Contains the delivery address where the purchased items should be shipped. * This information is part of the additional info sent with the payment. * * @see PaymentAdditionalInfo#getShipments() */ @Getter public class PaymentShipments { /** Full address of the shipment receiver, including state, city, floor, and apartment. */ private PaymentReceiverAddress receiverAddress; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentStatus.java ================================================ package com.mercadopago.resources.payment; /** * Constants representing all possible statuses of a MercadoPago payment. * *

Use these constants to compare against the {@code status} field of a {@link Payment} * resource instead of hard-coding string values. Each constant corresponds to a stage * in the payment lifecycle. * * @see Payment#getStatus() */ public class PaymentStatus { /** The payment has been approved and the funds have been accredited to the collector. */ public static final String APPROVED = "approved"; /** The user has not yet completed the payment process (e.g. waiting for bank transfer or ticket payment). */ public static final String PENDING = "pending"; /** The payment has been authorized by the card issuer but the funds have not yet been captured. */ public static final String AUTHORIZED = "authorized"; /** The payment is being reviewed by MercadoPago’s fraud prevention system. */ public static final String IN_PROCESS = "in_process"; /** A dispute has been initiated by the buyer and the payment is under mediation. */ public static final String IN_MEDIATION = "in_mediation"; /** The payment was rejected by the payment processor or issuer. The buyer may retry. */ public static final String REJECTED = "rejected"; /** The payment was cancelled by one of the parties or because the expiration time elapsed. */ public static final String CANCELLED = "cancelled"; /** The payment was fully refunded to the buyer. */ public static final String REFUNDED = "refunded"; /** A chargeback was initiated on the buyer’s credit card by the issuing bank. */ public static final String CHARGED_BACK = "charged_back"; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentSubscriptionSequence.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that represents the sequence position of a subscription-based MercadoPago payment. * *

Tracks the current installment number within the total number of scheduled payments * for a recurring subscription. * * @see PaymentTransactionData#getSubscriptionSequence() */ @Getter public class PaymentSubscriptionSequence { /** Current sequence number of this payment within the subscription (e.g. 3 of 12). */ private int number; /** Total number of payments expected in the subscription. */ private int total; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentTax.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that represents a tax applied to a MercadoPago payment. * *

Defines the type and value of a tax charge included in the payment, such as * IVA, ICMS, or other regional tax obligations. * * @see Payment#getTaxes() */ @Getter public class PaymentTax { /** Type of tax applied (e.g. IVA, ICMS, ISS). */ private String type; /** Monetary value of the tax. */ private BigDecimal value; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentThreeDSInfo.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that holds 3D Secure (3DS) authentication information for a MercadoPago payment. * *

Contains the external resource URL for the 3DS challenge flow and the challenge request * (creq) data needed to complete cardholder authentication. * * @see Payment#getThreeDSInfo() */ @Getter public class PaymentThreeDSInfo { /** URL of the external 3DS challenge page where the cardholder completes authentication. */ private String externalResourceUrl; /** Challenge request (creq) payload used in the 3DS authentication flow. */ private String creq; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentTransactionData.java ================================================ package com.mercadopago.resources.payment; import lombok.Getter; /** * Resource that holds transaction-level data from the point of interaction for a MercadoPago payment. * *

Contains QR code information for Pix payments, bank transfer details, ticket URLs for * offline payment methods, and subscription-related data for recurring payments. This data * is typically provided within the {@link PaymentPointOfInteraction} resource. * * @see PaymentPointOfInteraction#getTransactionData() */ @Getter public class PaymentTransactionData { /** QR code string content used for Pix or other QR-based payment methods. */ private String qrCode; /** Base64-encoded image of the QR code for rendering in client applications. */ private String qrCodeBase64; /** BACEN (Brazilian Central Bank) end-to-end identifier for Pix transactions. */ private String transactionId; /** Identifier of the bank transfer transaction. */ private Long bankTransferId; /** Identifier of the financial institution that processed the transaction. */ private Long financialInstitution; /** Banking information for both the payer and the collector involved in the transaction. */ private PaymentBankInfo bankInfo; /** URL of the payment ticket or voucher for offline payment methods. */ private String ticketUrl; /** Whether this is the first time the payment method is being used by the payer. */ private boolean firstTimeUse; /** Sequence information for subscription-based recurring payments. */ private PaymentSubscriptionSequence subscriptionSequence; /** Identifier of the subscription associated with this recurring payment. */ private String subscriptionId; /** Invoice period details for subscription or recurring billing payments. */ private PaymentInvoicePeriod invoicePeriod; /** Reference to a related payment in the context of recurring or linked transactions. */ private PaymentPaymentReference paymentReference; /** Billing date for subscription or recurring payment invoices. */ private String billingDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentTransactionDetails.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that holds detailed transaction information for a MercadoPago payment. * *

Includes financial details such as the net received amount, total paid amount, installment * breakdown, and references used by payment processors, acquirers, and financial institutions. * Also contains barcode and digitable line data for ticket-based payment methods. * * @see Payment#getTransactionDetails() */ @Getter public class PaymentTransactionDetails { /** Name or identifier of the external financial institution that processed the payment. */ private String financialInstitution; /** Net amount received by the seller after deducting all fees. */ private BigDecimal netReceivedAmount; /** Total amount paid by the buyer, including fees and financing costs. */ private BigDecimal totalPaidAmount; /** Amount of each installment when the payment is split into multiple installments. */ private BigDecimal installmentAmount; /** Amount overpaid by the buyer, applicable only for ticket-based payment methods. */ private BigDecimal overpaidAmount; /** URL of the external resource at the payment processor (e.g. ticket or voucher page). */ private String externalResourceUrl; /** * Reference identifier at the payment method level. For credit cards this is the USN (Unique * Sequence Number); for offline methods it is the code to provide at the cashier or ATM. */ private String paymentMethodReferenceId; /** Reference identifier assigned by the payment acquirer. */ private String acquirerReference; /** BACEN (Brazilian Central Bank) end-to-end identifier for Pix transactions. */ private String transactionId; /** Digitable line representation of the barcode for boleto or ticket payments. */ private String digitableLine; /** Verification code used to validate the payment at certain financial institutions. */ private String verificationCode; /** Period during which the payment amount can be deferred before becoming payable. */ private String payableDeferralPeriod; /** Identifier of the bank transfer transaction. */ private String bankTransferId; /** Barcode data associated with ticket or boleto payment methods. */ private PaymentBarcode barcode; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentUsersAmountCollector.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that represents the amount breakdown from the collector's (seller's) perspective * in a MercadoPago payment. * *

Contains the transaction amount and net received amount in the collector's currency, * useful for cross-currency marketplace reconciliation. * * @see PaymentAmounts#getCollector() */ @Getter public class PaymentUsersAmountCollector { /** ISO 4217 currency code of the collector's settlement currency. */ private String currencyId; /** Gross transaction amount in the collector's currency. */ private BigDecimal transaction; /** Net amount received by the collector after all fees are deducted. */ private BigDecimal netReceived; } ================================================ FILE: src/main/java/com/mercadopago/resources/payment/PaymentUsersAmountPayer.java ================================================ package com.mercadopago.resources.payment; import java.math.BigDecimal; import lombok.Getter; /** * Resource that represents the amount breakdown from the payer's (buyer's) perspective * in a MercadoPago payment. * *

Contains the transaction amount and total paid amount in the payer's currency, * which may include fees and financing costs. * * @see PaymentAmounts#getPayer() */ @Getter public class PaymentUsersAmountPayer { /** ISO 4217 currency code of the payer's currency. */ private String currencyId; /** Transaction amount in the payer's currency before additional charges. */ private BigDecimal transaction; /** Total amount paid by the buyer, including fees and financing costs. */ private BigDecimal totalPaid; } ================================================ FILE: src/main/java/com/mercadopago/resources/paymentmethod/PaymentMethod.java ================================================ package com.mercadopago.resources.paymentmethod; import com.mercadopago.net.MPResource; import java.math.BigDecimal; import java.util.List; import lombok.Getter; /** * Resource that represents an available payment method in the MercadoPago platform. * *

Describes a payment method that can be used to process payments, including its type * (credit card, debit card, ticket, bank transfer, etc.), current status, amount limits, * accreditation time, and configuration settings such as card number validation rules * and security code requirements. * * @see Payment Methods API reference */ @Getter public class PaymentMethod extends MPResource { /** Unique identifier of the payment method (e.g. visa, master, pix, bolbradesco). */ private String id; /** Type classification of the payment method. */ private String type; /** Identifier of the card associated with this payment method, when applicable. */ private String cardId; /** Number of installments available for this payment method. */ private Integer installments; /** Human-readable display name of the payment method (e.g. Visa, Mastercard, Pix). */ private String name; /** Payment type identifier (e.g. credit_card, debit_card, ticket, bank_transfer, prepaid_card). */ private String paymentTypeId; /** Current availability status of the payment method (e.g. active, inactive, temporally_unavailable). */ private String status; /** URL of the payment method logo suitable for display on secure (HTTPS) sites. */ private String secureThumbnail; /** URL of the payment method logo for general display. */ private String thumbnail; /** Whether the payment capture can be deferred (e.g. supported, unsupported, does_not_apply). */ private String deferredCapture; /** List of configuration settings defining card number, BIN, and security code validation rules. */ private List settings; /** List of additional information fields that must be provided by the payer (e.g. cardholder_name, issuer_id). */ private List additionalInfoNeeded; /** Minimum transaction amount allowed for this payment method. */ private BigDecimal minAllowedAmount; /** Maximum transaction amount allowed for this payment method. */ private BigDecimal maxAllowedAmount; /** Estimated accreditation time in minutes for payments processed with this method. */ private Long accreditationTime; /** List of financial institutions that support this payment method. */ private List financialInstitutions; /** List of processing modes supported by this payment method (e.g. aggregator, gateway). */ private List processingModes; } ================================================ FILE: src/main/java/com/mercadopago/resources/paymentmethod/PaymentMethodFinancialInstitutions.java ================================================ package com.mercadopago.resources.paymentmethod; import lombok.Getter; /** * Resource that represents a financial institution that supports a MercadoPago payment method. * *

Identifies a bank or financial entity that processes payments for a specific payment * method, such as ATM networks, banks for transfers, or card-issuing institutions. * * @see PaymentMethod#getFinancialInstitutions() */ @Getter public class PaymentMethodFinancialInstitutions { /** Unique external identifier of the financial institution (e.g. bank code, ATM company ID). */ private Long id; /** Human-readable name or description of the financial institution. */ private String description; } ================================================ FILE: src/main/java/com/mercadopago/resources/paymentmethod/PaymentMethodSettings.java ================================================ package com.mercadopago.resources.paymentmethod; import lombok.Getter; /** * Resource that groups the validation and configuration settings for a MercadoPago payment method. * *

Combines BIN pattern rules, card number length and validation settings, and security * code requirements into a single settings object. A payment method may have multiple * settings entries for different card ranges. * * @see PaymentMethod#getSettings() */ @Getter public class PaymentMethodSettings { /** BIN (Bank Identification Number) pattern and exclusion rules for card acceptance. */ private PaymentMethodSettingsBin bin; /** Card number length and checksum validation settings. */ private PaymentMethodSettingsCardNumber cardNumber; /** Security code (CVV/CVC) mode, length, and card location settings. */ private PaymentMethodSettingsSecurityCode securityCode; } ================================================ FILE: src/main/java/com/mercadopago/resources/paymentmethod/PaymentMethodSettingsBin.java ================================================ package com.mercadopago.resources.paymentmethod; import lombok.Getter; /** * Resource that defines BIN (Bank Identification Number) validation rules for a payment method. * *

Uses regular expression patterns to determine which card BINs are accepted, excluded, * or eligible for installment payments. These rules help identify the card issuer and * control which cards can be used with a given payment method. * * @see PaymentMethodSettings#getBin() */ @Getter public class PaymentMethodSettingsBin { /** Regular expression pattern matching the accepted BIN ranges for this payment method. */ private String pattern; /** Regular expression pattern matching BIN ranges that are explicitly excluded. */ private String exclusionPattern; /** Regular expression pattern matching BIN ranges eligible for multi-installment payments. */ private String installmentsPattern; } ================================================ FILE: src/main/java/com/mercadopago/resources/paymentmethod/PaymentMethodSettingsCardNumber.java ================================================ package com.mercadopago.resources.paymentmethod; import lombok.Getter; /** * Resource that defines card number validation settings for a MercadoPago payment method. * *

Specifies the expected card number length and whether checksum validation (typically * the Luhn algorithm) should be applied to verify the card number. * * @see PaymentMethodSettings#getCardNumber() */ @Getter public class PaymentMethodSettingsCardNumber { /** Expected number of digits in the card number. */ private Integer length; /** Validation algorithm to apply (e.g. standard for Luhn checksum, or none). */ private String validation; } ================================================ FILE: src/main/java/com/mercadopago/resources/paymentmethod/PaymentMethodSettingsSecurityCode.java ================================================ package com.mercadopago.resources.paymentmethod; import lombok.Getter; /** * Resource that defines security code (CVV/CVC) settings for a MercadoPago payment method. * *

Specifies whether the security code is mandatory, its expected length, and where * it is located on the physical card (front or back). * * @see PaymentMethodSettings#getSecurityCode() */ @Getter public class PaymentMethodSettingsSecurityCode { /** Whether the security code is mandatory or optional (e.g. mandatory, optional). */ private String mode; /** Expected number of digits in the security code (typically 3 or 4). */ private int length; /** Physical location of the security code on the card (e.g. back, front). */ private String cardLocation; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/OperatingMode.java ================================================ package com.mercadopago.resources.point; /** * Enumeration of operating modes available for Point of Sale (POS) devices. * *

Defines how a MercadoPago Point device operates in the payment ecosystem: *

    *
  • {@link #PDV} - Integrated with an external point-of-sale system.
  • *
  • {@link #STANDALONE} - Operates independently without external system integration.
  • *
* * @see PointDeviceOperatingMode */ public enum OperatingMode { /** Device is integrated with an external point-of-sale (PDV) system. */ PDV, /** Device operates independently without external system integration. */ STANDALONE } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointCancelPaymentIntent.java ================================================ package com.mercadopago.resources.point; import com.mercadopago.net.MPResource; import lombok.Getter; /** * Resource representing the result of cancelling a payment intent on a Point device. * *

Returned after successfully requesting the cancellation of a previously created payment * intent. Contains the identifier of the cancelled intent for confirmation purposes. * * @see com.mercadopago.client.point.PointClient#cancelPaymentIntent(String, String) */ @Getter public class PointCancelPaymentIntent extends MPResource { /** Unique identifier of the cancelled payment intent. */ private String id; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointDevice.java ================================================ package com.mercadopago.resources.point; import lombok.Getter; /** * Resource representing a MercadoPago Point device. * *

Contains basic identifying information about a physical Point device, including its unique * identifier and current operating mode (e.g., PDV or STANDALONE). * * @see PointDevices * @see OperatingMode */ @Getter public class PointDevice { /** Unique identifier of the Point device. */ private String id; /** Current operating mode of the device (e.g., PDV or STANDALONE). */ private String operatingMode; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointDeviceOperatingMode.java ================================================ package com.mercadopago.resources.point; import com.mercadopago.client.point.OperatingMode; import com.mercadopago.net.MPResource; import lombok.Getter; /** * Resource representing the result of changing a Point device's operating mode. * *

Returned after requesting a change in the operating mode of a Point device. Contains the * updated {@link OperatingMode} value confirming the applied configuration. * * @see OperatingMode * @see com.mercadopago.client.point.PointClient#changeDeviceOperatingMode(String, * com.mercadopago.client.point.PointDeviceOperatingModeRequest) */ @Getter public class PointDeviceOperatingMode extends MPResource { /** Updated operating mode of the device after the change request. */ private OperatingMode operatingMode; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointDevices.java ================================================ package com.mercadopago.resources.point; import com.mercadopago.net.MPResource; import com.mercadopago.resources.ResultsPaging; import java.util.List; import lombok.Getter; /** * Resource representing a paginated list of MercadoPago Point devices. * *

Contains the collection of {@link PointDevice} entries associated with the authenticated * account, along with pagination metadata for navigating large result sets. * * @see PointDevice * @see com.mercadopago.client.point.PointClient#getDevices(com.mercadopago.client.point.PointDevicesRequest) */ @Getter public class PointDevices extends MPResource { /** Collection of Point devices returned in this page. */ private List devices; /** Pagination metadata including total count, offset, and limit. */ private ResultsPaging paging; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointPaymentIntent.java ================================================ package com.mercadopago.resources.point; import com.mercadopago.net.MPResource; import java.math.BigDecimal; import lombok.Getter; /** * Resource representing a payment intent created on a MercadoPago Point device. * *

A payment intent encapsulates a pending charge that is queued on a specific Point device. * It holds the amount, description, payment configuration, and optional additional information * such as external references and ticket printing preferences. * * @see PointPaymentIntentAdditionalInfo * @see PointPaymentIntentPayment * @see com.mercadopago.client.point.PointClient#createPaymentIntent(String, * com.mercadopago.client.point.PointPaymentIntentRequest) */ @Getter public class PointPaymentIntent extends MPResource { /** Unique identifier of the payment intent. */ private String id; /** Short description of the payment intent shown on the device. */ private String description; /** Identifier of the Point device where this payment intent is queued. */ private String deviceId; /** Total amount to be charged for this payment intent. */ private BigDecimal amount; /** Additional metadata such as external reference, ticket number, and print settings. */ private PointPaymentIntentAdditionalInfo additionalInfo; /** Payment configuration including type, installments, and cost allocation. */ private PointPaymentIntentPayment payment; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointPaymentIntentAdditionalInfo.java ================================================ package com.mercadopago.resources.point; import lombok.Getter; /** * Resource containing additional metadata for a Point payment intent. * *

Holds supplementary information that enriches the payment intent, including an external * reference for integration with external systems, ticket printing preferences, and a ticket * number for invoice tracking. * * @see PointPaymentIntent */ @Getter public class PointPaymentIntentAdditionalInfo { /** * An alphanumeric value can be an identifier in your application. It will be returned in the * Webhook notification. */ private String externalReference; /** A boolean value that determines if you want to print the ticket on the device. */ private Boolean printOnTerminal; /** * An alphanumeric value to identify the invoice or ticket number. It will be printed on the * device ticket. */ private String ticketNumber; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointPaymentIntentList.java ================================================ package com.mercadopago.resources.point; import com.mercadopago.net.MPResource; import java.util.List; import lombok.Getter; /** * Resource representing a list of payment intent events from Point devices. * *

Contains a collection of {@link PointPaymentIntentListEvent} entries, each representing a * payment intent event with its status and creation timestamp. Used to retrieve the history of * payment intents processed on a device. * * @see PointPaymentIntentListEvent * @see com.mercadopago.client.point.PointClient#getPaymentIntentList(String) */ @Getter public class PointPaymentIntentList extends MPResource { /** Collection of payment intent events associated with the device. */ private List events; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointPaymentIntentListEvent.java ================================================ package com.mercadopago.resources.point; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource representing an individual event in the payment intent history of a Point device. * *

Each event captures a snapshot of a payment intent at a given point in time, including its * current processing status and the timestamp when it was created. * * @see PointPaymentIntentList */ @Getter public class PointPaymentIntentListEvent { /** Unique identifier of the payment intent associated with this event. */ private String paymentIntentId; /** Current processing status of the payment intent (e.g., open, finished, cancelled). */ private String status; /** Timestamp when the payment intent was created. */ private OffsetDateTime createdOn; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointPaymentIntentPayment.java ================================================ package com.mercadopago.resources.point; import lombok.Getter; /** * Resource containing payment configuration details for a Point payment intent. * *

Defines how the payment should be processed, including the payment method type (credit card, * debit card, or voucher), installment settings, and who bears the installment cost. * * @see PointPaymentIntent */ @Getter public class PointPaymentIntentPayment { /** Unique identifier of the resulting payment, available after processing. */ private String id; /** * Number of installments (1 to 72). Only applicable when {@code type} is {@code credit_card}. */ private Integer installments; /** * Party responsible for the installment cost ({@code seller} or {@code buyer}). Only applicable * when {@code type} is {@code credit_card}. */ private String installmentsCost; /** Payment method type: {@code credit_card}, {@code debit_card}, or {@code voucher_card}. */ private String type; /** Specific voucher type when payment type is {@code voucher_card}. */ private String voucherType; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointSearchPaymentIntent.java ================================================ package com.mercadopago.resources.point; import com.mercadopago.net.MPResource; import java.math.BigDecimal; import lombok.Getter; /** * Resource representing the result of searching for a specific payment intent on a Point device. * *

Extends the standard payment intent data with an additional {@code state} field that indicates * the current lifecycle state of the intent. This resource is returned when querying for a * previously created payment intent by its identifier. * * @see PointPaymentIntent * @see PointPaymentIntentAdditionalInfo * @see PointPaymentIntentPayment * @see com.mercadopago.client.point.PointClient#searchPaymentIntent(String, String) */ @Getter public class PointSearchPaymentIntent extends MPResource { /** Unique identifier of the payment intent. */ private String id; /** Short description of the payment intent shown on the device. */ private String description; /** Identifier of the Point device where this payment intent is queued. */ private String deviceId; /** Total amount to be charged for this payment intent. */ private BigDecimal amount; /** Additional metadata such as external reference, ticket number, and print settings. */ private PointPaymentIntentAdditionalInfo additionalInfo; /** Payment configuration including type, installments, and cost allocation. */ private PointPaymentIntentPayment payment; /** Current lifecycle state of the payment intent (e.g., OPEN, FINISHED, CANCELED, ERROR). */ private String state; } ================================================ FILE: src/main/java/com/mercadopago/resources/point/PointStatusPaymentIntent.java ================================================ package com.mercadopago.resources.point; import com.mercadopago.net.MPResource; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource representing the current status of a payment intent on a Point device. * *

Provides a lightweight view of a payment intent's processing status along with its creation * timestamp. Useful for polling or checking the progress of a payment intent. * * @see PointPaymentIntent * @see com.mercadopago.client.point.PointClient#getPaymentIntentStatus(String, String) */ @Getter public class PointStatusPaymentIntent extends MPResource { /** Current processing status of the payment intent. */ private String status; /** Timestamp when the payment intent was created. */ private OffsetDateTime createdOn; } ================================================ FILE: src/main/java/com/mercadopago/resources/preapproval/Preapproval.java ================================================ package com.mercadopago.resources.preapproval; import com.mercadopago.net.MPResource; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource representing a MercadoPago subscription (preapproval). * *

A preapproval authorizes the seller to collect recurring payments from a payer according to * the billing configuration defined in {@link PreapprovalAutoRecurring}. The lifecycle of a * subscription includes creation, activation via the checkout link ({@code initPoint}), and * ongoing automated billing until cancellation or expiration. * * @see PreapprovalAutoRecurring * @see com.mercadopago.client.preapproval.PreapprovalClient */ @Getter public class Preapproval extends MPResource { /** Unique identifier of the preapproval (subscription). */ private String id; /** Identifier of the payer who authorized the recurring charges. */ private Long payerId; /** Email address of the payer associated with this subscription. */ private String payerEmail; /** URL the payer is redirected to after completing the subscription flow. */ private String backUrl; /** Identifier of the seller (collector) who receives the recurring payments. */ private Long collectorId; /** Identifier of the application that created this subscription. */ private Long applicationId; /** Current status of the subscription (e.g., pending, authorized, paused, cancelled). */ private String status; /** Title or reason describing the purpose of the subscription. */ private String reason; /** External reference for correlating this subscription with the integrator's system. */ private String externalReference; /** Scheduled date of the next automatic payment debit. */ private OffsetDateTime nextPaymentDate; /** Timestamp when the subscription was created. */ private OffsetDateTime dateCreated; /** Timestamp when the subscription was last modified. */ private OffsetDateTime lastModified; /** Production checkout URL where the payer authorizes the subscription. */ private String initPoint; /** Sandbox checkout URL for testing the subscription flow. */ private String sandboxInitPoint; /** Identifier of the payment method used for recurring charges. */ private String paymentMethodId; /** Recurring billing configuration including frequency, currency, and amount. */ private PreapprovalAutoRecurring autoRecurring; /** Optimistic concurrency control version number. */ private Long version; } ================================================ FILE: src/main/java/com/mercadopago/resources/preapproval/PreapprovalAutoRecurring.java ================================================ package com.mercadopago.resources.preapproval; import java.math.BigDecimal; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource representing the recurring billing configuration of a subscription (preapproval). * *

Defines how often and how much is charged to the payer on each billing cycle, including the * currency, amount, frequency, and the active time window of the recurring charges. * * @see Preapproval */ @Getter public class PreapprovalAutoRecurring { /** ISO 4217 currency code for the recurring charges (e.g., ARS, BRL, USD). */ private String currencyId; /** Amount charged on each billing cycle. */ private BigDecimal transactionAmount; /** Number of time units between each billing cycle. */ private Integer frequency; /** Unit of time for the billing frequency ({@code days} or {@code months}). */ private String frequencyType; /** Date when the recurring charges begin. */ private OffsetDateTime startDate; /** Date when the recurring charges end. */ private OffsetDateTime endDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/Preference.java ================================================ package com.mercadopago.resources.preference; import com.mercadopago.net.MPResource; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.util.List; import java.util.Map; import lombok.Getter; /** * Resource representing a MercadoPago checkout preference. * *

A preference defines the payment experience for the buyer, including which items are being * purchased, accepted payment methods, shipping options, redirect URLs, and expiration rules. * After creation, the {@code initPoint} URL is used to redirect buyers to the MercadoPago * Checkout flow. * * @see PreferenceItem * @see PreferencePayer * @see PreferencePaymentMethods * @see PreferenceBackUrls * @see PreferenceShipments * @see com.mercadopago.client.preference.PreferenceClient */ @Getter public class Preference extends MPResource { /** Unique identifier of the preference. */ private String id; /** Collection of items included in this checkout preference. */ private List items; /** Information about the buyer who will pay for the items. */ private PreferencePayer payer; /** Identifier of the OAuth application client that created this preference. */ private String clientId; /** Configuration of accepted and excluded payment methods for this preference. */ private PreferencePaymentMethods paymentMethods; /** Redirect URLs for success, pending, and failure payment outcomes. */ private PreferenceBackUrls backUrls; /** Shipping configuration including mode, cost, and delivery address. */ private PreferenceShipments shipments; /** Webhook URL where payment notifications (IPN) will be sent. */ private String notificationUrl; /** Descriptor that appears on the buyer's card or bank statement. */ private String statementDescriptor; /** External reference for correlating this preference with the integrator's system. */ private String externalReference; /** Whether this preference has an expiration window. */ private Boolean expires; /** Expiration date for cash-based payment methods. */ private OffsetDateTime dateOfExpiration; /** Start date from which the preference becomes active. */ private OffsetDateTime expirationDateFrom; /** End date after which the preference is no longer valid. */ private OffsetDateTime expirationDateTo; /** Identifier of the seller (collector) who receives the payment. */ private Long collectorId; /** Marketplace origin identifier. Default value: NONE. */ private String marketplace; /** Fee amount charged by the marketplace application owner. */ private BigDecimal marketplaceFee; /** Free-form additional information attached to the preference. */ private String additionalInfo; /** * Auto-return mode. When specified, buyers are redirected back to the seller's site immediately * after completing the purchase (e.g., {@code approved}, {@code all}). */ private String autoReturn; /** Type of operation (e.g., regular_payment, money_transfer). */ private String operationType; /** Differential pricing configuration that applies special pricing rules. */ private PreferenceDifferentialPricing differentialPricing; /** List of processing modes to use (e.g., aggregator, gateway). */ private List processingModes; /** * When {@code true}, payments can only be approved or rejected immediately; the * {@code in_process} intermediate status is not used. */ private Boolean binaryMode; /** List of applicable taxes for this preference. */ private List taxes; /** Tracking tags executed during the buyer's interaction in the Checkout flow. */ private List tracks; /** Arbitrary key-value metadata attached to the preference for merchant use. */ private Map metadata; /** Production checkout URL that initiates the payment flow for this preference. */ private String initPoint; /** Sandbox checkout URL for testing the payment flow. */ private String sandboxInitPoint; /** Timestamp when the preference was created. */ private OffsetDateTime dateCreated; /** Breakdown of amounts for the payer and collector. */ private PreferenceAmounts amounts; /** Counter currency configuration for cross-currency payments. */ private PreferenceCounterCurrency counterCurrency; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceAmounts.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource representing the amount breakdown for a checkout preference. * *

Contains the individual amounts applicable to both the payer and the collector (seller), * including their respective currencies and transaction values. * * @see Preference * @see PreferenceUserAmount */ @Getter public class PreferenceAmounts { /** Amount information applicable to the payer. */ private PreferenceUserAmount payer; /** Amount information applicable to the collector (seller). */ private PreferenceUserAmount collector; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceBackUrls.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource representing the redirect URLs configured in a checkout preference. * *

Defines the URLs where the buyer is redirected after completing the checkout flow, depending * on the payment outcome: approved, pending, or failed. * * @see Preference */ @Getter public class PreferenceBackUrls { /** URL to redirect the buyer when the payment is approved. */ private String success; /** URL to redirect the buyer when the payment is pending review or processing. */ private String pending; /** URL to redirect the buyer when the payment is rejected or fails. */ private String failure; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceCategoryDescriptor.java ================================================ package com.mercadopago.resources.preference; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource representing category-specific descriptive information for a preference item. * *

Provides additional context for items in specialized categories such as travel. Includes * passenger details, route information for flights, and the date of the event or trip. * * @see PreferenceItem * @see PreferencePassenger * @see PreferenceRoute */ @Getter public class PreferenceCategoryDescriptor { /** Passenger details associated with this item (e.g., for airline tickets). */ private PreferencePassenger passenger; /** Flight route information including departure and destination. */ private PreferenceRoute route; /** Date of the event or trip associated with this item. */ private OffsetDateTime eventDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceCounterCurrency.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource representing the counter currency configuration for cross-currency payments. * *

Specifies the alternative currency in which the payment amount is displayed or settled * when it differs from the preference's primary currency. * * @see Preference */ @Getter public class PreferenceCounterCurrency { /** ISO 4217 currency code of the counter currency (e.g., USD, EUR). */ private String currencyId; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceDifferentialPricing.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource representing the differential pricing configuration of a checkout preference. * *

References a pre-configured differential pricing rule by its identifier. When applied, it * enables special pricing conditions for specific buyer segments or payment methods. * * @see Preference */ @Getter public class PreferenceDifferentialPricing { /** Unique identifier of the differential pricing rule to apply. */ private Long id; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceFreeMethod.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource representing a shipping method offered as free shipping in a checkout preference. * *

Identifies a specific shipping method by its ID that the seller offers at no cost to the * buyer. Only applicable when the shipment mode is {@code me2}. * * @see PreferenceShipments */ @Getter public class PreferenceFreeMethod { /** Unique identifier of the shipping method offered for free. */ private Long id; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceItem.java ================================================ package com.mercadopago.resources.preference; import java.math.BigDecimal; import lombok.Getter; /** * Resource representing an item included in a checkout preference. * *

Describes a product or service the buyer is purchasing, including its title, price, quantity, * and optional metadata such as category, image, and warranty information. * * @see Preference * @see PreferenceCategoryDescriptor */ @Getter public class PreferenceItem { /** Unique item code or SKU identifier. */ private String id; /** Display title or name of the item. */ private String title; /** Type classification of the item. */ private String type; /** Detailed description of the item. */ private String description; /** URL of the item's representative image. */ private String pictureUrl; /** MercadoPago category identifier for the item. */ private String categoryId; /** Number of units of this item being purchased. */ private int quantity; /** Price per unit in the specified currency. */ private BigDecimal unitPrice; /** Whether the item includes a warranty. */ private boolean warranty; /** ISO 4217 currency code for the item's price (e.g., ARS, BRL, USD). */ private String currencyId; /** Category-specific descriptor with additional details (e.g., passenger and route for travel). */ private PreferenceCategoryDescriptor categoryDescriptor; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferencePassenger.java ================================================ package com.mercadopago.resources.preference; import com.mercadopago.client.common.IdentificationRequest; import lombok.Getter; /** * Resource representing passenger information for travel-related preference items. * *

Contains the personal details and identification of a passenger, typically used in * airline or transportation category descriptors within a checkout preference. * * @see PreferenceCategoryDescriptor */ @Getter public class PreferencePassenger { /** First name of the passenger. */ private String firstName; /** Last name of the passenger. */ private String lastName; /** Official identification document of the passenger (type and number). */ private IdentificationRequest identification; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferencePayer.java ================================================ package com.mercadopago.resources.preference; import com.mercadopago.resources.common.Address; import com.mercadopago.resources.common.Identification; import com.mercadopago.resources.common.Phone; import java.time.OffsetDateTime; import java.util.Date; import lombok.Getter; /** * Resource representing the buyer (payer) information in a checkout preference. * *

Contains the payer's personal details, contact information, address, and behavioral metadata * used by MercadoPago to enhance the checkout experience and fraud prevention analysis. * * @see Preference */ @Getter public class PreferencePayer { /** First name of the payer. */ private String name; /** Last name (surname) of the payer. */ private String surname; /** Email address of the payer. */ private String email; /** Phone contact information of the payer. */ private Phone phone; /** Official identification document of the payer (type and number). */ private Identification identification; /** Residential or billing address of the payer. */ private Address address; /** Timestamp when the payer's user account was created. */ private OffsetDateTime dateCreated; /** Timestamp of the payer's most recent purchase. */ private OffsetDateTime lastPurchase; /** Authentication method used by the payer (e.g., gmail, facebook, native). */ private String authenticationType; /** Whether the payer is a MercadoLibre Nivel 6 / Prime subscriber. */ private Boolean isPrimeUser; /** Whether this is the payer's first online purchase. */ private Boolean isFirstPurchaseOnline; /** Date when the payer registered on the platform. */ private OffsetDateTime registrationDate; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferencePaymentMethod.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource representing a specific payment method referenced in a checkout preference. * *

Used to identify individual payment methods that are either excluded from or set as default * in the preference's payment configuration. * * @see PreferencePaymentMethods */ @Getter public class PreferencePaymentMethod { /** Unique identifier of the payment method (e.g., visa, master, amex). */ private String id; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferencePaymentMethods.java ================================================ package com.mercadopago.resources.preference; import java.util.List; import lombok.Getter; /** * Resource representing the payment methods configuration of a checkout preference. * *

Controls which payment methods and types are available to the buyer during checkout, * including exclusions, default selections, and installment limits. * * @see Preference * @see PreferencePaymentMethod * @see PreferencePaymentType */ @Getter public class PreferencePaymentMethods { /** Payment methods excluded from the checkout (except account_money). */ private List excludedPaymentMethods; /** Payment types excluded from the checkout (e.g., ticket, atm, credit_card). */ private List excludedPaymentTypes; /** Identifier of the payment method pre-selected by default in the checkout. */ private String defaultPaymentMethodId; /** Maximum number of installments allowed for credit card payments. */ private Integer installments; /** Number of installments pre-selected by default for credit card payments. */ private Integer defaultInstallments; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferencePaymentType.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource representing a payment type referenced in a checkout preference. * *

Used to identify payment type categories (e.g., credit_card, debit_card, ticket) that can * be excluded from the checkout flow. * * @see PreferencePaymentMethods */ @Getter public class PreferencePaymentType { /** Identifier of the payment type (e.g., credit_card, debit_card, ticket, atm). */ private String id; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceReceiverAddress.java ================================================ package com.mercadopago.resources.preference; import com.mercadopago.resources.common.Address; import lombok.Getter; /** * Resource representing the shipping receiver's address in a checkout preference. * *

Extends the base {@link Address} with additional location details such as country name, * state name, city, floor, and apartment. Used to specify where the shipment should be delivered. * * @see PreferenceShipments * @see Address */ @Getter public class PreferenceReceiverAddress extends Address { /** Full name of the country for the delivery address. */ private String countryName; /** Full name of the state or province for the delivery address. */ private String stateName; /** Floor number within the building. */ private String floor; /** Apartment or unit identifier within the building. */ private String apartment; /** Full name of the city for the delivery address. */ private String cityName; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceRoute.java ================================================ package com.mercadopago.resources.preference; import java.time.OffsetDateTime; import lombok.Getter; /** * Resource representing flight route information for travel-related preference items. * *

Contains departure and arrival details for a flight segment, including airport codes, * scheduled times, and the operating airline. Used within the category descriptor of travel items. * * @see PreferenceCategoryDescriptor */ @Getter public class PreferenceRoute { /** Departure airport code or city name. */ private String departure; /** Destination airport code or city name. */ private String destination; /** Scheduled departure date and time. */ private OffsetDateTime departureDateTime; /** Scheduled arrival date and time. */ private OffsetDateTime arrivalDateTime; /** Name of the airline or transportation company. */ private String company; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceSearch.java ================================================ package com.mercadopago.resources.preference; import com.mercadopago.net.MPResource; import java.time.OffsetDateTime; import java.util.List; import lombok.Getter; /** * Resource representing a lightweight preference summary returned from search results. * *

Contains a subset of preference attributes optimized for listing and filtering, including * identifiers, dates, payer information, and operational metadata. Unlike {@link Preference}, this * resource does not include the full item details or nested configuration objects. * * @see Preference * @see com.mercadopago.client.preference.PreferenceClient#search(com.mercadopago.client.preference.PreferenceSearchRequest) */ @Getter public class PreferenceSearch extends MPResource { /** Unique identifier of the preference. */ private String id; /** Identifier of the OAuth application client that created this preference. */ private String clientId; /** Identifier of the seller (collector) who receives the payment. */ private Long collectorId; /** Timestamp when the preference was created. */ private OffsetDateTime dateCreated; /** Start date from which the preference becomes active. */ private OffsetDateTime expirationDateFrom; /** End date after which the preference is no longer valid. */ private OffsetDateTime expirationDateTo; /** Whether this preference has an expiration window. */ private Boolean expires; /** External reference for correlating this preference with the integrator's system. */ private String externalReference; /** List of item identifiers included in this preference. */ private List items; /** Timestamp when the preference was last updated. */ private OffsetDateTime lastUpdated; /** Whether the preference was created in production (live) mode. */ private Boolean liveMode; /** Marketplace origin identifier. Default value: NONE. */ private String marketplace; /** Type of operation (e.g., regular_payment, money_transfer). */ private String operationType; /** Email address of the payer. */ private String payerEmail; /** Identifier of the payer. */ private String payerId; /** Identifier of the platform that originated this preference. */ private String platformId; /** List of processing modes used (e.g., aggregator, gateway). */ private List processingModes; /** Identifier of the product associated with this preference. */ private String productId; /** Purpose of the preference (e.g., wallet_purchase). */ private String purpose; /** MercadoPago site identifier (e.g., MLA, MLB, MLM). */ private String siteId; /** Identifier of the sponsoring account, if applicable. */ private Long sponsorId; /** Shipping mode configured for this preference. */ private String shippingMode; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceShipments.java ================================================ package com.mercadopago.resources.preference; import java.math.BigDecimal; import java.util.List; import lombok.Getter; /** * Resource representing the shipment configuration of a checkout preference. * *

Defines how purchased items are delivered to the buyer, including the shipping mode, cost, * dimensions, available free methods, and the receiver's delivery address. Supports both * MercadoEnvios ({@code me2}) and custom shipping modes. * * @see Preference * @see PreferenceFreeMethod * @see PreferenceReceiverAddress */ @Getter public class PreferenceShipments { /** Shipping mode (e.g., custom, me2, not_specified). */ private String mode; /** Whether the buyer can pick up the shipment at the seller's store (me2 mode only). */ private Boolean localPickup; /** Package dimensions in the format "height x width x length, weight" (me2 mode only). */ private String dimensions; /** Identifier of the default shipping method pre-selected in checkout (me2 mode only). */ private String defaultShippingMethod; /** List of shipping methods offered at no cost to the buyer (me2 mode only). */ private List freeMethods; /** Fixed shipping cost charged to the buyer (custom mode only). */ private BigDecimal cost; /** Whether shipping is free of charge (custom mode only). */ private Boolean freeShipping; /** Delivery address where the shipment will be sent. */ private PreferenceReceiverAddress receiverAddress; /** Whether express (expedited) shipment is enabled. */ private Boolean expressShipment; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceTax.java ================================================ package com.mercadopago.resources.preference; import java.math.BigDecimal; import lombok.Getter; /** * Resource representing a tax applied to a checkout preference. * *

Defines a tax entry with its type and monetary value. Multiple taxes can be associated with * a single preference to cover different tax obligations (e.g., IVA, IIBB). * * @see Preference */ @Getter public class PreferenceTax { /** Tax type identifier (e.g., IVA, INC). */ private String type; /** Monetary value of the tax. */ private BigDecimal value; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceTrack.java ================================================ package com.mercadopago.resources.preference; import com.mercadopago.client.preference.PreferenceTrackValuesRequest; import lombok.Getter; /** * Resource representing a tracking tag executed during the buyer's checkout interaction. * *

Enables conversion tracking by associating the checkout flow with advertising platforms * such as Google Ads or Facebook Ads. Each track specifies a type and its corresponding * platform-specific identifiers. * * @see Preference * @see PreferenceTrackValues */ @Getter public class PreferenceTrack { /** Tracking platform type ({@code google_ad} or {@code facebook_ad}). */ private String type; /** Platform-specific tracking values (conversion IDs, pixel IDs, etc.). */ private PreferenceTrackValuesRequest values; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceTrackValues.java ================================================ package com.mercadopago.resources.preference; import lombok.Getter; /** * Resource containing platform-specific tracking identifiers for checkout conversion tracking. * *

Holds the values needed by advertising platforms to register conversions during the checkout * flow. Supports Google Ads (via conversion ID and label) and Facebook Ads (via pixel ID). * * @see PreferenceTrack */ @Getter public class PreferenceTrackValues { /** Google Ads conversion ID used in the GTM Conversion Tracking tag. */ private String conversionId; /** Google Ads conversion label used in the GTM Conversion Tracking tag. */ private String conversionLabel; /** Facebook Pixel ID for tracking conversions on Facebook Ads. */ private String pixelId; } ================================================ FILE: src/main/java/com/mercadopago/resources/preference/PreferenceUserAmount.java ================================================ package com.mercadopago.resources.preference; import java.math.BigDecimal; import lombok.Getter; /** * Resource representing the amount details for a specific party (payer or collector) in a * checkout preference. * *

Contains the currency and transaction amount applicable to the party. Used within * {@link PreferenceAmounts} to break down the total preference amount by role. * * @see PreferenceAmounts */ @Getter public class PreferenceUserAmount { /** ISO 4217 currency code for the transaction amount (e.g., ARS, BRL, USD). */ private String currencyId; /** Transaction amount applicable to this party. */ private BigDecimal transaction; } ================================================ FILE: src/main/java/com/mercadopago/resources/user/User.java ================================================ package com.mercadopago.resources.user; import com.mercadopago.net.MPResource; import lombok.Getter; /** * Resource representing the authenticated MercadoPago user account. * *

Contains profile information of the user associated with the current access token, including * personal details, site affiliation, and country. Typically retrieved to verify credentials or * obtain account metadata. * * @see com.mercadopago.client.user.UserClient */ @Getter public class User extends MPResource { /** Unique numeric identifier of the user account. */ private Long id; /** Public nickname or display name of the user. */ private String nickname; /** First name of the user. */ private String firstName; /** Last name of the user. */ private String lastName; /** Email address associated with the user account. */ private String email; /** Identifier of the MercadoPago site the user belongs to (e.g., MLA, MLB, MLM). */ private String siteId; /** ISO 3166-1 country code of the user's registered country. */ private String countryId; } ================================================ FILE: src/main/java/com/mercadopago/serialization/Serializer.java ================================================ package com.mercadopago.serialization; import static com.google.gson.stream.JsonToken.END_DOCUMENT; import com.google.gson.FieldNamingPolicy; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import com.google.gson.JsonSerializer; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.MalformedJsonException; import com.mercadopago.exceptions.MPJsonParseException; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPResource; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResultsResourcesPage; import java.io.IOException; import java.io.StringReader; import java.lang.reflect.Type; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.format.DateTimeFormatter; import java.time.format.DateTimeParseException; import java.util.ArrayList; import java.util.List; /** * Central JSON serialization and deserialization utility for the MercadoPago Java SDK. * *

This class wraps Google Gson and provides static helper methods to convert between * Java objects (extending {@link MPResource}) and their JSON representations. Key behaviors: *

    *
  • Field naming: Java camelCase fields are mapped to JSON snake_case * via {@link FieldNamingPolicy#LOWER_CASE_WITH_UNDERSCORES}.
  • *
  • Date handling: {@link OffsetDateTime} and {@link LocalDate} are serialized * as ISO 8601 strings. Deserialization attempts multiple ISO 8601 format variants * (see {@link #ISO8601_DATETIME_FORMATTERS}) to handle responses from different * API versions.
  • *
  • Validation: JSON strings are validated before deserialization via * {@link #isJsonValid(String)} to provide clearer error messages.
  • *
* * @see MPResource * @see MPJsonParseException */ public class Serializer { /** * ISO 8601 extended date-time formatter for deserialization. * Pattern: {@code yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX][XX][X]} -- supports optional * milliseconds and various offset formats. */ private static final DateTimeFormatter DESERIALIZE_DATE_FORMAT_ISO8601_EXTENDED = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss[.SSS][XXX][XX][X]"); /** * ISO 8601 basic (compact) date-time formatter for deserialization. * Pattern: {@code yyyyMMdd'T'HHmmss[.SSS][XXX][XX][X]} -- no hyphens or colons in * the date/time portion. */ private static final DateTimeFormatter DESERIALIZE_DATE_FORMAT_ISO8601_BASIC = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss[.SSS][XXX][XX][X]"); /** * Ordered array of date-time formatters tried during deserialization. The first * formatter that successfully parses the input wins. Order: * {@link DateTimeFormatter#ISO_DATE_TIME}, extended ISO 8601, basic ISO 8601. */ private static final DateTimeFormatter[] ISO8601_DATETIME_FORMATTERS = new DateTimeFormatter[] { DateTimeFormatter.ISO_DATE_TIME, DESERIALIZE_DATE_FORMAT_ISO8601_EXTENDED, DESERIALIZE_DATE_FORMAT_ISO8601_BASIC, }; /** * ISO 8601 date-time pattern used for serialization of {@link OffsetDateTime} * values. Always includes milliseconds and a full timezone offset * (e.g., {@code 2023-10-15T14:30:00.000-03:00}). */ private static final String SERIALIZE_DATE_FORMAT_ISO8601 = "yyyy-MM-dd'T'HH:mm:ss.SSSXXX"; /** * Attempts to parse a JSON element as an {@link OffsetDateTime} by trying each formatter * in {@link #ISO8601_DATETIME_FORMATTERS} in order. * * @param json the JSON element containing a date-time string * @return the parsed {@link OffsetDateTime}, or {@code null} if the element is null/empty * @throws DateTimeParseException if none of the known formatters can parse the value */ private static OffsetDateTime parseDateTime(JsonElement json) { if (json == null || json.getAsString().isEmpty()) { return null; } for (int i = 0; i < ISO8601_DATETIME_FORMATTERS.length; i++) { try { return OffsetDateTime.parse(json.getAsString(), ISO8601_DATETIME_FORMATTERS[i]); } catch (DateTimeParseException e) { // try all formatters, if none works, throw exception from last one if (i == ISO8601_DATETIME_FORMATTERS.length - 1) { throw e; } } } return null; } /** * Pre-configured Gson instance shared by all serialization methods. Configured with: *
    *
  • {@link FieldNamingPolicy#LOWER_CASE_WITH_UNDERSCORES} for snake_case JSON mapping
  • *
  • Custom {@link OffsetDateTime} serializer/deserializer using ISO 8601 formats
  • *
  • Custom {@link LocalDate} serializer/deserializer using {@link DateTimeFormatter#ISO_LOCAL_DATE}
  • *
*/ private static final Gson GSON = new GsonBuilder() .registerTypeAdapter( OffsetDateTime.class, (JsonDeserializer) (json, type, context) -> parseDateTime(json)) .registerTypeAdapter( OffsetDateTime.class, (JsonSerializer) (offsetDateTime, type, context) -> new JsonPrimitive( DateTimeFormatter.ofPattern(SERIALIZE_DATE_FORMAT_ISO8601) .format(offsetDateTime))) .registerTypeAdapter( LocalDate.class, (JsonSerializer) (localDate, type, context) -> new JsonPrimitive(localDate.format(DateTimeFormatter.ISO_LOCAL_DATE))) .registerTypeAdapter( LocalDate.class, (JsonDeserializer) (localDate, type, context) -> LocalDate.parse(localDate.getAsString())) .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) .create(); /** * Deserializes a JSON string into a single {@link MPResource} instance. * *

The JSON is first validated with {@link #isJsonValid(String)}, then converted * using the pre-configured Gson instance (snake_case mapping, ISO 8601 dates). * * @param clazz the target class to deserialize into * @param jsonObject the raw JSON string returned by the API * @param a type extending {@link MPResource} * @return the deserialized resource instance * @throws MPJsonParseException if the JSON is malformed or cannot be mapped to the target class */ public static T deserializeFromJson(Class clazz, String jsonObject) throws MPJsonParseException { try { if (isJsonValid(jsonObject)) { return GSON.fromJson(jsonObject, clazz); } else { throw new MPJsonParseException(String.format("Could not parse json: %s", jsonObject)); } } catch (IOException e) { throw new MPJsonParseException("Could not parse json", e); } } /** * Deserializes a JSON string into an {@link MPResultsResourcesPage}, which represents * a paginated API response whose items are nested under a {@code "results"} key. * * @param type the parameterized type token (e.g., * {@code new TypeToken>(){}.getType()}) * @param jsonObject the raw JSON string containing the paginated response * @param a type extending {@link MPResource} * @return the deserialized page containing a list of results and paging metadata * @throws MPJsonParseException if the JSON is malformed or cannot be mapped to the target type * @see MPResultsResourcesPage */ public static MPResultsResourcesPage deserializeResultsResourcesPageFromJson( Type type, String jsonObject) throws MPJsonParseException { try { if (isJsonValid(jsonObject)) { return GSON.fromJson(jsonObject, type); } else { throw new MPJsonParseException(String.format("Could not parse json: %s", jsonObject)); } } catch (IOException e) { throw new MPJsonParseException("Could not parse json", e); } } /** * Deserializes a JSON string into an {@link MPElementsResourcesPage}, which represents * a paginated API response whose items are nested under an {@code "elements"} key. * * @param type the parameterized type token (e.g., * {@code new TypeToken>(){}.getType()}) * @param jsonObject the raw JSON string containing the paginated response * @param a type extending {@link MPResource} * @return the deserialized page containing a list of elements and paging metadata * @throws MPJsonParseException if the JSON is malformed or cannot be mapped to the target type * @see MPElementsResourcesPage */ public static MPElementsResourcesPage deserializeElementsResourcesPageFromJson( Type type, String jsonObject) throws MPJsonParseException { try { if (isJsonValid(jsonObject)) { return GSON.fromJson(jsonObject, type); } else { throw new MPJsonParseException(String.format("Could not parse json: %s", jsonObject)); } } catch (IOException | MPJsonParseException e) { throw new MPJsonParseException("Could not parse json", e); } } /** * Deserializes a JSON array string into an {@link MPResourceList} containing individual * resource instances. * *

This method handles API responses that return a top-level JSON array (as opposed * to a paginated wrapper object). Each element of the array is deserialized independently * and collected into the returned list. * * @param clazz the class of each element in the JSON array * @param jsonObject the raw JSON array string (e.g., {@code [{"id":1}, {"id":2}]}) * @param a type extending {@link MPResource} * @return an {@link MPResourceList} containing the deserialized resources * @throws MPJsonParseException if the JSON is malformed or an element cannot be deserialized * @see MPResourceList */ public static MPResourceList deserializeListFromJson( Class clazz, String jsonObject) throws MPJsonParseException { try { if (isJsonValid(jsonObject)) { MPResourceList resourceList = new MPResourceList<>(); List results = new ArrayList<>(); JsonArray jsonArray = JsonParser.parseString(jsonObject).getAsJsonArray(); for (int i = 0; i < jsonArray.size(); i++) { T resource = GSON.fromJson(jsonArray.get(i), clazz); results.add(resource); } resourceList.setResults(results); return resourceList; } else { throw new MPJsonParseException(String.format("Could not parse json: %s", jsonObject)); } } catch (IOException e) { throw new MPJsonParseException("Could not parse json", e); } } /** * Serializes a Java object into a Gson {@link JsonObject} suitable for use as an * API request body. * *

Fields are converted to snake_case and dates are formatted as ISO 8601 strings * per the SDK's Gson configuration. * * @param resource the object to serialize (typically an API request DTO) * @param the type of the object * @return a {@link JsonObject} representation of the resource */ public static JsonObject serializeToJson(T resource) { return (JsonObject) GSON.toJsonTree(resource); } /** * Validates whether the given string is syntactically correct JSON. * *

The method uses a streaming {@link JsonReader} to walk the entire token structure * without materializing objects, making it efficient for large payloads. It returns * {@code false} for malformed JSON and {@code true} for valid JSON objects, arrays, * or primitive values. * * @param json the raw string to validate * @return {@code true} if the string is valid JSON, {@code false} otherwise * @throws IOException if an I/O error occurs while reading the string */ public static boolean isJsonValid(String json) throws IOException { try { JsonReader jsonReader = new JsonReader(new StringReader(json)); JsonToken token; loop: while ((token = jsonReader.peek()) != END_DOCUMENT && token != null) { switch (token) { case BEGIN_ARRAY: jsonReader.beginArray(); break; case END_ARRAY: jsonReader.endArray(); break; case BEGIN_OBJECT: jsonReader.beginObject(); break; case END_OBJECT: jsonReader.endObject(); break; case NAME: jsonReader.nextName(); break; case STRING: case NUMBER: case BOOLEAN: case NULL: jsonReader.skipValue(); break; case END_DOCUMENT: break loop; default: throw new AssertionError(token); } } return true; } catch (final MalformedJsonException ignored) { return false; } } } ================================================ FILE: src/main/java/com/mercadopago/webhook/WebhookSignatureValidator.java ================================================ package com.mercadopago.webhook; import com.mercadopago.exceptions.MPInvalidWebhookSignatureException; import com.mercadopago.exceptions.SignatureFailureReason; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.time.Duration; import java.time.Instant; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Supplier; import java.util.regex.Pattern; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; /** * Verifies the authenticity of an incoming MercadoPago webhook notification by * recomputing the HMAC-SHA256 signature locally and comparing it against the value * carried in the {@code x-signature} header. * *

This is a stateless, CPU-only utility. It performs no outbound HTTP calls and * does not depend on {@link com.mercadopago.MercadoPagoConfig}; the integrator * passes the secret signature explicitly on every call. The comparison is performed * in constant time (via {@link MessageDigest#isEqual(byte[], byte[])}) to mitigate * timing attacks. * *

On failure, the validator throws {@link MPInvalidWebhookSignatureException} * with a specific {@link SignatureFailureReason}. The integrator should respond with * HTTP 401 to MercadoPago in all failure cases, log the request id for correlation, * and not expose the failure reason in the HTTP response body. * *

QR Code notifications are not signed by MercadoPago — do not call this * validator for those events; they will always fail signature verification. */ public final class WebhookSignatureValidator { private static final List DEFAULT_SUPPORTED_VERSIONS = List.of("v1"); private static final Pattern VERSION_KEY_REGEX = Pattern.compile("^v\\d+$"); private static final Pattern DIGITS_REGEX = Pattern.compile("^\\d+$"); private WebhookSignatureValidator() { // Static-only class — prevent instantiation. } /** * Validates the signature of a MercadoPago webhook notification. * * @param xSignature raw value of the {@code x-signature} request header * @param xRequestId value of the {@code x-request-id} request header; may be {@code null} * or blank, in which case the {@code request-id:} pair is omitted from the * manifest before computing the HMAC * @param dataId value of the {@code data.id} query parameter; may be {@code null} or * blank, in which case the {@code id:} pair is omitted. When present, * it is lowercased before being included in the manifest * @param secret secret signature configured for the application in Tus Integraciones, * used as the HMAC key * @throws MPInvalidWebhookSignatureException when the signature is missing, malformed, or * does not match the expected HMAC * @throws NullPointerException when {@code secret} is {@code null} */ public static void validate(String xSignature, String xRequestId, String dataId, String secret) throws MPInvalidWebhookSignatureException { validate(xSignature, xRequestId, dataId, secret, null, null, null); } /** * Validates the signature with an optional replay-window tolerance. See * {@link #validate(String, String, String, String, Duration, List, Supplier)} for the full * documentation. */ public static void validate( String xSignature, String xRequestId, String dataId, String secret, Duration tolerance) throws MPInvalidWebhookSignatureException { validate(xSignature, xRequestId, dataId, secret, tolerance, null, null); } /** * Full-featured overload that exposes all options. * * @param xSignature raw value of the {@code x-signature} request header * @param xRequestId value of the {@code x-request-id} request header; may be {@code null} * @param dataId value of the {@code data.id} query parameter; may be {@code null} * @param secret secret signature configured for the application * @param tolerance optional maximum allowed drift between the timestamp in the header * and the current clock; {@code null} disables the check * @param supportedVersions optional ordered list of signature versions to accept; defaults * to {@code ["v1"]}. The first version found in the header is used * @param clock optional clock supplier used for the tolerance check; intended for * tests. Defaults to {@link Instant#now()} * @throws MPInvalidWebhookSignatureException when the signature is missing, malformed, or * does not match the expected HMAC * @throws NullPointerException when {@code secret} is {@code null} */ public static void validate( String xSignature, String xRequestId, String dataId, String secret, Duration tolerance, List supportedVersions, Supplier clock) throws MPInvalidWebhookSignatureException { Objects.requireNonNull(secret, "secret must not be null"); String signature = normalize(xSignature); String requestId = normalize(xRequestId); String normalizedDataId = normalize(dataId); List versions = (supportedVersions == null || supportedVersions.isEmpty()) ? DEFAULT_SUPPORTED_VERSIONS : supportedVersions; Supplier nowSupplier = clock != null ? clock : Instant::now; if (signature == null) { throw new MPInvalidWebhookSignatureException( SignatureFailureReason.MISSING_SIGNATURE_HEADER, requestId, null); } ParsedSignature parsed = parseSignatureHeader(signature); if (parsed.timestamp == null && parsed.hashes.isEmpty()) { throw new MPInvalidWebhookSignatureException( SignatureFailureReason.MALFORMED_SIGNATURE_HEADER, requestId, null); } if (parsed.timestamp == null) { throw new MPInvalidWebhookSignatureException( SignatureFailureReason.MISSING_TIMESTAMP, requestId, null); } if (!DIGITS_REGEX.matcher(parsed.timestamp).matches()) { throw new MPInvalidWebhookSignatureException( SignatureFailureReason.MALFORMED_SIGNATURE_HEADER, requestId, parsed.timestamp); } String receivedHash = null; for (String version : versions) { String hash = parsed.hashes.get(version); if (hash != null) { receivedHash = hash; break; } } if (receivedHash == null) { throw new MPInvalidWebhookSignatureException( SignatureFailureReason.MISSING_HASH, requestId, parsed.timestamp); } String manifest = buildManifest(normalizedDataId, requestId, parsed.timestamp); String computed = computeHmacHex(secret, manifest); if (!constantTimeEquals(computed, receivedHash)) { throw new MPInvalidWebhookSignatureException( SignatureFailureReason.SIGNATURE_MISMATCH, requestId, parsed.timestamp); } if (tolerance != null) { long tsMs = Long.parseLong(parsed.timestamp); long nowMs = nowSupplier.get().toEpochMilli(); long drift = Math.abs(nowMs - tsMs); if (drift > tolerance.toMillis()) { throw new MPInvalidWebhookSignatureException( SignatureFailureReason.TIMESTAMP_OUT_OF_TOLERANCE, requestId, parsed.timestamp); } } } private static String normalize(String value) { if (value == null) { return null; } String trimmed = value.trim(); return trimmed.isEmpty() ? null : trimmed; } private static ParsedSignature parseSignatureHeader(String header) { Map hashes = new HashMap<>(); String ts = null; for (String part : header.split(",")) { int eq = part.indexOf('='); if (eq <= 0 || eq == part.length() - 1) { continue; } String key = part.substring(0, eq).trim().toLowerCase(); String value = part.substring(eq + 1).trim(); if (key.isEmpty() || value.isEmpty()) { continue; } if ("ts".equals(key)) { ts = value; } else if (VERSION_KEY_REGEX.matcher(key).matches()) { hashes.put(key, value); } } return new ParsedSignature(ts, hashes); } private static String buildManifest(String dataId, String requestId, String timestamp) { StringBuilder sb = new StringBuilder(); if (dataId != null) { sb.append("id:").append(dataId.toLowerCase()).append(';'); } if (requestId != null) { sb.append("request-id:").append(requestId).append(';'); } sb.append("ts:").append(timestamp).append(';'); return sb.toString(); } private static String computeHmacHex(String secret, String message) { try { Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); byte[] hashBytes = mac.doFinal(message.getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(hashBytes.length * 2); for (byte b : hashBytes) { sb.append(String.format("%02x", b & 0xff)); } return sb.toString(); } catch (Exception e) { // HmacSHA256 is mandated by every JRE; failures here indicate a broken runtime. throw new IllegalStateException("HMAC-SHA256 not available in this JVM", e); } } private static boolean constantTimeEquals(String a, String b) { if (a == null || b == null || a.length() != b.length()) { return false; } return MessageDigest.isEqual( a.getBytes(StandardCharsets.UTF_8), b.getBytes(StandardCharsets.UTF_8)); } /** Internal carrier for the parsed {@code x-signature} components. */ private static final class ParsedSignature { final String timestamp; final Map hashes; ParsedSignature(String timestamp, Map hashes) { this.timestamp = timestamp; this.hashes = hashes; } } } ================================================ FILE: src/test/java/com/mercadopago/BaseClientIT.java ================================================ package com.mercadopago; import com.mercadopago.core.MPRequestOptions; import org.junit.jupiter.api.BeforeAll; /** BaseClientIT class. */ public abstract class BaseClientIT { protected static final int DEFAULT_TIMEOUT = 2000; protected static final String ACCESS_TOKEN = System.getenv("ACCESS_TOKEN"); @BeforeAll static void setup() { MercadoPagoConfig.setAccessToken(ACCESS_TOKEN); MercadoPagoConfig.setHttpClient(null); } protected static MPRequestOptions buildRequestOptions() { return MPRequestOptions.builder() .connectionTimeout(DEFAULT_TIMEOUT) .connectionRequestTimeout(DEFAULT_TIMEOUT) .socketTimeout(DEFAULT_TIMEOUT) .build(); } protected static String generateTestEmail() { int minValue = 10000000; int maxValue = 99999999; int complement = (int) (Math.random() * (maxValue - minValue) + minValue); return String.format("test_user_%s@testuser.com", complement); } } ================================================ FILE: src/test/java/com/mercadopago/BaseClientTest.java ================================================ package com.mercadopago; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.mock.HttpClientMock; import com.mercadopago.mock.MPDefaultHttpClientMock; import java.util.TimeZone; import org.apache.http.client.HttpClient; import org.junit.jupiter.api.BeforeAll; /** BaseClientTest class. */ public abstract class BaseClientTest { protected static final String APPLICATION_JSON = "application/json"; protected static final HttpClientMock HTTP_CLIENT_MOCK = new HttpClientMock(); protected static final HttpClient HTTP_CLIENT = HTTP_CLIENT_MOCK.getHttpClient(); protected static final int DEFAULT_TIMEOUT = 1000; @BeforeAll static void setup() { TimeZone.setDefault(TimeZone.getTimeZone("UTC")); String accessToken = "token"; MercadoPagoConfig.setAccessToken(accessToken); MercadoPagoConfig.setHttpClient(new MPDefaultHttpClientMock(HTTP_CLIENT_MOCK)); } protected static MPRequestOptions buildRequestOptions() { return MPRequestOptions.builder() .accessToken("abc") .connectionTimeout(DEFAULT_TIMEOUT) .connectionRequestTimeout(DEFAULT_TIMEOUT) .socketTimeout(DEFAULT_TIMEOUT) .build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/MercadoPagoClientTest.java ================================================ package com.mercadopago.client; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.mercadopago.BaseClientTest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.helper.MockHelper; import com.mercadopago.mock.MPDefaultHttpClientMock; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPRequest; import com.mercadopago.net.MPResponse; import com.mercadopago.net.MPSearchRequest; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.ArgumentCaptor; import static org.mockito.ArgumentMatchers.any; /** MercadoPagoClientTest class. */ public class MercadoPagoClientTest extends BaseClientTest { private final HttpClient httpClientMock = mock(HttpClient.class); private final MPDefaultHttpClientMock mpHttpClient = new MPDefaultHttpClientMock(httpClientMock); private final TestClient testClient = new TestClient(mpHttpClient); private final String requestFile = "request_generic.json"; private final String responseFile = "response_generic_success.json"; @Test public void sendWithBodySuccess() throws IOException, MPException, MPApiException { String request = MockHelper.readRequestFile(requestFile); JsonObject requestObject = JsonParser.parseString(request).getAsJsonObject(); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPRequest mpRequest = MPRequest.builder() .uri("https://test.com") .method(HttpMethod.POST) .payload(requestObject) .build(); MPResponse mpResponse = testClient.sendRequest(mpRequest); assertNotNull(mpResponse); assertEquals(200, (int) mpResponse.getStatusCode()); } @Test public void sendWithIdempotentHeaderIfMethodIsPost() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 201); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); testClient.sendRequest("/test", HttpMethod.POST, null, null, null); ArgumentCaptor httpBaseCaptor = ArgumentCaptor.forClass(HttpRequestBase.class); ArgumentCaptor httpClientContextCaptor = ArgumentCaptor.forClass(HttpClientContext.class); verify(httpClientMock).execute(httpBaseCaptor.capture(), httpClientContextCaptor.capture()); assertTrue( MockHelper.areHeadersValid( httpBaseCaptor.getValue().getAllHeaders(), httpBaseCaptor.getValue().getMethod())); } @Test public void sendWithoutBodySuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPRequest mpRequest = MPRequest.builder() .uri("https://test.com") .method(HttpMethod.GET) .headers(new HashMap<>()) .build(); MPResponse mpResponse = testClient.sendRequest(mpRequest); assertNotNull(mpResponse); assertEquals(200, (int) mpResponse.getStatusCode()); } @Test public void sendWithQueryStringSuccess() throws IOException, MPException, MPApiException { HashMap queryParams = new HashMap<>(); queryParams.put("entry1", "value&1"); queryParams.put("entry2", "value!2"); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPRequest mpRequest = MPRequest.builder() .uri("https://test.com") .method(HttpMethod.GET) .headers(new HashMap<>()) .queryParams(queryParams) .build(); testClient.sendRequest(mpRequest); ArgumentCaptor httpBaseCaptor = ArgumentCaptor.forClass(HttpRequestBase.class); ArgumentCaptor httpClientContextCaptor = ArgumentCaptor.forClass(HttpClientContext.class); verify(httpClientMock).execute(httpBaseCaptor.capture(), httpClientContextCaptor.capture()); assertTrue(httpBaseCaptor.getValue().getURI().getRawQuery().contains("entry1=value%261")); assertTrue(httpBaseCaptor.getValue().getURI().getRawQuery().contains("entry2=value%212")); } @Test public void sendWithMPRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResponse mpResponse = testClient.sendRequest("/test", HttpMethod.GET, null, null, buildRequestOptions()); assertNotNull(mpResponse); assertEquals(200, (int) mpResponse.getStatusCode()); } @Test public void sendWithRequiredHeaders() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); testClient.sendRequest("/test", HttpMethod.GET, null, null, null); ArgumentCaptor httpBaseCaptor = ArgumentCaptor.forClass(HttpRequestBase.class); ArgumentCaptor httpClientContextCaptor = ArgumentCaptor.forClass(HttpClientContext.class); verify(httpClientMock).execute(httpBaseCaptor.capture(), httpClientContextCaptor.capture()); assertTrue( MockHelper.areHeadersValid( httpBaseCaptor.getValue().getAllHeaders(), httpBaseCaptor.getValue().getMethod())); } @Test public void sendInvalidResponseError() throws IOException { String response = "invalid json"; HttpResponse httpResponse = MockHelper.generateHttpResponseFromString(response, 500); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPRequest mpRequest = MPRequest.builder() .uri("https://test.com") .method(HttpMethod.GET) .headers(new HashMap<>()) .build(); Assertions.assertThrows(MPApiException.class, () -> testClient.sendRequest(mpRequest)); } @Test public void sendHttpStatusCodeError() throws IOException { String response = "{\"error\": \"internal server error\"}"; HttpResponse httpResponse = MockHelper.generateHttpResponseFromString(response, 500); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPRequest mpRequest = MPRequest.builder() .uri("https://test.com") .method(HttpMethod.GET) .headers(new HashMap<>()) .build(); Assertions.assertThrows(MPApiException.class, () -> testClient.sendRequest(mpRequest)); } @Test public void searchWithParametersSuccess() throws IOException, MPException, MPApiException { Map filters = new HashMap<>(); filters.put("abc", "xyz"); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(10).offset(100).filters(filters).build(); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); testClient.searchRequest("/test", searchRequest); ArgumentCaptor httpBaseCaptor = ArgumentCaptor.forClass(HttpRequestBase.class); ArgumentCaptor httpClientContextCaptor = ArgumentCaptor.forClass(HttpClientContext.class); verify(httpClientMock).execute(httpBaseCaptor.capture(), httpClientContextCaptor.capture()); assertTrue(httpBaseCaptor.getValue().getURI().getRawQuery().contains("limit=10")); assertTrue(httpBaseCaptor.getValue().getURI().getRawQuery().contains("offset=100")); assertTrue(httpBaseCaptor.getValue().getURI().getRawQuery().contains("abc=xyz")); } @Test public void searchWithoutParametersSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResponse mpResponse = testClient.searchRequest("/test", null); assertNotNull(mpResponse); assertEquals(200, (int) mpResponse.getStatusCode()); } @Test public void listWithBodySuccess() throws IOException, MPException, MPApiException { String request = MockHelper.readRequestFile(requestFile); JsonObject requestObject = JsonParser.parseString(request).getAsJsonObject(); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResponse mpResponse = testClient.listRequest("/test", HttpMethod.POST, requestObject, null, null); assertNotNull(mpResponse); assertEquals(200, (int) mpResponse.getStatusCode()); } @Test public void listWithoutBodySuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResponse mpResponse = testClient.listRequest("/test", HttpMethod.GET, null, null, null); assertNotNull(mpResponse); assertEquals(200, (int) mpResponse.getStatusCode()); } @Test public void listWithQueryStringSuccess() throws IOException, MPException, MPApiException { HashMap queryParams = new HashMap<>(); queryParams.put("entry1", "value&1"); queryParams.put("entry2", "value!2"); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); testClient.listRequest("/test", HttpMethod.GET, null, queryParams, null); ArgumentCaptor httpBaseCaptor = ArgumentCaptor.forClass(HttpRequestBase.class); ArgumentCaptor httpClientContextCaptor = ArgumentCaptor.forClass(HttpClientContext.class); verify(httpClientMock).execute(httpBaseCaptor.capture(), httpClientContextCaptor.capture()); assertTrue(httpBaseCaptor.getValue().getURI().getRawQuery().contains("entry1=value%261")); assertTrue(httpBaseCaptor.getValue().getURI().getRawQuery().contains("entry2=value%212")); } @Test public void listWithMPRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFile, 200); doReturn(httpResponse) .when(httpClientMock) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResponse mpResponse = testClient.listRequest("/test", HttpMethod.GET, null, null, buildRequestOptions()); assertNotNull(mpResponse); assertEquals(200, (int) mpResponse.getStatusCode()); } private static class TestClient extends MercadoPagoClient { /** * MercadoPagoClient constructor. * * @param httpClient http client */ public TestClient(MPHttpClient httpClient) { super(httpClient); } public MPResponse sendRequest(MPRequest request) throws MPException, MPApiException { return send(request); } public MPResponse sendRequest( String path, HttpMethod method, JsonObject payload, Map queryParams, MPRequestOptions requestOptions) throws MPException, MPApiException { return send(path, method, payload, queryParams, requestOptions); } public MPResponse searchRequest(String path, MPSearchRequest searchRequest) throws MPException, MPApiException { return search(path, searchRequest); } public MPResponse listRequest( String path, HttpMethod method, JsonObject payload, HashMap queryParams, MPRequestOptions requestOptions) throws MPException, MPApiException { return list(path, method, payload, queryParams, requestOptions); } } } ================================================ FILE: src/test/java/com/mercadopago/client/cardtoken/CardTokenCardholderTestCreateRequest.java ================================================ package com.mercadopago.client.cardtoken; import com.mercadopago.client.common.IdentificationRequest; import lombok.Builder; /** CardTokenCardholderTestCreateRequest class. */ @Builder public class CardTokenCardholderTestCreateRequest { /** Cardholder name. */ public String name; /** Cardholder identification. */ public IdentificationRequest identification; } ================================================ FILE: src/test/java/com/mercadopago/client/cardtoken/CardTokenClientIT.java ================================================ package com.mercadopago.client.cardtoken; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.client.customer.CustomerCardCreateRequest; import com.mercadopago.client.customer.CustomerClient; import com.mercadopago.client.customer.CustomerRequest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.CardToken; import com.mercadopago.resources.customer.Customer; import com.mercadopago.resources.customer.CustomerCard; import org.junit.jupiter.api.Test; /** CardTokenClientIT class. */ public class CardTokenClientIT extends BaseClientIT { private final CustomerClient customerClient = new CustomerClient(); private final CardTokenClient tokenClient = new CardTokenClient(); private final CardTokenTestClient cardTokenTestClient = new CardTokenTestClient(); @Test public void getCardTokenSuccess() { try { CardToken createdCardToken = cardTokenTestClient.createTestCardToken("approved"); CardToken token = tokenClient.get(createdCardToken.getId()); assertNotNull(token); assertEquals(OK, token.getResponse().getStatusCode()); assertEquals(createdCardToken.getId(), token.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getCardTokenWithRequestOptionsSuccess() { try { CardToken createdCardToken = cardTokenTestClient.createTestCardToken("approved"); CardToken token = tokenClient.get(createdCardToken.getId(), buildRequestOptions()); assertNotNull(token); assertEquals(OK, token.getResponse().getStatusCode()); assertEquals(createdCardToken.getId(), token.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createCardTokenSuccess() { try { CustomerRequest customerRequest = buildCustomerRequest(); Customer customer = customerClient.create(customerRequest); try { CustomerCardCreateRequest cardCreateRequest = buildCardCreateRequest(); CustomerCard customerCard = customerClient.createCard(customer.getId(), cardCreateRequest); CardTokenRequest cardTokenRequest = CardTokenRequest.builder() .cardId(customerCard.getId()) .customerId(customer.getId()) .securityCode("123") .build(); CardToken token = tokenClient.create(cardTokenRequest); assertNotNull(token); assertNotNull(token.getResponse()); assertEquals(CREATED, token.getResponse().getStatusCode()); assertNotNull(token.getId()); assertEquals(customerCard.getId(), token.getCardId()); } finally { customerClient.delete(customer.getId()); } } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createCardTokenWithRequestOptionsSuccess() { try { CustomerRequest customerRequest = buildCustomerRequest(); Customer customer = customerClient.create(customerRequest); try { CustomerCardCreateRequest cardCreateRequest = buildCardCreateRequest(); CustomerCard customerCard = customerClient.createCard(customer.getId(), cardCreateRequest); CardTokenRequest cardTokenRequest = CardTokenRequest.builder() .cardId(customerCard.getId()) .customerId(customer.getId()) .securityCode("123") .build(); CardToken token = tokenClient.create(cardTokenRequest, buildRequestOptions()); assertNotNull(token); assertNotNull(token.getResponse()); assertEquals(CREATED, token.getResponse().getStatusCode()); assertNotNull(token.getId()); assertEquals(customerCard.getId(), token.getCardId()); } finally { customerClient.delete(customer.getId()); } } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } private CustomerCardCreateRequest buildCardCreateRequest() throws MPException, MPApiException { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); return CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); } private CustomerRequest buildCustomerRequest() { String email = generateTestEmail(); return CustomerRequest.builder().email(email).build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/cardtoken/CardTokenClientTest.java ================================================ package com.mercadopago.client.cardtoken; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.ArgumentMatchers.any; import com.mercadopago.BaseClientTest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.helper.MockHelper; import com.mercadopago.net.HttpStatus; import com.mercadopago.resources.CardToken; import java.io.IOException; import java.time.OffsetDateTime; import java.time.ZoneOffset; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.ParseException; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; /** CardTokenClientTest class. */ public class CardTokenClientTest extends BaseClientTest { private final String responseFileCardToken = "/cardtoken/card_token_base.json"; private final String cardId = "1562188766852"; private final CardTokenClient tokenClient = new CardTokenClient(); @Test public void getCardTokenSuccess() throws IOException, MPException, MPApiException, ParseException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileCardToken, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CardToken token = tokenClient.get(cardId); assertNotNull(token); assertCardTokenFields(token); } @Test public void getCardTokenWithRequestOptionsSuccess() throws IOException, MPException, MPApiException, ParseException { MPRequestOptions requestOptions = MPRequestOptions.builder() .accessToken("abc") .connectionTimeout(DEFAULT_TIMEOUT) .connectionRequestTimeout(DEFAULT_TIMEOUT) .socketTimeout(DEFAULT_TIMEOUT) .build(); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileCardToken, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CardToken token = tokenClient.get(cardId, requestOptions); assertNotNull(token); assertCardTokenFields(token); } @Test public void createCardTokenSuccess() throws IOException, MPException, MPApiException, ParseException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileCardToken, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CardToken token = tokenClient.create(buildCardTokenRequest()); assertNotNull(token); assertCardTokenFields(token); } @Test public void createCardTokenWithRequestOptionsSuccess() throws ParseException, IOException, MPException, MPApiException { MPRequestOptions requestOptions = MPRequestOptions.builder() .accessToken("abc") .connectionTimeout(DEFAULT_TIMEOUT) .connectionRequestTimeout(DEFAULT_TIMEOUT) .socketTimeout(DEFAULT_TIMEOUT) .build(); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileCardToken, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CardToken token = tokenClient.create(buildCardTokenRequest(), requestOptions); assertNotNull(token); assertCardTokenFields(token); } private CardTokenRequest buildCardTokenRequest() { return CardTokenRequest.builder() .cardId(cardId) .customerId("649457098-FybpOkG6zH8QRm") .securityCode("456") .build(); } private void assertCardTokenFields(CardToken token) { assertEquals("97849c845e879427b5cb1cb941a52806", token.getId()); assertEquals("989192037129", token.getCardId()); assertEquals("503143", token.getFirstSixDigits()); assertEquals(11, token.getExpirationMonth()); assertEquals(2025, token.getExpirationYear()); assertEquals("6351", token.getLastFourDigits()); assertEquals("57096407006", token.getCardholder().getIdentification().getNumber()); assertEquals("CPF", token.getCardholder().getIdentification().getType()); assertEquals("APRO", token.getCardholder().getName()); assertEquals("active", token.getStatus()); assertTrue(token.getLuhnValidation()); assertFalse(token.getRequireEsc()); assertTrue(token.getLiveMode()); assertEquals(16, token.getCardNumberLength()); assertEquals(3, token.getSecurityCodeLength()); assertEquals( OffsetDateTime.of(2022, 1, 24, 8, 3, 55, 227000000, ZoneOffset.ofHours(-4)), token.getDateCreated()); assertEquals( OffsetDateTime.of(2022, 1, 24, 8, 3, 55, 227000000, ZoneOffset.ofHours(-4)), token.getDateLastUpdated()); assertEquals( OffsetDateTime.of(2022, 2, 1, 8, 3, 55, 227000000, ZoneOffset.ofHours(-4)), token.getDateDue()); assertNotNull(token.getResponse().getContent()); assertEquals(HttpStatus.OK, token.getResponse().getStatusCode()); assertEquals(1, token.getResponse().getHeaders().size()); } } ================================================ FILE: src/test/java/com/mercadopago/client/cardtoken/CardTokenTestClient.java ================================================ package com.mercadopago.client.cardtoken; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.client.MercadoPagoClient; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.HttpMethod; import com.mercadopago.net.MPHttpClient; import com.mercadopago.net.MPResponse; import com.mercadopago.resources.CardToken; import com.mercadopago.serialization.Serializer; import java.util.AbstractMap; import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; /** CardTokenTestClient class. */ public class CardTokenTestClient extends MercadoPagoClient { private final Map status = Stream.of( new AbstractMap.SimpleImmutableEntry<>("approved", "APRO"), new AbstractMap.SimpleImmutableEntry<>("pending", "CONT"), new AbstractMap.SimpleImmutableEntry<>("rejected", "OTHE")) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); /** Default constructor. Uses http client provided by MercadoPagoConfig. */ public CardTokenTestClient() { this(MercadoPagoConfig.getHttpClient()); } /** * MercadoPagoClient constructor. * * @param httpClient http client */ public CardTokenTestClient(MPHttpClient httpClient) { super(httpClient); } /** * Method for creating test card token. * * @return Card token * @throws MPException an error if the request fails * @throws MPApiException an error if api call fails */ public CardToken createTestCardToken(String paymentStatus) throws MPException, MPApiException { CardTokenTestCreateRequest request = CardTokenTestCreateRequest.builder() .cardNumber("5031433215406351") .expirationYear(2099) .expirationMonth(12) .securityCode("123") .cardholder( CardTokenCardholderTestCreateRequest.builder() .identification( IdentificationRequest.builder().type("CPF").number("19119119100").build()) .name(status.get(paymentStatus)) .build()) .build(); MPResponse response = send("/v1/card_tokens", HttpMethod.POST, Serializer.serializeToJson(request), null, null); CardToken cardToken = Serializer.deserializeFromJson(CardToken.class, response.getContent()); cardToken.setResponse(response); return cardToken; } } ================================================ FILE: src/test/java/com/mercadopago/client/cardtoken/CardTokenTestCreateRequest.java ================================================ package com.mercadopago.client.cardtoken; import lombok.Builder; /** CardTokenTestCreateRequest class. */ @Builder public class CardTokenTestCreateRequest { /** Card number. */ public String cardNumber; /** Security code. */ public String securityCode; /** Expiration month. */ public int expirationMonth; /** Expiration year. */ public int expirationYear; /** Card holder. */ public CardTokenCardholderTestCreateRequest cardholder; } ================================================ FILE: src/test/java/com/mercadopago/client/customer/CustomerCardClientTest.java ================================================ package com.mercadopago.client.customer; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.helper.MockHelper; import com.mercadopago.net.HttpStatus; import com.mercadopago.net.MPResourceList; import com.mercadopago.resources.customer.CustomerCard; import com.mercadopago.resources.customer.CustomerCardIssuer; import java.io.IOException; import java.time.OffsetDateTime; import java.time.ZoneOffset; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; /** CustomerCardClientTest class. */ public class CustomerCardClientTest extends BaseClientTest { private final String cardId = "1562188766852"; private final String customerId = "649457098-FybpOkG6zH8QRm"; private final String responseFileSingleCard = "/card/card_single.json"; private final String responseFileAllCards = "/card/card_all.json"; private final CustomerCardClient cardClient = new CustomerCardClient(); @Test public void getCardSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileSingleCard, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = cardClient.get(customerId, cardId); assertNotNull(card); assertCustomerCardFields(card); } @Test public void getCardWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileSingleCard, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = cardClient.get(customerId, cardId, buildRequestOptions()); assertNotNull(card); assertCustomerCardFields(card); } @Test public void createCardSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileSingleCard, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = cardClient.create(customerId, buildCustomerCardCreateRequest()); assertNotNull(card); assertCustomerCardFields(card); } @Test public void createCardWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileSingleCard, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = cardClient.create(customerId, buildCustomerCardCreateRequest(), buildRequestOptions()); assertNotNull(card); assertCustomerCardFields(card); } @Test public void deleteCardSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileSingleCard, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = cardClient.delete(customerId, cardId); assertNotNull(card); assertCustomerCardFields(card); } @Test public void deleteCardWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileSingleCard, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = cardClient.delete(customerId, cardId, buildRequestOptions()); assertNotNull(card); assertCustomerCardFields(card); } @Test public void listAllCardsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileAllCards, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList cards = cardClient.listAll(customerId); assertNotNull(cards); assertNotNull(cards.getResponse()); assertEquals(HttpStatus.OK, cards.getResponse().getStatusCode()); assertEquals(1, cards.getResponse().getHeaders().size()); assertEquals(1, cards.getResults().size()); assertCustomerCardFields(cards.getResults().get(0)); } @Test public void listAllCardsWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile(responseFileAllCards, HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList cards = cardClient.listAll(customerId, buildRequestOptions()); assertNotNull(cards); assertNotNull(cards.getResponse()); assertEquals(HttpStatus.OK, cards.getResponse().getStatusCode()); assertEquals(1, cards.getResponse().getHeaders().size()); assertEquals(1, cards.getResults().size()); assertCustomerCardFields(cards.getResults().get(0)); } private CustomerCardCreateRequest buildCustomerCardCreateRequest() { return CustomerCardCreateRequest.builder() .token("abc") .issuer(CustomerCardIssuer.builder().id("123").name("visa").build()) .build(); } private void assertCustomerCardFields(CustomerCard card) { assertEquals("1562188766852", card.getId()); assertEquals(6, card.getExpirationMonth()); assertEquals(2023, card.getExpirationYear()); assertEquals("423564", card.getFirstSixDigits()); assertEquals("5682", card.getLastFourDigits()); assertEquals("visa", card.getPaymentMethod().getId()); assertEquals("visa", card.getPaymentMethod().getName()); assertEquals("credit_card", card.getPaymentMethod().getPaymentTypeId()); assertEquals( "http://img.mlstatic.com/org-img/MP3/API/logos/visa.gif", card.getPaymentMethod().getThumbnail()); assertEquals( "https://www.mercadopago.com/org-img/MP3/API/logos/visa.gif", card.getPaymentMethod().getSecureThumbnail()); assertEquals(3, card.getSecurityCode().getLength()); assertEquals("back", card.getSecurityCode().getCardLocation()); assertEquals("25", card.getIssuer().getId()); assertEquals("Visa", card.getIssuer().getName()); assertEquals("APRO", card.getCardholder().getName()); assertEquals("19119119100", card.getCardholder().getIdentification().getNumber()); assertEquals("CPF", card.getCardholder().getIdentification().getType()); assertEquals( OffsetDateTime.of(2019, 7, 3, 21, 15, 35, 0, ZoneOffset.UTC), card.getDateCreated()); assertEquals( OffsetDateTime.of(2019, 7, 3, 21, 19, 18, 0, ZoneOffset.UTC), card.getDateLastUpdated()); assertEquals("649457098-FybpOkG6zH8QRm", card.getCustomerId()); assertEquals("448870796", card.getUserId()); assertTrue(card.isLiveMode()); } } ================================================ FILE: src/test/java/com/mercadopago/client/customer/CustomerClientIT.java ================================================ package com.mercadopago.client.customer; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.client.cardtoken.CardTokenTestClient; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.CardToken; import com.mercadopago.resources.customer.Customer; import com.mercadopago.resources.customer.CustomerCard; import java.util.HashMap; import java.util.Map; import org.junit.jupiter.api.Test; /** CustomerClientIT class. */ public class CustomerClientIT extends BaseClientIT { private final CustomerClient customerClient = new CustomerClient(); private final CardTokenTestClient cardTokenTestClient = new CardTokenTestClient(); @Test public void getSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); Customer customer = customerClient.get(createdCustomer.getId()); assertNotNull(customer.getResponse()); assertEquals(OK, customer.getResponse().getStatusCode()); assertEquals(createdCustomer.getId(), customer.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); Customer customer = customerClient.get(createdCustomer.getId(), buildRequestOptions()); assertNotNull(customer.getResponse()); assertEquals(OK, customer.getResponse().getStatusCode()); assertEquals(createdCustomer.getId(), customer.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer customer = customerClient.create(request); assertNotNull(customer.getResponse()); assertEquals(CREATED, customer.getResponse().getStatusCode()); assertNotNull(customer.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer customer = customerClient.create(request, buildRequestOptions()); assertNotNull(customer.getResponse()); assertEquals(CREATED, customer.getResponse().getStatusCode()); assertNotNull(customer.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void updateSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CustomerRequest updateRequest = CustomerRequest.builder().firstName("John").lastName("Doe").build(); Customer customer = customerClient.update(createdCustomer.getId(), updateRequest); assertNotNull(customer.getResponse()); assertEquals(OK, customer.getResponse().getStatusCode()); assertNotNull(customer.getId()); assertEquals("John", customer.getFirstName()); assertEquals("Doe", customer.getLastName()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void updateWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CustomerRequest updateRequest = CustomerRequest.builder().firstName("John").lastName("Doe").build(); Customer customer = customerClient.update(createdCustomer.getId(), updateRequest, buildRequestOptions()); assertNotNull(customer.getResponse()); assertEquals(OK, customer.getResponse().getStatusCode()); assertNotNull(customer.getId()); assertEquals("John", customer.getFirstName()); assertEquals("Doe", customer.getLastName()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void deleteSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); Customer customer = customerClient.delete(createdCustomer.getId()); assertNotNull(customer.getResponse()); assertEquals(OK, customer.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void deleteWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); Customer customer = customerClient.delete(createdCustomer.getId(), buildRequestOptions()); assertNotNull(customer.getResponse()); assertEquals(OK, customer.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void searchSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); Map filters = new HashMap<>(); filters.put("email", createdCustomer.getEmail()); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(0).offset(0).filters(filters).build(); MPResultsResourcesPage result = customerClient.search(searchRequest); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getCardSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); CustomerCard createdCard = customerClient.createCard(createdCustomer.getId(), customerCardCreateRequest); CustomerCard card = customerClient.getCard(createdCustomer.getId(), createdCard.getId()); assertNotNull(card.getResponse()); assertEquals(OK, card.getResponse().getStatusCode()); assertEquals(createdCard.getId(), card.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getCardWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); CustomerCard createdCard = customerClient.createCard(createdCustomer.getId(), customerCardCreateRequest); CustomerCard card = customerClient.getCard( createdCustomer.getId(), createdCard.getId(), buildRequestOptions()); assertNotNull(card.getResponse()); assertEquals(OK, card.getResponse().getStatusCode()); assertEquals(createdCard.getId(), card.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createCardSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); CustomerCard card = customerClient.createCard(createdCustomer.getId(), customerCardCreateRequest); assertNotNull(card.getResponse()); assertEquals(CREATED, card.getResponse().getStatusCode()); assertNotNull(card.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createCardWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); CustomerCard card = customerClient.createCard( createdCustomer.getId(), customerCardCreateRequest, buildRequestOptions()); assertNotNull(card.getResponse()); assertEquals(CREATED, card.getResponse().getStatusCode()); assertNotNull(card.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void deleteCardSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); CustomerCard createdCard = customerClient.createCard(createdCustomer.getId(), customerCardCreateRequest); CustomerCard card = customerClient.deleteCard(createdCustomer.getId(), createdCard.getId()); assertNotNull(card.getResponse()); assertEquals(OK, card.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void deleteCardWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); CustomerCard createdCard = customerClient.createCard(createdCustomer.getId(), customerCardCreateRequest); CustomerCard card = customerClient.deleteCard( createdCustomer.getId(), createdCard.getId(), buildRequestOptions()); assertNotNull(card.getResponse()); assertEquals(OK, card.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void listCardsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); customerClient.createCard(createdCustomer.getId(), customerCardCreateRequest); MPResourceList cards = customerClient.listCards(createdCustomer.getId()); assertNotNull(cards.getResponse()); assertEquals(OK, cards.getResponse().getStatusCode()); assertFalse(cards.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void listCardsWithRequestOptionsSuccess() { try { CustomerRequest request = CustomerRequest.builder().email(generateTestEmail()).build(); Customer createdCustomer = customerClient.create(request); CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); CustomerCardCreateRequest customerCardCreateRequest = CustomerCardCreateRequest.builder().token(cardToken.getId()).build(); customerClient.createCard(createdCustomer.getId(), customerCardCreateRequest); MPResourceList cards = customerClient.listCards(createdCustomer.getId(), buildRequestOptions()); assertNotNull(cards.getResponse()); assertEquals(OK, cards.getResponse().getStatusCode()); assertFalse(cards.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } } ================================================ FILE: src/test/java/com/mercadopago/client/customer/CustomerClientTest.java ================================================ package com.mercadopago.client.customer; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.mercadopago.BaseClientTest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.helper.MockHelper; import com.mercadopago.net.HttpStatus; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.customer.Customer; import com.mercadopago.resources.customer.CustomerCard; import com.mercadopago.resources.customer.CustomerCardIssuer; import java.io.IOException; import java.text.ParseException; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; /** CustomerClientTest class. */ public class CustomerClientTest extends BaseClientTest { private final CustomerClient customerClient = new CustomerClient(); private final String customerId = "1068193981-pXRewrKqlP6pnn"; @Test public void getSuccess() throws MPException, MPApiException, ParseException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.get(customerId); assertCustomerFields(customer); } @Test public void getWithRequestOptionsSuccess() throws MPException, MPApiException, ParseException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.get(customerId, buildRequestOptions()); assertCustomerFields(customer); } @Test public void createSuccess() throws MPException, MPApiException, ParseException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.create(buildCustomerRequest()); assertCustomerFields(customer); } @Test public void createWithRequestOptionsSuccess() throws MPException, MPApiException, ParseException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.create(buildCustomerRequest(), buildRequestOptions()); assertCustomerFields(customer); } @Test public void updateSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.update(customerId, buildCustomerRequest()); assertCustomerFields(customer); } @Test public void updateWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.update(customerId, buildCustomerRequest(), buildRequestOptions()); assertCustomerFields(customer); } @Test public void deleteSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.delete(customerId); assertCustomerFields(customer); } @Test public void deleteWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/customer_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Customer customer = customerClient.delete(customerId, buildRequestOptions()); assertCustomerFields(customer); } @Test public void searchSuccess() throws MPException, MPApiException, ParseException, IOException { Map filters = new HashMap<>(); filters.put("email", "test@user.com"); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(0).offset(0).filters(filters).build(); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/search_by_email.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResultsResourcesPage result = customerClient.search(searchRequest); assertNotNull(result); assertEquals(10, result.getPaging().getLimit()); assertEquals(0, result.getPaging().getOffset()); assertEquals(1, result.getPaging().getTotal()); assertEquals(1, result.getResults().size()); } @Test public void searchWithRequestOptionsSuccess() throws MPException, MPApiException, ParseException, IOException { Map filters = new HashMap<>(); filters.put("email", "test@user.com"); HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/customer/search_by_email.json", HttpStatus.OK); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(0).offset(0).filters(filters).build(); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResultsResourcesPage result = customerClient.search(searchRequest, buildRequestOptions()); assertNotNull(result); assertEquals(10, result.getPaging().getLimit()); assertEquals(0, result.getPaging().getOffset()); assertEquals(1, result.getPaging().getTotal()); assertEquals(1, result.getResults().size()); } @Test public void getCardSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_single.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = customerClient.getCard("649457098-FybpOkG6zH8QRm", "1562188766852"); assertNotNull(card); assertEquals("1562188766852", card.getId()); } @Test public void getCardWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_single.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = customerClient.getCard("649457098-FybpOkG6zH8QRm", "1562188766852", buildRequestOptions()); assertNotNull(card); assertEquals("1562188766852", card.getId()); } @Test public void createCardSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_single.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = customerClient.createCard("649457098-FybpOkG6zH8QRm", buildCustomerCardCreateRequest()); assertNotNull(card); assertEquals("1562188766852", card.getId()); } @Test public void createCardWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_single.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = customerClient.createCard( "649457098-FybpOkG6zH8QRm", buildCustomerCardCreateRequest(), buildRequestOptions()); assertNotNull(card); assertEquals("1562188766852", card.getId()); } @Test public void deleteCardSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_single.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = customerClient.deleteCard("649457098-FybpOkG6zH8QRm", "1562188766852"); assertNotNull(card); assertEquals("1562188766852", card.getId()); } @Test public void deleteCardWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_single.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CustomerCard card = customerClient.deleteCard( "649457098-FybpOkG6zH8QRm", "1562188766852", buildRequestOptions()); assertNotNull(card); assertEquals("1562188766852", card.getId()); } @Test public void listCardsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_all.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList cards = customerClient.listCards("649457098-FybpOkG6zH8QRm"); assertNotNull(cards); assertNotNull(cards.getResponse()); assertEquals(HttpStatus.OK, cards.getResponse().getStatusCode()); assertEquals("1562188766852", cards.getResults().get(0).getId()); } @Test public void listCardsWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/card/card_all.json", HttpStatus.OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList cards = customerClient.listCards("649457098-FybpOkG6zH8QRm", buildRequestOptions()); assertNotNull(cards); assertNotNull(cards.getResponse()); assertEquals(HttpStatus.OK, cards.getResponse().getStatusCode()); assertEquals("1562188766852", cards.getResults().get(0).getId()); } private CustomerRequest buildCustomerRequest() { return CustomerRequest.builder() .address( CustomerAddressRequest.builder() .streetName("abc") .streetNumber(123) .zipCode("xyz") .build()) .defaultAddress("Default address") .firstName("John") .lastName("Doe") .phone(PhoneRequest.builder().areaCode("55").number("555555555").build()) .email("test@user.com") .identification(IdentificationRequest.builder().type("CPF").number("1234").build()) .build(); } private CustomerCardCreateRequest buildCustomerCardCreateRequest() { return CustomerCardCreateRequest.builder() .token("abc") .issuer(CustomerCardIssuer.builder().id("123").name("visa").build()) .build(); } private void assertCustomerFields(Customer customer) { assertNotNull(customer); assertEquals("1068193981-pXRewrKqlP6pnn", customer.getId()); assertEquals("test_payer_1629112604@testuser.com", customer.getEmail()); assertEquals("Jhon", customer.getFirstName()); assertEquals("Doe", customer.getLastName()); assertEquals("55", customer.getPhone().getAreaCode()); assertEquals("991234567", customer.getPhone().getNumber()); assertEquals("CPF", customer.getIdentification().getType()); assertEquals("12345678900", customer.getIdentification().getNumber()); assertEquals("1215179651", customer.getAddress().getId()); assertEquals("01313000", customer.getAddress().getZipCode()); assertEquals("Rua Exemplo", customer.getAddress().getStreetName()); assertEquals(123, customer.getAddress().getStreetNumber()); assertEquals("Description del user", customer.getDescription()); assertEquals(OffsetDateTime.of(1, 1, 1, 0, 0, 0, 0, ZoneOffset.UTC), customer.getDateCreated()); assertEquals("source_k", customer.getMetadata().get("source_sync")); assertEquals("1215179651", customer.getDefaultAddress()); assertEquals("APRO", customer.getCards().get(0).getCardholder().getName()); assertEquals("CPF", customer.getCards().get(0).getCardholder().getIdentification().getType()); assertEquals("1068193981-pXRewrKqlP6pnn", customer.getCards().get(0).getCustomerId()); assertEquals( OffsetDateTime.of(2022, 2, 3, 15, 30, 27, 449000000, ZoneOffset.ofHours(-4)), customer.getCards().get(0).getDateCreated()); assertEquals( OffsetDateTime.of(2022, 2, 3, 15, 30, 27, 449000000, ZoneOffset.ofHours(-4)), customer.getCards().get(0).getDateLastUpdated()); assertEquals(12, customer.getCards().get(0).getExpirationMonth()); assertEquals(2022, customer.getCards().get(0).getExpirationYear()); assertEquals("503143", customer.getCards().get(0).getFirstSixDigits()); assertEquals("1643916656196", customer.getCards().get(0).getId()); assertEquals("24", customer.getCards().get(0).getIssuer().getId()); assertEquals("Mastercard", customer.getCards().get(0).getIssuer().getName()); assertEquals("6351", customer.getCards().get(0).getLastFourDigits()); assertEquals("master", customer.getCards().get(0).getPaymentMethod().getId()); assertEquals("master", customer.getCards().get(0).getPaymentMethod().getName()); assertEquals("credit_card", customer.getCards().get(0).getPaymentMethod().getPaymentTypeId()); assertEquals( "http://img.mlstatic.com/org-img/MP3/API/logos/master.gif", customer.getCards().get(0).getPaymentMethod().getThumbnail()); assertEquals( "https://www.mercadopago.com/org-img/MP3/API/logos/master.gif", customer.getCards().get(0).getPaymentMethod().getSecureThumbnail()); assertEquals(3, customer.getCards().get(0).getSecurityCode().getLength()); assertEquals("back", customer.getCards().get(0).getSecurityCode().getCardLocation()); assertEquals("1068193981", customer.getCards().get(0).getUserId()); assertEquals("BR-SP-44", customer.getAddresses().get(0).getCity().getId()); assertEquals("São Paulo", customer.getAddresses().get(0).getCity().getName()); assertEquals("BR", customer.getAddresses().get(0).getCountry().getId()); assertEquals("Brasil", customer.getAddresses().get(0).getCountry().getName()); assertEquals( OffsetDateTime.of(2022, 2, 3, 15, 30, 27, 449000000, ZoneOffset.ofHours(-4)), customer.getAddresses().get(0).getDateCreated()); assertEquals("1215179651", customer.getAddresses().get(0).getId()); assertEquals("Bela Vista", customer.getAddresses().get(0).getNeighborhood().getName()); assertEquals("0000000000", customer.getAddresses().get(0).getPhone()); assertEquals("BR-SP", customer.getAddresses().get(0).getState().getId()); assertEquals("São Paulo", customer.getAddresses().get(0).getState().getName()); assertEquals("Rua Exemplo", customer.getAddresses().get(0).getStreetName()); assertEquals("123", customer.getAddresses().get(0).getStreetNumber()); assertEquals("01313000", customer.getAddresses().get(0).getZipCode()); assertFalse(customer.getLiveMode()); } } ================================================ FILE: src/test/java/com/mercadopago/client/identificationtype/IdentificationTypeClientIT.java ================================================ package com.mercadopago.client.identificationtype; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.resources.identificationtype.IdentificationType; import org.junit.jupiter.api.Test; /** IdentificationTypeClientIT class. */ class IdentificationTypeClientIT extends BaseClientIT { private final IdentificationTypeClient client = new IdentificationTypeClient(); @Test void listSuccess() { try { MPResourceList identificationTypes = client.list(); assertNotNull(identificationTypes.getResponse()); assertEquals(OK, identificationTypes.getResponse().getStatusCode()); assertFalse(identificationTypes.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void testListWithRequestOptionsSuccess() { try { MPResourceList identificationTypes = client.list(buildRequestOptions()); assertNotNull(identificationTypes.getResponse()); assertEquals(OK, identificationTypes.getResponse().getStatusCode()); assertFalse(identificationTypes.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } } ================================================ FILE: src/test/java/com/mercadopago/client/identificationtype/IdentificationTypeClientTest.java ================================================ package com.mercadopago.client.identificationtype; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.resources.identificationtype.IdentificationType; import java.io.IOException; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; class IdentificationTypeClientTest extends BaseClientTest { private final String identificationTypesJson = "identification/types.json"; private final IdentificationTypeClient client = new IdentificationTypeClient(); @Test void listSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(identificationTypesJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList identificationTypes = client.list(); assertNotNull(identificationTypes.getResponse()); assertEquals(OK, identificationTypes.getResponse().getStatusCode()); assertIdentificationTypes(identificationTypes); } @Test void testListWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(identificationTypesJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList identificationTypes = client.list(buildRequestOptions()); assertNotNull(identificationTypes.getResponse()); assertEquals(OK, identificationTypes.getResponse().getStatusCode()); assertIdentificationTypes(identificationTypes); } private void assertIdentificationTypes(MPResourceList identificationTypes) { assertNull(identificationTypes.getResults().get(0).getResponse()); assertEquals("CPF", identificationTypes.getResults().get(0).getId()); assertEquals("CPF", identificationTypes.getResults().get(0).getName()); assertEquals("number", identificationTypes.getResults().get(0).getType()); assertEquals(11, identificationTypes.getResults().get(0).getMinLength()); assertEquals(11, identificationTypes.getResults().get(0).getMaxLength()); assertNull(identificationTypes.getResults().get(1).getResponse()); assertEquals("CNPJ", identificationTypes.getResults().get(1).getId()); assertEquals("CNPJ", identificationTypes.getResults().get(1).getName()); assertEquals("number", identificationTypes.getResults().get(1).getType()); assertEquals(14, identificationTypes.getResults().get(1).getMinLength()); assertEquals(14, identificationTypes.getResults().get(1).getMaxLength()); } } ================================================ FILE: src/test/java/com/mercadopago/client/merchantorder/MerchantOrderClientIT.java ================================================ package com.mercadopago.client.merchantorder; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.client.preference.PreferenceBackUrlsRequest; import com.mercadopago.client.preference.PreferenceClient; import com.mercadopago.client.preference.PreferenceItemRequest; import com.mercadopago.client.preference.PreferencePayerRequest; import com.mercadopago.client.preference.PreferencePaymentMethodRequest; import com.mercadopago.client.preference.PreferencePaymentMethodsRequest; import com.mercadopago.client.preference.PreferencePaymentTypeRequest; import com.mercadopago.client.preference.PreferenceReceiverAddressRequest; import com.mercadopago.client.preference.PreferenceRequest; import com.mercadopago.client.preference.PreferenceShipmentsRequest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.merchantorder.MerchantOrder; import com.mercadopago.resources.preference.Preference; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.jupiter.api.Test; class MerchantOrderClientIT extends BaseClientIT { private final PreferenceClient preferenceClient = new PreferenceClient(); private final MerchantOrderClient merchantOrderClient = new MerchantOrderClient(); @Test void createSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); MerchantOrder merchantOrder = merchantOrderClient.create(request); assertNotNull(merchantOrder.getResponse()); assertEquals(CREATED, merchantOrder.getResponse().getStatusCode()); assertNotNull(merchantOrder.getId()); assertNotNull(merchantOrder.getPreferenceId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void createWithRequestOptionsSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); MerchantOrder merchantOrder = merchantOrderClient.create(request, buildRequestOptions()); assertNotNull(merchantOrder.getResponse()); assertEquals(CREATED, merchantOrder.getResponse().getStatusCode()); assertNotNull(merchantOrder.getId()); assertNotNull(merchantOrder.getPreferenceId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); MerchantOrder createdMerchantOrder = merchantOrderClient.create(request); MerchantOrder merchantOrder = merchantOrderClient.get(createdMerchantOrder.getId()); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertEquals(createdMerchantOrder.getId(), merchantOrder.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getWithRequestOptionsSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); MerchantOrder createdMerchantOrder = merchantOrderClient.create(request); MerchantOrder merchantOrder = merchantOrderClient.get(createdMerchantOrder.getId(), buildRequestOptions()); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertEquals(createdMerchantOrder.getId(), merchantOrder.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void updateSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); MerchantOrder createdMerchantOrder = merchantOrderClient.create(request); MerchantOrderPayerRequest payerRequest = MerchantOrderPayerRequest.builder().id(0L).nickname("Test").build(); MerchantOrderUpdateRequest updateRequest = MerchantOrderUpdateRequest.builder().payer(payerRequest).build(); MerchantOrder merchantOrder = merchantOrderClient.update(createdMerchantOrder.getId(), updateRequest); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertEquals(createdMerchantOrder.getId(), merchantOrder.getId()); assertEquals("Test", merchantOrder.getPayer().getNickname()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void updateWithRequestOptionsSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); MerchantOrder createdMerchantOrder = merchantOrderClient.create(request); MerchantOrderPayerRequest payerRequest = MerchantOrderPayerRequest.builder().id(0L).nickname("Test").build(); MerchantOrderUpdateRequest updateRequest = MerchantOrderUpdateRequest.builder().payer(payerRequest).build(); MerchantOrder merchantOrder = merchantOrderClient.update( createdMerchantOrder.getId(), updateRequest, buildRequestOptions()); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertEquals(createdMerchantOrder.getId(), merchantOrder.getId()); assertEquals("Test", merchantOrder.getPayer().getNickname()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); merchantOrderClient.create(request); Map filters = new HashMap<>(); filters.put("preference_id", createdPreference.getId()); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(0).offset(0).filters(filters).build(); MPElementsResourcesPage results = merchantOrderClient.search(searchRequest); assertNotNull(results.getResponse()); assertEquals(OK, results.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchWithRequestOptionsSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = preferenceClient.create(preferenceRequest); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(createdPreference.getId()).build(); merchantOrderClient.create(request); Map filters = new HashMap<>(); filters.put("preference_id", createdPreference.getId()); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(0).offset(0).filters(filters).build(); MPElementsResourcesPage results = merchantOrderClient.search(searchRequest, buildRequestOptions()); assertEquals(OK, results.getResponse().getStatusCode()); assertNotNull(results.getResponse()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } private PreferenceRequest buildPreferenceRequest() { PreferenceItemRequest itemRequest = PreferenceItemRequest.builder() .id("1234") .title("Games") .description("PS5") .pictureUrl("http://picture.com/PS5") .categoryId("games") .quantity(2) .currencyId("BRL") .unitPrice(new BigDecimal("4000")) .build(); List items = new ArrayList<>(); items.add(itemRequest); List excludedPaymentTypes = new ArrayList<>(); excludedPaymentTypes.add(PreferencePaymentTypeRequest.builder().id("ticket").build()); List excludedPaymentMethods = new ArrayList<>(); excludedPaymentMethods.add(PreferencePaymentMethodRequest.builder().id("").build()); return PreferenceRequest.builder() .additionalInfo("Discount: 12.00") .autoReturn("all") .backUrls( PreferenceBackUrlsRequest.builder() .success("https://test.com/success") .failure("https://test.com/failure") .pending("https://test.com/pending") .build()) .binaryMode(true) .expires(false) .externalReference("1643827245") .items(items) .marketplace("marketplace") .marketplaceFee(new BigDecimal("5")) .notificationUrl("http://notificationurl.com") .operationType("regular_payment") .payer( PreferencePayerRequest.builder() .name("Test") .surname("User") .email(generateTestEmail()) .phone(PhoneRequest.builder().areaCode("11").number("4444-4444").build()) .identification( IdentificationRequest.builder().type("CPF").number("19119119100").build()) .address( AddressRequest.builder() .zipCode("06233200") .streetName("Street") .streetNumber("123") .build()) .build()) .paymentMethods( PreferencePaymentMethodsRequest.builder() .defaultPaymentMethodId("master") .excludedPaymentTypes(excludedPaymentTypes) .excludedPaymentMethods(excludedPaymentMethods) .installments(5) .defaultInstallments(1) .build()) .shipments( PreferenceShipmentsRequest.builder() .mode("custom") .localPickup(false) .dimensions("10x10x20,500") .cost(BigDecimal.TEN) .receiverAddress( PreferenceReceiverAddressRequest.builder() .zipCode("06000000") .streetNumber("123") .streetName("Street") .floor("12") .apartment("120A") .build()) .build()) .statementDescriptor("Test Store") .build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/merchantorder/MerchantOrderClientTest.java ================================================ package com.mercadopago.client.merchantorder; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.helper.MockHelper.generateJsonElement; import static com.mercadopago.helper.MockHelper.generateJsonElementFromUriRequest; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.google.gson.JsonElement; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.merchantorder.MerchantOrder; import java.io.IOException; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; class MerchantOrderClientTest extends BaseClientTest { private final String orderBaseJson = "merchant/order_base.json"; private final String orderUpdatedJson = "merchant/order_updated.json"; private final String orderSearchJson = "merchant/order_search.json"; private final String preferenceId = "798798399-13769cb5-b898-448f-8d5a-c939a8cee479"; private final long merchantOrderId = 4018801790L; private final OffsetDateTime date = OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final MerchantOrderClient client = new MerchantOrderClient(); @Test void createSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(preferenceId).build(); MerchantOrder merchantOrder = client.create(request); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(orderBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(merchantOrder.getResponse()); assertEquals(CREATED, merchantOrder.getResponse().getStatusCode()); assertMerchantOrderFields(merchantOrder); } @Test void createWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MerchantOrderCreateRequest request = MerchantOrderCreateRequest.builder().preferenceId(preferenceId).build(); MerchantOrder merchantOrder = client.create(request, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(orderBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(merchantOrder.getResponse()); assertEquals(CREATED, merchantOrder.getResponse().getStatusCode()); assertMerchantOrderFields(merchantOrder); } @Test void getSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MerchantOrder merchantOrder = client.get(merchantOrderId); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertMerchantOrderFields(merchantOrder); } @Test void getWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MerchantOrder merchantOrder = client.get(merchantOrderId, buildRequestOptions()); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertMerchantOrderFields(merchantOrder); } @Test void updateSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderUpdatedJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MerchantOrderPayerRequest payerRequest = MerchantOrderPayerRequest.builder().id(0L).nickname("Test").build(); MerchantOrderUpdateRequest updateRequest = MerchantOrderUpdateRequest.builder().payer(payerRequest).build(); MerchantOrder merchantOrder = client.update(merchantOrderId, updateRequest); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(orderUpdatedJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertEquals("Test", merchantOrder.getPayer().getNickname()); } @Test void updateWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderUpdatedJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MerchantOrderPayerRequest payerRequest = MerchantOrderPayerRequest.builder().id(0L).nickname("Test").build(); MerchantOrderUpdateRequest updateRequest = MerchantOrderUpdateRequest.builder().payer(payerRequest).build(); MerchantOrder merchantOrder = client.update(merchantOrderId, updateRequest, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(orderUpdatedJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(merchantOrder.getResponse()); assertEquals(OK, merchantOrder.getResponse().getStatusCode()); assertEquals("Test", merchantOrder.getPayer().getNickname()); } @Test void searchSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderSearchJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Map filters = new HashMap<>(); filters.put("preference_id", preferenceId); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(0).offset(0).filters(filters).build(); MPElementsResourcesPage results = client.search(searchRequest); assertEquals(OK, results.getResponse().getStatusCode()); assertNotNull(results.getResponse()); assertEquals(2, results.getTotal()); assertEquals(2, results.getElements().size()); assertEquals(2, results.getNextOffset()); assertMerchantOrderFields(results.getElements().get(0)); } @Test void searchWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(orderSearchJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Map filters = new HashMap<>(); filters.put("preference_id", preferenceId); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(0).offset(0).filters(filters).build(); MPElementsResourcesPage results = client.search(searchRequest, buildRequestOptions()); assertEquals(OK, results.getResponse().getStatusCode()); assertNotNull(results.getResponse()); assertEquals(2, results.getTotal()); assertEquals(2, results.getElements().size()); assertEquals(2, results.getNextOffset()); assertMerchantOrderFields(results.getElements().get(0)); } private void assertMerchantOrderFields(MerchantOrder merchantOrder) { assertEquals(merchantOrderId, merchantOrder.getId()); assertEquals("opened", merchantOrder.getStatus()); assertNull(merchantOrder.getExternalReference()); assertEquals(preferenceId, merchantOrder.getPreferenceId()); assertTrue(merchantOrder.getPayments().isEmpty()); assertTrue(merchantOrder.getShipments().isEmpty()); assertTrue(merchantOrder.getPayments().isEmpty()); assertEquals(798798399L, merchantOrder.getCollector().getId()); assertEquals("TETE8419469", merchantOrder.getCollector().getNickname()); assertTrue(merchantOrder.getMarketplace().isEmpty()); assertNull(merchantOrder.getNotificationUrl()); assertEquals(date, merchantOrder.getDateCreated()); assertEquals(date, merchantOrder.getLastUpdated()); assertNull(merchantOrder.getSponsorId()); assertEquals(BigDecimal.ZERO, merchantOrder.getShippingCost()); assertEquals(new BigDecimal("206.02"), merchantOrder.getTotalAmount()); assertEquals("MLM", merchantOrder.getSiteId()); assertEquals(BigDecimal.ZERO, merchantOrder.getPaidAmount()); assertEquals(BigDecimal.ZERO, merchantOrder.getRefundedAmount()); assertNull(merchantOrder.getPayer()); assertTrue(merchantOrder.getItems().isEmpty()); assertFalse(merchantOrder.isCancelled()); assertNull(merchantOrder.getAdditionalInfo()); assertNull(merchantOrder.getApplicationId()); assertEquals("payment_required", merchantOrder.getOrderStatus()); } } ================================================ FILE: src/test/java/com/mercadopago/client/oauth/OauthClientTest.java ================================================ package com.mercadopago.client.oauth; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.argThat; import com.mercadopago.BaseClientTest; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.helper.MockHelper; import com.mercadopago.mock.HttpRequestMatcher; import com.mercadopago.net.HttpStatus; import com.mercadopago.resources.oauth.CreateOauthCredential; import com.mercadopago.resources.oauth.RefreshOauthCredential; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; /** OauthClientTest class. */ public class OauthClientTest extends BaseClientTest { private static HttpResponse oauthHttpResponse; private final String appId = "123"; private final String redirectUri = "https://redirect-uri.com"; private final String authorizationCode = "authCode"; private final String refreshToken = "refreshToken"; private HttpResponse userHttpResponse; @Test public void getAuthorizationURLSuccess() throws IOException, MPException, MPApiException, URISyntaxException { userHttpResponse = MockHelper.generateHttpResponseFromFile("/user/user_base.json", HttpStatus.OK); doReturn(userHttpResponse) .when(HTTP_CLIENT) .execute( argThat( new HttpRequestMatcher( new HttpGet(String.format("%s/users/me", MercadoPagoConfig.BASE_URL)))), any(HttpContext.class)); doReturn(oauthHttpResponse) .when(HTTP_CLIENT) .execute( argThat( new HttpRequestMatcher(new HttpGet("https://auth.mercadopago.com/oauth/token"))), any(HttpContext.class)); String authorizationURL = new OauthClient().getAuthorizationURL(appId, redirectUri); assertAuthorizationUrlComponents(authorizationURL); } @Test public void getAuthorizationURLWithRequestOptionsSuccess() throws MPException, MPApiException, IOException, URISyntaxException { userHttpResponse = MockHelper.generateHttpResponseFromFile("/user/user_base.json", HttpStatus.OK); doReturn(userHttpResponse) .when(HTTP_CLIENT) .execute( argThat( new HttpRequestMatcher( new HttpGet(String.format("%s/users/me", MercadoPagoConfig.BASE_URL)))), any(HttpContext.class)); doReturn(oauthHttpResponse) .when(HTTP_CLIENT) .execute( argThat( new HttpRequestMatcher(new HttpGet("https://auth.mercadopago.com/oauth/token"))), any(HttpContext.class)); String authorizationURL = new OauthClient().getAuthorizationURL(appId, redirectUri, buildRequestOptions()); assertAuthorizationUrlComponents(authorizationURL); } @Test public void createCredentialSuccess() throws IOException, MPException, MPApiException { oauthHttpResponse = MockHelper.generateHttpResponseFromFile("/oauth/oauth_credential.json", HttpStatus.OK); oauthHttpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(oauthHttpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CreateOauthCredential credential = new OauthClient().createCredential(authorizationCode, redirectUri); assertCreateOauthCredentialFields(credential); } @Test public void createCredentialWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { oauthHttpResponse = MockHelper.generateHttpResponseFromFile("/oauth/oauth_credential.json", HttpStatus.OK); oauthHttpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); MPRequestOptions requestOptions = MPRequestOptions.builder() .accessToken("abc") .connectionTimeout(MercadoPagoConfig.getConnectionTimeout()) .connectionRequestTimeout(MercadoPagoConfig.getConnectionRequestTimeout()) .socketTimeout(MercadoPagoConfig.getSocketTimeout()) .build(); doReturn(oauthHttpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); CreateOauthCredential credential = new OauthClient().createCredential(authorizationCode, redirectUri, requestOptions); assertCreateOauthCredentialFields(credential); } @Test public void refreshCredentialSuccess() throws IOException, MPException, MPApiException { oauthHttpResponse = MockHelper.generateHttpResponseFromFile("/oauth/oauth_refresh_token.json", HttpStatus.OK); oauthHttpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(oauthHttpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); RefreshOauthCredential credential = new OauthClient().refreshCredential(refreshToken); assertRefreshOauthCredentialFields(credential); } @Test public void refreshCredentialWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { oauthHttpResponse = MockHelper.generateHttpResponseFromFile("/oauth/oauth_refresh_token.json", HttpStatus.OK); oauthHttpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); MPRequestOptions requestOptions = MPRequestOptions.builder() .accessToken("abc") .connectionTimeout(MercadoPagoConfig.getConnectionTimeout()) .connectionRequestTimeout(MercadoPagoConfig.getConnectionRequestTimeout()) .socketTimeout(MercadoPagoConfig.getSocketTimeout()) .build(); doReturn(oauthHttpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); RefreshOauthCredential credential = new OauthClient().refreshCredential(refreshToken, requestOptions); assertRefreshOauthCredentialFields(credential); } private void assertAuthorizationUrlComponents(String authorizationURL) throws URISyntaxException { URI responseURL = new URI(authorizationURL); assertEquals("https", responseURL.getScheme()); assertEquals("auth.mercadopago.com.br", responseURL.getHost()); assertEquals("/authorization", responseURL.getPath()); assertTrue(responseURL.getQuery().contains("client_id=123")); assertTrue(responseURL.getQuery().contains("response_type=code")); assertTrue(responseURL.getQuery().contains("platform_id=mp")); assertTrue(responseURL.getQuery().contains(String.format("redirect_uri=%s", redirectUri))); } private void assertCreateOauthCredentialFields(CreateOauthCredential credential) { assertEquals("APP_USR-4934588586838432-XXXXXXXX-241983636", credential.getAccessToken()); assertEquals("bearer", credential.getTokenType()); assertEquals("offline_access read write", credential.getScope()); assertEquals(15552000, credential.getExpiresIn()); assertEquals("TG-XXXXXXXX-241983636", credential.getRefreshToken()); assertEquals("APP_USR-d0a26210-XXXXXXXX-479f0400869e", credential.getPublicKey()); assertTrue(credential.isLiveMode()); } private void assertRefreshOauthCredentialFields(RefreshOauthCredential credential) { assertEquals("APP_USR-4934588586838432-XXXXXXXX-241983636", credential.getAccessToken()); assertEquals("bearer", credential.getTokenType()); assertEquals("offline_access read write", credential.getScope()); assertEquals(15552000, credential.getExpiresIn()); assertEquals("TG-XXXXXXXXXXXX-241983636", credential.getRefreshToken()); } } ================================================ FILE: src/test/java/com/mercadopago/client/order/OrderClientIT.java ================================================ package com.mercadopago.client.order; import com.mercadopago.BaseClientIT; import com.mercadopago.client.cardtoken.CardTokenTestClient; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.CardToken; import com.mercadopago.resources.order.Order; import com.mercadopago.resources.order.OrderTransaction; import com.mercadopago.resources.order.UpdateOrderTransaction; import org.junit.jupiter.api.Test; import java.util.*; import static com.mercadopago.net.HttpStatus.*; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; /** OrderClientIT class. */ public class OrderClientIT extends BaseClientIT { private final OrderClient client = new OrderClient(); private final CardTokenTestClient cardTokenTestClient = new CardTokenTestClient(); @Test public void createOrderSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("automatic") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); Order order = client.create(orderCreateRequest); assertNotNull(order.getResponse()); assertEquals(CREATED, order.getResponse().getStatusCode()); assertNotNull(order.getId()); assertEquals("100.00", order.getTotalAmount()); assertEquals("master", order.getTransactions().getPayments().get(0).getPaymentMethod().getId()); assertEquals("credit_card", order.getTransactions().getPayments().get(0).getPaymentMethod().getType()); assertEquals(1, order.getTransactions().getPayments().get(0).getPaymentMethod() .getInstallments()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getOrderSuccess() { try { List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("pix") .type("bank_transfer") .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("automatic") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); Order order = client.create(orderCreateRequest); Order foundOrder = client.get(order.getId()); assertNotNull(foundOrder.getResponse()); assertEquals(OK, foundOrder.getResponse().getStatusCode()); assertEquals(order.getId(), foundOrder.getId()); assertEquals("100.00", foundOrder.getTotalAmount()); assertEquals("pix", foundOrder.getTransactions().getPayments().get(0).getPaymentMethod().getId()); assertEquals("bank_transfer", foundOrder.getTransactions().getPayments().get(0).getPaymentMethod().getType()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void processOrderSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("manual") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); Order order = client.create(orderCreateRequest); Order processedOrder = client.process(order.getId()); assertNotNull(processedOrder.getResponse()); assertEquals(OK, processedOrder.getResponse().getStatusCode()); assertNotNull(order.getId()); assertEquals("100.00", processedOrder.getTotalAmount()); assertEquals("processed", processedOrder.getStatus()); assertEquals("processed", processedOrder.getTransactions().getPayments().get(0).getStatus()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void captureOrderSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("automatic") .captureMode("automatic_async") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); Order order = client.create(orderCreateRequest); Order capturedOrder = client.capture(order.getId()); assertNotNull(capturedOrder.getResponse()); assertEquals(OK, capturedOrder.getResponse().getStatusCode()); assertEquals(order.getId(), capturedOrder.getId()); assertEquals("processed", capturedOrder.getStatus()); assertEquals("100.00", capturedOrder.getTransactions().getPayments().get(0).getAmount()); assertEquals("processed", capturedOrder.getTransactions().getPayments().get(0).getStatus()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void cancelOrderSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("manual") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); Order order = client.create(orderCreateRequest); Order cancelledOrder = client.cancel(order.getId()); assertNotNull(cancelledOrder.getResponse()); assertEquals(OK, cancelledOrder.getResponse().getStatusCode()); assertEquals(order.getId(), cancelledOrder.getId()); assertEquals("canceled", cancelledOrder.getStatus()); assertEquals("canceled", cancelledOrder.getTransactions().getPayments().get(0).getStatus()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void totalRefundOrderSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("automatic") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); Order order = client.create(orderCreateRequest); Thread.sleep(3000); Order refundedOrder = client.refund(order.getId()); assertNotNull(refundedOrder.getResponse()); assertEquals(CREATED, refundedOrder.getResponse().getStatusCode()); assertEquals(order.getId(), refundedOrder.getId()); assertEquals("refunded", refundedOrder.getStatus()); assertEquals("refunded", refundedOrder.getStatusDetail()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException | InterruptedException e) { fail(e.getMessage()); } } @Test public void partialRefundOrderSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("automatic") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); Order order = client.create(orderCreateRequest); Thread.sleep(3000); List refundPaymentRequest = new ArrayList<>(); refundPaymentRequest.add(OrderRefundPaymentRequest.builder() .id(order.getTransactions().getPayments().get(0).getId()) .amount("25.00") .build()); OrderRefundRequest orderRefundRequest = OrderRefundRequest.builder() .transactions(refundPaymentRequest) .build(); Order refundedOrder = client.refund(order.getId(), orderRefundRequest); assertNotNull(refundedOrder.getResponse()); assertEquals(CREATED, refundedOrder.getResponse().getStatusCode()); assertEquals(order.getId(), refundedOrder.getId()); assertEquals("processed", refundedOrder.getStatus()); assertEquals("partially_refunded", refundedOrder.getStatusDetail()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException | InterruptedException e) { fail(e.getMessage()); } } @Test public void createOrderTransactionSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("manual") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .build(); List orderPaymentRequestList = new ArrayList<>(); OrderPaymentRequest orderPaymentRequest = OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build(); orderPaymentRequestList.add(orderPaymentRequest); OrderTransactionRequest orderTransactionRequest = OrderTransactionRequest.builder() .payments(orderPaymentRequestList) .build(); Order order = client.create(orderCreateRequest); OrderTransaction orderTransaction = client.createTransaction(order.getId(), orderTransactionRequest); assertNotNull(orderTransaction.getResponse()); assertEquals(CREATED, orderTransaction.getResponse().getStatusCode()); assertNotNull(orderTransaction.getPayments().get(0).getId()); assertEquals("100.00", orderTransaction.getPayments().get(0).getAmount()); assertEquals("master", orderTransaction.getPayments().get(0).getPaymentMethod().getId()); assertEquals("credit_card", orderTransaction.getPayments().get(0).getPaymentMethod().getType()); assertEquals(1, orderTransaction.getPayments().get(0).getPaymentMethod().getInstallments()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void updateOrderTransactionSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("manual") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); OrderPaymentRequest updatePaymentRequest = OrderPaymentRequest.builder() .paymentMethod(OrderPaymentMethodRequest.builder() .installments(3) .build()) .build(); Order order = client.create(orderCreateRequest); String orderId = order.getId(); String transactionId = order.getTransactions().getPayments().get(0).getId(); UpdateOrderTransaction updatedTransaction = client.updateTransaction(orderId, transactionId, updatePaymentRequest); assertNotNull(updatedTransaction.getResponse()); assertEquals(OK, updatedTransaction.getResponse().getStatusCode()); assertEquals(3, updatedTransaction.getPaymentMethod().getInstallments()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void deleteOrderTransactionSuccess() { try { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); List paymentRequest = new ArrayList<>(); paymentRequest.add(OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token(cardToken.getId()) .installments(1) .build()) .build()); OrderPayerRequest orderPayerRequest = OrderPayerRequest.builder() .email("test_1731350184@testuser.com") .build(); OrderCreateRequest orderCreateRequest = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .processingMode("manual") .externalReference("ext_ref_1234") .payer(orderPayerRequest) .transactions(OrderTransactionRequest.builder() .payments(paymentRequest) .build()) .build(); MPRequestOptions requestOptions = MPRequestOptions.builder().build(); Map headers = new HashMap<>(); headers.put("X-Idempotency-Key", UUID.randomUUID().toString()); requestOptions.setCustomHeaders(headers); Order order = client.create(orderCreateRequest); String orderId = order.getId(); String transactionId = order.getTransactions().getPayments().get(0).getId(); OrderTransaction deletedTransaction = client.deleteTransaction(orderId, transactionId, requestOptions); assertNotNull(deletedTransaction.getResponse()); assertEquals(NO_CONTENT, deletedTransaction.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } } ================================================ FILE: src/test/java/com/mercadopago/client/order/OrderClientTest.java ================================================ package com.mercadopago.client.order; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static org.mockito.ArgumentMatchers.any; import com.google.gson.JsonObject; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.helper.MockHelper; import com.mercadopago.net.HttpStatus; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.order.Order; import com.mercadopago.resources.order.OrderSearchResponse; import com.mercadopago.resources.order.OrderTransaction; import com.mercadopago.resources.order.UpdateOrderTransaction; import com.mercadopago.serialization.Serializer; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import org.mockito.Mockito; class OrderClientTest extends BaseClientTest { private static final String CREATE_ORDER_RESPONSE_FILE = "order/create_order_response.json"; private static final String CREATE_TRANSACTION_RESPONSE_FILE = "order/create_transaction_response.json"; private static final String UPDATE_TRANSACTION_FILE = "order/update_transaction_response.json"; private static final String CAPTURE_ORDER_RESPONSE_FILE = "order/capture_order_response.json"; private static final String CREATE_REFUND_TOTAL_RESPONSE_FILE = "order/create_refund_total_response.json"; private static final String CREATE_REFUND_PARTIAL_RESPONSE_FILE = "order/create_refund_partial_response.json"; private static final String ORDER_SEARCH_RESPONSE_FILE = "order/order_search_response.json"; private final OrderClient client = new OrderClient(); @Test void createSuccess() throws MPException, MPApiException, IOException { // given OrderCreateRequest request = getMinimumOrderCreateRequest(); // Mock HttpClient HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.CREATED); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); // when Order order = client.create(request); // then Assertions.assertNotNull(order); Assertions.assertEquals(request.getTotalAmount(), order.getTotalAmount()); } private static OrderCreateRequest getMinimumOrderCreateRequest() { OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("10.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("card_token") .installments(1) .build()) .build(); List payments = new ArrayList<>(); payments.add(payment); return OrderCreateRequest.builder() .type("online") .totalAmount("10.00") .externalReference("ext_ref") .payer(OrderPayerRequest.builder().email("test@email.com").build()) .transactions(OrderTransactionRequest.builder() .payments(payments) .build()) .build(); } @Test void getSuccess() throws MPException, MPApiException, IOException { HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); String orderId = "123"; Order order = client.get(orderId); Assertions.assertNotNull(order); Assertions.assertEquals(orderId, order.getId()); } @Test void processSuccess() throws MPException, MPApiException, IOException { HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); String orderId = "123"; Order order = client.process(orderId); Assertions.assertNotNull(order); Assertions.assertEquals(orderId, order.getId()); } @Test void processWithNullIdThrowsException() { String orderId = null; IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> { client.process(orderId); }); Assertions.assertEquals("Order id cannot be null or empty", exception.getMessage()); } @Test void processWithEmptyIdThrowsException() { String orderId = ""; IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> { client.process(orderId); }); Assertions.assertEquals("Order id cannot be null or empty", exception.getMessage()); } @Test void createTransactionWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_TRANSACTION_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); String orderId = "123"; OrderPaymentRequest paymentRequest = OrderPaymentRequest.builder() .amount("100.00") .paymentMethod(OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("some-token") .installments(1) .statementDescriptor("statement") .build()) .build(); OrderTransactionRequest request = OrderTransactionRequest.builder() .payments(Collections.singletonList(paymentRequest)) .build(); OrderTransaction orderTransaction = client.createTransaction(orderId, request); Assertions.assertNotNull(orderTransaction); Assertions.assertEquals("100.00", orderTransaction.getPayments().get(0).getAmount()); Assertions.assertEquals("master", orderTransaction.getPayments().get(0).getPaymentMethod().getId()); } @Test void deleteTransactionSuccessWithValidIds() throws MPException, MPApiException, IOException { HttpResponse response = MockHelper.generateHttpResponse(HttpStatus.NO_CONTENT); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); String orderId = "123"; String transactionId = "pay_01JC44RS4MZE4Z7KJVCDP249FR"; OrderTransaction result = client.deleteTransaction(orderId, transactionId); Assertions.assertNotNull(result); Assertions.assertNotNull(result.getResponse()); Assertions.assertEquals(HttpStatus.NO_CONTENT, result.getResponse().getStatusCode()); } @Test void updateTransactionSuccessWithValidIds() throws MPException, MPApiException, IOException { HttpResponse response = MockHelper.generateHttpResponseFromFile(UPDATE_TRANSACTION_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); String orderId = "123"; String transactionId = "pay_01JC44RS4MZE4Z7KJVCDP249FR"; OrderPaymentRequest paymentRequest = OrderPaymentRequest.builder() .paymentMethod(OrderPaymentMethodRequest.builder().installments(3).build()) .build(); UpdateOrderTransaction updatedTransaction = client.updateTransaction(orderId, transactionId, paymentRequest); Assertions.assertNotNull(updatedTransaction); Assertions.assertEquals(HttpStatus.OK, updatedTransaction.getResponse().getStatusCode()); } @Test void captureSuccess() throws MPException, MPApiException, IOException { // Mock HttpClient HttpResponse response = MockHelper.generateHttpResponseFromFile(CAPTURE_ORDER_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); // when Order order = client.capture("123"); // then Assertions.assertNotNull(order); Assertions.assertEquals(order.getStatus(), "processed"); } @Test void refundTotalSuccess() throws MPException, MPApiException, IOException { HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_REFUND_TOTAL_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); String id = "123"; Order orderRefund = client.refund(id); Assertions.assertNotNull(orderRefund); Assertions.assertEquals(HttpStatus.OK, orderRefund.getResponse().getStatusCode()); Assertions.assertNotNull(orderRefund.getResponse()); Assertions.assertEquals("refunded", orderRefund.getStatus()); } @Test void refundPartialSuccess() throws MPException, MPApiException, IOException { HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_REFUND_PARTIAL_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); String orderId = "123"; OrderRefundPaymentRequest paymentRequest = OrderRefundPaymentRequest.builder() .id("pay_01JCK2RRKV10XVTEBJR598QH9Z") .amount("50.00") .build(); OrderRefundRequest refundRequest = OrderRefundRequest.builder() .transactions(Collections.singletonList(paymentRequest)) .build(); JsonObject payload = Serializer.serializeToJson(refundRequest); Order orderRefund = client.refund(orderId, refundRequest); Assertions.assertNotNull(payload); Assertions.assertTrue(payload.has("transactions")); Assertions.assertEquals("50.00", payload.getAsJsonArray("transactions").get(0).getAsJsonObject().get("amount").getAsString()); Assertions.assertNotNull(orderRefund); Assertions.assertEquals(HttpStatus.OK, orderRefund.getResponse().getStatusCode()); } @Test void refundWithValidRequestPayload() throws IOException { HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_REFUND_TOTAL_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); OrderRefundRequest refundRequest = OrderRefundRequest.builder() .transactions(Collections.singletonList(OrderRefundPaymentRequest.builder() .id("pay_01JCK2RRKV10XVTEBJR598QH9Z") .amount("50.00") .build())) .build(); JsonObject payload = Serializer.serializeToJson(refundRequest); Assertions.assertNotNull(payload); Assertions.assertTrue(payload.has("transactions")); Assertions.assertEquals("50.00", payload.getAsJsonArray("transactions").get(0).getAsJsonObject().get("amount").getAsString()); } @Test void validOrderIDWithValidId() { String validId = "123"; Assertions.assertDoesNotThrow(() -> { client.validateOrderID(validId); }); } @Test void validOrderIDWithNullIdThrowsException() { String nullId = null; IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> { client.validateOrderID(nullId); }); Assertions.assertEquals("Order id cannot be null or empty", exception.getMessage()); } @Test void validOrderIDWithEmptyIdThrowsException() { String emptyId = ""; IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> { client.validateOrderID(emptyId); }); Assertions.assertEquals("Order id cannot be null or empty", exception.getMessage()); } @Test void validTransactionIDWithValidId() { String validId = "trans_123"; Assertions.assertDoesNotThrow(() -> { client.validateTransactionID(validId); }); } @Test void validTransactionIDWithNullIdThrowsException() { IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> { client.validateTransactionID(null); }); Assertions.assertEquals("Transaction id cannot be null or empty", exception.getMessage()); } @Test void validTransactionIDWithEmptyIdThrowsException() { String emptyId = ""; IllegalArgumentException exception = Assertions.assertThrows(IllegalArgumentException.class, () -> { client.validateTransactionID(emptyId); }); Assertions.assertEquals("Transaction id cannot be null or empty", exception.getMessage()); } @Test void captureModeIsAutomaticAsync() throws Exception { OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .externalReference("ext_ref") .captureMode("automatic_async") .payer(OrderPayerRequest.builder().email("test@email.com").build()) .transactions(OrderTransactionRequest.builder().build()) .build(); HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.CREATED); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); Order order = client.create(request); Assertions.assertNotNull(order); JsonObject payload = com.mercadopago.serialization.Serializer.serializeToJson(request); Assertions.assertEquals("automatic_async", payload.get("capture_mode").getAsString()); } @Test void captureModeIsManual() throws Exception { OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .externalReference("ext_ref") .captureMode("manual") .payer(OrderPayerRequest.builder().email("test@email.com").build()) .transactions(OrderTransactionRequest.builder().build()) .build(); HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.CREATED); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); Order order = client.create(request); Assertions.assertNotNull(order); JsonObject payload = com.mercadopago.serialization.Serializer.serializeToJson(request); Assertions.assertEquals("manual", payload.get("capture_mode").getAsString()); } @Test void orderHasAdditionalInfo() throws Exception { AdditionalInfoRequest additionalInfo = AdditionalInfoRequest.builder() .payer(PayerInfo.builder() .authenticationType("MFA") .registrationDate("2025-09-15") .isPrimeUser(true) .build()) .platform(PlatformInfo.builder() .seller(SellerInfo.builder() .email("loja@email.com") .address(SellerAddress.builder().country("BR").build()) .build()) .build()) .build(); OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .totalAmount("100.00") .externalReference("ext_ref") .additionalInfo(additionalInfo) .payer(OrderPayerRequest.builder().email("test@email.com").build()) .transactions(OrderTransactionRequest.builder().build()) .build(); HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.CREATED); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); Order order = client.create(request); Assertions.assertNotNull(order); JsonObject additionalInfoJson = com.mercadopago.serialization.Serializer .serializeToJson(request) .getAsJsonObject("additional_info"); Assertions.assertNotNull(additionalInfoJson); Assertions.assertEquals( "MFA", additionalInfoJson.getAsJsonObject("payer").get("authentication_type").getAsString()); Assertions.assertEquals( "2025-09-15", additionalInfoJson.getAsJsonObject("payer").get("registration_date").getAsString()); Assertions.assertTrue( additionalInfoJson.getAsJsonObject("payer").get("is_prime_user").getAsBoolean()); Assertions.assertEquals( "loja@email.com", additionalInfoJson.getAsJsonObject("platform").getAsJsonObject("seller").get("email").getAsString()); Assertions.assertEquals( "BR", additionalInfoJson.getAsJsonObject("platform").getAsJsonObject("seller") .getAsJsonObject("address").get("country").getAsString()); } @Test void orderHasPaymentMethodIdBolbradesco() throws Exception { OrderPaymentMethodRequest paymentMethod = OrderPaymentMethodRequest.builder() .type("ticket") .id("bolbradesco") .build(); OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("84.00") .paymentMethod(paymentMethod) .build(); OrderCreateRequest request = OrderCreateRequest.builder() .type("ticket") .totalAmount("84.00") .transactions(OrderTransactionRequest.builder().payments(Arrays.asList(payment)).build()) .payer(OrderPayerRequest.builder().email("test@email.com").build()) .build(); HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.CREATED); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); Order order = client.create(request); Assertions.assertNotNull(order); JsonObject paymentMethodJson = com.mercadopago.serialization.Serializer .serializeToJson(request) .getAsJsonObject("transactions") .getAsJsonArray("payments") .get(0).getAsJsonObject() .getAsJsonObject("payment_method"); Assertions.assertNotNull(paymentMethodJson); Assertions.assertEquals("ticket", paymentMethodJson.get("type").getAsString()); Assertions.assertEquals("bolbradesco", paymentMethodJson.get("id").getAsString()); } @Test void orderHasPaymentMethodIdBoleto() throws Exception { OrderPaymentMethodRequest paymentMethod = OrderPaymentMethodRequest.builder() .type("ticket") .id("boleto") .build(); OrderPaymentRequest payment = OrderPaymentRequest.builder() .amount("84.00") .paymentMethod(paymentMethod) .build(); OrderCreateRequest request = OrderCreateRequest.builder() .type("ticket") .totalAmount("84.00") .transactions(OrderTransactionRequest.builder().payments(Arrays.asList(payment)).build()) .payer(OrderPayerRequest.builder().email("test@email.com").build()) .build(); HttpResponse response = MockHelper.generateHttpResponseFromFile(CREATE_ORDER_RESPONSE_FILE, HttpStatus.CREATED); Mockito.doReturn(response).when(HTTP_CLIENT).execute(any(HttpRequestBase.class), any(HttpContext.class)); Order order = client.create(request); Assertions.assertNotNull(order); JsonObject paymentMethodJson = com.mercadopago.serialization.Serializer .serializeToJson(request) .getAsJsonObject("transactions") .getAsJsonArray("payments") .get(0).getAsJsonObject() .getAsJsonObject("payment_method"); Assertions.assertNotNull(paymentMethodJson); Assertions.assertEquals("ticket", paymentMethodJson.get("type").getAsString()); Assertions.assertEquals("boleto", paymentMethodJson.get("id").getAsString()); } @Test void searchSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(ORDER_SEARCH_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest request = MPSearchRequest.builder().limit(5).offset(0).build(); OrderSearchResponse result = client.search(request); Assertions.assertEquals(HttpStatus.OK, result.getResponse().getStatusCode()); Assertions.assertEquals(10, result.getPaging().getTotal()); Assertions.assertEquals(2, result.getPaging().getTotalPages()); Assertions.assertEquals(5, result.getPaging().getLimit()); Assertions.assertEquals(0, result.getPaging().getOffset()); Assertions.assertEquals(1, result.getData().size()); Assertions.assertEquals("123", result.getData().get(0).getId()); } @Test void searchWithRequestOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(ORDER_SEARCH_RESPONSE_FILE, HttpStatus.OK); Mockito.doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest request = MPSearchRequest.builder().limit(5).offset(0).build(); OrderSearchResponse result = client.search(request, buildRequestOptions()); Assertions.assertEquals(HttpStatus.OK, result.getResponse().getStatusCode()); Assertions.assertEquals(10, result.getPaging().getTotal()); Assertions.assertEquals(1, result.getData().size()); } } ================================================ FILE: src/test/java/com/mercadopago/client/order/OrderClientWith3DSTest.java ================================================ package com.mercadopago.client.order; import com.mercadopago.BaseClientIT; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.order.Order; import org.junit.jupiter.api.Test; import java.util.ArrayList; import java.util.List; import static org.junit.jupiter.api.Assertions.*; /** * Test class for Order creation with 3DS authentication. */ public class OrderClientWith3DSTest extends BaseClientIT { private final OrderClient client = new OrderClient(); @Test public void testCreateOrderWith3DS_Success() throws MPException, MPApiException { // Configure 3DS transaction security OrderTransactionSecurity transactionSecurity = OrderTransactionSecurity.builder() .validation("on_fraud_risk") .liabilityShift("required") .build(); // Configure online settings with 3DS OrderOnlineConfig onlineConfig = OrderOnlineConfig.builder() .transactionSecurity(transactionSecurity) .build(); // Configure order settings OrderConfigRequest config = OrderConfigRequest.builder() .online(onlineConfig) .build(); // Configure payment method OrderPaymentMethodRequest paymentMethod = OrderPaymentMethodRequest.builder() .id("master") .type("credit_card") .token("test_card_token") .installments(1) .build(); // Configure payment List payments = new ArrayList<>(); payments.add(OrderPaymentRequest.builder() .amount("150.00") .paymentMethod(paymentMethod) .build()); // Configure transactions OrderTransactionRequest transactions = OrderTransactionRequest.builder() .payments(payments) .build(); // Configure payer information IdentificationRequest identification = IdentificationRequest.builder() .type("CPF") .number("12345678901") .build(); OrderPayerRequest payer = OrderPayerRequest.builder() .email("test_user@example.com") .identification(identification) .build(); // Create the order request OrderCreateRequest request = OrderCreateRequest.builder() .type("online") .externalReference("3ds_test_" + System.currentTimeMillis()) .processingMode("automatic") .totalAmount("150.00") .config(config) .payer(payer) .transactions(transactions) .build(); // Verify that the request is properly configured assertNotNull(request.getConfig()); assertNotNull(request.getConfig().getOnline()); assertNotNull(request.getConfig().getOnline().getTransactionSecurity()); assertEquals("on_fraud_risk", request.getConfig().getOnline().getTransactionSecurity().getValidation()); assertEquals("required", request.getConfig().getOnline().getTransactionSecurity().getLiabilityShift()); } @Test public void testTransactionSecurityBuilder() { // Test building transaction security with all validation options OrderTransactionSecurity alwaysValidation = OrderTransactionSecurity.builder() .validation("always") .liabilityShift("preferred") .build(); assertEquals("always", alwaysValidation.getValidation()); assertEquals("preferred", alwaysValidation.getLiabilityShift()); OrderTransactionSecurity neverValidation = OrderTransactionSecurity.builder() .validation("never") .liabilityShift("required") .build(); assertEquals("never", neverValidation.getValidation()); assertEquals("required", neverValidation.getLiabilityShift()); OrderTransactionSecurity fraudRiskValidation = OrderTransactionSecurity.builder() .validation("on_fraud_risk") .liabilityShift("required") .build(); assertEquals("on_fraud_risk", fraudRiskValidation.getValidation()); assertEquals("required", fraudRiskValidation.getLiabilityShift()); } @Test public void testOrderOnlineConfigWith3DS() { OrderTransactionSecurity transactionSecurity = OrderTransactionSecurity.builder() .validation("on_fraud_risk") .liabilityShift("required") .build(); OrderOnlineConfig onlineConfig = OrderOnlineConfig.builder() .callbackUrl("https://example.com/callback") .successUrl("https://example.com/success") .failureUrl("https://example.com/failure") .transactionSecurity(transactionSecurity) .build(); assertNotNull(onlineConfig.getTransactionSecurity()); assertEquals("on_fraud_risk", onlineConfig.getTransactionSecurity().getValidation()); assertEquals("required", onlineConfig.getTransactionSecurity().getLiabilityShift()); assertEquals("https://example.com/callback", onlineConfig.getCallbackUrl()); assertEquals("https://example.com/success", onlineConfig.getSuccessUrl()); assertEquals("https://example.com/failure", onlineConfig.getFailureUrl()); } } ================================================ FILE: src/test/java/com/mercadopago/client/order/OrderPointConfigTest.java ================================================ package com.mercadopago.client.order; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; /** OrderPointConfigTest class. */ class OrderPointConfigTest { @Test void testOrderPointConfigBuilder() { OrderPointConfig pointConfig = OrderPointConfig.builder() .terminalId("") .printOnTerminal("seller_ticket") .screenTime("") .build(); assertNotNull(pointConfig); assertEquals("", pointConfig.getTerminalId()); assertEquals("seller_ticket", pointConfig.getPrintOnTerminal()); assertEquals("", pointConfig.getScreenTime()); } @Test void testOrderPointConfigMinimalBuilder() { OrderPointConfig pointConfig = OrderPointConfig.builder() .terminalId("") .build(); assertNotNull(pointConfig); assertEquals("", pointConfig.getTerminalId()); assertNull(pointConfig.getPrintOnTerminal()); assertNull(pointConfig.getScreenTime()); } } ================================================ FILE: src/test/java/com/mercadopago/client/payment/PaymentClientIT.java ================================================ package com.mercadopago.client.payment; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.client.cardtoken.CardTokenTestClient; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.Headers; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.CardToken; import com.mercadopago.resources.payment.Payment; import com.mercadopago.resources.payment.PaymentRefund; import java.math.BigDecimal; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import lombok.var; import org.junit.jupiter.api.Test; /** PaymentClientIT class. */ public class PaymentClientIT extends BaseClientIT { private final PaymentClient client = new PaymentClient(); private final CardTokenTestClient cardTokenTestClient = new CardTokenTestClient(); @Test public void createSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment payment = client.create(paymentCreateRequest); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertNotNull(payment.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createPaymentWithCustomizedHeadersWithSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); String idempotencyKey = UUID.randomUUID().toString(); Map customHeaders = new HashMap<>(); customHeaders.put(Headers.IDEMPOTENCY_KEY, idempotencyKey); MPRequestOptions requestOptions = MPRequestOptions.builder() .customHeaders(customHeaders) .build(); var firstPayment = client.create(paymentCreateRequest, requestOptions); var secondPayment = client.create(paymentCreateRequest, requestOptions); assertNotNull(firstPayment.getResponse()); assertNotNull(secondPayment.getResponse()); assertEquals(CREATED, firstPayment.getResponse().getStatusCode()); assertEquals(OK, secondPayment.getResponse().getStatusCode()); assertEquals(firstPayment.getId(), secondPayment.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void createWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment payment = client.create(paymentCreateRequest, buildRequestOptions()); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertNotNull(payment.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Payment payment = client.get(createdPayment.getId()); assertNotNull(payment); assertEquals(OK, payment.getResponse().getStatusCode()); assertEquals(createdPayment.getId(), payment.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Payment payment = client.get(createdPayment.getId(), buildRequestOptions()); assertNotNull(payment); assertEquals(OK, payment.getResponse().getStatusCode()); assertEquals(createdPayment.getId(), payment.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void cancelSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("pending"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(5000); Payment payment = client.cancel(createdPayment.getId()); assertNotNull(payment.getResponse()); assertEquals(OK, payment.getResponse().getStatusCode()); assertEquals("cancelled", payment.getStatus()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void cancelWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("pending"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(3000); Payment paymentCancelled = client.cancel(createdPayment.getId(), buildRequestOptions()); assertNotNull(paymentCancelled.getResponse()); assertEquals(OK, paymentCancelled.getResponse().getStatusCode()); assertEquals("cancelled", paymentCancelled.getStatus()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void captureSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Payment paymentCaptured = client.capture(createdPayment.getId()); assertNotNull(paymentCaptured.getResponse()); assertEquals(OK, paymentCaptured.getResponse().getStatusCode()); assertTrue(paymentCaptured.isCaptured()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void captureWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Payment paymentCaptured = client.capture(createdPayment.getId(), buildRequestOptions()); assertNotNull(paymentCaptured.getResponse()); assertEquals(OK, paymentCaptured.getResponse().getStatusCode()); assertTrue(paymentCaptured.isCaptured()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void searchSuccess() { try { MPSearchRequest request = MPSearchRequest.builder().limit(5).offset(0).build(); MPResultsResourcesPage result = client.search(request); assertNotNull(result.getResponse().getContent()); assertEquals(OK, result.getResponse().getStatusCode()); assertFalse(result.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void searchWithRequestOptionsSuccess() { try { MPSearchRequest request = MPSearchRequest.builder().limit(5).offset(0).build(); MPResultsResourcesPage result = client.search(request, buildRequestOptions()); assertNotNull(result.getResponse().getContent()); assertEquals(OK, result.getResponse().getStatusCode()); assertFalse(result.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void refundPartialSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(3000); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = client.refund(createdPayment.getId(), amount); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void refundPartialWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(3000); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = client.refund(createdPayment.getId(), amount, buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void refundTotalSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(3000); PaymentRefund result = client.refund(createdPayment.getId()); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void refundTotalWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(5000); PaymentRefund result = client.refund(createdPayment.getId(), buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void getRefundSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(3000); PaymentRefund createdRefund = client.refund(createdPayment.getId()); PaymentRefund result = client.getRefund(createdPayment.getId(), createdRefund.getId()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void getRefundWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(3000); PaymentRefund createdRefund = client.refund(createdPayment.getId()); PaymentRefund result = client.getRefund(createdPayment.getId(), createdRefund.getId(), buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void listRefundsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(3000); client.refund(createdPayment.getId()); MPResourceList result = client.listRefunds(createdPayment.getId()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertEquals(1, result.getResults().size()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } @Test public void listRefundsWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment("approved"); Payment createdPayment = client.create(paymentCreateRequest); Thread.sleep(5000); client.refund(createdPayment.getId()); MPResourceList result = client.listRefunds(createdPayment.getId(), buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertEquals(1, result.getResults().size()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } catch (InterruptedException e) { throw new RuntimeException(e); } } private PaymentCreateRequest newPayment(String paymentStatus) throws MPException, MPApiException { CardToken cardToken = cardTokenTestClient.createTestCardToken(paymentStatus); IdentificationRequest identification = IdentificationRequest.builder().type("CPF").number("19119119100").build(); PaymentPayerRequest payer = PaymentPayerRequest.builder() .email(generateTestEmail()) .firstName("Test") .lastName("User") .identification(identification) .build(); PaymentItemRequest item = PaymentItemRequest.builder() .id("1941") .title("title") .description("product") .pictureUrl("pictureUrl") .categoryId("categoryId") .quantity(1) .unitPrice(new BigDecimal("100")) .build(); List itemRequestList = new ArrayList<>(); itemRequestList.add(item); PhoneRequest phone = PhoneRequest.builder().areaCode("11").number("987654321").build(); AddressRequest address = AddressRequest.builder() .streetName("Av. das Nações Unidas") .zipCode("06233-200") .streetNumber("3003") .build(); PaymentAdditionalInfoPayerRequest additionalInfoPayer = PaymentAdditionalInfoPayerRequest.builder() .firstName("Test") .lastName("User") .phone(phone) .address(address) .registrationDate(OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC)) .build(); PaymentReceiverAddressRequest receiverAddress = PaymentReceiverAddressRequest.builder() .floor("12") .apartment("123") .zipCode("95630000") .streetNumber("15") .streetName("Av São Luiz") .build(); PaymentShipmentsRequest shipments = PaymentShipmentsRequest.builder().receiverAddress(receiverAddress).build(); PaymentAdditionalInfoRequest additionalInfo = PaymentAdditionalInfoRequest.builder() .items(itemRequestList) .payer(additionalInfoPayer) .shipments(shipments) .ipAddress("127.0.0.1") .build(); PaymentPointOfInteractionRequest pointOfInteraction = PaymentPointOfInteractionRequest.builder().type("OPENPLATFORM").build(); return PaymentCreateRequest.builder() .transactionAmount(new BigDecimal("100")) .token(cardToken.getId()) .installments(1) .payer(payer) .description("description") .metadata(new HashMap<>()) .paymentMethodId("master") .additionalInfo(additionalInfo) .pointOfInteraction(pointOfInteraction) .build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/payment/PaymentClientTest.java ================================================ package com.mercadopago.client.payment; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.helper.MockHelper.generateJsonElement; import static com.mercadopago.helper.MockHelper.generateJsonElementFromUriRequest; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static java.math.BigInteger.ZERO; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.google.gson.JsonElement; import com.mercadopago.BaseClientTest; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.payment.Payment; import com.mercadopago.resources.payment.PaymentRefund; import java.io.IOException; import java.math.BigDecimal; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.function.Supplier; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; /** PaymentClientTest class. */ public class PaymentClientTest extends BaseClientTest { private final Long paymentTestId = 17014025134L; private final Long refundTestId = 1245678203L; private final String paymentBaseJson = "payment/payment_base.json"; private final String paymentPixJson = "payment/payment_pix.json"; private final String paymentCapturedJson = "payment/payment_captured.json"; private final String paymentCancelledJson = "payment/payment_cancelled.json"; private final String capturedJson = "payment/captured.json"; private final String statusCancelledJson = "payment/status_cancelled.json"; private final String paymentSearchJson = "payment/payment_search.json"; private final String payment3dsJson = "payment/payment_3ds.json"; private final String paymentBoletoJson = "payment/payment_boleto.json"; private final String paymentPseJson = "payment/payment_pse.json"; private final String refundBaseJson = "refund/refund_base.json"; private final String refundListJson = "refund/refund_list.json"; private final String refundPartialJson = "refund/refund_partial.json"; private final OffsetDateTime date = OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final PaymentClient client = new PaymentClient(); @Test public void createSuccess() throws MPException, IOException, MPApiException { Payment payment = createCardPayment(); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertPaymentFields(payment); } @Test public void createWithThreeDSecureSuccess() throws MPException, IOException, MPApiException { Payment payment = createCardPaymentWith3ds(); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(payment3dsJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertEquals( payment.getThreeDSInfo().getCreq(), "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImE4NDQ1NTE2LThjNzktNGQ1NC04MjRmLTU5YzgzNDRiY2FjNCIsImFj"); assertEquals( payment.getThreeDSInfo().getExternalResourceUrl(), "https://acs-public.tp.mastercard.com/api/v1/browser_challenges"); } @Test public void createWithRequestOptionsSuccess() throws MPException, IOException, MPApiException { Payment payment = createCardPayment(buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertPaymentFields(payment); } @Test public void createPixSuccess() throws MPException, IOException, MPApiException { Payment payment = createPixPayment(); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentPixJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertEquals("pix", payment.getPaymentMethodId()); assertEquals( "https://www.mercadopago.com.br/payments/21071815560/ticket?caller_id=471763966&hash=abcd1234efgh5678", payment.getPointOfInteraction().getTransactionData().getTicketUrl()); assertEquals("openfinance", payment.getPointOfInteraction().getLinkedTo()); assertNotNull(payment.getPointOfInteraction().getTransactionData().getQrCode()); assertNotNull(payment.getPointOfInteraction().getTransactionData().getQrCodeBase64()); } @Test public void createPixWithRequestOptionsSuccess() throws MPException, IOException, MPApiException { Payment payment = createPixPayment(buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentPixJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertEquals("pix", payment.getPaymentMethodId()); assertEquals( "https://www.mercadopago.com.br/payments/21071815560/ticket?caller_id=471763966&hash=abcd1234efgh5678", payment.getPointOfInteraction().getTransactionData().getTicketUrl()); assertEquals("openfinance", payment.getPointOfInteraction().getLinkedTo()); assertNotNull(payment.getPointOfInteraction().getTransactionData().getQrCode()); assertNotNull(payment.getPointOfInteraction().getTransactionData().getQrCodeBase64()); } @Test public void createBoletoWithDiscountFineInterestSuccess() throws IOException, MPException, MPApiException { Payment payment = createBoletoPayment(); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentBoletoJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertEquals("bolbradesco", payment.getPaymentMethodId()); assertEquals( "fixed", payment.getPaymentMethod().getData().getRules().getDiscounts().get(0).getType()); assertEquals( new BigDecimal(5), payment.getPaymentMethod().getData().getRules().getDiscounts().get(0).getValue()); assertEquals( "2022-10-25", payment .getPaymentMethod() .getData() .getRules() .getDiscounts() .get(0) .getLimitDate() .toString()); assertEquals("percentage", payment.getPaymentMethod().getData().getRules().getFine().getType()); assertEquals( new BigDecimal(2), payment.getPaymentMethod().getData().getRules().getFine().getValue()); assertEquals( "percentage", payment.getPaymentMethod().getData().getRules().getInterest().getType()); assertEquals( new BigDecimal("0.03"), payment.getPaymentMethod().getData().getRules().getInterest().getValue()); } @Test public void createPsePaymentSuccess() throws MPException, MPApiException, IOException { Payment payment = createPsePayment(); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentPseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(payment.getResponse()); assertEquals(CREATED, payment.getResponse().getStatusCode()); assertEquals("pse", payment.getPaymentMethodId()); assertEquals("COP", payment.getCurrencyId()); assertEquals("bank_transfer", payment.getPaymentTypeId()); assertEquals("pending", payment.getStatus()); assertEquals("1009", payment.getTransactionDetails().getFinancialInstitution()); assertEquals( "https://www.mercadopago.com.co/sandbox/payments/1111/bank_transfer?caller_id=2222&hash=1234", payment.getTransactionDetails().getExternalResourceUrl()); } @Test public void getSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Payment findPayment = client.get(paymentTestId); assertNotNull(findPayment); assertPaymentFields(findPayment); } @Test public void getWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Payment findPayment = client.get(paymentTestId, buildRequestOptions()); assertNotNull(findPayment); assertPaymentFields(findPayment); } @Test public void cancelSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentCancelledJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Payment paymentCancelled = client.cancel(paymentTestId); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(statusCancelledJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(paymentCancelled.getResponse()); assertEquals(OK, paymentCancelled.getResponse().getStatusCode()); assertEquals("cancelled", paymentCancelled.getStatus()); } @Test public void cancelWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentCancelledJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Payment paymentCancelled = client.cancel(paymentTestId, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(statusCancelledJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(paymentCancelled.getResponse()); assertEquals(OK, paymentCancelled.getResponse().getStatusCode()); assertEquals("cancelled", paymentCancelled.getStatus()); } @Test public void captureSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentCapturedJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Payment paymentCaptured = client.capture(paymentTestId); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(capturedJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(paymentCaptured.getResponse()); assertEquals(OK, paymentCaptured.getResponse().getStatusCode()); assertTrue(paymentCaptured.isCaptured()); } @Test public void captureWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentCapturedJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Payment paymentCaptured = client.capture(paymentTestId, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(capturedJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(paymentCaptured.getResponse()); assertEquals(OK, paymentCaptured.getResponse().getStatusCode()); assertTrue(paymentCaptured.isCaptured()); } @Test public void searchSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentSearchJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest request = MPSearchRequest.builder().limit(5).offset(0).build(); MPResultsResourcesPage result = client.search(request); assertNotNull(result.getResponse().getContent()); assertEquals(OK, result.getResponse().getStatusCode()); assertEquals(5, result.getPaging().getLimit()); assertEquals(0, result.getPaging().getOffset()); assertEquals(102, result.getPaging().getTotal()); assertEquals(5, result.getResults().size()); assertEquals("pix", result.getResults().get(0).getPaymentMethodId()); } @Test public void searchWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentSearchJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest request = MPSearchRequest.builder().limit(5).offset(0).build(); MPResultsResourcesPage result = client.search(request, buildRequestOptions()); assertNotNull(result.getResponse().getContent()); assertEquals(OK, result.getResponse().getStatusCode()); assertEquals(5, result.getPaging().getLimit()); assertEquals(0, result.getPaging().getOffset()); assertEquals(102, result.getPaging().getTotal()); assertEquals(5, result.getResults().size()); assertEquals("pix", result.getResults().get(0).getPaymentMethodId()); } @Test public void refundPartialSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = client.refund(paymentTestId, amount); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(refundPartialJson); assertEquals(requestPayloadMock, requestPayload); assertRefundFields(result); } @Test public void refundPartialWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = client.refund(paymentTestId, amount, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(refundPartialJson); assertEquals(requestPayloadMock, requestPayload); assertRefundFields(result); } @Test public void refundTotalSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.refund(paymentTestId); assertRefundFields(result); } @Test public void refundTotalWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.refund(paymentTestId, buildRequestOptions()); assertRefundFields(result); } @Test public void getRefundSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.getRefund(paymentTestId, refundTestId); assertRefundFields(result); } @Test public void getRefundWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.getRefund(paymentTestId, refundTestId, buildRequestOptions()); assertRefundFields(result); } @Test public void listRefundsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList result = client.listRefunds(paymentTestId); assertEquals(OK, result.getResponse().getStatusCode()); assertNotNull(result.getResponse()); assertEquals(2, result.getResults().size()); assertRefundFields(result.getResults().get(0)); } @Test public void listRefundsWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList result = client.listRefunds(paymentTestId, buildRequestOptions()); assertEquals(OK, result.getResponse().getStatusCode()); assertNotNull(result.getResponse()); assertEquals(2, result.getResults().size()); assertRefundFields(result.getResults().get(0)); } private void assertRefundFields(PaymentRefund refund) { assertEquals(refundTestId, refund.getId()); assertEquals(paymentTestId, refund.getPaymentId()); assertEquals(new BigDecimal("50"), refund.getAmount()); assertEquals("823549964", refund.getSource().getId()); assertEquals("Mullins Hillary", refund.getSource().getName()); assertEquals("collector", refund.getSource().getType()); assertEquals(date, refund.getDateCreated()); assertNull(refund.getUniqueSequenceNumber()); assertEquals("standard", refund.getRefundMode()); assertEquals(BigDecimal.ZERO, refund.getAdjustmentAmount()); assertEquals("approved", refund.getStatus()); assertNull(refund.getReason()); } private Payment createCardPayment() throws IOException, MPException, MPApiException { return this.createPayment("card", null); } private Payment createCardPayment(MPRequestOptions requestOptions) throws IOException, MPException, MPApiException { return this.createPayment("card", requestOptions); } private Payment createCardPaymentWith3ds() throws IOException, MPException, MPApiException { return this.createPayment("3ds", null); } private Payment createPixPayment() throws IOException, MPException, MPApiException { return this.createPayment("pix", null); } private Payment createPixPayment(MPRequestOptions requestOptions) throws IOException, MPException, MPApiException { return this.createPayment("pix", requestOptions); } private Payment createBoletoPayment() throws IOException, MPException, MPApiException { return this.createPayment("bolbradesco", null); } private Payment createPsePayment() throws IOException, MPException, MPApiException { return this.createPayment("pse", null); } private Payment createPayment(String paymentMethod, MPRequestOptions requestOptions) throws IOException, MPException, MPApiException { class CreateInfo { final Supplier createRequestFn; private final String responseFile; protected CreateInfo(String responseFile, Supplier createRequestFn) { this.responseFile = responseFile; this.createRequestFn = createRequestFn; } } Map paymentMethods = new HashMap<>(); paymentMethods.put("pix", new CreateInfo(paymentPixJson, this::newPixPayment)); paymentMethods.put("card", new CreateInfo(paymentBaseJson, () -> newCardPayment(false))); paymentMethods.put("3ds", new CreateInfo(payment3dsJson, () -> newCardPayment(true))); paymentMethods.put("bolbradesco", new CreateInfo(paymentBoletoJson, this::newBoletoPayment)); paymentMethods.put("pse", new CreateInfo(paymentPseJson, this::newPsePayment)); PaymentCreateRequest paymentCreateRequest = paymentMethods.get(paymentMethod).createRequestFn.get(); HttpResponse httpResponse = generateHttpResponseFromFile(paymentMethods.get(paymentMethod).responseFile, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); return Objects.nonNull(requestOptions) ? client.create(paymentCreateRequest, requestOptions) : client.create(paymentCreateRequest); } private void assertPaymentFields(Payment payment) { assertEquals(paymentTestId, payment.getId()); assertEquals(date, payment.getDateCreated()); assertEquals(date, payment.getDateApproved()); assertEquals(date, payment.getDateLastUpdated()); assertNull(payment.getDateOfExpiration()); assertNull(payment.getMoneyReleaseDate()); assertEquals("regular_payment", payment.getOperationType()); assertEquals("24", payment.getIssuerId()); assertEquals("master", payment.getPaymentMethodId()); assertEquals("credit_card", payment.getPaymentTypeId()); assertEquals("approved", payment.getStatus()); assertEquals("accredited", payment.getStatusDetail()); assertEquals("BRL", payment.getCurrencyId()); assertEquals("PEDIDO NOVO - VIDEOGAME", payment.getDescription()); assertTrue(payment.isLiveMode()); assertNull(payment.getSponsorId()); assertEquals("301299", payment.getAuthorizationCode()); assertNull(payment.getMoneyReleaseSchema()); assertEquals(new BigDecimal(ZERO), payment.getTaxesAmount()); assertNull(payment.getCounterCurrency()); assertEquals(new BigDecimal(ZERO), payment.getShippingAmount()); assertNull(payment.getPosId()); assertNull(payment.getStoreId()); assertNull(payment.getIntegratorId()); assertNull(payment.getPlatformId()); assertNull(payment.getCorporationId()); Long paymentCollectorId = 810882223L; assertEquals(paymentCollectorId, payment.getCollectorId()); assertNotNull(payment.getPayer()); assertNull(payment.getPayer().getType()); assertEquals("128185910", payment.getPayer().getId()); assertNull(payment.getPayer().getType()); assertEquals("test_user_1631894348@testuser.com", payment.getPayer().getEmail()); assertEquals("CPF", payment.getPayer().getIdentification().getType()); assertEquals("19119119100", payment.getPayer().getIdentification().getNumber()); assertNull(payment.getPayer().getFirstName()); assertNull(payment.getPayer().getLastName()); assertNull(payment.getPayer().getEntityType()); assertEquals("order_1631894348", payment.getMetadata().get("order_number")); assertNotNull(payment.getAdditionalInfo()); assertEquals("1941", payment.getAdditionalInfo().getItems().get(0).getId()); assertEquals("Ingresso Antecipado", payment.getAdditionalInfo().getItems().get(0).getTitle()); assertEquals( "Natal Iluminado 2019", payment.getAdditionalInfo().getItems().get(0).getDescription()); assertNull(payment.getAdditionalInfo().getItems().get(0).getPictureUrl()); assertEquals("Tickets", payment.getAdditionalInfo().getItems().get(0).getCategoryId()); assertEquals(1, payment.getAdditionalInfo().getItems().get(0).getQuantity()); assertEquals("100.0", payment.getAdditionalInfo().getItems().get(0).getUnitPrice().toString()); assertEquals("11", payment.getAdditionalInfo().getPayer().getPhone().getAreaCode()); assertEquals("987654321", payment.getAdditionalInfo().getPayer().getPhone().getNumber()); assertEquals("06233-200", payment.getAdditionalInfo().getPayer().getAddress().getZipCode()); assertEquals( "Av. das Nações Unidas", payment.getAdditionalInfo().getPayer().getAddress().getStreetName()); assertEquals("3003", payment.getAdditionalInfo().getPayer().getAddress().getStreetNumber()); assertEquals("Nome", payment.getAdditionalInfo().getPayer().getFirstName()); assertEquals("Sobrenome", payment.getAdditionalInfo().getPayer().getLastName()); assertEquals(date, payment.getAdditionalInfo().getPayer().getRegistrationDate()); assertEquals("95630000", payment.getAdditionalInfo().getShipments().getReceiverAddress().getZipCode()); assertEquals( "são Luiz", payment.getAdditionalInfo().getShipments().getReceiverAddress().getStreetName()); assertEquals( "15", payment.getAdditionalInfo().getShipments().getReceiverAddress().getStreetNumber()); assertNull(payment.getOrder().getId()); assertNull(payment.getOrder().getType()); assertEquals("1631894348", payment.getExternalReference()); assertEquals("12.34", payment.getTransactionAmount().toString()); assertEquals("0", payment.getTransactionAmountRefunded().toString()); assertEquals("0", payment.getCouponAmount().toString()); assertNull(payment.getDifferentialPricingId()); assertNull(payment.getDeductionSchema()); assertEquals(1, payment.getInstallments()); assertNull(payment.getTransactionDetails().getPaymentMethodReferenceId()); assertEquals("11.72", payment.getTransactionDetails().getNetReceivedAmount().toString()); assertEquals("12.34", payment.getTransactionDetails().getTotalPaidAmount().toString()); assertEquals("0", payment.getTransactionDetails().getOverpaidAmount().toString()); assertNull(payment.getTransactionDetails().getExternalResourceUrl()); assertEquals("12.34", payment.getTransactionDetails().getInstallmentAmount().toString()); assertNull(payment.getTransactionDetails().getFinancialInstitution()); assertNull(payment.getTransactionDetails().getPaymentMethodReferenceId()); assertNull(payment.getTransactionDetails().getAcquirerReference()); assertNotNull(payment.getFeeDetails()); assertEquals("mercadopago_fee", payment.getFeeDetails().get(0).getType()); assertEquals("0.62", payment.getFeeDetails().get(0).getAmount().toString()); assertEquals("collector", payment.getFeeDetails().get(0).getFeePayer()); assertFalse(payment.isCaptured()); assertFalse(payment.isBinaryMode()); assertNull(payment.getCallForAuthorizeId()); assertEquals("Mercadopago*fake", payment.getStatementDescriptor()); assertNull(payment.getCard().getId()); assertEquals("503143", payment.getCard().getFirstSixDigits()); assertEquals("6351", payment.getCard().getLastFourDigits()); assertEquals(12, payment.getCard().getExpirationMonth()); assertEquals(2022, payment.getCard().getExpirationYear()); assertEquals(date, payment.getCard().getDateCreated()); assertEquals(date, payment.getCard().getDateLastUpdated()); assertEquals("APRO", payment.getCard().getCardholder().getName()); assertEquals("19119119100", payment.getCard().getCardholder().getIdentification().getNumber()); assertEquals("CPF", payment.getCard().getCardholder().getIdentification().getType()); assertEquals( "https://seu-site.com.br/webhookshttps://seu-site.com.br/webhooks", payment.getNotificationUrl()); assertTrue(payment.getRefunds().isEmpty()); assertEquals("aggregator", payment.getProcessingMode()); assertNull(payment.getMerchantAccountId()); assertNull(payment.getMerchantNumber()); assertNull(payment.getPointOfInteraction().getType()); assertNull(payment.getPointOfInteraction().getSubType()); assertNull(payment.getPointOfInteraction().getApplicationData()); assertNull(payment.getPointOfInteraction().getTransactionData()); } private PaymentCreateRequest newCardPayment(boolean with3ds) { String threeDSecureMode = with3ds ? "optional" : "not_supported"; IdentificationRequest identification = IdentificationRequest.builder().type("CPF").number("37462770865").build(); PaymentPayerRequest payer = PaymentPayerRequest.builder() .type("customer") .email("test_payer_9999999@testuser.com") .entityType("individual") .firstName("Test") .lastName("User") .identification(identification) .build(); PaymentItemRequest item = PaymentItemRequest.builder() .id("id") .title("title") .description("description") .pictureUrl("pictureUrl") .categoryId("categoryId") .quantity(1) .unitPrice(new BigDecimal(100)) .build(); List itemRequestList = new ArrayList<>(); itemRequestList.add(item); PhoneRequest phone = PhoneRequest.builder().areaCode("000").number("0000-0000").build(); AddressRequest address = AddressRequest.builder() .streetName("streetName") .zipCode("0000") .streetNumber("1234") .build(); PaymentAdditionalInfoPayerRequest additionalInfoPayer = PaymentAdditionalInfoPayerRequest.builder() .firstName("Test") .lastName("User") .phone(phone) .address(address) .registrationDate(date) .build(); PaymentReceiverAddressRequest receiverAddress = PaymentReceiverAddressRequest.builder() .floor("floor") .apartment("apartment") .streetName("streetName") .zipCode("0000") .streetNumber("1234") .build(); PaymentShipmentsRequest shipments = PaymentShipmentsRequest.builder().receiverAddress(receiverAddress).build(); PaymentAdditionalInfoRequest additionalInfo = PaymentAdditionalInfoRequest.builder() .items(itemRequestList) .payer(additionalInfoPayer) .shipments(shipments) .ipAddress("127.0.0.1") .build(); return PaymentCreateRequest.builder() .payer(payer) .binaryMode(false) .externalReference("212efa19-da7a-4b4f-a3f0-4f458136d9ca") .description("description") .metadata(new HashMap<>()) .threeDSecureMode(threeDSecureMode) .transactionAmount(new BigDecimal(100)) .capture(false) .paymentMethodId("master") .token("bf9edf6ffae3ab5742033f33c557d54e") .statementDescriptor("statementDescriptor") .installments(1) .notificationUrl("https://seu-site.com.br/webhooks") .additionalInfo(additionalInfo) .build(); } private PaymentCreateRequest newPixPayment() { return PaymentCreateRequest.builder() .transactionAmount(new BigDecimal(100)) .dateOfExpiration(OffsetDateTime.of(2022, 2, 10, 10, 10, 10, 0, ZoneOffset.UTC)) .paymentMethodId("pix") .description("description") .payer(PaymentPayerRequest.builder().email("test_user_1648059260@testuser.com").build()) .pointOfInteraction( PaymentPointOfInteractionRequest.builder().linkedTo("openfinance").build()) .build(); } private PaymentCreateRequest newBoletoPayment() { IdentificationRequest identification = IdentificationRequest.builder().type("CPF").number("37462770865").build(); PaymentPayerRequest payer = PaymentPayerRequest.builder() .type("customer") .email("test_payer_9999999@testuser.com") .entityType("individual") .firstName("Test") .lastName("User") .identification(identification) .build(); PaymentItemRequest item = PaymentItemRequest.builder() .id("id") .title("title") .description("description") .pictureUrl("pictureUrl") .categoryId("categoryId") .quantity(1) .unitPrice(new BigDecimal(100)) .build(); List itemRequestList = new ArrayList<>(); itemRequestList.add(item); PhoneRequest phone = PhoneRequest.builder().areaCode("000").number("0000-0000").build(); AddressRequest address = AddressRequest.builder() .streetName("streetName") .zipCode("0000") .streetNumber("1234") .build(); PaymentAdditionalInfoPayerRequest additionalInfoPayer = PaymentAdditionalInfoPayerRequest.builder() .firstName("Test") .lastName("User") .phone(phone) .address(address) .registrationDate(date) .build(); PaymentReceiverAddressRequest receiverAddress = PaymentReceiverAddressRequest.builder() .floor("floor") .apartment("apartment") .streetName("streetName") .zipCode("0000") .streetNumber("1234") .build(); PaymentShipmentsRequest shipments = PaymentShipmentsRequest.builder().receiverAddress(receiverAddress).build(); PaymentAdditionalInfoRequest additionalInfo = PaymentAdditionalInfoRequest.builder() .items(itemRequestList) .payer(additionalInfoPayer) .shipments(shipments) .ipAddress("127.0.0.1") .build(); PaymentFeeRequest fine = PaymentFeeRequest.builder().type("percentage").value(new BigDecimal(2)).build(); PaymentFeeRequest interest = PaymentFeeRequest.builder().type("percentage").value(new BigDecimal("0.03")).build(); PaymentDiscountRequest discount = PaymentDiscountRequest.builder() .type("fixed") .value(new BigDecimal(5)) .limitDate(LocalDate.of(2022, 10, 25)) .build(); List discounts = new ArrayList<>(); discounts.add(discount); PaymentRulesRequest rules = PaymentRulesRequest.builder().fine(fine).interest(interest).discounts(discounts).build(); PaymentDataRequest data = PaymentDataRequest.builder().rules(rules).build(); PaymentMethodRequest paymentMethod = PaymentMethodRequest.builder().data(data).build(); return PaymentCreateRequest.builder() .payer(payer) .binaryMode(false) .externalReference("212efa19-da7a-4b4f-a3f0-4f458136d9ca") .description("description") .metadata(new HashMap<>()) .transactionAmount(new BigDecimal(100)) .capture(false) .paymentMethodId("bolbradesco") .statementDescriptor("statementDescriptor") .installments(1) .notificationUrl("https://seu-site.com.br/webhooks") .additionalInfo(additionalInfo) .paymentMethod(paymentMethod) .build(); } private PaymentCreateRequest newPsePayment() { IdentificationRequest identification = IdentificationRequest.builder().type("C.C.").number("1111111111").build(); PaymentPayerAddressRequest address = PaymentPayerAddressRequest.builder() .streetName("streetName") .streetNumber("streetNumber") .zipCode("zipCode") .build(); PaymentPayerPhoneRequest phone = PaymentPayerPhoneRequest.builder().areaCode("111").number("123456").build(); PaymentPayerRequest payer = PaymentPayerRequest.builder() .type("customer") .email("test_payer_9999999@testuser.com") .entityType("individual") .firstName("Test") .lastName("User") .identification(identification) .address(address) .phone(phone) .build(); PaymentAdditionalInfoRequest additionalInfo = PaymentAdditionalInfoRequest.builder().ipAddress("127.0.0.1").build(); PaymentTransactionDetailsRequest transactionDetails = PaymentTransactionDetailsRequest.builder().financialInstitution("1009").build(); return PaymentCreateRequest.builder() .payer(payer) .description("description") .transactionAmount(new BigDecimal(100)) .transactionDetails(transactionDetails) .paymentMethodId("pse") .additionalInfo(additionalInfo) .build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/payment/PaymentRefundClientIT.java ================================================ package com.mercadopago.client.payment; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.client.cardtoken.CardTokenTestClient; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.resources.CardToken; import com.mercadopago.resources.payment.Payment; import com.mercadopago.resources.payment.PaymentRefund; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import org.junit.jupiter.api.Test; /** PaymentRefundClientIT class. */ class PaymentRefundClientIT extends BaseClientIT { private final PaymentRefundClient paymentRefundClient = new PaymentRefundClient(); private final PaymentClient paymentClient = new PaymentClient(); private final CardTokenTestClient cardTokenTestClient = new CardTokenTestClient(); @Test void refundSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); PaymentRefund result = paymentRefundClient.refund(createdPayment.getId()); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); assertNotNull(result.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void refundWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); PaymentRefund result = paymentRefundClient.refund(createdPayment.getId(), buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); assertNotNull(result.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void refundPartialSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = paymentRefundClient.refund(createdPayment.getId(), amount); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); assertNotNull(result.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void refundPartialWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = paymentRefundClient.refund(createdPayment.getId(), amount, buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(CREATED, result.getResponse().getStatusCode()); assertNotNull(result.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getRefundSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); PaymentRefund createdRefund = paymentRefundClient.refund(createdPayment.getId()); PaymentRefund result = paymentRefundClient.get(createdPayment.getId(), createdRefund.getId()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertEquals(createdRefund.getId(), result.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void getRefundWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); PaymentRefund createdRefund = paymentRefundClient.refund(createdPayment.getId()); PaymentRefund result = paymentRefundClient.get( createdPayment.getId(), createdRefund.getId(), buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertEquals(createdRefund.getId(), result.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void listRefundsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); paymentRefundClient.refund(createdPayment.getId()); MPResourceList result = paymentRefundClient.list(createdPayment.getId()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertFalse(result.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void listRefundsWithRequestOptionsSuccess() { try { PaymentCreateRequest paymentCreateRequest = newPayment(); Payment createdPayment = paymentClient.create(paymentCreateRequest); paymentRefundClient.refund(createdPayment.getId()); MPResourceList result = paymentRefundClient.list(createdPayment.getId(), buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertFalse(result.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } private PaymentCreateRequest newPayment() throws MPException, MPApiException { CardToken cardToken = cardTokenTestClient.createTestCardToken("approved"); IdentificationRequest identification = IdentificationRequest.builder().type("CPF").number("19119119100").build(); PaymentPayerRequest payer = PaymentPayerRequest.builder() .email(generateTestEmail()) .firstName("Test") .lastName("User") .identification(identification) .build(); PaymentItemRequest item = PaymentItemRequest.builder() .id("1941") .title("title") .description("product") .pictureUrl("pictureUrl") .categoryId("categoryId") .quantity(1) .unitPrice(new BigDecimal("100")) .build(); List itemRequestList = new ArrayList<>(); itemRequestList.add(item); PhoneRequest phone = PhoneRequest.builder().areaCode("11").number("987654321").build(); AddressRequest address = AddressRequest.builder() .streetName("Av. das Nações Unidas") .zipCode("06233-200") .streetNumber("3003") .build(); PaymentAdditionalInfoPayerRequest additionalInfoPayer = PaymentAdditionalInfoPayerRequest.builder() .firstName("Test") .lastName("User") .phone(phone) .address(address) .registrationDate(OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC)) .build(); PaymentReceiverAddressRequest receiverAddress = PaymentReceiverAddressRequest.builder() .floor("12") .apartment("123") .zipCode("95630000") .streetNumber("15") .streetName("Av São Luiz") .build(); PaymentShipmentsRequest shipments = PaymentShipmentsRequest.builder().receiverAddress(receiverAddress).build(); PaymentAdditionalInfoRequest additionalInfo = PaymentAdditionalInfoRequest.builder() .items(itemRequestList) .payer(additionalInfoPayer) .shipments(shipments) .ipAddress("127.0.0.1") .build(); return PaymentCreateRequest.builder() .transactionAmount(new BigDecimal("100")) .token(cardToken.getId()) .installments(1) .payer(payer) .description("description") .metadata(new HashMap<>()) .paymentMethodId("master") .additionalInfo(additionalInfo) .build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/payment/PaymentRefundClientTest.java ================================================ package com.mercadopago.client.payment; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.helper.MockHelper.generateJsonElement; import static com.mercadopago.helper.MockHelper.generateJsonElementFromUriRequest; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.google.gson.JsonElement; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.resources.payment.PaymentRefund; import java.io.IOException; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.ZoneOffset; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; class PaymentRefundClientTest extends BaseClientTest { private final Long paymentTestId = 17014025134L; private final Long refundTestId = 1245678203L; private final String refundBaseJson = "refund/refund_base.json"; private final String refundListJson = "refund/refund_list.json"; private final String refundPartialJson = "refund/refund_partial.json"; private final OffsetDateTime date = OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final PaymentRefundClient client = new PaymentRefundClient(); @Test void refundSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.refund(paymentTestId); assertRefundFields(result); } @Test public void refundWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.refund(paymentTestId, buildRequestOptions()); assertRefundFields(result); } @Test void refundPartialSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = client.refund(paymentTestId, amount); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(refundPartialJson); assertEquals(requestPayloadMock, requestPayload); assertRefundFields(result); } @Test public void refundPartialWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); BigDecimal amount = new BigDecimal("50"); PaymentRefund result = client.refund(paymentTestId, amount, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(refundPartialJson); assertEquals(requestPayloadMock, requestPayload); assertRefundFields(result); } @Test public void getRefundSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.get(paymentTestId, refundTestId); assertRefundFields(result); } @Test public void getRefundWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PaymentRefund result = client.get(paymentTestId, refundTestId, buildRequestOptions()); assertRefundFields(result); } @Test public void listRefundsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList result = client.list(paymentTestId); assertEquals(OK, result.getResponse().getStatusCode()); assertNotNull(result.getResponse()); assertEquals(2, result.getResults().size()); assertRefundFields(result.getResults().get(0)); } @Test public void listRefundsWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(refundListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList result = client.list(paymentTestId, buildRequestOptions()); assertEquals(OK, result.getResponse().getStatusCode()); assertNotNull(result.getResponse()); assertEquals(2, result.getResults().size()); assertRefundFields(result.getResults().get(0)); } private void assertRefundFields(PaymentRefund refund) { assertEquals(refundTestId, refund.getId()); assertEquals(paymentTestId, refund.getPaymentId()); assertEquals(new BigDecimal("50"), refund.getAmount()); assertEquals("823549964", refund.getSource().getId()); assertEquals("Mullins Hillary", refund.getSource().getName()); assertEquals("collector", refund.getSource().getType()); assertEquals(date, refund.getDateCreated()); assertNull(refund.getUniqueSequenceNumber()); assertEquals("standard", refund.getRefundMode()); assertEquals(BigDecimal.ZERO, refund.getAdjustmentAmount()); assertEquals("approved", refund.getStatus()); assertNull(refund.getReason()); } } ================================================ FILE: src/test/java/com/mercadopago/client/paymentmethod/PaymentMethodClientIT.java ================================================ package com.mercadopago.client.paymentmethod; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.resources.paymentmethod.PaymentMethod; import org.junit.jupiter.api.Test; /** PaymentMethodClientIT class. */ class PaymentMethodClientIT extends BaseClientIT { private final PaymentMethodClient client = new PaymentMethodClient(); @Test void listSuccess() { try { MPResourceList paymentMethods = client.list(); assertNotNull(paymentMethods.getResponse()); assertEquals(OK, paymentMethods.getResponse().getStatusCode()); assertFalse(paymentMethods.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test public void listSuccessWithRequestOptions() { try { MPResourceList paymentMethods = client.list(buildRequestOptions()); assertNotNull(paymentMethods.getResponse()); assertEquals(OK, paymentMethods.getResponse().getStatusCode()); assertFalse(paymentMethods.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } } ================================================ FILE: src/test/java/com/mercadopago/client/paymentmethod/PaymentMethodClientTest.java ================================================ package com.mercadopago.client.paymentmethod; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResourceList; import com.mercadopago.resources.paymentmethod.PaymentMethod; import java.io.IOException; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; class PaymentMethodClientTest extends BaseClientTest { private final String paymentMethodBaseJson = "paymentmethod/payment_method_base.json"; private final PaymentMethodClient client = new PaymentMethodClient(); @Test void listSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentMethodBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList paymentMethods = client.list(); assertNotNull(paymentMethods.getResponse()); assertEquals(OK, paymentMethods.getResponse().getStatusCode()); assertPaymentMethodFields(paymentMethods); } @Test public void listSuccessWithRequestOptions() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentMethodBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResourceList paymentMethods = client.list(buildRequestOptions()); assertNotNull(paymentMethods.getResponse()); assertEquals(OK, paymentMethods.getResponse().getStatusCode()); assertPaymentMethodFields(paymentMethods); } private void assertPaymentMethodFields(MPResourceList paymentMethods) { String thumbnail = "https://www.mercadopago.com/org-img/MP3/API/logos/debmaster.gif"; Long accreditationTime = 1440L; List additionalInfoNeeded = new ArrayList<>(); additionalInfoNeeded.add("cardholder_name"); additionalInfoNeeded.add("cardholder_identification_type"); additionalInfoNeeded.add("cardholder_identification_number"); assertEquals("debmaster", paymentMethods.getResults().get(0).getId()); assertEquals("Mastercard Débito", paymentMethods.getResults().get(0).getName()); assertEquals("debit_card", paymentMethods.getResults().get(0).getPaymentTypeId()); assertEquals("testing", paymentMethods.getResults().get(0).getStatus()); assertEquals(thumbnail, paymentMethods.getResults().get(0).getSecureThumbnail()); assertEquals(thumbnail, paymentMethods.getResults().get(0).getThumbnail()); assertEquals("unsupported", paymentMethods.getResults().get(0).getDeferredCapture()); assertEquals(1, paymentMethods.getResults().get(0).getSettings().size()); assertEquals( "standard", paymentMethods.getResults().get(0).getSettings().get(0).getCardNumber().getValidation()); assertEquals( 16, paymentMethods.getResults().get(0).getSettings().get(0).getCardNumber().getLength()); assertEquals( "^(502121)", paymentMethods.getResults().get(0).getSettings().get(0).getBin().getPattern()); assertNull( paymentMethods.getResults().get(0).getSettings().get(0).getBin().getInstallmentsPattern()); assertNull( paymentMethods.getResults().get(0).getSettings().get(0).getBin().getExclusionPattern()); assertEquals( 3, paymentMethods.getResults().get(0).getSettings().get(0).getSecurityCode().getLength()); assertEquals( "back", paymentMethods .getResults() .get(0) .getSettings() .get(0) .getSecurityCode() .getCardLocation()); assertEquals( "mandatory", paymentMethods.getResults().get(0).getSettings().get(0).getSecurityCode().getMode()); assertEquals(3, paymentMethods.getResults().get(0).getAdditionalInfoNeeded().size()); assertTrue( paymentMethods .getResults() .get(0) .getAdditionalInfoNeeded() .containsAll(additionalInfoNeeded)); assertEquals(new BigDecimal("0.5"), paymentMethods.getResults().get(0).getMinAllowedAmount()); assertEquals(new BigDecimal("60000"), paymentMethods.getResults().get(0).getMaxAllowedAmount()); assertEquals(accreditationTime, paymentMethods.getResults().get(0).getAccreditationTime()); assertTrue(paymentMethods.getResults().get(0).getFinancialInstitutions().isEmpty()); assertTrue(paymentMethods.getResults().get(0).getProcessingModes().contains("aggregator")); } } ================================================ FILE: src/test/java/com/mercadopago/client/point/PointClientIT.java ================================================ package com.mercadopago.client.point; import static com.mercadopago.client.point.OperatingMode.PDV; import static com.mercadopago.client.point.OperatingMode.STANDALONE; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.point.PointCancelPaymentIntent; import com.mercadopago.resources.point.PointDeviceOperatingMode; import com.mercadopago.resources.point.PointDevices; import com.mercadopago.resources.point.PointPaymentIntent; import com.mercadopago.resources.point.PointPaymentIntentList; import com.mercadopago.resources.point.PointSearchPaymentIntent; import com.mercadopago.resources.point.PointStatusPaymentIntent; import java.math.BigDecimal; import java.time.LocalDate; import org.junit.jupiter.api.Test; /** PointClientIT class. */ class PointClientIT extends BaseClientIT { private final String deviceId = "GERTEC_MP35P__8701012051267123"; private final PointClient client = new PointClient(); @Test void createPaymentIntentSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request); assertNotNull(paymentIntent.getResponse()); assertEquals(CREATED, paymentIntent.getResponse().getStatusCode()); assertPaymentIntentFields(paymentIntent); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void createPaymentIntentWithRequestOptionsSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request, buildRequestOptions()); assertNotNull(paymentIntent.getResponse()); assertEquals(CREATED, paymentIntent.getResponse().getStatusCode()); assertPaymentIntentFields(paymentIntent); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getPaymentIntentListSuccess() { try { PointPaymentIntentList paymentIntentList = client.getPaymentIntentList(newPaymentIntentListRequest()); assertNotNull(paymentIntentList.getResponse()); assertEquals(OK, paymentIntentList.getResponse().getStatusCode()); assertNotNull(paymentIntentList.getEvents()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getPaymentIntentListWithRequestOptionsSuccess() { try { PointPaymentIntentList paymentIntentList = client.getPaymentIntentList(newPaymentIntentListRequest(), buildRequestOptions()); assertNotNull(paymentIntentList.getResponse()); assertEquals(OK, paymentIntentList.getResponse().getStatusCode()); assertNotNull(paymentIntentList.getEvents()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void cancelPaymentIntentSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request); PointCancelPaymentIntent cancelPaymentIntent = client.cancelPaymentIntent(deviceId, paymentIntent.getId()); assertNotNull(cancelPaymentIntent.getResponse()); assertEquals(OK, cancelPaymentIntent.getResponse().getStatusCode()); assertEquals(paymentIntent.getId(), cancelPaymentIntent.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void cancelPaymentIntentWithRequestOptionsSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request); PointCancelPaymentIntent cancelPaymentIntent = client.cancelPaymentIntent(deviceId, paymentIntent.getId(), buildRequestOptions()); assertNotNull(cancelPaymentIntent.getResponse()); assertEquals(OK, cancelPaymentIntent.getResponse().getStatusCode()); assertEquals(paymentIntent.getId(), cancelPaymentIntent.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchPaymentIntentSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request); PointSearchPaymentIntent searchPaymentIntent = client.searchPaymentIntent(paymentIntent.getId()); assertNotNull(searchPaymentIntent.getResponse()); assertEquals(OK, searchPaymentIntent.getResponse().getStatusCode()); assertEquals(paymentIntent.getId(), searchPaymentIntent.getId()); assertNotNull(searchPaymentIntent.getState()); client.cancelPaymentIntent(deviceId, paymentIntent.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchPaymentIntentWithRequestOptionsSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request); PointSearchPaymentIntent searchPaymentIntent = client.searchPaymentIntent(paymentIntent.getId(), buildRequestOptions()); assertNotNull(searchPaymentIntent.getResponse()); assertEquals(OK, searchPaymentIntent.getResponse().getStatusCode()); assertEquals(paymentIntent.getId(), searchPaymentIntent.getId()); assertNotNull(searchPaymentIntent.getState()); client.cancelPaymentIntent(deviceId, paymentIntent.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getPaymentIntentStatusSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request); PointStatusPaymentIntent paymentIntentStatus = client.getPaymentIntentStatus(paymentIntent.getId()); assertNotNull(paymentIntentStatus.getResponse()); assertEquals(OK, paymentIntentStatus.getResponse().getStatusCode()); assertEquals("OPEN", paymentIntentStatus.getStatus()); assertNotNull(paymentIntentStatus.getCreatedOn()); client.cancelPaymentIntent(deviceId, paymentIntent.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getPaymentIntentStatusWithRequestOptionsSuccess() { try { PointPaymentIntentRequest request = buildPaymentIntentRequest(); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, request); PointStatusPaymentIntent paymentIntentStatus = client.getPaymentIntentStatus(paymentIntent.getId(), buildRequestOptions()); assertNotNull(paymentIntentStatus.getResponse()); assertEquals(OK, paymentIntentStatus.getResponse().getStatusCode()); assertEquals("OPEN", paymentIntentStatus.getStatus()); assertNotNull(paymentIntentStatus.getCreatedOn()); client.cancelPaymentIntent(deviceId, paymentIntent.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getDevicesSuccess() { try { PointDevices pointDevices = client.getDevices(newSearchDevicesRequest()); assertNotNull(pointDevices.getResponse()); assertEquals(OK, pointDevices.getResponse().getStatusCode()); assertNotNull(pointDevices.getDevices()); assertNotNull(pointDevices.getPaging()); assertEquals(50, pointDevices.getPaging().getLimit()); assertEquals(0, pointDevices.getPaging().getOffset()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getDevicesWithRequestOptionsSuccess() { try { PointDevices pointDevices = client.getDevices(newSearchDevicesRequest(), buildRequestOptions()); assertNotNull(pointDevices.getResponse()); assertEquals(OK, pointDevices.getResponse().getStatusCode()); assertNotNull(pointDevices.getDevices()); assertNotNull(pointDevices.getPaging()); assertEquals(50, pointDevices.getPaging().getLimit()); assertEquals(0, pointDevices.getPaging().getOffset()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void changeDeviceOperatingModeSuccess() { try { PointDeviceOperatingModeRequest request = PointDeviceOperatingModeRequest.builder().operatingMode(STANDALONE).build(); PointDeviceOperatingMode deviceOperatingMode = client.changeDeviceOperatingMode(deviceId, request); assertNotNull(deviceOperatingMode.getResponse()); assertEquals(OK, deviceOperatingMode.getResponse().getStatusCode()); assertEquals(STANDALONE, deviceOperatingMode.getOperatingMode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void changeDeviceOperatingModeWithRequestOptionsSuccess() { try { PointDeviceOperatingModeRequest request = PointDeviceOperatingModeRequest.builder().operatingMode(PDV).build(); PointDeviceOperatingMode deviceOperatingMode = client.changeDeviceOperatingMode(deviceId, request, buildRequestOptions()); assertNotNull(deviceOperatingMode.getResponse()); assertEquals(OK, deviceOperatingMode.getResponse().getStatusCode()); assertEquals(PDV, deviceOperatingMode.getOperatingMode()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } private void assertPaymentIntentFields(PointPaymentIntent paymentIntent) { assertNotNull(paymentIntent.getId()); assertNotNull(paymentIntent.getAdditionalInfo()); assertNotNull(paymentIntent.getAdditionalInfo().getExternalReference()); assertTrue(paymentIntent.getAdditionalInfo().getPrintOnTerminal()); assertEquals(new BigDecimal("1500"), paymentIntent.getAmount()); assertEquals("your payment intent description", paymentIntent.getDescription()); assertEquals("GERTEC_MP35P__8701012051267123", paymentIntent.getDeviceId()); assertNotNull(paymentIntent.getPayment()); assertEquals(1, paymentIntent.getPayment().getInstallments()); assertEquals("seller", paymentIntent.getPayment().getInstallmentsCost()); assertEquals("credit_card", paymentIntent.getPayment().getType()); } private PointPaymentIntentRequest buildPaymentIntentRequest() { PointPaymentIntentPaymentRequest payment = PointPaymentIntentPaymentRequest.builder() .installments(1) .type("credit_card") .installmentsCost("seller") .build(); PointPaymentIntentAdditionalInfoRequest additionalInfo = PointPaymentIntentAdditionalInfoRequest.builder() .externalReference("4561ads-das4das4-das4754-das456") .printOnTerminal(true) .build(); return PointPaymentIntentRequest.builder() .amount(new BigDecimal(1500)) .description("your payment intent description") .payment(payment) .additionalInfo(additionalInfo) .build(); } private PointPaymentIntentListRequest newPaymentIntentListRequest() { LocalDate startDate = LocalDate.of(2022, 1, 1); LocalDate endDate = LocalDate.of(2022, 1, 30); return PointPaymentIntentListRequest.builder().startDate(startDate).endDate(endDate).build(); } private MPSearchRequest newSearchDevicesRequest() { return MPSearchRequest.builder().limit(50).offset(0).build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/point/PointClientTest.java ================================================ package com.mercadopago.client.point; import static com.mercadopago.client.point.OperatingMode.PDV; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.helper.MockHelper.generateJsonElement; import static com.mercadopago.helper.MockHelper.generateJsonElementFromUriRequest; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.google.gson.JsonElement; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.point.PointCancelPaymentIntent; import com.mercadopago.resources.point.PointDeviceOperatingMode; import com.mercadopago.resources.point.PointDevices; import com.mercadopago.resources.point.PointPaymentIntent; import com.mercadopago.resources.point.PointPaymentIntentList; import com.mercadopago.resources.point.PointSearchPaymentIntent; import com.mercadopago.resources.point.PointStatusPaymentIntent; import java.io.IOException; import java.math.BigDecimal; import java.time.LocalDate; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; /** PointClientTest class. */ class PointClientTest extends BaseClientTest { private final String paymentIntentJson = "point/payment_intent.json"; private final String paymentIntentListJson = "point/payment_intent_list.json"; private final String paymentIntentDeleteJson = "point/payment_intent_delete.json"; private final String paymentIntentSearchJson = "point/payment_intent_search.json"; private final String paymentIntentStatusJson = "point/payment_intent_status.json"; private final String devicesListJson = "point/devices_list.json"; private final String devicesOperatingModeJson = "point/devices_operating_mode.json"; private final String deviceId = "GERTEC_MP35P__8701012051267123"; private final String paymentIntentId = "afa5ffb4-9094-43de-8192-fb951e96ee95"; private final PointClient client = new PointClient(); @Test void createPaymentIntentSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, newPaymentIntentRequest()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentIntentJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(paymentIntent.getResponse()); assertEquals(CREATED, paymentIntent.getResponse().getStatusCode()); assertPaymentIntentFields(paymentIntent); } @Test void createPaymentIntentWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointPaymentIntent paymentIntent = client.createPaymentIntent(deviceId, newPaymentIntentRequest(), buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(paymentIntentJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(paymentIntent.getResponse()); assertEquals(CREATED, paymentIntent.getResponse().getStatusCode()); assertPaymentIntentFields(paymentIntent); } @Test void getPaymentIntentListSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointPaymentIntentList paymentIntentList = client.getPaymentIntentList(newPaymentIntentListRequest()); assertNotNull(paymentIntentList.getResponse()); assertEquals(OK, paymentIntentList.getResponse().getStatusCode()); assertPaymentIntentListFields(paymentIntentList); } @Test void getPaymentIntentListWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointPaymentIntentList paymentIntentList = client.getPaymentIntentList(newPaymentIntentListRequest(), buildRequestOptions()); assertNotNull(paymentIntentList.getResponse()); assertEquals(OK, paymentIntentList.getResponse().getStatusCode()); assertPaymentIntentListFields(paymentIntentList); } @Test void cancelPaymentIntentSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentDeleteJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointCancelPaymentIntent cancelPaymentIntent = client.cancelPaymentIntent(deviceId, paymentIntentId); assertNotNull(cancelPaymentIntent.getResponse()); assertEquals(OK, cancelPaymentIntent.getResponse().getStatusCode()); assertEquals(paymentIntentId, cancelPaymentIntent.getId()); } @Test void cancelPaymentIntentWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentDeleteJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointCancelPaymentIntent cancelPaymentIntent = client.cancelPaymentIntent(deviceId, paymentIntentId, buildRequestOptions()); assertNotNull(cancelPaymentIntent.getResponse()); assertEquals(OK, cancelPaymentIntent.getResponse().getStatusCode()); assertEquals(paymentIntentId, cancelPaymentIntent.getId()); } @Test void searchPaymentIntentSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentSearchJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointSearchPaymentIntent searchPaymentIntent = client.searchPaymentIntent(paymentIntentId); assertNotNull(searchPaymentIntent.getResponse()); assertEquals(OK, searchPaymentIntent.getResponse().getStatusCode()); assertSearchPaymentIntentFields(searchPaymentIntent); } @Test void searchPaymentIntentWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentSearchJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointSearchPaymentIntent searchPaymentIntent = client.searchPaymentIntent(paymentIntentId, buildRequestOptions()); assertNotNull(searchPaymentIntent.getResponse()); assertEquals(OK, searchPaymentIntent.getResponse().getStatusCode()); assertSearchPaymentIntentFields(searchPaymentIntent); } @Test void getPaymentIntentStatusSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentStatusJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointStatusPaymentIntent paymentIntentStatus = client.getPaymentIntentStatus(paymentIntentId); assertNotNull(paymentIntentStatus.getResponse()); assertEquals(OK, paymentIntentStatus.getResponse().getStatusCode()); assertEquals("CANCELED", paymentIntentStatus.getStatus()); assertEquals( OffsetDateTime.of(2022, 6, 27, 10, 10, 10, 0, ZoneOffset.UTC), paymentIntentStatus.getCreatedOn()); } @Test void getPaymentIntentStatusWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(paymentIntentStatusJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointStatusPaymentIntent paymentIntentStatus = client.getPaymentIntentStatus(paymentIntentId, buildRequestOptions()); assertNotNull(paymentIntentStatus.getResponse()); assertEquals(OK, paymentIntentStatus.getResponse().getStatusCode()); assertEquals("CANCELED", paymentIntentStatus.getStatus()); assertEquals( OffsetDateTime.of(2022, 6, 27, 10, 10, 10, 0, ZoneOffset.UTC), paymentIntentStatus.getCreatedOn()); } @Test void getDevicesSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(devicesListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointDevices pointDevices = client.getDevices(newSearchDevicesRequest()); assertNotNull(pointDevices.getResponse()); assertEquals(OK, pointDevices.getResponse().getStatusCode()); assertSearchDevicesFields(pointDevices); } @Test void getDevicesWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(devicesListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointDevices pointDevices = client.getDevices(newSearchDevicesRequest(), buildRequestOptions()); assertNotNull(pointDevices.getResponse()); assertEquals(OK, pointDevices.getResponse().getStatusCode()); assertSearchDevicesFields(pointDevices); } @Test void changeDeviceOperatingModeSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(devicesOperatingModeJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointDeviceOperatingModeRequest request = PointDeviceOperatingModeRequest.builder().operatingMode(PDV).build(); PointDeviceOperatingMode deviceOperatingMode = client.changeDeviceOperatingMode(deviceId, request); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(devicesOperatingModeJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(deviceOperatingMode.getResponse()); assertEquals(OK, deviceOperatingMode.getResponse().getStatusCode()); assertEquals(PDV, deviceOperatingMode.getOperatingMode()); } @Test void changeDeviceOperatingModeWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(devicesOperatingModeJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PointDeviceOperatingModeRequest request = PointDeviceOperatingModeRequest.builder().operatingMode(PDV).build(); PointDeviceOperatingMode deviceOperatingMode = client.changeDeviceOperatingMode(deviceId, request, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(devicesOperatingModeJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(deviceOperatingMode.getResponse()); assertEquals(OK, deviceOperatingMode.getResponse().getStatusCode()); assertEquals(PDV, deviceOperatingMode.getOperatingMode()); } private void assertPaymentIntentFields(PointPaymentIntent paymentIntent) { assertNotNull(paymentIntent.getAdditionalInfo()); assertEquals( "4561ads-das4das4-das4754-das456", paymentIntent.getAdditionalInfo().getExternalReference()); assertTrue(paymentIntent.getAdditionalInfo().getPrintOnTerminal()); assertEquals(new BigDecimal("1500"), paymentIntent.getAmount()); assertEquals("your payment intent description", paymentIntent.getDescription()); assertEquals("GERTEC_MP35P__8701012051267123", paymentIntent.getDeviceId()); assertEquals("68bf6839-ddb3-4825-8f4c-7eb26e68a5c3", paymentIntent.getId()); assertNotNull(paymentIntent.getPayment()); assertEquals(1, paymentIntent.getPayment().getInstallments()); assertEquals("seller", paymentIntent.getPayment().getInstallmentsCost()); assertEquals("credit_card", paymentIntent.getPayment().getType()); } private void assertPaymentIntentListFields(PointPaymentIntentList paymentIntentList) { assertFalse(paymentIntentList.getEvents().isEmpty()); assertEquals(3, paymentIntentList.getEvents().size()); assertEquals( "d2ee3a75-ca25-4bf3-9eca-f5f2d8f23bf4", paymentIntentList.getEvents().get(0).getPaymentIntentId()); assertEquals("ABANDONED", paymentIntentList.getEvents().get(0).getStatus()); assertEquals( OffsetDateTime.of(2022, 1, 24, 10, 10, 10, 0, ZoneOffset.UTC), paymentIntentList.getEvents().get(0).getCreatedOn()); assertEquals( "a16aba35-d43c-409d-b6c8-c3020797b061", paymentIntentList.getEvents().get(1).getPaymentIntentId()); assertEquals("CANCELED", paymentIntentList.getEvents().get(1).getStatus()); assertEquals( OffsetDateTime.of(2022, 1, 25, 10, 10, 10, 0, ZoneOffset.UTC), paymentIntentList.getEvents().get(1).getCreatedOn()); assertEquals( "68bf6839-ddb3-4825-8f4c-7eb26e68a5c3", paymentIntentList.getEvents().get(2).getPaymentIntentId()); assertEquals("ABANDONED", paymentIntentList.getEvents().get(2).getStatus()); assertEquals( OffsetDateTime.of(2022, 1, 26, 10, 10, 10, 0, ZoneOffset.UTC), paymentIntentList.getEvents().get(2).getCreatedOn()); } private void assertSearchPaymentIntentFields(PointSearchPaymentIntent searchPaymentIntent) { assertNotNull(searchPaymentIntent.getAdditionalInfo()); assertEquals( "4561ads-das4das4-das4754-das456", searchPaymentIntent.getAdditionalInfo().getExternalReference()); assertTrue(searchPaymentIntent.getAdditionalInfo().getPrintOnTerminal()); assertEquals(new BigDecimal("1500"), searchPaymentIntent.getAmount()); assertEquals("your payment intent description", searchPaymentIntent.getDescription()); assertEquals("GERTEC_MP35P__8701012051267123", searchPaymentIntent.getDeviceId()); assertEquals("afa5ffb4-9094-43de-8192-fb951e96ee95", searchPaymentIntent.getId()); assertNotNull(searchPaymentIntent.getPayment()); assertEquals(1, searchPaymentIntent.getPayment().getInstallments()); assertEquals("seller", searchPaymentIntent.getPayment().getInstallmentsCost()); assertEquals("credit_card", searchPaymentIntent.getPayment().getType()); assertEquals("OPEN", searchPaymentIntent.getState()); } private void assertSearchDevicesFields(PointDevices pointDevices) { assertEquals(1, pointDevices.getDevices().size()); assertEquals("GERTEC_MP35P__8701012051267123", pointDevices.getDevices().get(0).getId()); assertEquals("PDV", pointDevices.getDevices().get(0).getOperatingMode()); assertNotNull(pointDevices.getPaging()); assertEquals(1, pointDevices.getPaging().getTotal()); assertEquals(50, pointDevices.getPaging().getLimit()); assertEquals(0, pointDevices.getPaging().getOffset()); } private PointPaymentIntentRequest newPaymentIntentRequest() { PointPaymentIntentPaymentRequest payment = PointPaymentIntentPaymentRequest.builder() .installments(1) .type("credit_card") .installmentsCost("seller") .voucherType(null) .build(); PointPaymentIntentAdditionalInfoRequest additionalInfo = PointPaymentIntentAdditionalInfoRequest.builder() .externalReference("4561ads-das4das4-das4754-das456") .printOnTerminal(true) .build(); return PointPaymentIntentRequest.builder() .amount(new BigDecimal(1500)) .description("your payment intent description") .payment(payment) .additionalInfo(additionalInfo) .build(); } private PointPaymentIntentListRequest newPaymentIntentListRequest() { LocalDate startDate = LocalDate.of(2022, 1, 1); LocalDate endDate = LocalDate.of(2022, 1, 30); return PointPaymentIntentListRequest.builder().startDate(startDate).endDate(endDate).build(); } private MPSearchRequest newSearchDevicesRequest() { Map filters = new HashMap<>(); filters.put("store_id", "9999999"); filters.put("posId", 8888888); return MPSearchRequest.builder().filters(filters).limit(50).offset(0).build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/preapproval/PreapprovalClientIT.java ================================================ package com.mercadopago.client.preapproval; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.preapproval.Preapproval; import java.math.BigDecimal; import org.junit.jupiter.api.Test; /** PreapprovalClientIT class. */ class PreapprovalClientIT extends BaseClientIT { private final PreapprovalClient client = new PreapprovalClient(); @Test void getSuccess() { try { PreapprovalCreateRequest request = generatePreapprovalRequest(); Preapproval preapprovalCreated = client.create(request); Preapproval preapproval = client.get(preapprovalCreated.getId()); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertEquals(preapprovalCreated.getId(), preapproval.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getWithRequestOptionsSuccess() { try { PreapprovalCreateRequest request = generatePreapprovalRequest(); Preapproval preapprovalCreated = client.create(request); MPRequestOptions requestOptions = buildRequestOptions(); Preapproval preapproval = client.get(preapprovalCreated.getId(), requestOptions); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertEquals(preapprovalCreated.getId(), preapproval.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void createSuccess() { try { PreapprovalCreateRequest request = generatePreapprovalRequest(); Preapproval preapproval = client.create(request); assertNotNull(preapproval.getResponse()); assertEquals(CREATED, preapproval.getResponse().getStatusCode()); assertNotNull(preapproval.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void createWithRequestOptionsSuccess() { try { MPRequestOptions requestOptions = buildRequestOptions(); PreapprovalCreateRequest request = generatePreapprovalRequest(); Preapproval preapproval = client.create(request, requestOptions); assertNotNull(preapproval.getResponse()); assertEquals(CREATED, preapproval.getResponse().getStatusCode()); assertNotNull(preapproval.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void updateSuccess() { try { PreapprovalCreateRequest request = generatePreapprovalRequest(); Preapproval preapprovalCreated = client.create(request); PreapprovalUpdateRequest updateRequest = PreapprovalUpdateRequest.builder().reason("Updated reason").build(); Preapproval preapproval = client.update(preapprovalCreated.getId(), updateRequest); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertEquals(preapprovalCreated.getId(), preapproval.getId()); assertEquals("Updated reason", preapproval.getReason()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void updateWithRequestOptionsSuccess() { try { PreapprovalCreateRequest request = generatePreapprovalRequest(); Preapproval preapprovalCreated = client.create(request); MPRequestOptions requestOptions = buildRequestOptions(); PreapprovalUpdateRequest updateRequest = PreapprovalUpdateRequest.builder().reason("Updated reason").build(); Preapproval preapproval = client.update(preapprovalCreated.getId(), updateRequest, requestOptions); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertEquals(preapprovalCreated.getId(), preapproval.getId()); assertEquals("Updated reason", preapproval.getReason()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchSuccess() { try { MPSearchRequest searchRequest = MPSearchRequest.builder().offset(0).limit(2).build(); MPResultsResourcesPage preapprovalList = client.search(searchRequest); assertNotNull(preapprovalList.getResponse()); assertEquals(OK, preapprovalList.getResponse().getStatusCode()); assertFalse(preapprovalList.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchWithRequestOptionsSuccess() { try { MPRequestOptions requestOptions = buildRequestOptions(); MPSearchRequest searchRequest = MPSearchRequest.builder().offset(0).limit(2).build(); MPResultsResourcesPage preapprovalList = client.search(searchRequest, requestOptions); assertNotNull(preapprovalList.getResponse()); assertEquals(OK, preapprovalList.getResponse().getStatusCode()); assertFalse(preapprovalList.getResults().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } private PreapprovalCreateRequest generatePreapprovalRequest() { PreApprovalAutoRecurringCreateRequest autoRecurring = PreApprovalAutoRecurringCreateRequest.builder() .transactionAmount(BigDecimal.TEN) .frequency(1) .frequencyType("months") .currencyId("BRL") .build(); return PreapprovalCreateRequest.builder() .backUrl("https://www.mercadopago.com.br") .externalReference("23546246234") .reason("reason") .payerEmail("test_user_28355466@testuser.com") .autoRecurring(autoRecurring) .build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/preapproval/PreapprovalClientTest.java ================================================ package com.mercadopago.client.preapproval; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.helper.MockHelper.generateJsonElement; import static com.mercadopago.helper.MockHelper.generateJsonElementFromUriRequest; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.google.gson.JsonElement; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.preapproval.Preapproval; import java.io.IOException; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.ZoneOffset; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; class PreapprovalClientTest extends BaseClientTest { private final String preapprovalBaseJson = "preapproval/preapproval_base.json"; private final String preapprovalUpdateJson = "preapproval/preapproval_update.json"; private final String preapprovalListJson = "preapproval/preapproval_list.json"; private final String preapprovalId = "2c9380847e9b451c017ea1bd70ba0219"; private final OffsetDateTime startDate = OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final OffsetDateTime endDate = OffsetDateTime.of(2023, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final OffsetDateTime nextPaymentDate = OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final PreapprovalClient client = new PreapprovalClient(); @Test void getSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preapproval preapproval = client.get(preapprovalId); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertPreapprovalFields(preapproval, false); } @Test void getWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preapproval preapproval = client.get(preapprovalId, buildRequestOptions()); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertPreapprovalFields(preapproval, false); } @Test void createSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PreapprovalCreateRequest request = buildPreapprovalCreateRequest(); Preapproval preapproval = client.create(request); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preapprovalBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preapproval.getResponse()); assertEquals(CREATED, preapproval.getResponse().getStatusCode()); assertPreapprovalFields(preapproval, false); } @Test void createWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PreapprovalCreateRequest request = buildPreapprovalCreateRequest(); Preapproval preapproval = client.create(request, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preapprovalBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preapproval.getResponse()); assertEquals(CREATED, preapproval.getResponse().getStatusCode()); assertPreapprovalFields(preapproval, false); } @Test void updateSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalUpdateJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PreapprovalUpdateRequest updateRequest = PreapprovalUpdateRequest.builder().reason("Updated reason").build(); Preapproval preapproval = client.update(preapprovalId, updateRequest); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preapprovalUpdateJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertPreapprovalFields(preapproval, true); } @Test void updateWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalUpdateJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); PreapprovalUpdateRequest updateRequest = PreapprovalUpdateRequest.builder().reason("Updated reason").build(); Preapproval preapproval = client.update(preapprovalId, updateRequest, buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preapprovalUpdateJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preapproval.getResponse()); assertEquals(OK, preapproval.getResponse().getStatusCode()); assertPreapprovalFields(preapproval, true); } @Test void searchSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest searchRequest = MPSearchRequest.builder().offset(0).limit(2).build(); MPResultsResourcesPage preapprovalList = client.search(searchRequest); assertNotNull(preapprovalList.getResponse()); assertEquals(OK, preapprovalList.getResponse().getStatusCode()); assertEquals(7, preapprovalList.getPaging().getTotal()); assertEquals(2, preapprovalList.getPaging().getLimit()); assertEquals(0, preapprovalList.getPaging().getOffset()); assertEquals(2, preapprovalList.getResults().size()); assertNotNull(preapprovalList.getResults().get(0)); assertNotNull(preapprovalList.getResults().get(1)); } @Test void searchWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preapprovalListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest searchRequest = MPSearchRequest.builder().offset(0).limit(2).build(); MPResultsResourcesPage preapprovalList = client.search(searchRequest, buildRequestOptions()); assertNotNull(preapprovalList.getResponse()); assertEquals(OK, preapprovalList.getResponse().getStatusCode()); assertEquals(7, preapprovalList.getPaging().getTotal()); assertEquals(2, preapprovalList.getPaging().getLimit()); assertEquals(0, preapprovalList.getPaging().getOffset()); assertEquals(2, preapprovalList.getResults().size()); assertNotNull(preapprovalList.getResults().get(0)); assertNotNull(preapprovalList.getResults().get(1)); } private void assertPreapprovalFields(Preapproval preapproval, boolean updated) { String reason = updated ? "Updated reason" : "reason"; assertEquals(preapprovalId, preapproval.getId()); assertEquals(766790067L, preapproval.getPayerId()); assertTrue(preapproval.getPayerEmail().isEmpty()); assertEquals("https://www.mercadopago.com.br", preapproval.getBackUrl()); assertEquals(823549964L, preapproval.getCollectorId()); assertEquals(6245132082630004L, preapproval.getApplicationId()); assertEquals("pending", preapproval.getStatus()); assertEquals(reason, preapproval.getReason()); assertEquals("23546246234", preapproval.getExternalReference()); assertEquals(startDate, preapproval.getDateCreated()); assertEquals(nextPaymentDate, preapproval.getNextPaymentDate()); assertEquals( "https://www.mercadopago.com.br/subscriptions/checkout?preapproval_id=2c9380847e9b451c017ea1bd70ba0219", preapproval.getInitPoint()); assertNull(preapproval.getPaymentMethodId()); assertEquals(1, preapproval.getAutoRecurring().getFrequency()); assertEquals("months", preapproval.getAutoRecurring().getFrequencyType()); assertEquals(new BigDecimal("10.00"), preapproval.getAutoRecurring().getTransactionAmount()); assertEquals("BRL", preapproval.getAutoRecurring().getCurrencyId()); assertEquals(startDate, preapproval.getAutoRecurring().getStartDate()); assertEquals(endDate, preapproval.getAutoRecurring().getEndDate()); } private PreapprovalCreateRequest buildPreapprovalCreateRequest() { PreApprovalAutoRecurringCreateRequest autoRecurring = PreApprovalAutoRecurringCreateRequest.builder() .transactionAmount(BigDecimal.TEN) .frequency(1) .frequencyType("months") .currencyId("BRL") .startDate(startDate) .endDate(endDate) .build(); return PreapprovalCreateRequest.builder() .backUrl("https://www.mercadopago.com.br") .externalReference("23546246234") .reason("reason") .payerEmail("test_user_28355466@testuser.com") .autoRecurring(autoRecurring) .build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/preference/PreferenceClientIT.java ================================================ package com.mercadopago.client.preference; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.core.MPRequestOptions; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.Headers; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.preference.Preference; import com.mercadopago.resources.preference.PreferenceSearch; import java.math.BigDecimal; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.Test; /** PreferenceClientIT class. */ class PreferenceClientIT extends BaseClientIT { private final PreferenceClient client = new PreferenceClient(); @Test void getSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = client.create(preferenceRequest); Preference preference = client.get(createdPreference.getId()); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertEquals(createdPreference.getId(), preference.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getWithRequestOptionsSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = client.create(preferenceRequest); Preference preference = client.get(createdPreference.getId(), buildRequestOptions()); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertEquals(createdPreference.getId(), preference.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void createSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference preference = client.create(preferenceRequest); assertNotNull(preference.getResponse()); assertEquals(CREATED, preference.getResponse().getStatusCode()); assertNotNull(preference.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void createWithRequestOptionsSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); String idempotency = UUID.randomUUID().toString(); Map idempotencyKey = new HashMap<>(); idempotencyKey.put(Headers.IDEMPOTENCY_KEY, idempotency); MPRequestOptions mpRequestOptions = MPRequestOptions .builder() .customHeaders(idempotencyKey) .build(); Preference preference = client.create(preferenceRequest, mpRequestOptions); assertNotNull(preference.getResponse()); assertEquals(CREATED, preference.getResponse().getStatusCode()); assertNotNull(preference.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void updateSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = client.create(preferenceRequest); Preference preference = client.update(createdPreference.getId(), buildUpdatePreferenceRequest()); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertEquals(createdPreference.getId(), preference.getId()); assertEquals("Updated Store", preference.getStatementDescriptor()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void updateWithRequestOptionsSuccess() { try { PreferenceRequest preferenceRequest = buildPreferenceRequest(); Preference createdPreference = client.create(preferenceRequest); Preference preference = client.update( createdPreference.getId(), buildUpdatePreferenceRequest(), buildRequestOptions()); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertEquals(createdPreference.getId(), preference.getId()); assertEquals("Updated Store", preference.getStatementDescriptor()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchSuccess() { try { MPSearchRequest searchRequest = MPSearchRequest.builder().limit(2).offset(0).build(); MPElementsResourcesPage result = client.search(searchRequest); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertFalse(result.getElements().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void searchWithRequestOptionsSuccess() { try { MPSearchRequest searchRequest = MPSearchRequest.builder().limit(2).offset(0).build(); MPElementsResourcesPage result = client.search(searchRequest, buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertFalse(result.getElements().isEmpty()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } private PreferenceRequest buildPreferenceRequest() { PreferenceItemRequest itemRequest = PreferenceItemRequest.builder() .id("1234") .title("Games") .description("PS5") .pictureUrl("http://picture.com/PS5") .categoryId("games") .quantity(2) .currencyId("BRL") .unitPrice(new BigDecimal("4000")) .build(); List items = new ArrayList<>(); items.add(itemRequest); List excludedPaymentTypes = new ArrayList<>(); excludedPaymentTypes.add(PreferencePaymentTypeRequest.builder().id("ticket").build()); List excludedPaymentMethods = new ArrayList<>(); excludedPaymentMethods.add(PreferencePaymentMethodRequest.builder().id("").build()); return PreferenceRequest.builder() .additionalInfo("Discount: 12.00") .autoReturn("all") .backUrls( PreferenceBackUrlsRequest.builder() .success("https://test.com/success") .failure("https://test.com/failure") .pending("https://test.com/pending") .build()) .binaryMode(true) .expires(false) .externalReference("1643827245") .items(items) .marketplace("marketplace") .marketplaceFee(new BigDecimal("5")) .notificationUrl("http://notificationurl.com") .operationType("regular_payment") .payer( PreferencePayerRequest.builder() .name("Test") .surname("User") .email(generateTestEmail()) .phone(PhoneRequest.builder().areaCode("11").number("4444-4444").build()) .identification( IdentificationRequest.builder().type("CPF").number("19119119100").build()) .address( AddressRequest.builder() .zipCode("06233200") .streetName("Street") .streetNumber("123") .build()) .build()) .paymentMethods( PreferencePaymentMethodsRequest.builder() .defaultPaymentMethodId("master") .excludedPaymentTypes(excludedPaymentTypes) .excludedPaymentMethods(excludedPaymentMethods) .installments(5) .defaultInstallments(1) .build()) .shipments( PreferenceShipmentsRequest.builder() .mode("custom") .localPickup(false) .dimensions("10x10x20,500") .cost(BigDecimal.TEN) .receiverAddress( PreferenceReceiverAddressRequest.builder() .zipCode("06000000") .streetNumber("123") .streetName("Street") .floor("12") .apartment("120A") .build()) .build()) .statementDescriptor("Test Store") .build(); } private PreferenceRequest buildUpdatePreferenceRequest() { return PreferenceRequest.builder().statementDescriptor("Updated Store").build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/preference/PreferenceClientTest.java ================================================ package com.mercadopago.client.preference; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.helper.MockHelper.generateJsonElement; import static com.mercadopago.helper.MockHelper.generateJsonElementFromUriRequest; import static com.mercadopago.net.HttpStatus.CREATED; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.google.gson.JsonElement; import com.mercadopago.BaseClientTest; import com.mercadopago.client.common.AddressRequest; import com.mercadopago.client.common.IdentificationRequest; import com.mercadopago.client.common.PhoneRequest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPSearchRequest; import com.mercadopago.resources.preference.Preference; import com.mercadopago.resources.preference.PreferenceSearch; import java.io.IOException; import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.ZoneOffset; import java.util.ArrayList; import java.util.List; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; class PreferenceClientTest extends BaseClientTest { private final String preferenceBaseJson = "preference/preference_base.json"; private final String preferenceUpdatedJson = "preference/preference_updated.json"; private final String preferenceListJson = "preference/preference_list.json"; private final String preferenceTestId = "823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8"; private final OffsetDateTime expirationDateFrom = OffsetDateTime.of(2022, 1, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final OffsetDateTime expirationDateTo = OffsetDateTime.of(2022, 2, 10, 10, 10, 10, 0, ZoneOffset.UTC); private final PreferenceClient client = new PreferenceClient(); @Test void getSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preference preference = client.get(preferenceTestId); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertPreferenceFields(preference); } @Test void getWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceBaseJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preference preference = client.get(preferenceTestId, buildRequestOptions()); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertPreferenceFields(preference); } @Test void createSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preference preference = client.create(newPreference()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preferenceBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preference.getResponse()); assertEquals(CREATED, preference.getResponse().getStatusCode()); assertPreferenceFields(preference); } @Test void createWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceBaseJson, CREATED); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preference preference = client.create(newPreference(), buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preferenceBaseJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preference.getResponse()); assertEquals(CREATED, preference.getResponse().getStatusCode()); assertPreferenceFields(preference); } @Test void updateSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceUpdatedJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preference preference = client.update(preferenceTestId, updatedPreference()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preferenceUpdatedJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertEquals(preferenceTestId, preference.getId()); assertEquals("Updated Store", preference.getStatementDescriptor()); } @Test void updateWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceUpdatedJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); Preference preference = client.update(preferenceTestId, updatedPreference(), buildRequestOptions()); JsonElement requestPayload = generateJsonElementFromUriRequest(HTTP_CLIENT_MOCK.getRequestPayload()); JsonElement requestPayloadMock = generateJsonElement(preferenceUpdatedJson); assertEquals(requestPayloadMock, requestPayload); assertNotNull(preference.getResponse()); assertEquals(OK, preference.getResponse().getStatusCode()); assertEquals(preferenceTestId, preference.getId()); assertEquals("Updated Store", preference.getStatementDescriptor()); } @Test void searchSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(2).offset(0).build(); MPElementsResourcesPage result = client.search(searchRequest); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertPreferenceSearchFields(result.getElements().get(0)); } @Test void searchWithRequestOptionsSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = generateHttpResponseFromFile(preferenceListJson, OK); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPSearchRequest searchRequest = MPSearchRequest.builder().limit(2).offset(0).build(); MPElementsResourcesPage result = client.search(searchRequest, buildRequestOptions()); assertNotNull(result.getResponse()); assertEquals(OK, result.getResponse().getStatusCode()); assertPreferenceSearchFields(result.getElements().get(0)); } private void assertPreferenceFields(Preference preference) { assertEquals("Discount: 12.00", preference.getAdditionalInfo()); assertEquals("all", preference.getAutoReturn()); assertEquals("http://test.com/failure", preference.getBackUrls().getFailure()); assertEquals("http://test.com/pending", preference.getBackUrls().getPending()); assertEquals("http://test.com/success", preference.getBackUrls().getSuccess()); assertTrue(preference.getBinaryMode()); assertEquals("6245132082630004", preference.getClientId()); assertEquals(823549964L, preference.getCollectorId()); assertEquals(expirationDateFrom, preference.getDateCreated()); assertEquals(expirationDateTo, preference.getDateOfExpiration()); assertEquals(expirationDateFrom, preference.getExpirationDateFrom()); assertEquals(expirationDateTo, preference.getExpirationDateTo()); assertFalse(preference.getExpires()); assertEquals("1643827245", preference.getExternalReference()); assertEquals(preferenceTestId, preference.getId()); assertEquals( "https://www.mercadopago.com.br/checkout/v1/redirect?pref_id=823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", preference.getInitPoint()); assertEquals("1234", preference.getItems().get(0).getId()); assertEquals("games", preference.getItems().get(0).getCategoryId()); assertEquals("BRL", preference.getItems().get(0).getCurrencyId()); assertEquals("PS5", preference.getItems().get(0).getDescription()); assertEquals("http://picture.com/PS5", preference.getItems().get(0).getPictureUrl()); assertEquals("Games", preference.getItems().get(0).getTitle()); assertEquals(2, preference.getItems().get(0).getQuantity()); assertEquals(new BigDecimal("4000"), preference.getItems().get(0).getUnitPrice()); assertEquals("NONE", preference.getMarketplace()); assertEquals(new BigDecimal("5"), preference.getMarketplaceFee()); assertTrue(preference.getMetadata().isEmpty()); assertEquals("http://notificationurl.com", preference.getNotificationUrl()); assertEquals("regular_payment", preference.getOperationType()); assertEquals("11", preference.getPayer().getPhone().getAreaCode()); assertEquals("06233200", preference.getPayer().getAddress().getZipCode()); assertEquals("Street", preference.getPayer().getAddress().getStreetName()); assertEquals("123", preference.getPayer().getAddress().getStreetNumber()); assertEquals("test_user_64585784@testuser.com", preference.getPayer().getEmail()); assertEquals("19119119100", preference.getPayer().getIdentification().getNumber()); assertEquals("CPF", preference.getPayer().getIdentification().getType()); assertEquals("Test", preference.getPayer().getName()); assertEquals("User", preference.getPayer().getSurname()); assertNull(preference.getPayer().getDateCreated()); assertNull(preference.getPayer().getLastPurchase()); assertEquals("master", preference.getPaymentMethods().getDefaultPaymentMethodId()); assertEquals("", preference.getPaymentMethods().getExcludedPaymentMethods().get(0).getId()); assertEquals("ticket", preference.getPaymentMethods().getExcludedPaymentTypes().get(0).getId()); assertEquals(5, preference.getPaymentMethods().getInstallments()); assertEquals(1, preference.getPaymentMethods().getDefaultInstallments()); assertNull(preference.getProcessingModes()); assertEquals( "https://sandbox.mercadopago.com.br/checkout/v1/redirect?pref_id=823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", preference.getSandboxInitPoint()); assertEquals("custom", preference.getShipments().getMode()); assertNull(preference.getShipments().getDefaultShippingMethod()); assertEquals(BigDecimal.TEN, preference.getShipments().getCost()); assertEquals("Street", preference.getShipments().getReceiverAddress().getStreetName()); assertEquals("06000000", preference.getShipments().getReceiverAddress().getZipCode()); assertEquals("123", preference.getShipments().getReceiverAddress().getStreetNumber()); assertEquals("12", preference.getShipments().getReceiverAddress().getFloor()); assertEquals("120A", preference.getShipments().getReceiverAddress().getApartment()); assertNull(preference.getShipments().getReceiverAddress().getCityName()); assertNull(preference.getShipments().getReceiverAddress().getStateName()); assertNull(preference.getShipments().getReceiverAddress().getCountryName()); assertEquals("Test Store", preference.getStatementDescriptor()); } private void assertPreferenceSearchFields(PreferenceSearch preference) { assertEquals(preferenceTestId, preference.getId()); assertEquals("6245132082630004", preference.getClientId()); assertEquals(823549964L, preference.getCollectorId()); assertEquals(expirationDateFrom, preference.getDateCreated()); assertEquals(expirationDateFrom, preference.getExpirationDateFrom()); assertEquals(expirationDateTo, preference.getExpirationDateTo()); assertEquals(expirationDateFrom, preference.getLastUpdated()); assertFalse(preference.getExpires()); assertEquals("1643827245", preference.getExternalReference()); assertEquals("Games", preference.getItems().get(0)); assertFalse(preference.getLiveMode()); assertEquals("NONE", preference.getMarketplace()); assertEquals("regular_payment", preference.getOperationType()); assertEquals("test_user_64585784@testuser.com", preference.getPayerEmail()); assertNull(preference.getPayerId()); assertEquals("", preference.getPlatformId()); assertNull(preference.getProcessingModes()); assertEquals("", preference.getProductId()); assertEquals("", preference.getPurpose()); assertEquals("MLB", preference.getSiteId()); assertEquals(0, preference.getSponsorId()); assertEquals("custom", preference.getShippingMode()); } private PreferenceRequest newPreference() { PreferenceItemRequest itemRequest = PreferenceItemRequest.builder() .id("1234") .title("Games") .description("PS5") .pictureUrl("http://picture.com/PS5") .categoryId("games") .quantity(2) .currencyId("BRL") .unitPrice(new BigDecimal("4000")) .build(); List items = new ArrayList<>(); items.add(itemRequest); List excludedPaymentTypes = new ArrayList<>(); excludedPaymentTypes.add(PreferencePaymentTypeRequest.builder().id("ticket").build()); List excludedPaymentMethods = new ArrayList<>(); excludedPaymentMethods.add(PreferencePaymentMethodRequest.builder().id("").build()); return PreferenceRequest.builder() .additionalInfo("Discount: 12.00") .autoReturn("all") .backUrls( PreferenceBackUrlsRequest.builder() .success("http://test.com/success") .failure("http://test.com/failure") .pending("http://test.com/pending") .build()) .binaryMode(true) .dateOfExpiration(expirationDateTo) .expirationDateFrom(expirationDateFrom) .expirationDateTo(expirationDateTo) .expires(false) .externalReference("1643827245") .items(items) .marketplace("marketplace") .marketplaceFee(new BigDecimal("5")) .notificationUrl("http://notificationurl.com") .operationType("regular_payment") .payer( PreferencePayerRequest.builder() .name("Test") .surname("User") .email("test_user_64585784@testuser.com") .phone(PhoneRequest.builder().areaCode("11").number("4444-4444").build()) .identification( IdentificationRequest.builder().type("CPF").number("19119119100").build()) .address( AddressRequest.builder() .zipCode("06233200") .streetName("Street") .streetNumber("123") .build()) .build()) .paymentMethods( PreferencePaymentMethodsRequest.builder() .defaultPaymentMethodId("master") .excludedPaymentTypes(excludedPaymentTypes) .excludedPaymentMethods(excludedPaymentMethods) .installments(5) .defaultInstallments(1) .build()) .shipments( PreferenceShipmentsRequest.builder() .mode("custom") .localPickup(false) .dimensions("10x10x20,500") .cost(BigDecimal.TEN) .receiverAddress( PreferenceReceiverAddressRequest.builder() .zipCode("06000000") .streetNumber("123") .streetName("Street") .floor("12") .apartment("120A") .build()) .build()) .statementDescriptor("Test Store") .build(); } private PreferenceRequest updatedPreference() { return PreferenceRequest.builder().statementDescriptor("Updated Store").build(); } } ================================================ FILE: src/test/java/com/mercadopago/client/user/UserClientIT.java ================================================ package com.mercadopago.client.user; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; import com.mercadopago.BaseClientIT; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.resources.user.User; import org.junit.jupiter.api.Test; /** UserClientIT class. */ class UserClientIT extends BaseClientIT { private final UserClient client = new UserClient(); @Test void getUserSuccess() { try { User user = client.get(); assertNotNull(user.getResponse()); assertEquals(OK, user.getResponse().getStatusCode()); assertNotNull(user.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } @Test void getUserWithOptionsSuccess() { try { User user = client.get(buildRequestOptions()); assertNotNull(user.getResponse()); assertEquals(OK, user.getResponse().getStatusCode()); assertNotNull(user.getId()); } catch (MPApiException mpApiException) { fail(mpApiException.getApiResponse().getContent()); } catch (MPException mpException) { fail(mpException.getMessage()); } } } ================================================ FILE: src/test/java/com/mercadopago/client/user/UserClientTest.java ================================================ package com.mercadopago.client.user; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import com.mercadopago.helper.MockHelper; import com.mercadopago.net.HttpStatus; import com.mercadopago.resources.user.User; import java.io.IOException; import org.apache.http.HttpHeaders; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; class UserClientTest extends BaseClientTest { @Test void getUserSuccess() throws IOException, MPException, MPApiException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/user/user_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); User user = new UserClient().get(); assertNotNull(user); assertUserFields(user); } @Test void getUserWithOptionsSuccess() throws MPException, MPApiException, IOException { HttpResponse httpResponse = MockHelper.generateHttpResponseFromFile("/user/user_base.json", HttpStatus.OK); httpResponse.setHeader(HttpHeaders.CONTENT_TYPE, APPLICATION_JSON); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); User user = new UserClient().get(buildRequestOptions()); assertNotNull(user); assertUserFields(user); } private void assertUserFields(User user) { assertEquals(539675046, user.getId()); assertEquals("TETE7689213", user.getNickname()); assertEquals("Test", user.getFirstName()); assertEquals("Test", user.getLastName()); assertEquals("test_user_3851037@testuser.com", user.getEmail()); assertEquals("MLB", user.getSiteId()); assertEquals("BR", user.getCountryId()); assertNotNull(user.getResponse().getContent()); assertEquals(HttpStatus.OK, user.getResponse().getStatusCode()); assertEquals(1, user.getResponse().getHeaders().size()); } } ================================================ FILE: src/test/java/com/mercadopago/helper/HttpStatusCode.java ================================================ package com.mercadopago.helper; /** HttpStatusCode class. */ public class HttpStatusCode { public static final int HTTP_STATUS_OK = 200; public static final int HTTP_STATUS_CREATED = 201; public static final int HTTP_STATUS_BAD_REQUEST = 400; } ================================================ FILE: src/test/java/com/mercadopago/helper/MockHelper.java ================================================ package com.mercadopago.helper; import static com.mercadopago.helper.HttpStatusCode.HTTP_STATUS_BAD_REQUEST; import static com.mercadopago.helper.HttpStatusCode.HTTP_STATUS_CREATED; import static com.mercadopago.helper.HttpStatusCode.HTTP_STATUS_OK; import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.mercadopago.MercadoPagoConfig; import com.mercadopago.exceptions.MPException; import com.mercadopago.net.Headers; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.io.IOUtils; import org.apache.commons.io.output.ByteArrayOutputStream; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpResponse; import org.apache.http.HttpVersion; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.BasicHttpEntity; import org.apache.http.message.BasicHttpResponse; import org.apache.http.message.BasicStatusLine; /** MockHelper class. */ public class MockHelper { private static final String MOCKS_RESPONSE_PATH = "./src/test/java/com/mercadopago/resources/mocks/response/"; private static final String MOCKS_REQUEST_PATH = "./src/test/java/com/mercadopago/resources/mocks/request/"; private static final Map REASON_PHRASE = new HashMap<>(); static { REASON_PHRASE.put(HTTP_STATUS_OK, "Ok"); REASON_PHRASE.put(HTTP_STATUS_CREATED, "Created"); REASON_PHRASE.put(HTTP_STATUS_BAD_REQUEST, "Bad Request"); } /** * Generates a http response from file. * * @param mockFile mock file * @param statusCode status code * @return http response * @throws IOException exception */ public static HttpResponse generateHttpResponseFromFile(String mockFile, int statusCode) throws IOException { String payload = readResponseFile(mockFile); return generateHttpResponseFromString(payload, statusCode); } /** * Generates a http response only with status code. * * @param statusCode status code * @return http response */ public static HttpResponse generateHttpResponse(int statusCode) { return new BasicHttpResponse( new BasicStatusLine(HttpVersion.HTTP_1_1, statusCode, REASON_PHRASE.get(statusCode))); } /** * Generates a http response from string. * * @param response response * @param statusCode statusCode * @return http response */ public static HttpResponse generateHttpResponseFromString(String response, int statusCode) { HttpResponse httpResponse = new BasicHttpResponse( new BasicStatusLine(HttpVersion.HTTP_1_1, statusCode, REASON_PHRASE.get(statusCode))); BasicHttpEntity entity = new BasicHttpEntity(); entity.setContent(new ByteArrayInputStream(response.getBytes())); httpResponse.setEntity(entity); return httpResponse; } /** * Generate json element. * * @param mockFile mockFile * @return json element * @throws IOException exception */ public static JsonElement generateJsonElement(String mockFile) throws IOException { String payload = readRequestFile(mockFile); Gson gson = new Gson(); return gson.fromJson(payload, JsonElement.class); } public static boolean areHeadersValid(Header[] headers, String method) { return hasMandatoryHeaders(headers, method) && haveMandatoryHeadersCorrectValues(headers); } private static boolean hasMandatoryHeaders(Header[] headers, String method) { List mandatoryHeaders = new ArrayList<>(); mandatoryHeaders.add(Headers.AUTHORIZATION); mandatoryHeaders.add(Headers.USER_AGENT); mandatoryHeaders.add(Headers.PRODUCT_ID); mandatoryHeaders.add(Headers.TRACKING_ID); if ("POST".equals(method) || "PUT".equals(method)) { mandatoryHeaders.add(Headers.CONTENT_TYPE); } if ("POST".equals(method)) { mandatoryHeaders.add(Headers.IDEMPOTENCY_KEY); } for (String mandatoryHeader : mandatoryHeaders) { if (Arrays.stream(headers).noneMatch(header -> header.getName().equals(mandatoryHeader))) { return false; } } return true; } private static boolean haveMandatoryHeadersCorrectValues(Header[] headers) { for (Header header : headers) { if (Headers.AUTHORIZATION.equals(header.getName()) && !header.getValue().startsWith("Bearer")) { return false; } if (Headers.USER_AGENT.equals(header.getName()) && !String.format("MercadoPago Java SDK/%s", MercadoPagoConfig.CURRENT_VERSION) .equals(header.getValue())) { return false; } if (Headers.PRODUCT_ID.equals(header.getName()) && !MercadoPagoConfig.PRODUCT_ID.equals(header.getValue())) { return false; } if (Headers.TRACKING_ID.equals(header.getName()) && !MercadoPagoConfig.TRACKING_ID.equals(header.getValue())) { return false; } if (Headers.CONTENT_TYPE.equals(header.getName()) && !"application/json; charset=UTF-8".equals(header.getValue())) { return false; } } return true; } /** * Generate json element from uri request. * * @param httpUriRequest httpUriRequest * @return json element * @throws IOException exception */ public static JsonElement generateJsonElementFromUriRequest(HttpUriRequest httpUriRequest) throws IOException { String method = httpUriRequest.getMethod(); if ("POST".equals(method) || "PUT".equals(method) || "PATCH".equals(method)) { HttpEntityEnclosingRequestBase requestBase = (HttpEntityEnclosingRequestBase) httpUriRequest; if (requestBase.getEntity() != null) { InputStream content = requestBase.getEntity().getContent(); return parseJson(content); } } return null; } public static String readRequestFile(String mockFile) throws IOException { return readFile(mockFile, MOCKS_REQUEST_PATH); } public static String readResponseFile(String mockFile) throws IOException { return readFile(mockFile, MOCKS_RESPONSE_PATH); } /** * Read file contents and convert them to string. * * @param mockFile the mock file to be read * @param path path to file * @return string contents of file * @throws IOException problem reading file */ public static String readFile(String mockFile, String path) throws IOException { File file = new File(StringUtils.join(path, mockFile)); if (!file.exists()) { throw new IllegalStateException("Error loading mocks."); } InputStream is = Files.newInputStream(Paths.get(String.valueOf(file))); return IOUtils.toString(is, StandardCharsets.UTF_8); } private static JsonElement parseJson(InputStream content) { String requestPayload = null; try { requestPayload = inputStreamToString(content); } catch (MPException e) { e.printStackTrace(); } assert requestPayload != null; return new JsonParser().parse(requestPayload); } private static String inputStreamToString(InputStream is) throws MPException { String value = ""; if (is != null) { try { ByteArrayOutputStream result = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int length; while ((length = is.read(buffer)) != -1) { result.write(buffer, 0, length); } value = result.toString("UTF-8"); } catch (Exception ex) { throw new MPException(ex); } } return value; } } ================================================ FILE: src/test/java/com/mercadopago/mock/HttpClientMock.java ================================================ package com.mercadopago.mock; import java.io.IOException; import lombok.Getter; import org.apache.http.HttpHost; import org.apache.http.HttpRequest; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.conn.ClientConnectionManager; import org.apache.http.params.HttpParams; import org.apache.http.protocol.HttpContext; import org.mockito.Mockito; /** HttpClientMock class. */ @Getter public class HttpClientMock implements HttpClient { private final HttpClient httpClient; private HttpUriRequest requestPayload; public HttpClientMock() { this.httpClient = Mockito.mock(HttpClient.class); } @Override public HttpParams getParams() { return null; } @Override public ClientConnectionManager getConnectionManager() { return null; } @Override public HttpResponse execute(HttpUriRequest httpUriRequest) throws IOException { return null; } @Override public HttpResponse execute(HttpUriRequest httpUriRequest, HttpContext httpContext) throws IOException { this.requestPayload = httpUriRequest; return httpClient.execute(httpUriRequest, httpContext); } @Override public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest) throws IOException { return null; } @Override public HttpResponse execute(HttpHost httpHost, HttpRequest httpRequest, HttpContext httpContext) throws IOException { return null; } @Override public T execute(HttpUriRequest httpUriRequest, ResponseHandler responseHandler) throws IOException { return null; } @Override public T execute( HttpUriRequest httpUriRequest, ResponseHandler responseHandler, HttpContext httpContext) throws IOException { return null; } @Override public T execute( HttpHost httpHost, HttpRequest httpRequest, ResponseHandler responseHandler) throws IOException { return null; } @Override public T execute( HttpHost httpHost, HttpRequest httpRequest, ResponseHandler responseHandler, HttpContext httpContext) throws IOException { return null; } } ================================================ FILE: src/test/java/com/mercadopago/mock/HttpRequestMatcher.java ================================================ package com.mercadopago.mock; import org.apache.http.client.methods.HttpRequestBase; import org.mockito.ArgumentMatcher; public class HttpRequestMatcher implements ArgumentMatcher { private final HttpRequestBase httpRequest; public HttpRequestMatcher(HttpRequestBase httpRequest) { this.httpRequest = httpRequest; } @Override public boolean matches(HttpRequestBase other) { return other != null && httpRequest.getURI().compareTo(other.getURI()) == 0; } } ================================================ FILE: src/test/java/com/mercadopago/mock/MPDefaultHttpClientMock.java ================================================ package com.mercadopago.mock; import com.mercadopago.net.MPDefaultHttpClient; import org.apache.http.client.HttpClient; /** MPDefaultHttpClientMock class. */ public class MPDefaultHttpClientMock extends MPDefaultHttpClient { /** * MPDefaultHttpClientMock constructor. * * @param httpClientMock httpClientMock */ public MPDefaultHttpClientMock(HttpClient httpClientMock) { super(httpClientMock); } } ================================================ FILE: src/test/java/com/mercadopago/net/MPDefaultHttpClientTest.java ================================================ package com.mercadopago.net; import static com.mercadopago.helper.MockHelper.generateHttpResponseFromFile; import static com.mercadopago.net.HttpStatus.INTERNAL_SERVER_ERROR; import static com.mercadopago.net.HttpStatus.OK; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.doThrow; import com.mercadopago.BaseClientTest; import com.mercadopago.exceptions.MPApiException; import com.mercadopago.exceptions.MPException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import org.apache.http.HttpResponse; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.protocol.HttpContext; import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.any; class MPDefaultHttpClientTest extends BaseClientTest { private final String responseGenericSuccessJson = "/response_generic_success.json"; private MPDefaultHttpClient mpDefaultHttpClient; @Test void createDefaultHttpClientSuccess() { mpDefaultHttpClient = new MPDefaultHttpClient(); assertNotNull(mpDefaultHttpClient); } @Test void sendSuccess() throws MPException, MPApiException, IOException { mpDefaultHttpClient = new MPDefaultHttpClient(HTTP_CLIENT); Map headers = new HashMap<>(); headers.put("x-test", "test"); MPRequest request = MPRequest.builder().method(HttpMethod.GET).uri("http://test.com").headers(headers).build(); HttpResponse httpResponse = generateHttpResponseFromFile(responseGenericSuccessJson, OK); httpResponse.setHeader("x-test", "test"); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResponse response = mpDefaultHttpClient.send(request); assertNotNull(response); assertEquals(OK, response.getStatusCode()); assertEquals("{\n" + " \"success\": true\n" + "}", response.getContent()); assertEquals("test", response.getHeaders().get("x-test").get(0)); } @Test void sendWithCustomOptionsSuccess() throws MPException, MPApiException, IOException { mpDefaultHttpClient = new MPDefaultHttpClient(HTTP_CLIENT); Map headers = new HashMap<>(); headers.put("x-test", "test"); int customTimeout = 2000; MPRequest request = MPRequest.builder() .method(HttpMethod.GET) .uri("http://test.com") .headers(headers) .socketTimeout(customTimeout) .connectionRequestTimeout(customTimeout) .connectionTimeout(customTimeout) .build(); HttpResponse httpResponse = generateHttpResponseFromFile(responseGenericSuccessJson, OK); httpResponse.setHeader("x-test", "test"); doReturn(httpResponse) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); MPResponse response = mpDefaultHttpClient.send(request); assertNotNull(response); assertEquals(OK, response.getStatusCode()); assertEquals("{\n" + " \"success\": true\n" + "}", response.getContent()); } @Test void sendWithIOException() throws MPException, IOException { mpDefaultHttpClient = new MPDefaultHttpClient(HTTP_CLIENT); Map headers = new HashMap<>(); headers.put("x-test", "test"); MPRequest request = MPRequest.builder().method(HttpMethod.GET).uri("http://test.com").headers(headers).build(); HttpResponse httpResponse = generateHttpResponseFromFile(responseGenericSuccessJson, OK); httpResponse.setHeader("x-test", "test"); doThrow(IOException.class) .when(HTTP_CLIENT) .execute(any(HttpRequestBase.class), any(HttpContext.class)); try { mpDefaultHttpClient.send(request); } catch (MPApiException ex) { assertEquals(INTERNAL_SERVER_ERROR, ex.getStatusCode()); assertEquals("", ex.getApiResponse().getContent()); } } } ================================================ FILE: src/test/java/com/mercadopago/net/UrlFormatterTest.java ================================================ package com.mercadopago.net; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mercadopago.exceptions.MPException; import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; class UrlFormatterTest { private static Stream formatSuccess() throws MPException { String path = "/test"; String baseUrl = "https://api.mercadopago.com"; String pathWithQueryString = baseUrl.concat(path).concat("?param=1"); Map oneQueryParam = new HashMap<>(); oneQueryParam.put("param", "1"); Map twoQueryParams = new HashMap<>(); twoQueryParams.put("first", "1"); twoQueryParams.put("second", "2"); Map withSpecialQueryParams = new HashMap<>(); withSpecialQueryParams.put("email", "test@test.com"); return Stream.of( Arguments.of(UrlFormatter.format(baseUrl, null), "https://api.mercadopago.com"), Arguments.of( UrlFormatter.format(baseUrl.concat(path), null), "https://api.mercadopago.com/test"), Arguments.of( UrlFormatter.format(baseUrl.concat(path), oneQueryParam), "https://api.mercadopago.com/test?param=1"), Arguments.of(UrlFormatter.format(path, null), "https://api.mercadopago.com/test"), Arguments.of( UrlFormatter.format(path, oneQueryParam), "https://api.mercadopago.com/test?param=1"), Arguments.of( UrlFormatter.format(path, twoQueryParams), "https://api.mercadopago.com/test?first=1&second=2"), Arguments.of( UrlFormatter.format(pathWithQueryString, twoQueryParams), "https://api.mercadopago.com/test?param=1"), Arguments.of( UrlFormatter.format(path, withSpecialQueryParams), "https://api.mercadopago.com/test?email=test%40test.com")); } @ParameterizedTest @MethodSource void formatSuccess(String input, String expected) { assertEquals(expected, input); } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/helper/serializer_iso8601_timestamps.json ================================================ { "timestamps": [ "2021-01-13T17:06:29.595034354Z", "2021-01-13T17:06:29.595034354-04:00", "2021-02-14T08:52:52.000Z", "2021-02-14T08:52:52.000-04:00", "2021-04-16T03:03:03.3Z", "2021-04-16T03:03:03Z", "20210517T040404Z", "20210517T040404-03:00" ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/advancedPayment/advanced_payment_base.json ================================================ { "external_reference": "Adv53ebe8d0-33b7-49fe-9624-44522c88b9a6", "description": "description", "payer": { "email": "test_payer_9999988@testuser.com", "identification": { "type": "CPF", "number": "37462770865" }, "address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123" }, "first_name": "Test", "last_name": "User" }, "payments": [ { "payment_type_id": "credit_card", "payment_method_id": "master", "token": "bf9edf6ffae3ab5742033f33c557d54e", "transaction_amount": 100.0, "installments": 1, "processing_mode": "aggregator", "description": "description", "external_reference": "cc7c6175-8db4-4ed8-b359-b24ca8c60996", "statement_descriptor": "ADVPAY", "date_of_expiration": "3926-02-10T10:10:10.000Z" } ], "disbursements": [ { "amount": 40.0, "external_reference": "Seller12fa3e5ac-7edf-405c-878b-978e2a686cd0", "collector_id": "539673000", "application_fee": 1.0 }, { "amount": 60.0, "external_reference": "Seller28b56ba5e-7075-419a-8d35-817ff00f7593", "collector_id": "488656838", "application_fee": 0.5 } ], "binary_mode": false, "metadata": { "test": "123" }, "application_id": "59441713004005", "additional_info": { "ip_address": "127.0.0.1", "items": [ { "id": "123", "title": "title", "description": "description", "picture_url": "https://www.mercadopago.com/logomp3.gif", "category_id": "category", "quantity": 1, "unit_price": 100.0 } ], "payer": { "first_name": "Test", "last_name": "User", "registration_date": "3926-02-10T10:10:10.000+0000" }, "shipments": { "receiver_address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123", "floor": "1", "apartment": "300A" } } }, "capture": false } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/advancedPayment/captured.json ================================================ { "capture": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/advancedPayment/money_release_date.json ================================================ { "money_release_date": "3921-02-11T10:10:10.000+0000" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/advancedPayment/payment_captured.json ================================================ { "external_reference": "Adv53ebe8d0-33b7-49fe-9624-44522c88b9a6", "description": "description", "payer": { "email": "test_payer_9999988@testuser.com", "identification": { "type": "CPF", "number": "37462770865" }, "address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123" }, "first_name": "Test", "last_name": "User" }, "payments": [ { "payment_type_id": "credit_card", "payment_method_id": "master", "token": "bf9edf6ffae3ab5742033f33c557d54e", "transaction_amount": 100.0, "installments": 1, "processing_mode": "aggregator", "description": "description", "external_reference": "cc7c6175-8db4-4ed8-b359-b24ca8c60996", "statement_descriptor": "ADVPAY", "date_of_expiration": "3926-02-10T10:10:10.000Z" } ], "disbursements": [ { "amount": 40.0, "external_reference": "Seller12fa3e5ac-7edf-405c-878b-978e2a686cd0", "collector_id": "539673000", "application_fee": 1.0 }, { "amount": 60.0, "external_reference": "Seller28b56ba5e-7075-419a-8d35-817ff00f7593", "collector_id": "488656838", "application_fee": 0.5 } ], "binary_mode": false, "metadata": { "test": "123" }, "application_id": "59441713004005", "additional_info": { "ip_address": "127.0.0.1", "items": [ { "id": "123", "title": "title", "description": "description", "picture_url": "https://www.mercadopago.com/logomp3.gif", "category_id": "category", "quantity": 1, "unit_price": 100.0 } ], "payer": { "first_name": "Test", "last_name": "User", "registration_date": "3926-02-10T10:10:10.000+0000" }, "shipments": { "receiver_address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123", "floor": "1", "apartment": "300A" } } }, "capture": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/advancedPayment/status_cancelled.json ================================================ { "status": "cancelled" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/card/card_new.json ================================================ { "token": "bf9edf6ffae3ab5742033f33c557d54e", "customer_id": "649457098-FybpOkG6zH8QRm" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/customer/customer_base.json ================================================ { "email": "test_payer_999955@testuser.com", "first_name": "Test", "last_name": "Payer", "phone": { "area_code": "11", "number": "99999999" }, "identification": { "type": "CPF", "number": "19119119100" }, "description": "description", "metadata": { "test": "123" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/customer/customer_first_name.json ================================================ { "first_name": "New" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/merchant/order_base.json ================================================ { "preference_id": "798798399-13769cb5-b898-448f-8d5a-c939a8cee479" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/merchant/order_updated.json ================================================ { "payer": { "id": 0, "nickname": "Test" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/captured.json ================================================ { "capture": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/payment_3ds.json ================================================ { "additional_info": { "ip_address": "127.0.0.1", "items": [ { "id": "id", "title": "title", "description": "description", "picture_url": "pictureUrl", "category_id": "categoryId", "quantity": 1, "unit_price": 100, "warranty": false } ], "payer": { "first_name": "Test", "last_name": "User", "phone": { "area_code": "000", "number": "0000-0000" }, "address": { "zip_code": "0000", "street_name": "streetName", "street_number": "1234" }, "registration_date": "2022-01-10T10:10:10.000Z", "is_prime_user": false, "is_first_purchase_online": false }, "shipments": { "receiver_address": { "floor": "floor", "apartment": "apartment", "zip_code": "0000", "street_name": "streetName", "street_number": "1234" }, "local_pickup": false, "express_shipment": false } }, "binary_mode": false, "capture": false, "description": "description", "external_reference": "212efa19-da7a-4b4f-a3f0-4f458136d9ca", "installments": 1, "metadata": { }, "notification_url": "https://seu-site.com.br/webhooks", "payer": { "type": "customer", "email": "test_payer_9999999@testuser.com", "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "entity_type": "individual" }, "payment_method_id": "master", "token": "bf9edf6ffae3ab5742033f33c557d54e", "transaction_amount": 100, "statement_descriptor": "statementDescriptor", "three_d_secure_mode": "optional" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/payment_base.json ================================================ { "additional_info": { "ip_address": "127.0.0.1", "items": [ { "id": "id", "title": "title", "description": "description", "picture_url": "pictureUrl", "category_id": "categoryId", "quantity": 1, "unit_price": 100, "warranty": false } ], "payer": { "first_name": "Test", "last_name": "User", "phone": { "area_code": "000", "number": "0000-0000" }, "address": { "zip_code": "0000", "street_name": "streetName", "street_number": "1234" }, "registration_date": "2022-01-10T10:10:10.000Z", "is_prime_user": false, "is_first_purchase_online": false }, "shipments": { "receiver_address": { "floor": "floor", "apartment": "apartment", "zip_code": "0000", "street_name": "streetName", "street_number": "1234" }, "local_pickup": false, "express_shipment": false } }, "binary_mode": false, "capture": false, "description": "description", "external_reference": "212efa19-da7a-4b4f-a3f0-4f458136d9ca", "installments": 1, "metadata": { }, "notification_url": "https://seu-site.com.br/webhooks", "payer": { "type": "customer", "email": "test_payer_9999999@testuser.com", "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "entity_type": "individual" }, "payment_method_id": "master", "token": "bf9edf6ffae3ab5742033f33c557d54e", "transaction_amount": 100, "statement_descriptor": "statementDescriptor", "three_d_secure_mode": "not_supported" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/payment_boleto.json ================================================ { "additional_info": { "ip_address": "127.0.0.1", "items": [ { "id": "id", "title": "title", "description": "description", "picture_url": "pictureUrl", "category_id": "categoryId", "quantity": 1, "unit_price": 100, "warranty": false } ], "payer": { "first_name": "Test", "last_name": "User", "phone": { "area_code": "000", "number": "0000-0000" }, "address": { "zip_code": "0000", "street_name": "streetName", "street_number": "1234" }, "registration_date": "2022-01-10T10:10:10.000Z", "is_prime_user": false, "is_first_purchase_online": false }, "shipments": { "receiver_address": { "floor": "floor", "apartment": "apartment", "zip_code": "0000", "street_name": "streetName", "street_number": "1234" }, "local_pickup": false, "express_shipment": false } }, "binary_mode": false, "capture": false, "description": "description", "external_reference": "212efa19-da7a-4b4f-a3f0-4f458136d9ca", "installments": 1, "metadata": { }, "notification_url": "https://seu-site.com.br/webhooks", "payer": { "type": "customer", "email": "test_payer_9999999@testuser.com", "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "entity_type": "individual" }, "payment_method_id": "bolbradesco", "transaction_amount": 100, "statement_descriptor": "statementDescriptor", "payment_method": { "data": { "rules": { "discounts":[{ "type":"fixed", "value":5, "limit_date":"2022-10-25" }], "fine":{ "type":"percentage", "value":2 }, "interest":{ "type":"percentage", "value":0.03 } } } } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/payment_captured.json ================================================ { "payer": { "type": "customer", "email": "test_payer_9999999@testuser.com", "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "entity_type": "individual" }, "binary_mode": false, "external_reference": "212efa19-da7a-4b4f-a3f0-4f458136d9ca", "description": "description", "metadata": {}, "transaction_amount": 100.0, "capture": true, "payment_method_id": "master", "token": "bf9edf6ffae3ab5742033f33c557d54e", "statement_descriptor": "statementDescriptor", "installments": 1, "notification_url": "https://seu-site.com.br/webhooks", "additional_info": { "items": [ { "id": "id", "title": "title", "description": "description", "picture_url": "pictureUrl", "category_id": "categoryId", "quantity": 1, "unit_price": 100.0 } ], "payer": { "first_name": "Test", "last_name": "User", "phone": { "area_code": "000", "number": "0000-0000" }, "address": { "zip_code": "0000", "street_name": "streetName", "street_number": "1234" }, "registration_date": "3921-01-10T10:10:10.000+0000" }, "shipments": { "receiver_address": { "floor": "floor", "apartment": "apartment", "zip_code": "0000", "street_name": "streetName", "street_number": "1234" } }, "ip_address": "127.0.0.1" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/payment_pix.json ================================================ { "date_of_expiration": "2022-02-10T10:10:10.000Z", "description": "description", "payer": { "email": "test_user_1648059260@testuser.com" }, "payment_method_id": "pix", "point_of_interaction": { "linked_to": "openfinance" }, "transaction_amount": 100 } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/payment_pse.json ================================================ { "additional_info": { "ip_address": "127.0.0.1" }, "description": "description", "payer": { "type": "customer", "email": "test_payer_9999999@testuser.com", "entity_type": "individual", "first_name": "Test", "last_name": "User", "identification": { "type": "C.C.", "number": "1111111111" }, "address": { "street_name": "streetName", "street_number": "streetNumber", "zip_code": "zipCode" }, "phone": { "area_code": "111", "number": "123456" } }, "payment_method_id": "pse", "transaction_amount": 100, "transaction_details": { "financial_institution": "1009" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/payment/status_cancelled.json ================================================ { "status": "cancelled" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/point/devices_operating_mode.json ================================================ { "operating_mode": "PDV" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/point/payment_intent.json ================================================ { "amount": 1500, "description": "your payment intent description", "payment": { "installments": 1, "type": "credit_card", "installments_cost": "seller" }, "additional_info": { "external_reference": "4561ads-das4das4-das4754-das456", "print_on_terminal": true } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/preapproval/preapproval_base.json ================================================ { "payer_email": "test_user_28355466@testuser.com", "back_url": "https://www.mercadopago.com.br", "reason": "reason", "external_reference": "23546246234", "auto_recurring": { "currency_id": "BRL", "transaction_amount": 10, "frequency": 1, "frequency_type": "months", "start_date": "2022-01-10T10:10:10.000Z", "end_date": "2023-01-10T10:10:10.000Z" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/preapproval/preapproval_update.json ================================================ { "reason": "Updated reason" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/preference/preference_base.json ================================================ { "additional_info": "Discount: 12.00", "auto_return": "all", "back_urls": { "success": "http://test.com/success", "pending": "http://test.com/pending", "failure": "http://test.com/failure" }, "binary_mode": true, "date_of_expiration": "2022-02-10T10:10:10.000Z", "expiration_date_from": "2022-01-10T10:10:10.000Z", "expiration_date_to": "2022-02-10T10:10:10.000Z", "expires": false, "external_reference": "1643827245", "items": [ { "id": "1234", "title": "Games", "description": "PS5", "picture_url": "http://picture.com/PS5", "category_id": "games", "quantity": 2, "unit_price": 4000, "currency_id": "BRL", "warranty": false } ], "marketplace": "marketplace", "marketplace_fee": 5, "notification_url": "http://notificationurl.com", "operation_type": "regular_payment", "payer": { "name": "Test", "surname": "User", "email": "test_user_64585784@testuser.com", "is_prime_user": false, "is_first_purchase_online": false, "phone": { "area_code": "11", "number": "4444-4444" }, "identification": { "type": "CPF", "number": "19119119100" }, "address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123" } }, "payment_methods": { "excluded_payment_methods": [ { "id": "" } ], "excluded_payment_types": [ { "id": "ticket" } ], "default_payment_method_id": "master", "installments": 5, "default_installments": 1 }, "shipments": { "mode": "custom", "local_pickup": false, "dimensions": "10x10x20,500", "cost": 10, "receiver_address": { "zip_code": "06000000", "street_name": "Street", "street_number": "123", "floor": "12", "apartment": "120A" } }, "statement_descriptor": "Test Store" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/preference/preference_updated.json ================================================ { "statement_descriptor": "Updated Store" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/refund/refund.json ================================================ { "external_reference": "Adv53ebe8d0-33b7-49fe-9624-44522c88b9a6", "description": "description", "payer": { "email": "test_payer_9999988@testuser.com", "identification": { "type": "CPF", "number": "37462770865" }, "address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123" }, "first_name": "Test", "last_name": "User" }, "payments": [ { "payment_type_id": "credit_card", "payment_method_id": "master", "token": "bf9edf6ffae3ab5742033f33c557d54e", "transaction_amount": 100.0, "installments": 1, "processing_mode": "aggregator", "description": "description", "external_reference": "cc7c6175-8db4-4ed8-b359-b24ca8c60996", "statement_descriptor": "ADVPAY", "date_of_expiration": "3926-02-10T13:10:10.000Z" } ], "disbursements": [ { "amount": 40.0, "external_reference": "Seller12fa3e5ac-7edf-405c-878b-978e2a686cd0", "collector_id": "539673000", "application_fee": 1.0 }, { "amount": 60.0, "external_reference": "Seller28b56ba5e-7075-419a-8d35-817ff00f7593", "collector_id": "488656838", "application_fee": 0.5 } ], "binary_mode": false, "metadata": { "test": "123" }, "application_id": "59441713004005", "additional_info": { "ip_address": "127.0.0.1", "items": [ { "id": "123", "title": "title", "description": "description", "picture_url": "https://www.mercadopago.com/logomp3.gif", "category_id": "category", "quantity": 1, "unit_price": 100.0 } ], "payer": { "first_name": "Test", "last_name": "User", "registration_date": "3926-02-10T10:10:10.000+0000" }, "shipments": { "receiver_address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123", "floor": "1", "apartment": "300A" } } }, "capture": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/refund/refund_partial.json ================================================ { "amount": 50.0 } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/request/request_generic.json ================================================ { "abc": 123 } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/payment_base.json ================================================ { "id": 413372911, "status": "authorized", "marketplace": "MP-MKT-59441713004005", "sponsor_id": null, "payments": [ { "id": 17070479752, "status": "authorized", "status_detail": "pending_capture", "payment_type_id": "credit_card", "payment_method_id": "master", "token": "4985190ef28f65d9ebf127ffcc03c321", "transaction_amount": 100.0, "installments": 1, "processing_mode": "aggregator", "issuer_id": null, "coupon_amount": null, "campaign_id": null, "coupon_code": null, "description": "description", "external_reference": "4f4f56fd-2a89-44ca-984e-0eac4a51a86e", "statement_descriptor": "ADVPAY", "date_of_expiration": "2026-09-20T18:52:24.115Z", "merchant_account_id": null, "payment_method_option_id": null, "additional_info": null, "transaction_details": { "external_resource_url": null, "total_paid_amount": 100, "financial_institution": null }, "net_amount": null, "taxes": null } ], "disbursements": [ { "id": null, "amount": 40.0, "external_reference": "Seller17a45021f-62af-41b9-a199-066846e8dc7c", "collector_id": 539673000, "application_fee": 1.0, "money_release_days": 30, "additional_info": null }, { "id": null, "amount": 60.0, "external_reference": "Seller2fec72e67-c21e-43a3-9b6c-a1e06de46da6", "collector_id": 488656838, "application_fee": 0.5, "money_release_days": 30, "additional_info": null } ], "payer": { "id": null, "email": "test_payer_9999988@testuser.com", "address": { "street_number": "123", "zip_code": "06233200", "street_name": "Street" }, "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "phone": null, "token": null, "external_payer_id": null }, "external_reference": "Adva6abb0bb-84d1-49c7-b316-9efe29648b83", "description": "description", "binary_mode": false, "capture": false, "date_created": "2021-09-20T14:52:31.587-04:00", "date_last_updated": "2021-09-20T14:52:33.189-04:00", "metadata": { "test": "123" }, "additional_info": { "ip_address": "127.0.0.1", "shipments": { "receiver_address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123", "floor": "1", "apartment": "300A" } }, "payer": { "id": null, "type": null, "email": null, "first_name": "Test", "last_name": "User", "phone": null, "registration_date": "2021-09-10T15:52:24.119-0300", "address": null }, "items": [ { "id": "123", "title": "title", "description": "description", "picture_url": "https://www.mercadopago.com/logomp3.gif", "category_id": "category", "quantity": 1, "unit_price": 100.0 } ] }, "wallet_payment": null, "pos_id": null, "store_id": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/payment_cancelled.json ================================================ { "id": 413372911, "status": "cancelled", "marketplace": "MP-MKT-59441713004005", "sponsor_id": null, "payments": [ { "id": 17070479752, "status": "authorized", "status_detail": "pending_capture", "payment_type_id": "credit_card", "payment_method_id": "master", "token": "4985190ef28f65d9ebf127ffcc03c321", "transaction_amount": 100.0, "installments": 1, "processing_mode": "aggregator", "issuer_id": null, "coupon_amount": null, "campaign_id": null, "coupon_code": null, "description": "description", "external_reference": "4f4f56fd-2a89-44ca-984e-0eac4a51a86e", "statement_descriptor": "ADVPAY", "date_of_expiration": "2026-09-20T18:52:24.115Z", "merchant_account_id": null, "payment_method_option_id": null, "additional_info": null, "transaction_details": { "external_resource_url": null, "total_paid_amount": 100, "financial_institution": null }, "net_amount": null, "taxes": null } ], "disbursements": [ { "id": null, "amount": 40.0, "external_reference": "Seller17a45021f-62af-41b9-a199-066846e8dc7c", "collector_id": 539673000, "application_fee": 1.0, "money_release_days": 30, "additional_info": null }, { "id": null, "amount": 60.0, "external_reference": "Seller2fec72e67-c21e-43a3-9b6c-a1e06de46da6", "collector_id": 488656838, "application_fee": 0.5, "money_release_days": 30, "additional_info": null } ], "payer": { "id": null, "email": "test_payer_9999988@testuser.com", "address": { "street_number": "123", "zip_code": "06233200", "street_name": "Street" }, "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "phone": null, "token": null, "external_payer_id": null }, "external_reference": "Adva6abb0bb-84d1-49c7-b316-9efe29648b83", "description": "description", "binary_mode": false, "capture": false, "date_created": "2021-09-20T14:52:31.587-04:00", "date_last_updated": "2021-09-20T14:52:33.189-04:00", "metadata": { "test": "123" }, "additional_info": { "ip_address": "127.0.0.1", "shipments": { "receiver_address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123", "floor": "1", "apartment": "300A" } }, "payer": { "id": null, "type": null, "email": null, "first_name": "Test", "last_name": "User", "phone": null, "registration_date": "2021-09-10T15:52:24.119-0300", "address": null }, "items": [ { "id": "123", "title": "title", "description": "description", "picture_url": "https://www.mercadopago.com/logomp3.gif", "category_id": "category", "quantity": 1, "unit_price": 100.0 } ] }, "wallet_payment": null, "pos_id": null, "store_id": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/payment_captured.json ================================================ { "id": 413372911, "status": "approved", "marketplace": "MP-MKT-59441713004005", "sponsor_id": null, "payments": [ { "id": 17070590246, "status": "approved", "status_detail": "accredited", "payment_type_id": "credit_card", "payment_method_id": "master", "token": "4985190ef28f65d9ebf127ffcc03c321", "transaction_amount": 100.0, "installments": 1, "processing_mode": "aggregator", "issuer_id": null, "coupon_amount": null, "campaign_id": null, "coupon_code": null, "description": "description", "external_reference": "489aeeb8-3369-4cbf-8887-ebdfeef5d594", "statement_descriptor": "ADVPAY", "date_of_expiration": "2026-09-20T18:57:40.477Z", "merchant_account_id": null, "payment_method_option_id": null, "additional_info": null, "transaction_details": { "external_resource_url": null, "total_paid_amount": 100, "financial_institution": null }, "net_amount": null, "taxes": null } ], "disbursements": [ { "id": 17070604205, "amount": 40.0, "external_reference": "Seller12ee90515-1e3d-4337-85b6-972cbc754960", "collector_id": 539673000, "application_fee": 1.0, "money_release_days": 30, "additional_info": null }, { "id": 17070600291, "amount": 60.0, "external_reference": "Seller231b633a7-d3c8-4c36-a2f4-8de7e22809ea", "collector_id": 488656838, "application_fee": 0.5, "money_release_days": 30, "additional_info": null } ], "payer": { "id": null, "email": "test_payer_9999988@testuser.com", "address": { "street_number": "123", "zip_code": "06233200", "street_name": "Street" }, "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "phone": null, "token": null, "external_payer_id": null }, "external_reference": "Adv89591458-7f42-415a-b5c2-50ff4700acf4", "description": "description", "binary_mode": false, "capture": true, "date_created": "2021-09-20T14:57:45.212-04:00", "date_last_updated": "2021-09-20T14:58:13.286-04:00", "metadata": { "test": "123" }, "additional_info": { "ip_address": "127.0.0.1", "shipments": { "receiver_address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123", "floor": "1", "apartment": "300A" } }, "payer": { "id": null, "type": null, "email": null, "first_name": "Test", "last_name": "User", "phone": null, "registration_date": "2021-09-10T15:57:40.482-0300", "address": null }, "items": [ { "id": "123", "title": "title", "description": "description", "picture_url": "https://www.mercadopago.com/logomp3.gif", "category_id": "category", "quantity": 1, "unit_price": 100.0 } ] }, "wallet_payment": null, "pos_id": null, "store_id": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/payment_updated.json ================================================ { "id": 413378989, "status": "authorized", "marketplace": "MP-MKT-59441713004005", "sponsor_id": null, "payments": [ { "id": 17070722077, "status": "authorized", "status_detail": "pending_capture", "payment_type_id": "credit_card", "payment_method_id": "master", "token": "35eb6cf0955f4e574be6430d01b0f5d4", "transaction_amount": 100.0, "installments": 1, "processing_mode": "aggregator", "issuer_id": null, "coupon_amount": null, "campaign_id": null, "coupon_code": null, "description": "description", "external_reference": "3f3686ee-bf3d-45be-8de5-8d1d5d567bd8", "statement_descriptor": "ADVPAY", "date_of_expiration": "2026-09-20T19:04:27.424Z", "merchant_account_id": null, "payment_method_option_id": null, "additional_info": null, "transaction_details": { "external_resource_url": null, "total_paid_amount": 100, "financial_institution": null }, "net_amount": null, "taxes": null } ], "disbursements": [ { "id": null, "amount": 40.0, "external_reference": "Seller106650904-a63f-4b76-8791-d0a406f80803", "collector_id": 539673000, "application_fee": 1.0, "money_release_days": 30, "additional_info": null }, { "id": null, "amount": 60.0, "external_reference": "Seller265420e6d-e995-42ad-b415-ca1b631b83d9", "collector_id": 488656838, "application_fee": 0.5, "money_release_days": 30, "additional_info": null } ], "payer": { "id": null, "email": "test_payer_9999988@testuser.com", "address": { "street_number": "123", "zip_code": "06233200", "street_name": "Street" }, "identification": { "type": "CPF", "number": "37462770865" }, "first_name": "Test", "last_name": "User", "phone": null, "token": null, "external_payer_id": null }, "external_reference": "Adv998a355a-63b5-4d84-89fa-3282736f0fd1", "description": "description", "binary_mode": false, "capture": false, "date_created": "2021-09-20T15:04:32.424-04:00", "date_last_updated": "2021-09-20T15:04:52.950-04:00", "metadata": { "test": "123" }, "additional_info": { "ip_address": "127.0.0.1", "shipments": { "receiver_address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123", "floor": "1", "apartment": "300A" } }, "payer": { "id": null, "type": null, "email": null, "first_name": "Test", "last_name": "User", "phone": null, "registration_date": "2021-09-10T16:04:27.429-0300", "address": null }, "items": [ { "id": "123", "title": "title", "description": "description", "picture_url": "https://www.mercadopago.com/logomp3.gif", "category_id": "category", "quantity": 1, "unit_price": 100.0 } ] }, "wallet_payment": null, "pos_id": null, "store_id": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/advancedPayment/refund.json ================================================ [ { "id": 9842102419, "payment_id": 413372911, "amount": 100.0, "source": { "id": "810882223", "name": "Test Test", "type": "collector" }, "date_created": "2021-09-17T14:50:53.198-04:00", "status": "approved" } ] ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/card/card_all.json ================================================ [ { "id": 1562188766852, "expiration_month": 6, "expiration_year": 2023, "first_six_digits": 423564, "last_four_digits": 5682, "payment_method": { "id": "visa", "name": "visa", "payment_type_id": "credit_card", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/visa.gif", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/visa.gif" }, "security_code": { "length": 3, "card_location": "back" }, "issuer": { "id": 25, "name": "Visa" }, "cardholder": { "name": "APRO", "identification": { "number": 19119119100, "type": "CPF" } }, "date_created": "2019-07-03T21:15:35.000Z", "date_last_updated": "2019-07-03T21:19:18.000Z", "customer_id": "649457098-FybpOkG6zH8QRm", "user_id": 448870796, "live_mode": true } ] ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/card/card_new.json ================================================ { "id": 1562188766852, "expiration_month": 6, "expiration_year": 2023, "first_six_digits": 423564, "last_four_digits": 5682, "payment_method": { "id": "visa", "name": "visa", "payment_type_id": "credit_card", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/visa.gif", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/visa.gif" }, "security_code": { "length": 3, "card_location": "back" }, "issuer": { "id": 25, "name": "Visa" }, "cardholder": { "name": "APRO", "identification": { "number": 19119119100, "type": "CPF" } }, "date_created": "2019-07-03T21:15:35.000Z", "date_last_updated": "2019-07-03T21:19:18.000Z", "customer_id": "649457098-FybpOkG6zH8QRm", "user_id": 448870796, "live_mode": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/card/card_single.json ================================================ { "id": 1562188766852, "expiration_month": 6, "expiration_year": 2023, "first_six_digits": 423564, "last_four_digits": 5682, "payment_method": { "id": "visa", "name": "visa", "payment_type_id": "credit_card", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/visa.gif", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/visa.gif" }, "security_code": { "length": 3, "card_location": "back" }, "issuer": { "id": 25, "name": "Visa" }, "cardholder": { "name": "APRO", "identification": { "number": 19119119100, "type": "CPF" } }, "date_created": "2019-07-03T21:15:35.000Z", "date_last_updated": "2019-07-03T21:19:18.000Z", "customer_id": "649457098-FybpOkG6zH8QRm", "user_id": 448870796, "live_mode": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/cardtoken/card_token_base.json ================================================ { "id": "97849c845e879427b5cb1cb941a52806", "card_id": "989192037129", "first_six_digits": "503143", "expiration_month": 11, "expiration_year": 2025, "last_four_digits": "6351", "cardholder": { "identification": { "number": "57096407006", "type": "CPF" }, "name": "APRO" }, "status": "active", "date_created": "2022-01-24T08:03:55.227-04:00", "date_last_updated": "2022-01-24T08:03:55.227-04:00", "date_due": "2022-02-01T08:03:55.227-04:00", "luhn_validation": true, "live_mode": true, "require_esc": false, "card_number_length": 16, "security_code_length": 3 } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/customer/customer_base.json ================================================ { "id": "1068193981-pXRewrKqlP6pnn", "email": "test_payer_1629112604@testuser.com", "first_name": "Jhon", "last_name": "Doe", "phone": { "area_code": "55", "number": "991234567" }, "identification": { "type": "CPF", "number": "12345678900" }, "address": { "id": "1215179651", "zip_code": "01313000", "street_name": "Rua Exemplo", "street_number": 123 }, "date_registered": "2000-01-18T00:00:00.000-04:00", "description": "Description del user", "date_created": "0001-01-01T00:00:00.000+00:00", "date_last_updated": "2022-02-03T19:30:56.805+00:00", "metadata": { "source_sync": "source_k" }, "default_card": "1643916656196", "default_address": "1215179651", "cards": [ { "cardholder": { "name": "APRO", "identification": { "number": null, "type": "CPF" } }, "customer_id": "1068193981-pXRewrKqlP6pnn", "date_created": "2022-02-03T15:30:27.449-04:00", "date_last_updated": "2022-02-03T15:30:27.449-04:00", "expiration_month": 12, "expiration_year": 2022, "first_six_digits": "503143", "id": "1643916656196", "issuer": { "id": 24, "name": "Mastercard" }, "last_four_digits": "6351", "payment_method": { "id": "master", "name": "master", "payment_type_id": "credit_card", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/master.gif", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/master.gif" }, "security_code": { "length": 3, "card_location": "back" }, "user_id": "1068193981" } ], "addresses": [ { "apartment": null, "city": { "id": "BR-SP-44", "name": "São Paulo" }, "comments": null, "country": { "id": "BR", "name": "Brasil" }, "date_created": "2022-02-03T15:30:27.449-04:00", "date_last_updated": null, "floor": null, "id": "1215179651", "municipality": { "id": null, "name": null }, "name": null, "neighborhood": { "id": null, "name": "Bela Vista" }, "normalized": true, "phone": "0000000000", "state": { "id": "BR-SP", "name": "São Paulo" }, "street_name": "Rua Exemplo", "street_number": 123, "verifications": { "shipment": { "errors": [], "success": true } }, "zip_code": "01313000" } ], "live_mode": false } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/customer/customer_updated.json ================================================ { "id": "000000001-sT93QZFAsfxU9P5", "email": "test_payer_999955@testuser.com", "first_name": "New", "last_name": "Payer", "phone": { "area_code": 11, "number": 99999999 }, "identification": { "type": "CPF", "number": 19119119100 }, "address": { "id": "1162600094", "zip_code": "01234567", "street_name": "Rua Exemplo" }, "description": "description", "date_created": "2018-02-20T15:36:23.541Z", "metadata": { "test": "123" }, "default_address": "1162600094", "cards": [ {} ], "addresses": [ {} ], "live_mode": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/customer/search_by_email.json ================================================ { "paging": { "limit": 10, "offset": 0, "total": 1 }, "results": [ { "id": "000000001-sT93QZFAsfxU9P5", "email": "test_payer_999955@testuser.com", "first_name": "Test", "last_name": "Payer", "phone": { "area_code": 11, "number": 99999999 }, "identification": { "type": "CPF", "number": 19119119100 }, "address": { "id": "1162600094", "zip_code": "01234567", "street_name": "Rua Exemplo" }, "description": "description", "date_created": "2018-02-20T15:36:23.541Z", "metadata": { "test": "123" }, "default_address": "1162600094", "cards": [ {} ], "addresses": [ {} ], "live_mode": true } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/identification/types.json ================================================ [ { "id": "CPF", "name": "CPF", "type": "number", "min_length": 11, "max_length": 11 }, { "id": "CNPJ", "name": "CNPJ", "type": "number", "min_length": 14, "max_length": 14 } ] ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/merchant/order_base.json ================================================ { "id": 4018801790, "status": "opened", "external_reference": null, "preference_id": "798798399-13769cb5-b898-448f-8d5a-c939a8cee479", "payments": [], "shipments": [], "payouts": [], "collector": { "id": 798798399, "email": "", "nickname": "TETE8419469" }, "marketplace": "", "notification_url": null, "date_created": "2022-01-10T10:10:10.000-00:00", "last_updated": "2022-01-10T10:10:10.000-00:00", "sponsor_id": null, "shipping_cost": 0, "total_amount": 206.02, "site_id": "MLM", "paid_amount": 0, "refunded_amount": 0, "payer": null, "items": [], "cancelled": false, "additional_info": null, "application_id": null, "order_status": "payment_required" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/merchant/order_search.json ================================================ { "elements": [ { "id": 4018801790, "status": "opened", "external_reference": null, "preference_id": "798798399-13769cb5-b898-448f-8d5a-c939a8cee479", "payments": [], "shipments": [], "payouts": [], "collector": { "id": 798798399, "email": "", "nickname": "TETE8419469" }, "marketplace": "", "notification_url": null, "date_created": "2022-01-10T10:10:10.000-00:00", "last_updated": "2022-01-10T10:10:10.000-00:00", "sponsor_id": null, "shipping_cost": 0, "total_amount": 206.02, "site_id": "MLM", "paid_amount": 0, "refunded_amount": 0, "payer": null, "items": [], "cancelled": false, "additional_info": null, "application_id": null, "order_status": "payment_required" }, { "id": 4005684268, "status": "opened", "external_reference": null, "preference_id": "798798399-13769cb5-b898-448f-8d5a-c939a8cee479", "payments": [], "shipments": [], "payouts": [], "collector": { "id": 798798399, "email": "", "nickname": "TETE8419469" }, "marketplace": "", "notification_url": null, "date_created": "2022-01-21T17:52:58.563+00:00", "last_updated": "2022-01-21T17:52:58.563+00:00", "sponsor_id": null, "shipping_cost": 0, "total_amount": 206.02, "site_id": "MLM", "paid_amount": 0, "refunded_amount": 0, "payer": null, "items": [], "cancelled": false, "additional_info": null, "application_id": null, "order_status": "payment_required" } ], "next_offset": 2, "total": 2 } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/merchant/order_updated.json ================================================ { "id": 4018843653, "status": "opened", "external_reference": null, "preference_id": "798798399-13769cb5-b898-448f-8d5a-c939a8cee479", "payments": [], "shipments": [], "payouts": [], "collector": { "id": 798798399, "email": "", "nickname": "TETE8419469" }, "marketplace": "", "notification_url": null, "date_created": "2022-01-24T12:04:57.958+00:00", "last_updated": "2022-01-24T12:04:57.958+00:00", "sponsor_id": null, "shipping_cost": 0, "total_amount": 206.02, "site_id": "MLM", "paid_amount": 0, "refunded_amount": 0, "payer": { "id": 0, "email": null, "nickname": "Test" }, "items": [], "cancelled": false, "additional_info": null, "application_id": null, "order_status": "payment_required" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/oauth/oauth_credential.json ================================================ { "access_token": "APP_USR-4934588586838432-XXXXXXXX-241983636", "token_type": "bearer", "expires_in": 15552000, "scope": "offline_access read write", "user_id": 241983636, "refresh_token": "TG-XXXXXXXX-241983636", "public_key": "APP_USR-d0a26210-XXXXXXXX-479f0400869e", "live_mode": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/oauth/oauth_refresh_token.json ================================================ { "access_token": "APP_USR-4934588586838432-XXXXXXXX-241983636", "token_type": "bearer", "expires_in": 15552000, "scope": "offline_access read write", "refresh_token": "TG-XXXXXXXXXXXX-241983636" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/order/capture_order_response.json ================================================ { "id": "123", "status": "processed", "transactions": { "payments": [ { "id": "id", "amount": "10.00", "status": "processed", "reference_id": "id" } ] } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/order/create_order_response.json ================================================ { "id": "123", "type": "online", "processing_mode": "automatic", "external_reference": "ext_ref", "total_amount": "10.00", "site_id": "MLB", "status": "failed", "created_date": "2024-10-18T19:25:38.972924264Z", "last_updated_date": "2024-10-18T19:25:39.690267719Z", "integration_data": { "application_id": "id" }, "payer": { "email": "test@email.com" }, "transactions": { "payments": [ { "id": "id", "amount": "10.00", "status": "failed", "reference_id": "id", "status_detail": "invalid_card_token", "payment_method": { "id": "master", "type": "credit_card", "token": "card_token", "installments": 1 } } ] }, "capture_mode": "automatic_async" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/order/create_refund_partial_response.json ================================================ { "id": "01JCK7NYARQB4J3RN0SX6SSB2C", "status": "processed", "status_detail": "partially_refunded", "transactions": { "refunds": [ { "id": "ref_01JCK7R5R73JCYXRCKFH7MJR9K", "transaction_id": "pay_01JCK7NYARQB4J3RN0SX81MCPM", "reference_id": "01JCK7R50JP8NRMKC51R6B460C", "amount": "100.00", "status": "processed" } ] } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/order/create_refund_total_response.json ================================================ { "id": "01JCK2RRKV10XVTEBJR598QH9Z", "status": "refunded", "status_detail": "refunded", "transactions": { "refunds": [ { "id": "ref_01JCK2SDVFSJGY54AMJCDR9X7R", "transaction_id": "pay_01JCK2RRKV10XVTEBJR6W4CC18", "reference_id": "01JCK2SD3HC5GVDXSZK4926SAW", "amount": "200.00", "status": "processed" } ] } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/order/create_transaction_response.json ================================================ { "payments": [ { "amount": "100.00", "currency": "BRL", "payment_method": { "id": "master", "type": "credit_card", "token": "some-token", "installments": 1, "issuer_id": "701", "statement_descriptor": "statement" } } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/order/order_search_response.json ================================================ { "paging": { "total": 10, "total_pages": 2, "limit": 5, "offset": 0 }, "data": [ { "id": "123", "type": "online", "processing_mode": "automatic", "status": "processed", "status_detail": "accredited", "total_amount": "200.00", "external_reference": "ext_ref_1234" } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/order/update_transaction_response.json ================================================ { "id": "pay_012345", "amount": "100.00", "payment_method": { "id": "master", "type": "credit_card", "token": "card_token", "statement_descriptor": "statement", "installments": 1 } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/by_external_reference.json ================================================ { "paging": { "total": 1, "limit": 30, "offset": 0 }, "results": [ { "metadata": { "order_number": "order_1631894348" }, "corporation_id": null, "operation_type": "regular_payment", "point_of_interaction": {}, "fee_details": [ { "amount": 0.62, "fee_payer": "collector", "type": "mercadopago_fee" } ], "notification_url": "https://seu-site.com.br/webhookshttps://seu-site.com.br/webhooks", "date_approved": "2021-09-17T11:59:11.000-04:00", "money_release_schema": null, "payer": { "entity_type": null, "identification": { "number": "19119119100", "type": "CPF" }, "phone": { "number": null, "extension": null, "area_code": null }, "operator_id": null, "last_name": "Silva", "id": "128185910", "type": "anonymous", "first_name": "Joao", "email": "test_user_1631894348@testuser.com" }, "transaction_details": { "total_paid_amount": 12.34, "acquirer_reference": null, "installment_amount": 12.34, "financial_institution": null, "net_received_amount": 11.72, "overpaid_amount": 0, "external_resource_url": null, "payable_deferral_period": null, "payment_method_reference_id": null }, "statement_descriptor": "Mercadopago*fake", "call_for_authorize_id": null, "installments": 1, "pos_id": null, "external_reference": "1631894348", "date_of_expiration": null, "charges_details": [], "id": 17014025134, "payment_type_id": "credit_card", "order": {}, "counter_currency": null, "brand_id": null, "status_detail": "accredited", "differential_pricing_id": null, "additional_info": { "authentication_code": null, "nsu_processadora": null, "available_balance": null, "items": [ { "quantity": "1", "category_id": "Tickets", "picture_url": null, "description": "Natal Iluminado 2019", "id": "1941", "title": "Ingresso Antecipado", "unit_price": "100.0" } ], "payer": { "address": { "street_number": "3003", "street_name": "Av. das Nações Unidas", "zip_code": "06233-200" }, "registration_date": "2013-08-06T09:25:04.000-03:00" }, "shipments": { "receiver_address": { "street_number": "15", "street_name": "são Luiz", "zip_code": "95630000" } } }, "live_mode": true, "marketplace_owner": null, "card": { "first_six_digits": "503143", "expiration_year": 2022, "date_created": "2021-09-17T11:59:10.000-04:00", "expiration_month": 12, "id": null, "cardholder": { "identification": { "number": "19119119100", "type": "CPF" }, "name": "APRO" }, "last_four_digits": "6351", "date_last_updated": "2021-09-17T11:59:10.000-04:00" }, "integrator_id": null, "status": "approved", "transaction_amount_refunded": 0, "transaction_amount": 12.34, "description": "PEDIDO NOVO - VIDEOGAME", "money_release_date": "2021-09-17T11:59:11.000-04:00", "merchant_number": null, "refunds": [], "authorization_code": "301299", "captured": true, "collector_id": 810882223, "merchant_account_id": null, "taxes_amount": 0, "date_last_updated": "2021-09-17T11:59:11.000-04:00", "coupon_amount": 0, "store_id": null, "date_created": "2021-09-17T11:59:10.000-04:00", "acquirer_reconciliation": [], "sponsor_id": null, "shipping_amount": 0, "issuer_id": "24", "payment_method_id": "master", "binary_mode": false, "platform_id": null, "deduction_schema": null, "processing_mode": "aggregator", "currency_id": "BRL", "shipping_cost": 0 } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_3ds.json ================================================ { "id": 17014025134, "date_created": "2022-01-10T10:10:10.000-00:00", "date_approved": "2022-01-10T10:10:10.000-00:00", "date_last_updated": "2022-01-10T10:10:10.000-00:00", "date_of_expiration": null, "money_release_date": "2022-01-10T10:10:10.000-00:00", "operation_type": "regular_payment", "issuer_id": "24", "payment_method_id": "master", "payment_type_id": "credit_card", "status": "approved", "status_detail": "accredited", "currency_id": "BRL", "description": "PEDIDO NOVO - VIDEOGAME", "live_mode": true, "sponsor_id": null, "authorization_code": "301299", "money_release_schema": null, "taxes_amount": 0, "counter_currency": null, "shipping_amount": 0, "pos_id": null, "store_id": null, "integrator_id": null, "platform_id": null, "corporation_id": null, "collector_id": 810882223, "payer": { "type": null, "id": "128185910", "operator_id": null, "email": "test_user_1631894348@testuser.com", "identification": { "type": "CPF", "number": "19119119100" }, "phone": { "area_code": null, "number": null, "extension": null }, "first_name": null, "last_name": null, "entity_type": null }, "marketplace_owner": null, "metadata": { "order_number": "order_1631894348" }, "internal_metadata": { "rule_engine": { "with_promise": false, "valid_promise": false, "rules": [ { "rule_id": 21002808561, "rule_set": "processing_fee_and_release" }, { "rule_id": 21000231962, "rule_set": "financing_fee_collector" } ] }, "unified_processing": true, "3ds_disabled_reason": "none", "approval_optimization_context": [ { "trx_id": "86000149282_377b7377776e737f3377", "profile_id": "g2_getnet_getnet_7187497", "gtw_context": { "response_code": null, "http_status": null, "operation": "authorization" }, "approval_decision": { "abtesting_flows": null, "deferred_retry": true, "data_only": false, "retry_after_time": "2022-12-27T21:00:00Z", "approval_flows": [ "tokenization", "threeds", "data_only", "no_cvv", "default" ], "three_ds": true, "remove_cvv": false, "operation_mode": "async", "best_flows": ["threeds"] }, "mcc": null, "attempt": 1, "security_code_data": null } ], "g2": "on", "3ds_status": "CHALLENGE", "3ds_challenge": true, "3ds_challenge_drop_reason": "none", "rejected_by_penalty": false, "payment_method_id": "67696841", "pci_info": { "ct_x_forwarded_for": null, "pay_x_forwarded_for": "10.195.1.92, 10.54.29.159", "is_public": false }, "mcc_assigned": "5099", "internal_risk_analysis": "by_risk", "approval_decision": { "abtesting_flows": null, "deferred_retry": true, "data_only": false, "retry_after_time": "2022-12-27T21:00:00Z", "approval_flows": [ "tokenization", "threeds", "data_only", "no_cvv", "default" ], "three_ds": true, "remove_cvv": false, "operation_mode": "async", "best_flows": ["threeds"] }, "mcc_source": "DEFAULT" }, "additional_info": { "items": [ { "id": "1941", "title": "Ingresso Antecipado", "description": "Natal Iluminado 2019", "picture_url": null, "category_id": "Tickets", "quantity": "1", "unit_price": "100.0" } ], "payer": { "phone": { "area_code": "11", "number": "987654321" }, "address": { "zip_code": "06233-200", "street_name": "Av. das Nações Unidas", "street_number": "3003" }, "first_name": "Nome", "last_name": "Sobrenome", "registration_date": "2022-01-10T10:10:10.000-00:00" }, "shipments": { "receiver_address": { "zip_code": "95630000", "street_name": "são Luiz", "street_number": "15" } }, "available_balance": null, "nsu_processadora": null, "authentication_code": null }, "order": {}, "external_reference": "1631894348", "transaction_amount": 12.34, "transaction_amount_refunded": 0, "coupon_amount": 0, "differential_pricing_id": null, "deduction_schema": null, "installments": 1, "transaction_details": { "payment_method_reference_id": null, "net_received_amount": 11.72, "total_paid_amount": 12.34, "overpaid_amount": 0, "external_resource_url": null, "installment_amount": 12.34, "financial_institution": null, "payable_deferral_period": null, "acquirer_reference": null }, "fee_details": [ { "type": "mercadopago_fee", "amount": 0.62, "fee_payer": "collector" } ], "charges_details": [], "captured": false, "binary_mode": false, "call_for_authorize_id": null, "statement_descriptor": "Mercadopago*fake", "card": { "id": null, "first_six_digits": "503143", "last_four_digits": "6351", "expiration_month": 12, "expiration_year": 2022, "date_created": "2022-01-10T10:10:10.000-00:00", "date_last_updated": "2022-01-10T10:10:10.000-00:00", "cardholder": { "name": "APRO", "identification": { "number": "19119119100", "type": "CPF" } } }, "notification_url": "https://seu-site.com.br/webhookshttps://seu-site.com.br/webhooks", "refunds": [], "processing_mode": "aggregator", "merchant_account_id": null, "merchant_number": null, "acquirer_reconciliation": [], "point_of_interaction": {}, "three_ds_info": { "external_resource_url": "https://acs-public.tp.mastercard.com/api/v1/browser_challenges", "creq": "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImE4NDQ1NTE2LThjNzktNGQ1NC04MjRmLTU5YzgzNDRiY2FjNCIsImFj" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_base.json ================================================ { "id": 17014025134, "date_created": "2022-01-10T10:10:10.000-00:00", "date_approved": "2022-01-10T10:10:10.000-00:00", "date_last_updated": "2022-01-10T10:10:10.000-00:00", "date_of_expiration": null, "money_release_date": "", "operation_type": "regular_payment", "issuer_id": "24", "payment_method_id": "master", "payment_type_id": "credit_card", "status": "approved", "status_detail": "accredited", "currency_id": "BRL", "description": "PEDIDO NOVO - VIDEOGAME", "live_mode": true, "sponsor_id": null, "authorization_code": "301299", "money_release_schema": null, "taxes_amount": 0, "counter_currency": null, "shipping_amount": 0, "pos_id": null, "store_id": null, "integrator_id": null, "platform_id": null, "corporation_id": null, "collector_id": 810882223, "payer": { "type": null, "id": "128185910", "operator_id": null, "email": "test_user_1631894348@testuser.com", "identification": { "type": "CPF", "number": "19119119100" }, "phone": { "area_code": null, "number": null, "extension": null }, "first_name": null, "last_name": null, "entity_type": null }, "marketplace_owner": null, "metadata": { "order_number": "order_1631894348" }, "internal_metadata": { "rule_engine": { "with_promise": false, "valid_promise": false, "rules": [ { "rule_id": 21002808561, "rule_set": "processing_fee_and_release" }, { "rule_id": 21000231962, "rule_set": "financing_fee_collector" } ] }, "unified_processing": true, "3ds_disabled_reason": "none", "approval_optimization_context": [ { "trx_id": "86000149282_377b7377776e737f3377", "profile_id": "g2_getnet_getnet_7187497", "gtw_context": { "response_code": null, "http_status": null, "operation": "authorization" }, "approval_decision": { "abtesting_flows": null, "deferred_retry": true, "data_only": false, "retry_after_time": "2022-12-27T21:00:00Z", "approval_flows": [ "tokenization", "threeds", "data_only", "no_cvv", "default" ], "three_ds": true, "remove_cvv": false, "operation_mode": "async", "best_flows": ["threeds"] }, "mcc": null, "attempt": 1, "security_code_data": null } ], "g2": "on", "3ds_status": "CHALLENGE", "3ds_challenge": true, "3ds_challenge_drop_reason": "none", "rejected_by_penalty": false, "payment_method_id": "67696841", "pci_info": { "ct_x_forwarded_for": null, "pay_x_forwarded_for": "10.195.1.92, 10.54.29.159", "is_public": false }, "mcc_assigned": "5099", "internal_risk_analysis": "by_risk", "approval_decision": { "abtesting_flows": null, "deferred_retry": true, "data_only": false, "retry_after_time": "2022-12-27T21:00:00Z", "approval_flows": [ "tokenization", "threeds", "data_only", "no_cvv", "default" ], "three_ds": true, "remove_cvv": false, "operation_mode": "async", "best_flows": ["threeds"] }, "mcc_source": "DEFAULT" }, "additional_info": { "items": [ { "id": "1941", "title": "Ingresso Antecipado", "description": "Natal Iluminado 2019", "picture_url": null, "category_id": "Tickets", "quantity": "1", "unit_price": "100.0" } ], "payer": { "phone": { "area_code": "11", "number": "987654321" }, "address": { "zip_code": "06233-200", "street_name": "Av. das Nações Unidas", "street_number": "3003" }, "first_name": "Nome", "last_name": "Sobrenome", "registration_date": "2022-01-10T10:10:10.000-00:00" }, "shipments": { "receiver_address": { "zip_code": "95630000", "street_name": "são Luiz", "street_number": "15" } }, "available_balance": null, "nsu_processadora": null, "authentication_code": null }, "order": {}, "external_reference": "1631894348", "transaction_amount": 12.34, "transaction_amount_refunded": 0, "coupon_amount": 0, "differential_pricing_id": null, "deduction_schema": null, "installments": 1, "transaction_details": { "payment_method_reference_id": null, "net_received_amount": 11.72, "total_paid_amount": 12.34, "overpaid_amount": 0, "external_resource_url": null, "installment_amount": 12.34, "financial_institution": null, "payable_deferral_period": null, "acquirer_reference": null }, "fee_details": [ { "type": "mercadopago_fee", "amount": 0.62, "fee_payer": "collector" } ], "charges_details": [], "captured": false, "binary_mode": false, "call_for_authorize_id": null, "statement_descriptor": "Mercadopago*fake", "card": { "id": null, "first_six_digits": "503143", "last_four_digits": "6351", "expiration_month": 12, "expiration_year": 2022, "date_created": "2022-01-10T10:10:10.000-00:00", "date_last_updated": "2022-01-10T10:10:10.000-00:00", "cardholder": { "name": "APRO", "identification": { "number": "19119119100", "type": "CPF" } } }, "notification_url": "https://seu-site.com.br/webhookshttps://seu-site.com.br/webhooks", "refunds": [], "processing_mode": "aggregator", "merchant_account_id": null, "merchant_number": null, "acquirer_reconciliation": [], "point_of_interaction": {}, "three_ds_info": { "external_resource_url": "https://acs-public.tp.mastercard.com/api/v1/browser_challenges", "creq": "eyJ0aHJlZURTU2VydmVyVHJhbnNJRCI6ImE4NDQ1NTE2LThjNzktNGQ1NC04MjRmLTU5YzgzNDRiY2FjNCIsImFjc1RyYW5zSUQiOiJmZjVlMWM4YS00M2Y2LTQ5ZDEtYjhmMy02M2FmMzJkMzgwYTEiLCJjaGFsbGVuZ2VXaW5kb3dTaXplIjoiMDQiLCJtZXNzYWdlVHlwZSI6IkNSZXEiLCJtZXNzYWdlVmVyc2lvbiI6IjIuMS4wIn0" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_boleto.json ================================================ { "id": 1311781516, "date_created": "2023-02-23T16:32:52.889-04:00", "date_approved": null, "date_last_updated": "2023-02-23T16:32:52.889-04:00", "date_of_expiration": "2023-02-27T22:59:59.000-04:00", "money_release_date": null, "money_release_status": null, "operation_type": "regular_payment", "issuer_id": null, "payment_method_id": "bolbradesco", "payment_type_id": "ticket", "payment_method": { "id": "bolbradesco", "type": "ticket", "data": { "rules": { "discounts":[{ "type":"fixed", "value":5, "limit_date":"2022-10-25" }], "fine":{ "type":"percentage", "value":2 }, "interest":{ "type":"percentage", "value":0.03 } } }, "forward_data": { "ticket_number": "", "agreement_number": "" } }, "status": "pending", "status_detail": "pending_waiting_payment", "currency_id": "BRL", "description": "description", "live_mode": false, "sponsor_id": null, "authorization_code": null, "money_release_schema": null, "taxes_amount": 0, "counter_currency": null, "brand_id": null, "shipping_amount": 0, "build_version": "2.133.0", "pos_id": null, "store_id": null, "integrator_id": null, "platform_id": null, "corporation_id": null, "payer": { "first_name": null, "last_name": null, "email": "test_user@testuser.com", "identification": { "number": "32659430", "type": "DNI" }, "phone": { "area_code": null, "number": null, "extension": null }, "type": null, "entity_type": null, "id": "1316710913" }, "collector_id": 1036739580, "marketplace_owner": null, "metadata": { "order_number": "order_1677184372" }, "additional_info": { "items": [ { "id": "id", "title": "title", "description": "description", "picture_url": null, "category_id": "Tickets", "quantity": "1", "unit_price": "100" } ], "payer": { "phone": { "area_code": "11", "number": "985664721" }, "address": { "zip_code": "06233-200", "street_name": "Av. das Nações Unidas", "street_number": "3003" }, "first_name": "Test", "last_name": "User", "registration_date": "2022-08-06T09:25:04.000-03:00" }, "shipments": { "receiver_address": { "zip_code": "95630000", "street_name": "são Luiz", "street_number": "15", "floor": "12", "apartment": "123" } }, "available_balance": null, "nsu_processadora": null, "authentication_code": null }, "order": {}, "external_reference": "1677145242", "transaction_amount": 100, "transaction_amount_refunded": 0, "coupon_amount": 0, "differential_pricing_id": null, "financing_group": null, "deduction_schema": null, "barcode": { "content": "23793927400000100503000260600338183000633330" }, "installments": 1, "transaction_details": { "payment_method_reference_id": "6033391830", "acquirer_reference": "", "verification_code": "6002389830", "net_received_amount": 0, "total_paid_amount": 100, "overpaid_amount": 0, "external_resource_url": "https://www.mercadopago.com.br/sandbox/payments/1311781516/ticket?caller_id=1316710913&payment_method_id=bolbradesco&payment_id=1311781516&payment_method_reference_id=6003381830&hash=ec2351c2-3ddc-4458-b147-0a86d2573785", "installment_amount": 0, "financial_institution": "bradesco", "payable_deferral_period": null }, "fee_details": [], "charges_details": [], "captured": true, "binary_mode": false, "call_for_authorize_id": null, "statement_descriptor": null, "card": {}, "notification_url": null, "refunds": [], "processing_mode": "aggregator", "merchant_account_id": null, "merchant_number": null, "acquirer_reconciliation": [], "point_of_interaction": { "type": "UNSPECIFIED", "business_info": { "unit": "online_payments", "sub_unit": "default" } } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_cancelled.json ================================================ { "id": 17014025134, "date_created": "2021-09-17T11:59:10.367-04:00", "date_approved": "2021-09-17T11:59:11.481-04:00", "date_last_updated": "2021-09-17T11:59:11.481-04:00", "date_of_expiration": null, "money_release_date": "2021-09-17T11:59:11.481-04:00", "operation_type": "regular_payment", "issuer_id": "24", "payment_method_id": "master", "payment_type_id": "credit_card", "status": "cancelled", "status_detail": "accredited", "currency_id": "BRL", "description": "PEDIDO NOVO - VIDEOGAME", "live_mode": true, "sponsor_id": null, "authorization_code": "301299", "money_release_schema": null, "taxes_amount": 0, "counter_currency": null, "brand_id": null, "shipping_amount": 0, "pos_id": null, "store_id": null, "integrator_id": null, "platform_id": null, "corporation_id": null, "collector_id": 810882223, "payer": { "type": null, "id": "128185910", "operator_id": null, "email": "test_user_1631894348@testuser.com", "identification": { "type": "CPF", "number": "19119119100" }, "phone": { "area_code": null, "number": null, "extension": null }, "first_name": null, "last_name": null, "entity_type": null }, "marketplace_owner": null, "metadata": { "order_number": "order_1631894348" }, "additional_info": { "items": [ { "id": "1941", "title": "Ingresso Antecipado", "description": "Natal Iluminado 2019", "picture_url": null, "category_id": "Tickets", "quantity": "1", "unit_price": "100.0" } ], "payer": { "phone": { "area_code": "11", "number": "987654321" }, "address": { "zip_code": "06233-200", "street_name": "Av. das Nações Unidas", "street_number": "3003" }, "first_name": "Nome", "last_name": "Sobrenome", "registration_date": "2013-08-06T09:25:04.000-03:00" }, "shipments": { "receiver_address": { "zip_code": "95630000", "street_name": "são Luiz", "street_number": "15" } }, "available_balance": null, "nsu_processadora": null, "authentication_code": null }, "order": {}, "external_reference": "1631894348", "transaction_amount": 12.34, "transaction_amount_refunded": 0, "coupon_amount": 0, "differential_pricing_id": null, "deduction_schema": null, "installments": 1, "transaction_details": { "payment_method_reference_id": null, "net_received_amount": 11.72, "total_paid_amount": 12.34, "overpaid_amount": 0, "external_resource_url": null, "installment_amount": 12.34, "financial_institution": null, "payable_deferral_period": null, "acquirer_reference": null }, "fee_details": [ { "type": "mercadopago_fee", "amount": 0.62, "fee_payer": "collector" } ], "charges_details": [], "captured": true, "binary_mode": false, "call_for_authorize_id": null, "statement_descriptor": "Mercadopago*fake", "card": { "id": null, "first_six_digits": "503143", "last_four_digits": "6351", "expiration_month": 12, "expiration_year": 2022, "date_created": "2021-09-17T11:59:10.000-04:00", "date_last_updated": "2021-09-17T11:59:10.000-04:00", "cardholder": { "name": "APRO", "identification": { "number": "19119119100", "type": "CPF" } } }, "notification_url": "https://seu-site.com.br/webhookshttps://seu-site.com.br/webhooks", "refunds": [], "processing_mode": "aggregator", "merchant_account_id": null, "merchant_number": null, "acquirer_reconciliation": [], "point_of_interaction": {} } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_captured.json ================================================ { "id": 17014025134, "date_created": "2021-09-17T11:59:10.367-04:00", "date_approved": "2021-09-17T11:59:11.481-04:00", "date_last_updated": "2021-09-17T11:59:11.481-04:00", "date_of_expiration": null, "money_release_date": "2021-09-17T11:59:11.481-04:00", "operation_type": "regular_payment", "issuer_id": "24", "payment_method_id": "master", "payment_type_id": "credit_card", "status": "cancelled", "status_detail": "accredited", "currency_id": "BRL", "description": "PEDIDO NOVO - VIDEOGAME", "live_mode": true, "sponsor_id": null, "authorization_code": "301299", "money_release_schema": null, "taxes_amount": 0, "counter_currency": null, "brand_id": null, "shipping_amount": 0, "pos_id": null, "store_id": null, "integrator_id": null, "platform_id": null, "corporation_id": null, "collector_id": 810882223, "payer": { "type": null, "id": "128185910", "operator_id": null, "email": "test_user_1631894348@testuser.com", "identification": { "type": "CPF", "number": "19119119100" }, "phone": { "area_code": null, "number": null, "extension": null }, "first_name": null, "last_name": null, "entity_type": null }, "marketplace_owner": null, "metadata": { "order_number": "order_1631894348" }, "additional_info": { "items": [ { "id": "1941", "title": "Ingresso Antecipado", "description": "Natal Iluminado 2019", "picture_url": null, "category_id": "Tickets", "quantity": "1", "unit_price": "100.0" } ], "payer": { "phone": { "area_code": "11", "number": "987654321" }, "address": { "zip_code": "06233-200", "street_name": "Av. das Nações Unidas", "street_number": "3003" }, "first_name": "Nome", "last_name": "Sobrenome", "registration_date": "2013-08-06T09:25:04.000-03:00" }, "shipments": { "receiver_address": { "zip_code": "95630000", "street_name": "são Luiz", "street_number": "15" } }, "available_balance": null, "nsu_processadora": null, "authentication_code": null }, "order": {}, "external_reference": "1631894348", "transaction_amount": 12.34, "transaction_amount_refunded": 0, "coupon_amount": 0, "differential_pricing_id": null, "deduction_schema": null, "installments": 1, "transaction_details": { "payment_method_reference_id": null, "net_received_amount": 11.72, "total_paid_amount": 12.34, "overpaid_amount": 0, "external_resource_url": null, "installment_amount": 12.34, "financial_institution": null, "payable_deferral_period": null, "acquirer_reference": null }, "fee_details": [ { "type": "mercadopago_fee", "amount": 0.62, "fee_payer": "collector" } ], "charges_details": [], "captured": true, "binary_mode": false, "call_for_authorize_id": null, "statement_descriptor": "Mercadopago*fake", "card": { "id": null, "first_six_digits": "503143", "last_four_digits": "6351", "expiration_month": 12, "expiration_year": 2022, "date_created": "2021-09-17T11:59:10.000-04:00", "date_last_updated": "2021-09-17T11:59:10.000-04:00", "cardholder": { "name": "APRO", "identification": { "number": "19119119100", "type": "CPF" } } }, "notification_url": "https://seu-site.com.br/webhookshttps://seu-site.com.br/webhooks", "refunds": [], "processing_mode": "aggregator", "merchant_account_id": null, "merchant_number": null, "acquirer_reconciliation": [], "point_of_interaction": {} } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_card_token_error.json ================================================ { "message": "Card Token not found", "error": "bad_request", "status": 400, "cause": [ { "code": 2006, "description": "Card Token not found", "data": "23-09-2021T17:56:16UTC;3191d71e-86e6-481a-b218-977c0f01b14f" } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_pix.json ================================================ { "id": 21071815560, "date_created": "2022-01-10T10:10:10.000-00:00", "date_approved": null, "date_last_updated": "2022-01-10T10:10:10.000-00:00", "date_of_expiration": "2022-02-10T10:10:10.000-00:00", "money_release_date": null, "operation_type": "regular_payment", "issuer_id": null, "payment_method_id": "pix", "payment_type_id": "bank_transfer", "status": "pending", "status_detail": "pending_waiting_transfer", "currency_id": "BRL", "description": "description", "live_mode": true, "sponsor_id": null, "authorization_code": null, "money_release_schema": null, "taxes_amount": 0, "counter_currency": null, "brand_id": null, "shipping_amount": 0, "pos_id": null, "store_id": null, "integrator_id": null, "platform_id": null, "corporation_id": null, "collector_id": 471763966, "payer": { "type": null, "id": "128185910", "operator_id": null, "email": "test_user_1648059260@testuser.com", "identification": { "type": null, "number": null }, "phone": { "area_code": null, "number": null, "extension": null }, "first_name": null, "last_name": null, "entity_type": null }, "marketplace_owner": null, "metadata": {}, "additional_info": { "available_balance": null, "nsu_processadora": null, "authentication_code": null }, "order": {}, "external_reference": null, "transaction_amount": 100, "transaction_amount_refunded": 0, "coupon_amount": 0, "differential_pricing_id": null, "deduction_schema": null, "callback_url": null, "installments": 1, "transaction_details": { "payment_method_reference_id": null, "net_received_amount": 0, "total_paid_amount": 100, "overpaid_amount": 0, "external_resource_url": null, "installment_amount": 0, "financial_institution": null, "payable_deferral_period": null, "acquirer_reference": null, "bank_transfer_id": null, "transaction_id": null }, "fee_details": [], "charges_details": [], "captured": true, "binary_mode": false, "call_for_authorize_id": null, "statement_descriptor": null, "card": {}, "notification_url": null, "refunds": [], "processing_mode": "aggregator", "merchant_account_id": null, "merchant_number": null, "acquirer_reconciliation": [], "point_of_interaction": { "type": "OPENPLATFORM", "linked_to": "openfinance", "business_info": { "unit": "online_payments", "sub_unit": "default" }, "location": { "state_id": null, "source": null }, "application_data": { "name": null, "version": null }, "transaction_data": { "qr_code": "00020126580014br.gov.bcb.pix0136d58a7469-afb3-48dd-b279-5576754cd5f75204000053039865406100.005802BR5911TETE97814116009Sao Paulo62240520mpqrinter2107181556063044CC4", "bank_transfer_id": null, "transaction_id": null, "financial_institution": null, "bank_info": { "payer": { "account_id": null, "id": null, "long_name": null, "external_account_id": null }, "collector": { "account_id": null, "long_name": null, "account_holder_name": "Salazar Tucker", "transfer_account_id": null }, "is_same_bank_account_owner": null, "origin_bank_id": null, "origin_wallet_id": null }, "qr_code_base64": "iVBORw0KGgoAAAANSUhEUgAABWQAAAVkAQAAAAB79iscAAAI6UlEQVR42u3dW27kNhAFUO6A+9+ldsAAgZFRsy7Z7cwAianTH4ZtvY76r1CvNn7Q52q0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tH9e2+ZPv//v65RezvvnTu3XXf7+sxytp3yd179OSbf/OkpLS0tLS0tLS0tLS/sIbb+HbL/+vN+u3qS8S3r2/Yn1C5quWDBoaWlpaWlpaWlpaWkfob0HkC+P2Bx9uXZ6qylYvP9orwfa6ymZQUtLS0tLS0tLS0tL+zzt9frYlKtbhIgpbzil/cob0NLS0tLS0tLS0tLS0oZoLlNe8CmAnFDl/a4Qcg5aWlpaWlpaWlpaWtqnawu+l7vnprdaNJmLNaeKzVqY+Rs1orS0tLS0tLS0tLS0tD9dm6aU/Ac/fmOmCi0tLS0tLS0tLS0t7U/W5s+yt21RiZmiyBKVvqTz9hWbr6fQ0tLS0tLS0tLS0tKerU1Fk9cqqHyZ+/hBLJrH+NfpkfmdaWlpaWlpaWlpaWlpH6BNgNzb1nKFZTG27Jki0FxmecVAk5aWlpaWlpaWlpaW9mRtmRuSPKnfbeS1aSU+XfTU7ZN925iXlpaWlpaWlpaWlpb2MO1U/VizcYWyyP2l9WrvQsSaHvykRpSWlpaWlpaWlpaWlvYgbU7O1brKZchZ4r+X/rnNVP8Ui9Y/aWlpaWlpaWlpaWlpH6FdrqmejMvNavdbjXxtmXqSosj0LdHS0tLS0tLS0tLS0p6uXZRZTkFgyQIuHzZW106PbLkmc1t1SUtLS0tLS0tLS0tLe542Teu/TxWpFZFlRv9Ua5lmULZVFHmVk2lpaWlpaWlpaWlpaZ+onYohy7iRlxuXuY8t9Mr113euw/vzqoB3VZe0tLS0tLS0tLS0tLTnaUs6rx7Iz27vN2NPMWYq0bxKABm+JVpaWlpaWlpaWlpa2pO1eeJ+D7/VdF66toSSC9Ty6McxLy0tLS0tLS0tLS0t7Rna1RkVUDvVSvC5HCE5SjlmCTl7fhotLS0tLS0tLS0tLe352pq122fepua4vN265/Tg8i7fq7qkpaWlpaWlpaWlpaU9T1ub2VL7W87z7QLNTdVlL1d8HEXS0tLS0tLS0tLS0tIepa1RX35E7YErV0yBYVuVXvZwdHwWRdLS0tLS0tLS0tLS0p6rTcP2J0pxp89iS0BpoltkBj+MImlpaWlpaWlpaWlpaU/UjrAA+wpHR4kdy6a2xUK26bkpv1jItLS0tLS0tLS0tLS0p2un9Fu6UwtRZBryP3KxZiqzzHWa1/emlNDS0tLS0tLS0tLS0h6gXSbYcvda2qK2zAy2EmOWryBd22lpaWlpaWlpaWlpaZ+l/SjBVj+9jBYpawGu8FZTkNrepRFpaWlpaWlpaWlpaWnP1yZKK7NEJkUpqWxhSslihknCL4/S0tLS0tLS0tLS0tKerk2o0hI3XuO/tN26l4B0uktpk0stdjUVSEtLS0tLS0tLS0tLe7o2pfimKDIn7FpQpLBx0TW3TBS+iXlpaWlpaWlpaWlpaWlP027ybT2/Rk7d9VDAeYUtalOH3HRtLuCkpaWlpaWlpaWlpaU9W9s3pZdT0i3P8r9WxZotjznZPLeXzjxaWlpaWlpaWlpaWtrzte2uSBm/e9dc3y6sHqvM4ChhaH7GCAxaWlpaWlpaWlpaWtqztTk6XOT+cnTYwlD+GmguX6hMQhlvZ6rQ0tLS0tLS0tLS0tIepR2bprey/+xa3bh2yJWt2tfmJbfRKy0tLS0tLS0tLS0t7cnaHM0tgsDNDJP6pssxJ/l/H04poaWlpaWlpaWlpaWlPU1bwrzKKxm6a5W166F1bhEnTgeWqUBaWlpaWlpaWlpaWtrztcuqyyvMJulhDGROybUy2j9lAVPY+O9qRGlpaWlpaWlpaWlpaX+otlREpjLLZc9aK0P+84CSmjwsUekIB2hpaWlpaWlpaWlpaZ+iTZus8zCS1PQ2wgzKqWxzhGVuLawF6GXVGy0tLS0tLS0tLS0t7fnaXkLJZRC4T90tB49s+udqfvFNFElLS0tLS0tLS0tLS3uadrpgk8nrJf7bDzJJoyZzQDq+USNKS0tLS0tLS0tLS0t7mjb3oqWgMvGuFWoRYy4zg3k6Ci0tLS0tLS0tLS0t7SO0rUwp2WvLzJHpsSPUbl6hJnNK512l+JOWlpaWlpaWlpaWlvYh2npGXmKd6i+XtZvLmswrL8pOxZq0tLS0tLS0tLS0tLQP06b5/vsWtrLsegoq65D/6ctIX9AnU0poaWlpaWlpaWlpaWmP0qYRJCMk++rJKdmXea28VQk+62W0tLS0tLS0tLS0tLSP0KY0XcrapUrMNIJkU89Zd2nnF+pvZ6rQ0tLS0tLS0tLS0tIepb1WM0LqxrRUYTkFgena/fa2TREmLS0tLS0tLS0tLS3tI7SjzPLPk0v6KjAcuWFumc5LgWaZMtlpaWlpaWlpaWlpaWkfoi2VkyMP4F/2u6XZJIm3fIN3WwJoaWlpaWlpaWlpaWkfoW2b6seCbyEf2HLrXGpwK4NRprjz/Q4CWlpaWlpaWlpaWlrag7TLPrYpwsstcTUbNxVXlj67/QjJ9knVJS0tLS0tLS0tLS0t7VHaNn+WJZBX7l4rV/S8BTstu56CynsE2mlpaWlpaWlpaWlpaR+j3Y2LTGm/e3g5wgbtqbhyhBzhPUT8ZhRJS0tLS0tLS0tLS0t7pHZZ85hLL8fmz/KmKe6cpp4sR6TQ0tLS0tLS0tLS0tI+VtvyKuzSElfrNFOGrizKrmP8v5Pdo6WlpaWlpaWlpaWlfYa2FFyO8ltphOuvWbt0g7EZRJmyhbS0tLS0tLS0tLS0tI/QJnwprqzpt8/b32qy7377dy9OS0tLS0tLS0tLS0t7trYWPk7tasswbzPzf4QcYf1aPghNaWlpaWlpaWlpaWlpT9f+/z+0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tH9M+xd0qTe2JoomXQAAAABJRU5ErkJggg==", "ticket_url": "https://www.mercadopago.com.br/payments/21071815560/ticket?caller_id=471763966&hash=abcd1234efgh5678" } } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_pse.json ================================================ { "id": 111, "date_created": "2023-03-08T09:45:24.038-04:00", "date_approved": null, "date_last_updated": "2023-03-08T09:45:24.038-04:00", "date_of_expiration": null, "money_release_date": null, "money_release_status": null, "operation_type": "regular_payment", "issuer_id": null, "payment_method_id": "pse", "payment_type_id": "bank_transfer", "payment_method": { "id": "pse", "type": "bank_transfer" }, "status": "pending", "status_detail": "pending_waiting_transfer", "currency_id": "COP", "description": "description", "live_mode": false, "sponsor_id": null, "authorization_code": null, "money_release_schema": null, "taxes_amount": 0, "counter_currency": null, "brand_id": null, "shipping_amount": 0, "build_version": "2.136.0", "pos_id": null, "store_id": null, "integrator_id": null, "platform_id": null, "corporation_id": null, "payer": { "first_name": null, "last_name": null, "email": "email@example.com", "identification": { "number": "111111", "type": "DNI" }, "phone": { "area_code": null, "number": null, "extension": null }, "type": null, "entity_type": null, "id": "11111" }, "collector_id": 830082116, "marketplace_owner": null, "metadata": {}, "additional_info": { "ip_address": "127.0.0.1", "available_balance": null, "nsu_processadora": null, "authentication_code": null }, "order": {}, "external_reference": null, "transaction_amount": 5000, "net_amount": null, "taxes": [ { "value": null, "type": "IVA" } ], "transaction_amount_refunded": 0, "coupon_amount": 0, "differential_pricing_id": null, "financing_group": null, "deduction_schema": null, "callback_url": "http://your-site.com", "installments": 1, "transaction_details": { "payment_method_reference_id": null, "acquirer_reference": null, "net_received_amount": 0, "total_paid_amount": 5000, "overpaid_amount": 0, "external_resource_url": "https://www.mercadopago.com.co/sandbox/payments/1111/bank_transfer?caller_id=2222&hash=1234", "installment_amount": 0, "financial_institution": "1009", "payable_deferral_period": null, "bank_transfer_id": 153030, "transaction_id": "111" }, "fee_details": [], "charges_details": [], "captured": true, "binary_mode": false, "call_for_authorize_id": null, "statement_descriptor": null, "card": {}, "notification_url": "http://your-site.com", "refunds": [], "processing_mode": "aggregator", "merchant_account_id": null, "merchant_number": null, "acquirer_reconciliation": [], "point_of_interaction": { "type": "UNSPECIFIED", "business_info": { "unit": "online_payments", "sub_unit": "default" } }, "tags": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/payment/payment_search.json ================================================ { "paging": { "total": 102, "limit": 5, "offset": 0 }, "results": [ { "metadata": { }, "corporation_id": null, "operation_type": "regular_payment", "point_of_interaction": { "transaction_data": { "transaction_id": null, "bank_info": { "is_same_bank_account_owner": null, "payer": { "account_id": "9224382036864776100", "id": null, "long_name": null }, "collector": { "account_id": "9325372136954476022", "account_holder_name": "Salazar Tucker", "long_name": null, "transfer_account_id": null } }, "bank_transfer_id": null, "financial_institution": null, "qr_code": "00020126330014br.gov.bcb.pix0111129183146095204000053039865406100.005802BR5911Tourmania856006Santos62230519mpqrinter12410122386304D89B" }, "type": "OPENPLATFORM", "application_data": { "name": null, "version": null } }, "fee_details": [ ], "notification_url": null, "date_approved": null, "money_release_schema": null, "payer": { "first_name": null, "last_name": null, "email": "test_user_80507629@testuser.com", "identification": { "number": "32659430", "type": "DNI" }, "phone": { "area_code": null, "number": null, "extension": null }, "type": null, "entity_type": null, "id": "128185910" }, "transaction_details": { "transaction_id": null, "total_paid_amount": 100, "acquirer_reference": null, "installment_amount": 0, "bank_transfer_id": null, "financial_institution": null, "net_received_amount": 0, "overpaid_amount": 0, "external_resource_url": null, "payable_deferral_period": null, "payment_method_reference_id": null }, "statement_descriptor": null, "call_for_authorize_id": null, "installments": 1, "pos_id": null, "external_reference": null, "date_of_expiration": "2021-09-14T08:52:51.000-04:00", "charges_details": [ ], "id": 1241012238, "payment_type_id": "bank_transfer", "order": { }, "counter_currency": null, "brand_id": null, "status_detail": "expired", "differential_pricing_id": null, "additional_info": { "authentication_code": null, "nsu_processadora": null, "available_balance": null }, "live_mode": false, "marketplace_owner": null, "card": { }, "integrator_id": null, "status": "cancelled", "transaction_amount_refunded": 0, "transaction_amount": 100, "description": "description", "money_release_date": null, "merchant_number": null, "refunds": [ ], "callback_url": null, "authorization_code": null, "captured": true, "collector_id": 823549964, "merchant_account_id": null, "taxes_amount": 0, "date_last_updated": "2021-09-14T08:55:41.000-04:00", "coupon_amount": 0, "store_id": null, "date_created": "2021-09-13T08:52:52.000-04:00", "acquirer_reconciliation": [ ], "sponsor_id": null, "shipping_amount": 0, "issuer_id": null, "payment_method_id": "pix", "binary_mode": false, "platform_id": null, "deduction_schema": null, "processing_mode": "aggregator", "currency_id": "BRL", "shipping_cost": 0 }, { "metadata": { }, "corporation_id": null, "operation_type": "regular_payment", "point_of_interaction": { "transaction_data": { "transaction_id": null, "bank_info": { "is_same_bank_account_owner": null, "payer": { "account_id": null, "id": null, "long_name": null }, "collector": { "account_id": null, "account_holder_name": "Salazar Tucker", "long_name": null, "transfer_account_id": null } }, "bank_transfer_id": null, "financial_institution": null, "qr_code": "00020126330014br.gov.bcb.pix0111129183146095204000053039865406100.005802BR5911Tourmania856006Santos62230519mpqrinter1241012252630413D4" }, "type": "OPENPLATFORM", "application_data": { "name": null, "version": null } }, "fee_details": [ ], "notification_url": "https://seu-site.com.br/webhooks", "date_approved": null, "money_release_schema": null, "payer": { "first_name": null, "last_name": null, "email": "test_user_80507629@testuser.com", "identification": { "number": "32659430", "type": "DNI" }, "phone": { "area_code": null, "number": null, "extension": null }, "type": null, "entity_type": null, "id": "649457098" }, "transaction_details": { "transaction_id": null, "total_paid_amount": 100, "acquirer_reference": null, "installment_amount": 0, "bank_transfer_id": null, "financial_institution": null, "net_received_amount": 0, "overpaid_amount": 0, "external_resource_url": null, "payable_deferral_period": null, "payment_method_reference_id": null }, "statement_descriptor": null, "call_for_authorize_id": null, "installments": 1, "pos_id": null, "external_reference": "194a5325-87f7-4c47-8a6d-9caaa2e326ee", "date_of_expiration": "2021-09-14T08:53:55.000-04:00", "charges_details": [ ], "id": 1241012252, "payment_type_id": "bank_transfer", "order": { }, "counter_currency": null, "brand_id": null, "status_detail": "expired", "differential_pricing_id": null, "additional_info": { "authentication_code": null, "ip_address": "127.0.0.1", "nsu_processadora": null, "available_balance": null, "items": [ { "quantity": "1", "category_id": "categoryId", "picture_url": "pictureUrl", "description": "description", "id": "id", "title": "title", "unit_price": "100.0" } ], "payer": { "address": { "street_number": "1234", "street_name": "streetName", "zip_code": "0000" }, "registration_date": "2021-09-13T09:40:50.333-0300", "phone": { "number": "0000-0000", "area_code": "000" }, "last_name": "User", "first_name": "Test" }, "shipments": { "receiver_address": { "street_number": "1234", "floor": "floor", "apartment": "apartment", "street_name": "streetName", "zip_code": "0000" } } }, "live_mode": false, "marketplace_owner": null, "card": { }, "integrator_id": null, "status": "cancelled", "transaction_amount_refunded": 0, "transaction_amount": 100, "description": "description", "money_release_date": null, "merchant_number": null, "refunds": [ ], "callback_url": null, "authorization_code": null, "captured": true, "collector_id": 823549964, "merchant_account_id": null, "taxes_amount": 0, "date_last_updated": "2021-09-14T08:55:54.000-04:00", "coupon_amount": 0, "store_id": null, "date_created": "2021-09-13T08:53:55.000-04:00", "acquirer_reconciliation": [ ], "sponsor_id": null, "shipping_amount": 0, "issuer_id": null, "payment_method_id": "pix", "binary_mode": false, "platform_id": null, "deduction_schema": null, "processing_mode": "aggregator", "currency_id": "BRL", "shipping_cost": 0 }, { "metadata": { }, "corporation_id": null, "operation_type": "regular_payment", "point_of_interaction": { }, "fee_details": [ { "amount": 4.99, "fee_payer": "collector", "type": "mercadopago_fee" } ], "notification_url": "https://seu-site.com.br/webhooks", "date_approved": "2021-09-13T08:57:18.000-04:00", "money_release_schema": null, "payer": { "first_name": null, "last_name": null, "email": "test_user_80507629@testuser.com", "identification": { "number": "32659430", "type": "DNI" }, "phone": { "area_code": null, "number": null, "extension": null }, "type": null, "entity_type": null, "id": "649457098" }, "transaction_details": { "total_paid_amount": 100, "acquirer_reference": null, "installment_amount": 100, "financial_institution": null, "net_received_amount": 95.01, "overpaid_amount": 0, "external_resource_url": null, "payable_deferral_period": null, "payment_method_reference_id": null }, "statement_descriptor": "STATEMENTDESC", "call_for_authorize_id": null, "installments": 1, "pos_id": null, "external_reference": "85dd4f90-edfe-4b7b-bed5-efb368ca148e", "date_of_expiration": null, "charges_details": [ ], "id": 1241011467, "payment_type_id": "credit_card", "order": { }, "counter_currency": null, "brand_id": null, "status_detail": "partially_refunded", "differential_pricing_id": null, "additional_info": { "authentication_code": null, "ip_address": "127.0.0.1", "nsu_processadora": null, "available_balance": null, "items": [ { "quantity": "1", "category_id": "categoryId", "picture_url": "pictureUrl", "description": "description", "id": "id", "title": "title", "unit_price": "100.0" } ], "payer": { "address": { "street_number": "1234", "street_name": "streetName", "zip_code": "0000" }, "registration_date": "2021-09-13T09:57:10.755-0300", "phone": { "number": "0000-0000", "area_code": "000" }, "last_name": "User", "first_name": "Test" }, "shipments": { "receiver_address": { "street_number": "1234", "floor": "floor", "apartment": "apartment", "street_name": "streetName", "zip_code": "0000" } } }, "live_mode": false, "marketplace_owner": null, "card": { "first_six_digits": "503143", "expiration_year": 2031, "date_created": "2021-09-13T08:57:17.000-04:00", "expiration_month": 11, "id": null, "cardholder": { "identification": { "number": "37462770865", "type": "CPF" }, "name": "APRO" }, "last_four_digits": "6351", "date_last_updated": "2021-09-13T08:57:17.000-04:00" }, "integrator_id": null, "status": "approved", "transaction_amount_refunded": 1, "transaction_amount": 100, "description": "description", "money_release_date": "2021-09-13T08:57:18.000-04:00", "merchant_number": null, "refunds": [ { "reason": null, "amount": 1, "metadata": { }, "date_created": "2021-09-13T08:57:35.000-04:00", "external_refund_id": null, "source": { "name": "Mullins Hillary", "id": "823549964", "type": "collector" }, "unique_sequence_number": null, "refund_mode": "standard", "payment_id": 1241011467, "adjustment_amount": 0, "id": 1240999679, "status": "approved" } ], "authorization_code": null, "captured": true, "collector_id": 823549964, "merchant_account_id": null, "taxes_amount": 0, "date_last_updated": "2021-09-13T08:57:35.000-04:00", "coupon_amount": 0, "store_id": null, "date_created": "2021-09-13T08:57:18.000-04:00", "acquirer_reconciliation": [ ], "sponsor_id": null, "shipping_amount": 0, "issuer_id": "24", "payment_method_id": "master", "binary_mode": false, "platform_id": null, "deduction_schema": null, "processing_mode": "aggregator", "currency_id": "BRL", "shipping_cost": 0 }, { "metadata": { }, "corporation_id": null, "operation_type": "regular_payment", "point_of_interaction": { }, "fee_details": [ ], "notification_url": "https://seu-site.com.br/webhooks", "date_approved": null, "money_release_schema": null, "payer": { "first_name": null, "last_name": null, "email": "test_user_80507629@testuser.com", "identification": { "number": "32659430", "type": "DNI" }, "phone": { "area_code": null, "number": null, "extension": null }, "type": null, "entity_type": null, "id": "649457098" }, "transaction_details": { "total_paid_amount": 100, "acquirer_reference": null, "installment_amount": 100, "financial_institution": null, "net_received_amount": 0, "overpaid_amount": 0, "external_resource_url": null, "payable_deferral_period": null, "payment_method_reference_id": null }, "statement_descriptor": "STATEMENTDESC", "call_for_authorize_id": null, "installments": 1, "pos_id": null, "external_reference": "a862a6c5-af2c-43f1-9743-f535ba571c49", "date_of_expiration": null, "charges_details": [ ], "id": 1241012304, "payment_type_id": "credit_card", "order": { }, "counter_currency": null, "brand_id": null, "status_detail": "expired", "differential_pricing_id": null, "additional_info": { "authentication_code": null, "ip_address": "127.0.0.1", "nsu_processadora": null, "available_balance": null, "items": [ { "quantity": "1", "category_id": "categoryId", "picture_url": "pictureUrl", "description": "description", "id": "id", "title": "title", "unit_price": "100.0" } ], "payer": { "address": { "street_number": "1234", "street_name": "streetName", "zip_code": "0000" }, "registration_date": "2021-09-13T09:57:50.619-0300", "phone": { "number": "0000-0000", "area_code": "000" }, "last_name": "User", "first_name": "Test" }, "shipments": { "receiver_address": { "street_number": "1234", "floor": "floor", "apartment": "apartment", "street_name": "streetName", "zip_code": "0000" } } }, "live_mode": false, "marketplace_owner": null, "card": { "first_six_digits": "503143", "expiration_year": 2031, "date_created": "2021-09-13T08:57:51.000-04:00", "expiration_month": 11, "id": null, "cardholder": { "identification": { "number": "37462770865", "type": "CPF" }, "name": "APRO" }, "last_four_digits": "6351", "date_last_updated": "2021-09-13T08:57:51.000-04:00" }, "integrator_id": null, "status": "cancelled", "transaction_amount_refunded": 0, "transaction_amount": 100, "description": "description", "money_release_date": null, "merchant_number": null, "refunds": [ ], "authorization_code": null, "captured": false, "collector_id": 823549964, "merchant_account_id": null, "taxes_amount": 0, "date_last_updated": "2021-09-18T09:00:06.000-04:00", "coupon_amount": 0, "store_id": null, "date_created": "2021-09-13T08:57:52.000-04:00", "acquirer_reconciliation": [ ], "sponsor_id": null, "shipping_amount": 0, "issuer_id": "24", "payment_method_id": "master", "binary_mode": false, "platform_id": null, "deduction_schema": null, "processing_mode": "aggregator", "currency_id": "BRL", "shipping_cost": 0 }, { "metadata": { }, "corporation_id": null, "operation_type": "regular_payment", "point_of_interaction": { }, "fee_details": [ ], "notification_url": "https://seu-site.com.br/webhooks", "date_approved": null, "money_release_schema": null, "payer": { "first_name": null, "last_name": null, "email": "test_user_80507629@testuser.com", "identification": { "number": "32659430", "type": "DNI" }, "phone": { "area_code": null, "number": null, "extension": null }, "type": null, "entity_type": null, "id": "649457098" }, "transaction_details": { "total_paid_amount": 100, "acquirer_reference": null, "installment_amount": 100, "financial_institution": null, "net_received_amount": 0, "overpaid_amount": 0, "external_resource_url": null, "payable_deferral_period": null, "payment_method_reference_id": null }, "statement_descriptor": "STATEMENTDESC", "call_for_authorize_id": null, "installments": 1, "pos_id": null, "external_reference": "56ed682f-dcc5-49e8-8d9e-1a52ac421e7f", "date_of_expiration": null, "charges_details": [ ], "id": 1241012311, "payment_type_id": "credit_card", "order": { }, "counter_currency": null, "brand_id": null, "status_detail": "expired", "differential_pricing_id": null, "additional_info": { "authentication_code": null, "ip_address": "127.0.0.1", "nsu_processadora": null, "available_balance": null, "items": [ { "quantity": "1", "category_id": "categoryId", "picture_url": "pictureUrl", "description": "description", "id": "id", "title": "title", "unit_price": "100.0" } ], "payer": { "address": { "street_number": "1234", "street_name": "streetName", "zip_code": "0000" }, "registration_date": "2021-09-13T09:57:58.400-0300", "phone": { "number": "0000-0000", "area_code": "000" }, "last_name": "User", "first_name": "Test" }, "shipments": { "receiver_address": { "street_number": "1234", "floor": "floor", "apartment": "apartment", "street_name": "streetName", "zip_code": "0000" } } }, "live_mode": false, "marketplace_owner": null, "card": { "first_six_digits": "503143", "expiration_year": 2031, "date_created": "2021-09-13T08:57:59.000-04:00", "expiration_month": 11, "id": null, "cardholder": { "identification": { "number": "37462770865", "type": "CPF" }, "name": "APRO" }, "last_four_digits": "6351", "date_last_updated": "2021-09-13T08:57:59.000-04:00" }, "integrator_id": null, "status": "cancelled", "transaction_amount_refunded": 0, "transaction_amount": 100, "description": "description", "money_release_date": null, "merchant_number": null, "refunds": [ ], "authorization_code": null, "captured": false, "collector_id": 823549964, "merchant_account_id": null, "taxes_amount": 0, "date_last_updated": "2021-09-18T09:00:16.000-04:00", "coupon_amount": 0, "store_id": null, "date_created": "2021-09-13T08:58:00.000-04:00", "acquirer_reconciliation": [ ], "sponsor_id": null, "shipping_amount": 0, "issuer_id": "24", "payment_method_id": "master", "binary_mode": false, "platform_id": null, "deduction_schema": null, "processing_mode": "aggregator", "currency_id": "BRL", "shipping_cost": 0 } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/paymentmethod/payment_method_base.json ================================================ [ { "id": "debmaster", "name": "Mastercard Débito", "payment_type_id": "debit_card", "status": "testing", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/debmaster.gif", "thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/debmaster.gif", "deferred_capture": "unsupported", "settings": [ { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^(502121)", "installments_pattern": null, "exclusion_pattern": null }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_name", "cardholder_identification_type", "cardholder_identification_number" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 1440, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "pix", "name": "PIX", "payment_type_id": "bank_transfer", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/pix.gif", "thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/pix.gif", "deferred_capture": "does_not_apply", "settings": [ ], "additional_info_needed": [ ], "min_allowed_amount": 0.01, "max_allowed_amount": 9999999, "accreditation_time": 0, "financial_institutions": [ { "id": "1", "description": "PIX" } ], "processing_modes": [ "aggregator" ] }, { "id": "debcabal", "name": "Cabal Débito", "payment_type_id": "debit_card", "status": "testing", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/debcabal.gif", "thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/debcabal.gif", "deferred_capture": "unsupported", "settings": [ ], "additional_info_needed": [ "cardholder_name", "cardholder_identification_type", "cardholder_identification_number" ], "min_allowed_amount": 0.05, "max_allowed_amount": 60000, "accreditation_time": 0, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "debvisa", "name": "Visa Débito", "payment_type_id": "debit_card", "status": "testing", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/debvisa.gif", "thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/debvisa.gif", "deferred_capture": "unsupported", "settings": [ { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^(4)", "installments_pattern": "^(4)", "exclusion_pattern": null }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } }, { "card_number": { "validation": "standard", "length": 19 }, "bin": { "pattern": "^(4)", "installments_pattern": "^(4)", "exclusion_pattern": null }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } }, { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^(4)", "installments_pattern": "^(4)", "exclusion_pattern": null }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_name", "cardholder_identification_type", "cardholder_identification_number" ], "min_allowed_amount": 0.5, "max_allowed_amount": 50000, "accreditation_time": 1440, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "debelo", "name": "Elo Debito", "payment_type_id": "debit_card", "status": "testing", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/elo.gif", "thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/elo.gif", "deferred_capture": "unsupported", "settings": [ { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^(506722)", "installments_pattern": "", "exclusion_pattern": "^(506704|506706|506761|509887|506754|509882|506760|506764|506755|509881|506758|506702|506700|506770|509880|506768|506766|506716|506771|506767|506762|506735|506699|506756|506723|509884|506772|506713|506773|506710|506765|509901|509885|509815|506763|506734|506714|506712|506711|509894|509812|506769|506759|506757|506701)" }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_name", "cardholder_identification_type", "cardholder_identification_number" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 1440, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "hipercard", "name": "Hipercard", "payment_type_id": "credit_card", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/hipercard.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/hipercard.gif", "deferred_capture": "supported", "settings": [ { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^((606282)|(637095)|(637568)|(637599)|(637609)|(637612))", "installments_pattern": "^((606282)|(637095)|(637568)|(637599)|(637609)|(637612))", "exclusion_pattern": null }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } }, { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^((606282)|(637095)|(637568)|(637599)|(637609)|(637612))", "installments_pattern": "^((606282)|(637095)|(637568)|(637599)|(637609)|(637612))", "exclusion_pattern": null }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_identification_type", "cardholder_identification_number", "cardholder_name" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 2880, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "amex", "name": "American Express", "payment_type_id": "credit_card", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/amex.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/amex.gif", "deferred_capture": "supported", "settings": [ { "card_number": { "validation": "standard", "length": 15 }, "bin": { "pattern": "^((34)|(37))", "installments_pattern": "^(374758|374759|374760|374761|374762|374767|374768|374769|375130|375131|375132|375133|375134|375135|375136|375137|375138|375177|375178|375365|376421|376422|376423|376424|376425|376426|376427|376428|376429|376440|376441|376442|376443|376444|376445|376446|376449|376461|376462|376463|376464|376465|376466|376467|376471|376472|376473|376474|376475|376476|376477|376478|376479|376480|376481|376482|376483|376484|376485|376486|376487|376488|376489|376491|376493|376520|376521|376522|376523|376524|376525|376526|376527|376528|376529|376619|376620|376621|376622|376623|376624|376625|376626|376627|376628|376629|377169|377174|379966|379967|379968)", "exclusion_pattern": "^((384100)|(384140)|(384160))" }, "security_code": { "length": 4, "card_location": "front", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_identification_type", "cardholder_identification_number", "cardholder_name" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 2880, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "elo", "name": "Elo", "payment_type_id": "credit_card", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/elo.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/elo.gif", "deferred_capture": "supported", "settings": [ { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^((50670[7-8])|506715|(50671[8-9])|(50672[0-1])|(50672[4-9])|(50673[0-3])|506739|(50674[1-3])|(50674[5-7])|506753|(50677[4-8])|(50900[0-2])|(50900[4-7])|509009|(50901[0-2])|509014|(50902[0-9])|509030|(50903[5-9])|(50904[0-2])|(50904[4-9])|(50905[0-9])|(50906[0-4])|(50906[6-9])|(50907[0-2])|(50907[4-9])|(50908[0-9])|(50909[1-2])|(50909[5-9])|(50910[0-1])|(50910[6-9])|(50911[0-9])|(50912[0-9])|(50913[0-9])|(50914[0-9])|(50915[0-9])|(50916[0-9])|(50917[0-9])|(50918[0-9])|(50919[0-9])|(50920[0-9])|(50921[0-9])|(50922[0-9])|(50923[0-9])|(50924[0-9])|(50925[0-9])|(50926[0-9])|(50927[0-9])|(50928[0-9])|(50929[0-9])|(50930[0-9])|(50931[0-9])|(50932[0-9])|(50933[0-9])|(50934[0-9])|(50935[0-9])|(50936[0-9])|(50937[0-9])|(50938[0-9])|(50939[0-9])|(50940[0-9])|(50941[0-9])|(50942[0-9])|(50943[0-9])|(50944[0-9])|(50945[0-9])|(50946[0-9])|(50947[0-9])|(50948[0-9])|(50949[0-9])|(50950[0-9])|(50951[0-9])|(50952[0-9])|(50953[0-9])|(50954[0-9])|(50955[0-9])|(50956[0-9])|(50957[0-9])|(50958[0-9])|(50959[0-9])|(50960[0-9])|(50961[0-9])|(50962[0-9])|(50963[0-9])|(50964[0-9])|(50965[0-9])|(50966[0-9])|(50967[0-9])|(50968[0-9])|(50969[0-9])|(50970[0-9])|(50971[0-9])|(50972[0-9])|(50973[0-9])|(50974[0-9])|(50975[0-9])|(50976[0-9])|(50977[0-9])|(50978[0-9])|(50979[0-9])|(50980[0-7])|(50983[1-9])|(50984[0-9])|(50985[0-9])|(50986[0-9])|(50987[0-7])|(50989[7-9])|509900|(50991[8-9])|(50992[0-9])|(50993[0-9])|(50994[0-9])|(50995[0-9])|(50996[0-4])|(50997[1-9])|(50998[0-6])|(50999[5-9])|636368|(65040[6-9])|(65041[0-9])|(65042[0-9])|(65043[0-9])|(65048[5-9])|(65049[0-9])|(65050[0-4])|(65050[6-9])|(65051[0-5])|(65051[8-9])|(65052[0-9])|(65053[0-8])|(65055[2-9])|(65056[0-9])|(65057[0-9])|(65058[0-9])|(65059[0-8])|(65072[0-7])|(65090[1-9])|(65091[0-9])|(65092[0-2])|650928|650939|(65094[6-9])|(65095[0-9])|(65096[0-9])|(65097[0-8])|(65165[2-9])|(65166[0-1])|(65166[3-9])|(65167[0-9])|(65168[0-9])|(65169[0-9])|(65170[0-4])|(65500[0-9])|(65501[0-1])|(65501[3-9])|(65502[1-9])|(65503[0-9])|(65504[0-9])|(65505[0-7])|(506704|506706|506761|509887|636297))", "installments_pattern": "^(?!(506721))|(506718|(506720)|(50672[4-9])|(50673[0-3])|506739|(50674[1-3])|(50674[5-7])|506753|(50677[4-5])|(50677[7-8])|(50900[0-2])|(50900[4-7])|509009|509014|(50902[0-9])|509030|(50903[5-9])|(50904[0-2])|(50904[4-9])|(50905[0-3])|509064|(50906[6-9])|509072|(50907[4-9])|(50908[0-3])|(50908[5-6])|(50909[1-2])|(50909[5-9])|(50910[0-1])|(50910[7-9])|(50911[0-9])|(50912[0-9])|(50913[0-9])|(50914[0-9])|(50915[0-9])|(50916[0-9])|(50917[0-9])|(50918[0-9])|(50919[0-9])|(50920[0-9])|(50921[0-9])|(50922[0-9])|(50923[0-9])|(50924[0-9])|(50925[0-6])|(50950[7-9])|(50951[0-9])|(50952[0-9])|(50953[0-9])|(50954[0-9])|(50955[0-9])|(50956[0-9])|(50957[0-9])|(50958[0-9])|(50959[0-9])|(50960[0-9])|(50961[0-9])|(50962[0-9])|(50963[0-9])|(50964[0-9])|(50965[0-9])|(50966[0-9])|(50967[0-9])|(50968[0-9])|(50969[0-9])|(50970[0-9])|(50971[0-9])|(50972[0-9])|(50973[0-9])|(50974[0-9])|(50975[0-9])|(50976[0-9])|(50977[0-9])|(50978[0-9])|(50979[0-9])|(50980[0-7])|636368|(65048[5-9])|(65049[0-9])|(65050[0-4])|(65050[6-9])|(65051[0-3])|(65051[8-9])|(65052[0-9])|(65053[0-8])|(65055[2-9])|(65056[0-9])|(65057[0-9])|(65058[0-9])|(65059[0-8])|(65072[0-7])|(65090[1-9])|(65091[0-9])|(65092[0-2])|650928|650939|(65094[6-9])|(65095[0-9])|(65096[0-9])|(65097[0-8])|(65165[2-9])|(65166[0-1])|(65166[3-9])|(65167[0-9])|(65168[0-9])|(65169[0-9])|(65170[0-4])|(65500[0-9])|(65501[0-1])|(65501[3-9])|(65502[1-9])|(65503[0-9])|(65504[0-9])|(65505[0-7]))", "exclusion_pattern": "^(509023|506704|506706|506761|509887|506754|509882|506760|506764|506755|509881|506758|506702|506700|506770|509880|506768|506766|506716|506771|506767|506762|506735|506699|506756|506723|509884|506772|506713|506773|506710|506765|509901|509885|509815|506763|506734|506714|506712|506711|509894|509812|506769|506759|506757|506701)" }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_identification_number", "cardholder_identification_type", "cardholder_name" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 2880, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "cabal", "name": "Cabal", "payment_type_id": "credit_card", "status": "testing", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/cabal.gif", "thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/cabal.gif", "deferred_capture": "supported", "settings": [ ], "additional_info_needed": [ "cardholder_name", "cardholder_identification_type", "cardholder_identification_number" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 2880, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "visa", "name": "Visa", "payment_type_id": "credit_card", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/visa.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/visa.gif", "deferred_capture": "supported", "settings": [ { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^(4)", "installments_pattern": "^(?!(417401|453998|426398|462437|451212|456188|435087|404025|409280|406176|478507|430360|451302|410349))", "exclusion_pattern": "^(400163|400176|400178|400185|400199|423808|439267|471233|473200|476332|482481|451416|438935|(40117[8-9])|(45763[1-2])|457393|431274)" }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_name", "cardholder_identification_type", "cardholder_identification_number" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 2880, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "master", "name": "Mastercard", "payment_type_id": "credit_card", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/master.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/master.gif", "deferred_capture": "supported", "settings": [ { "card_number": { "validation": "standard", "length": 16 }, "bin": { "pattern": "^(5|(2(221|222|223|224|225|226|227|228|229|23|24|25|26|27|28|29|3|4|5|6|70|71|720)))", "installments_pattern": "^(?!(525823|525824|525834|527660|529133|529205|536390|513368|539131|529053|538450|538455|515675|549636|524886|546616|529115|511623|521580|527308|527648|528841|530551|533728|534300|539181|549622|528590|542865|538454|543299|549622|533728|230653|516129|527648|533519|557996|533433|511623|522157|529518|530551|546001|506704|506706|506761|509887|506754|509882|506760|506764|506755|509881|506758|506702|506700|506770|509880|506768|506766|506716|506771|506767|506762|506735|506699|506756|506723|509884|506772|506713|506773|506710|506765|509901|509885|509815|506763|506734|506714|506712|506711|509894|509812|506769|506759|506757|506701))", "exclusion_pattern": "^(506704|545377|506706|506761|509887|526968|550207|528635|542652|502121|506721|506722|506776|536969|589916|(50670[7-8])|(506715)|(50671[7-9])|(50672[0-1])|(50672[4-9])|(50673[0-3])|(506739)|(50674[0-8])|(50675[0-3])|(50677[4-8])|(50900[0-9])|(50901[3-9])|(50902[0-9])|(50903[1-5])|(50903[8-9])|(50904[0-9])|(50905[0-9])|(50906[0-4])|(50906[6-9])|(50907[0-2])|(50907[4-5])|(504175)|(50907[6-9])|(50908[0-9])|(509[0-7][0-9]{2})|(509[8]0[0-9])|(50983[1-9])|(5098[4-6][0-9])|(5098[7][0-7])|(50989[7-9])|(509900)|(50991[8-9])|(5099[2-5][0-9])|(5099[6][0-4])|(50997[1-9])|(50998[0-6])|(50999[5-9])|509810)" }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } }, { "card_number": { "validation": "standard", "length": 19 }, "bin": { "pattern": "^(532884)", "installments_pattern": "^(?!(549622|533728|230653|516129|527648|533519|557996|533433|511623|522157|529518|530551|546001))", "exclusion_pattern": "^(506704|545377|506706|506761|509887|506754|509882|506760|506764|506755|509881|506758|506702|506700|506770|509880|506768|506766|506716|506771|506767|506762|506735|506699|506756|506723|509884|506772|506713|506773|506710|506765|509901|509885|509815|506763|506734|506714|506712|506711|509894|509812|506769|506759|506757|506701)" }, "security_code": { "length": 3, "card_location": "back", "mode": "mandatory" } } ], "additional_info_needed": [ "cardholder_identification_type", "cardholder_name", "cardholder_identification_number" ], "min_allowed_amount": 0.5, "max_allowed_amount": 60000, "accreditation_time": 2880, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "pec", "name": "Pagamento na lotérica sem boleto", "payment_type_id": "ticket", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/pec.gif", "thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/pec.gif", "deferred_capture": "supported", "settings": [ ], "additional_info_needed": [ "identification_type", "identification_number", "first_name", "last_name" ], "min_allowed_amount": 4, "max_allowed_amount": 2000, "accreditation_time": 60, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "meliplace", "name": "Meliplaces", "payment_type_id": "ticket", "status": "testing", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/xxxxx.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/xxxxx.gif", "deferred_capture": "supported", "settings": [ ], "additional_info_needed": [ ], "min_allowed_amount": 0, "max_allowed_amount": 15000, "accreditation_time": 0, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "bolbradesco", "name": "Boleto", "payment_type_id": "ticket", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/bolbradesco.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/bolbradesco.gif", "deferred_capture": "does_not_apply", "settings": [ ], "additional_info_needed": [ "identification_type", "identification_number", "first_name", "last_name" ], "min_allowed_amount": 4, "max_allowed_amount": 100000, "accreditation_time": 1440, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] }, { "id": "account_money", "name": "Dinheiro na minha conta do MercadoPago", "payment_type_id": "account_money", "status": "active", "secure_thumbnail": "https://www.mercadopago.com/org-img/MP3/API/logos/account_money.gif", "thumbnail": "http://img.mlstatic.com/org-img/MP3/API/logos/account_money.gif", "deferred_capture": "supported", "settings": [ ], "additional_info_needed": [ ], "min_allowed_amount": 0.01, "max_allowed_amount": 10000000, "accreditation_time": 2880, "financial_institutions": [ ], "processing_modes": [ "aggregator" ] } ] ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/point/devices_list.json ================================================ { "devices": [ { "id": "GERTEC_MP35P__8701012051267123", "operating_mode": "PDV" } ], "paging": { "total": 1, "limit": 50, "offset": 0 } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/point/devices_operating_mode.json ================================================ { "operating_mode": "PDV" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/point/payment_intent.json ================================================ { "additional_info": { "external_reference": "4561ads-das4das4-das4754-das456", "print_on_terminal": true }, "amount": 1500, "description": "your payment intent description", "device_id": "GERTEC_MP35P__8701012051267123", "id": "68bf6839-ddb3-4825-8f4c-7eb26e68a5c3", "payment": { "installments": 1, "installments_cost": "seller", "type": "credit_card" } } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/point/payment_intent_delete.json ================================================ { "id": "afa5ffb4-9094-43de-8192-fb951e96ee95" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/point/payment_intent_list.json ================================================ { "events": [ { "payment_intent_id": "d2ee3a75-ca25-4bf3-9eca-f5f2d8f23bf4", "status": "ABANDONED", "created_on": "2022-01-24T10:10:10Z" }, { "payment_intent_id": "a16aba35-d43c-409d-b6c8-c3020797b061", "status": "CANCELED", "created_on": "2022-01-25T10:10:10Z" }, { "payment_intent_id": "68bf6839-ddb3-4825-8f4c-7eb26e68a5c3", "status": "ABANDONED", "created_on": "2022-01-26T10:10:10Z" } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/point/payment_intent_search.json ================================================ { "additional_info": { "external_reference": "4561ads-das4das4-das4754-das456", "print_on_terminal": true }, "amount": 1500, "description": "your payment intent description", "device_id": "GERTEC_MP35P__8701012051267123", "id": "afa5ffb4-9094-43de-8192-fb951e96ee95", "payment": { "installments": 1, "installments_cost": "seller", "type": "credit_card" }, "state": "OPEN" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/point/payment_intent_status.json ================================================ { "status": "CANCELED", "created_on": "2022-06-27T10:10:10Z" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/preapproval/preapproval_base.json ================================================ { "id": "2c9380847e9b451c017ea1bd70ba0219", "payer_id": 766790067, "payer_email": "", "back_url": "https://www.mercadopago.com.br", "collector_id": 823549964, "application_id": 6245132082630004, "status": "pending", "reason": "reason", "external_reference": "23546246234", "next_payment_date": "2022-01-10T10:10:10.000-00:00", "date_created": "2022-01-10T10:10:10.000-00:00", "last_modified": "2022-01-10T10:10:10.000-00:00", "init_point": "https://www.mercadopago.com.br/subscriptions/checkout?preapproval_id=2c9380847e9b451c017ea1bd70ba0219", "auto_recurring": { "frequency": 1, "frequency_type": "months", "transaction_amount": 10.00, "currency_id": "BRL", "start_date": "2022-01-10T10:10:10.000-00:00", "end_date": "2023-01-10T10:10:10.000-00:00", "free_trial": null }, "payment_method_id": null, "first_invoice_offset": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/preapproval/preapproval_list.json ================================================ { "paging": { "offset": 0, "limit": 2, "total": 7 }, "results": [ { "id": "2c9380847e9b1dd5017ea15e30fa01ee", "status": "pending", "reason": "Plan", "summarized": { "quotas": 25, "pending_charge_quantity": 25, "pending_charge_amount": 250.0 }, "payer_id": 766790067, "back_url": "https://www.mercadopago.com.br", "collector_id": 823549964, "application_id": 6245132082630004, "external_reference": "23546246234", "next_payment_date": "2022-01-10T10:10:10.000-00:00", "date_created": "2022-01-28T11:46:51.768-04:00", "last_modified": "2022-01-28T11:46:51.770-04:00", "init_point": "https://www.mercadopago.com.br/subscriptions/checkout?preapproval_id=2c9380847e9b1dd5017ea15e30fa01ee", "auto_recurring": { "frequency": 1, "frequency_type": "months", "transaction_amount": 10.0, "currency_id": "BRL", "start_date": "2020-06-02T09:07:14.260-04:00", "end_date": "2022-07-20T11:59:52.581-04:00" }, "payer_first_name": "Test", "payer_last_name": "" }, { "id": "2c9380847e9b1dd5017ea15f234701f0", "status": "pending", "reason": "Subscription", "summarized": { "quotas": 25, "pending_charge_quantity": 25, "pending_charge_amount": 250.0 }, "payer_id": 766790067, "back_url": "https://www.mercadopago.com.br", "collector_id": 823549964, "application_id": 6245132082630004, "external_reference": "23546246234", "next_payment_date": "2022-01-10T10:10:10.000-00:00", "date_created": "2022-01-28T11:47:53.795-04:00", "last_modified": "2022-01-28T11:47:53.799-04:00", "init_point": "https://www.mercadopago.com.br/subscriptions/checkout?preapproval_id=2c9380847e9b1dd5017ea15f234701f0", "auto_recurring": { "frequency": 1, "frequency_type": "months", "transaction_amount": 10.0, "currency_id": "BRL", "start_date": "2020-06-02T09:07:14.260-04:00", "end_date": "2022-07-20T11:59:52.581-04:00" }, "payer_first_name": "Test", "payer_last_name": "" } ] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/preapproval/preapproval_update.json ================================================ { "id": "2c9380847e9b451c017ea1bd70ba0219", "payer_id": 766790067, "payer_email": "", "back_url": "https://www.mercadopago.com.br", "collector_id": 823549964, "application_id": 6245132082630004, "status": "pending", "reason": "Updated reason", "external_reference": "23546246234", "next_payment_date": "2022-01-10T10:10:10.000-00:00", "date_created": "2022-01-10T10:10:10.000-00:00", "last_modified": "2022-01-10T10:10:10.000-00:00", "init_point": "https://www.mercadopago.com.br/subscriptions/checkout?preapproval_id=2c9380847e9b451c017ea1bd70ba0219", "auto_recurring": { "frequency": 1, "frequency_type": "months", "transaction_amount": 10.00, "currency_id": "BRL", "start_date": "2022-01-10T10:10:10.000-00:00", "end_date": "2023-01-10T10:10:10.000-00:00", "free_trial": null }, "payment_method_id": null, "first_invoice_offset": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/preference/preference_base.json ================================================ { "additional_info": "Discount: 12.00", "auto_return": "all", "back_urls": { "failure": "http://test.com/failure", "pending": "http://test.com/pending", "success": "http://test.com/success" }, "binary_mode": true, "client_id": "6245132082630004", "collector_id": 823549964, "coupon_code": null, "coupon_labels": null, "date_created": "2022-01-10T10:10:10.000+00:00", "date_of_expiration": "2022-02-10T10:10:10.000+00:00", "expiration_date_from": "2022-01-10T10:10:10.000+00:00", "expiration_date_to": "2022-02-10T10:10:10.000+00:00", "expires": false, "external_reference": "1643827245", "id": "823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", "init_point": "https://www.mercadopago.com.br/checkout/v1/redirect?pref_id=823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", "internal_metadata": null, "items": [ { "id": "1234", "category_id": "games", "currency_id": "BRL", "description": "PS5", "picture_url": "http://picture.com/PS5", "title": "Games", "quantity": 2, "unit_price": 4000 } ], "marketplace": "NONE", "marketplace_fee": 5, "metadata": {}, "notification_url": "http://notificationurl.com", "operation_type": "regular_payment", "payer": { "phone": { "area_code": "11", "number": "4444-4444" }, "address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123" }, "email": "test_user_64585784@testuser.com", "identification": { "number": "19119119100", "type": "CPF" }, "name": "Test", "surname": "User", "date_created": null, "last_purchase": null }, "payment_methods": { "default_card_id": null, "default_payment_method_id": "master", "excluded_payment_methods": [ { "id": "" } ], "excluded_payment_types": [ { "id": "ticket" } ], "installments": 5, "default_installments": 1 }, "processing_modes": null, "product_id": null, "redirect_urls": { "failure": "", "pending": "", "success": "" }, "sandbox_init_point": "https://sandbox.mercadopago.com.br/checkout/v1/redirect?pref_id=823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", "site_id": "MLB", "shipments": { "mode": "custom", "default_shipping_method": null, "cost": 10, "receiver_address": { "zip_code": "06000000", "street_name": "Street", "street_number": "123", "floor": "12", "apartment": "120A", "city_name": null, "state_name": null, "country_name": null } }, "statement_descriptor": "Test Store", "total_amount": null, "last_updated": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/preference/preference_list.json ================================================ { "elements": [ { "id": "823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", "client_id": "6245132082630004", "collector_id": 823549964, "concept_id": null, "corporation_id": "", "date_created": "2022-01-10T10:10:10.000+00:00", "expiration_date_from": "2022-01-10T10:10:10.000+00:00", "expiration_date_to": "2022-02-10T10:10:10.000+00:00", "expires": false, "external_reference": "1643827245", "integrator_id": "", "items": [ "Games" ], "last_updated": "2022-01-10T10:10:10.000+00:00", "live_mode": false, "marketplace": "NONE", "operation_type": "regular_payment", "payer_email": "test_user_64585784@testuser.com", "payer_id": null, "platform_id": "", "processing_modes": null, "product_id": "", "purpose": "", "site_id": "MLB", "sponsor_id": 0, "shipping_mode": "custom" }, { "id": "823549964-0348bff0-e5fc-4652-b7e2-957283c6478e", "client_id": "6245132082630004", "collector_id": 823549964, "concept_id": null, "corporation_id": "", "date_created": "2022-02-03T17:09:13.266+00:00", "expiration_date_from": "2022-01-10T10:10:10.000-03:00", "expiration_date_to": "2022-02-10T10:10:10.000-03:00", "expires": false, "external_reference": "1643827245", "integrator_id": "", "items": [ "Games" ], "last_updated": null, "live_mode": false, "marketplace": "NONE", "operation_type": "regular_payment", "payer_email": "test_user_64585784@testuser.com", "payer_id": null, "platform_id": "", "processing_modes": null, "product_id": "", "purpose": "", "site_id": "MLB", "sponsor_id": 0, "shipping_mode": "custom" } ], "next_offset": 2, "total": 19 } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/preference/preference_updated.json ================================================ { "additional_info": "Discount: 12.00", "auto_return": "all", "back_urls": { "failure": "http://test.com/failure", "pending": "http://test.com/pending", "success": "http://test.com/success" }, "binary_mode": false, "client_id": "6245132082630004", "collector": { "tags": [ "normal", "test_user", "messages_as_seller" ], "operator_id": null }, "collector_id": 823549964, "coupon_code": null, "coupon_labels": null, "date_created": "2022-02-03T17:09:52.992+00:00", "date_of_expiration": "2022-02-10T10:10:10.000-03:00", "expiration_date_from": "2022-01-10T10:10:10.000-03:00", "expiration_date_to": "2022-02-10T10:10:10.000-03:00", "expires": false, "external_reference": "1643827245", "headers": [], "id": "823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", "init_point": "https://www.mercadopago.com.br/checkout/v1/redirect?pref_id=823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", "internal_metadata": null, "items": [ { "id": "1234", "category_id": "games", "currency_id": "BRL", "description": "PS5", "picture_url": "http://picture.com/PS5", "title": "Games", "quantity": 2, "unit_price": 4000 } ], "live_mode": false, "marketplace": "NONE", "marketplace_fee": 5, "metadata": {}, "notification_url": "http://notificationurl.com", "operation_type": "regular_payment", "payer": { "phone": { "area_code": "11", "number": "4444-4444" }, "address": { "zip_code": "06233200", "street_name": "Street", "street_number": "123" }, "email": "test_user_64585784@testuser.com", "identification": { "number": "19119119100", "type": "CPF" }, "name": "Test", "surname": "User", "date_created": null, "last_purchase": null }, "payment_methods": { "default_card_id": null, "default_payment_method_id": "master", "excluded_payment_methods": [ { "id": "" } ], "excluded_payment_types": [ { "id": "ticket" } ], "installments": 5, "default_installments": 1 }, "processing_modes": null, "product_id": null, "purpose": "", "redirect_urls": { "failure": "", "pending": "", "success": "" }, "sandbox_init_point": "https://sandbox.mercadopago.com.br/checkout/v1/redirect?pref_id=823549964-e8063b12-1c8b-4333-b075-3ae52a0371c8", "site_id": "MLB", "shipments": { "mode": "custom", "default_shipping_method": null, "cost": 10, "receiver_address": { "zip_code": "06000000", "street_name": "Street", "street_number": "123", "floor": "12", "apartment": "120A", "city_name": null, "state_name": null, "country_name": null } }, "statement_descriptor": "Updated Store", "total_amount": 8000, "last_updated": "2022-02-03T17:11:17.678+00:00" } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/refund/refund_all.json ================================================ [ { "id": 934002419, "payment_id": 17014025134, "amount": 12.34, "metadata": {}, "source": { "id": "810882223", "name": "Test Test", "type": "collector" }, "date_created": "2021-09-17T14:50:53.198-04:00", "unique_sequence_number": null, "refund_mode": "standard", "adjustment_amount": 0, "status": "approved", "reason": null } ] ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/refund/refund_base.json ================================================ { "id": 1245678203, "payment_id": 17014025134, "amount": 50, "metadata": {}, "source": { "id": "823549964", "name": "Mullins Hillary", "type": "collector" }, "date_created": "2022-01-10T10:10:10.000-00:00", "unique_sequence_number": null, "refund_mode": "standard", "adjustment_amount": 0, "status": "approved", "reason": null, "labels": [], "partition_details": [] } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/refund/refund_list.json ================================================ [ { "id": 1245678203, "payment_id": 17014025134, "amount": 50, "metadata": {}, "source": { "name": "Mullins Hillary", "id": "823549964", "type": "collector" }, "date_created": "2022-01-10T10:10:10.000-00:00", "unique_sequence_number": null, "refund_mode": "standard", "adjustment_amount": 0, "status": "approved", "reason": null, "labels": [], "partition_details": [] }, { "id": 1245677387, "payment_id": 1245682962, "amount": 50, "metadata": {}, "source": { "name": "Mullins Hillary", "id": "823549964", "type": "collector" }, "date_created": "2022-01-10T10:10:10.000-00:00", "unique_sequence_number": null, "refund_mode": "standard", "adjustment_amount": 0, "status": "approved", "reason": null, "labels": [], "partition_details": [] } ] ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/refund/refund_partial.json ================================================ { "id": 934723769, "payment_id": 17014025134, "amount": 12.34, "metadata": {}, "source": { "id": "810882223", "name": "Test Test", "type": "collector" }, "date_created": "2021-09-17T14:50:53.198-04:00", "unique_sequence_number": null, "refund_mode": "standard", "adjustment_amount": 0, "status": "approved", "reason": null } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/response_generic_success.json ================================================ { "success": true } ================================================ FILE: src/test/java/com/mercadopago/resources/mocks/response/user/user_base.json ================================================ { "id": 539675046, "nickname": "TETE7689213", "registration_date": "2020-03-27T07:56:26.000-04:00", "first_name": "Test", "last_name": "Test", "gender": "", "country_id": "BR", "email": "test_user_3851037@testuser.com", "identification": { "number": "15635614680", "type": "CPF" }, "address": { "address": "Test Address 123", "city": "Sao Paulo", "state": "BR-SP", "zip_code": "47807078" }, "phone": { "area_code": "01", "extension": "", "number": "1111-1111", "verified": false }, "alternative_phone": { "area_code": "", "extension": "", "number": "" }, "user_type": "normal", "tags": [ "normal", "test_user", "messages_as_seller" ], "logo": null, "points": 100, "site_id": "MLB", "permalink": "http://perfil.mercadolivre.com.br/TETE7689213", "shipping_modes": [ "custom", "not_specified" ], "seller_experience": "ADVANCED", "bill_data": { "accept_credit_note": null }, "seller_reputation": { "level_id": "5_green", "power_seller_status": "platinum", "real_level": "newbie", "protection_end_date": "2021-03-27T07:56:34.000-04:00", "transactions": { "canceled": 0, "completed": 0, "period": "historic", "ratings": { "negative": 0, "neutral": 0, "positive": 0 }, "total": 0 }, "metrics": { "sales": { "period": "60 months", "completed": 0 }, "claims": { "period": "60 months", "rate": 0, "value": 0, "excluded": { "real_value": 0, "real_rate": 0 } }, "delayed_handling_time": { "period": "60 months", "rate": 0, "value": 0, "excluded": { "real_value": 0, "real_rate": 0 } }, "cancellations": { "period": "60 months", "rate": 0, "value": 0, "excluded": { "real_value": 0, "real_rate": 0 } } } }, "buyer_reputation": { "canceled_transactions": 0, "tags": [], "transactions": { "canceled": { "paid": null, "total": null }, "completed": null, "not_yet_rated": { "paid": null, "total": null, "units": null }, "period": "historic", "total": null, "unrated": { "paid": null, "total": null } } }, "status": { "billing": { "allow": true, "codes": [] }, "buy": { "allow": true, "codes": [], "immediate_payment": { "reasons": [], "required": false } }, "confirmed_email": false, "shopping_cart": { "buy": "allowed", "sell": "allowed" }, "immediate_payment": false, "list": { "allow": true, "codes": [], "immediate_payment": { "reasons": [], "required": false } }, "mercadoenvios": "not_accepted", "mercadopago_account_type": "personal", "mercadopago_tc_accepted": true, "required_action": null, "sell": { "allow": true, "codes": [], "immediate_payment": { "reasons": [], "required": false } }, "site_status": "active", "user_type": null }, "secure_email": "ttest.p892kv@mail.mercadolivre.com", "company": { "brand_name": null, "city_tax_id": "", "corporate_name": "", "identification": "", "state_tax_id": "", "cust_type_id": "CO", "soft_descriptor": null }, "credit": { "consumed": 0, "credit_level_id": "MLB1", "rank": "premium" }, "context": {}, "registration_identifiers": [] } ================================================ FILE: src/test/java/com/mercadopago/serialization/SerializerTest.java ================================================ package com.mercadopago.serialization; import static com.mercadopago.serialization.Serializer.deserializeResultsResourcesPageFromJson; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import com.google.gson.JsonObject; import com.google.gson.reflect.TypeToken; import com.mercadopago.client.customer.CustomerCardCreateRequest; import com.mercadopago.exceptions.MPJsonParseException; import com.mercadopago.helper.MockHelper; import com.mercadopago.net.MPElementsResourcesPage; import com.mercadopago.net.MPResource; import com.mercadopago.net.MPResourceList; import com.mercadopago.net.MPResultsResourcesPage; import com.mercadopago.resources.customer.CustomerCard; import com.mercadopago.resources.merchantorder.MerchantOrder; import com.mercadopago.resources.payment.Payment; import java.io.IOException; import java.lang.reflect.Type; import java.time.OffsetDateTime; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** SerializerTest class. */ public class SerializerTest { public final String malformedJson = "/*** malformed json */"; private String customerCardJson; @BeforeEach public void init() throws IOException { customerCardJson = MockHelper.readResponseFile("/card/card_new.json"); } @Test public void isJsonValidWithValidJson() throws IOException { assertTrue(Serializer.isJsonValid(customerCardJson)); } @Test public void isJsonValidWithInvalidJson() throws IOException { assertFalse(Serializer.isJsonValid(malformedJson)); } @Test public void deserializeFromJsonSuccess() throws MPJsonParseException { CustomerCard card = Serializer.deserializeFromJson(CustomerCard.class, customerCardJson); assertNotNull(card); assertEquals(2023, card.getExpirationYear()); assertEquals(6, card.getExpirationMonth()); } @Test public void deserializeFromJsonErrorThrowsMPJsonParseException() { assertThrows( MPJsonParseException.class, () -> Serializer.deserializeFromJson(CustomerCard.class, malformedJson)); } @Test public void deserializeResultsResourcesPageFromJsonSuccess() throws IOException, MPJsonParseException { String paymentSearchJson = MockHelper.readResponseFile("/payment/payment_search.json"); Type responseType = new TypeToken>() {}.getType(); MPResultsResourcesPage result = deserializeResultsResourcesPageFromJson(responseType, paymentSearchJson); assertNotNull(result); assertEquals(5, result.getResults().size()); } @Test public void deserializeResultsResourcesPageFromJsonErrorThrowsJsonParseException() { Type responseType = new TypeToken>() {}.getType(); assertThrows( MPJsonParseException.class, () -> Serializer.deserializeElementsResourcesPageFromJson(responseType, malformedJson)); } @Test public void deserializeElementsResourcesPageFromJsonSuccess() throws IOException, MPJsonParseException { String merchantOrderJson = MockHelper.readResponseFile("/merchant/order_search.json"); Type responseType = new TypeToken>() {}.getType(); MPElementsResourcesPage result = Serializer.deserializeElementsResourcesPageFromJson(responseType, merchantOrderJson); assertNotNull(result); assertEquals(2, result.getElements().size()); } @Test public void deserializeElementsResourcesPageFromJsonErrorThrowsJsonParseException() { Type responseType = new TypeToken>() {}.getType(); assertThrows( MPJsonParseException.class, () -> Serializer.deserializeElementsResourcesPageFromJson(responseType, malformedJson)); } @Test public void deserializeListFromJsonSuccess() throws IOException, MPJsonParseException { String cardListJson = MockHelper.readResponseFile("/card/card_all.json"); MPResourceList cards = Serializer.deserializeListFromJson(CustomerCard.class, cardListJson); assertNotNull(cards); assertEquals(2023, cards.getResults().get(0).getExpirationYear()); assertEquals(6, cards.getResults().get(0).getExpirationMonth()); } @Test public void deserializeListFromJsonErrorThrowsMPJsonParseException() { assertThrows( MPJsonParseException.class, () -> Serializer.deserializeListFromJson(CustomerCard.class, malformedJson)); } @Test public void serializeToJsonSuccess() { CustomerCardCreateRequest cardCreateRequest = CustomerCardCreateRequest.builder().token("abc").paymentMethodId("credit_card").build(); JsonObject json = Serializer.serializeToJson(cardCreateRequest); assertNotNull(json); } @Test public void deserializeListFromJsonIso8601Timestamps() throws IOException, MPJsonParseException { String timestampsJson = MockHelper.readFile( "serializer_iso8601_timestamps.json", "./src/test/java/com/mercadopago/resources/mocks/helper/"); Iso8601Timestamps deserialized = Serializer.deserializeFromJson(Iso8601Timestamps.class, timestampsJson); assertEquals(2021, deserialized.timestamps.get(0).getYear()); assertEquals(1, deserialized.timestamps.get(0).getMonth().getValue()); assertEquals(13, deserialized.timestamps.get(0).getDayOfYear()); } private static class Iso8601Timestamps extends MPResource { public List timestamps; } } ================================================ FILE: src/test/java/com/mercadopago/webhook/WebhookSignatureValidatorTest.java ================================================ package com.mercadopago.webhook; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import com.mercadopago.exceptions.MPInvalidWebhookSignatureException; import com.mercadopago.exceptions.SignatureFailureReason; import java.nio.charset.StandardCharsets; import java.time.Duration; import java.time.Instant; import java.util.List; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; import org.junit.jupiter.api.Test; /** Unit tests for {@link WebhookSignatureValidator}. Self-contained; no network access. */ class WebhookSignatureValidatorTest { private static final String SECRET = "your_secret_key_here"; private static final String REQUEST_ID = "2066ca19-c6f1-498a-be75-1923005edd06"; private static final String DATA_ID_RAW = "ORD01JQ4S4KY8HWQ6NA5PXB65B3D3"; private static final String DATA_ID_LOWER = "ord01jq4s4ky8hwq6na5pxb65b3d3"; private static final String TS = "1742505638683"; private static String computeHash(String dataId, String requestId, String ts, String secret) { try { StringBuilder mb = new StringBuilder(); if (dataId != null && !dataId.isEmpty()) { mb.append("id:").append(dataId.toLowerCase()).append(';'); } if (requestId != null && !requestId.isEmpty()) { mb.append("request-id:").append(requestId).append(';'); } mb.append("ts:").append(ts).append(';'); Mac mac = Mac.getInstance("HmacSHA256"); mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256")); byte[] hashBytes = mac.doFinal(mb.toString().getBytes(StandardCharsets.UTF_8)); StringBuilder sb = new StringBuilder(hashBytes.length * 2); for (byte b : hashBytes) { sb.append(String.format("%02x", b & 0xff)); } return sb.toString(); } catch (Exception e) { throw new RuntimeException(e); } } private static String buildHeader(String hash) { return "ts=" + TS + ",v1=" + hash; } private static String buildHeader(String hash, String ts) { return "ts=" + ts + ",v1=" + hash; } private static String validHash() { return computeHash(DATA_ID_LOWER, REQUEST_ID, TS, SECRET); } // case 1 @Test void happyPathLowercase() { assertDoesNotThrow(() -> WebhookSignatureValidator.validate(buildHeader(validHash()), REQUEST_ID, DATA_ID_LOWER, SECRET)); } // case 2 @Test void uppercaseDataIdIsLowercased() { assertDoesNotThrow(() -> WebhookSignatureValidator.validate(buildHeader(validHash()), REQUEST_ID, DATA_ID_RAW, SECRET)); } // case 3 @Test void malformedHeaderThrowsMalformed() { MPInvalidWebhookSignatureException ex = assertThrows(MPInvalidWebhookSignatureException.class, () -> WebhookSignatureValidator.validate("this-is-garbage", REQUEST_ID, DATA_ID_LOWER, SECRET)); assertEquals(SignatureFailureReason.MALFORMED_SIGNATURE_HEADER, ex.getReason()); assertEquals(REQUEST_ID, ex.getRequestId()); } // case 4 @Test void missingHeaderThrowsMissingHeader() { MPInvalidWebhookSignatureException ex = assertThrows(MPInvalidWebhookSignatureException.class, () -> WebhookSignatureValidator.validate(null, REQUEST_ID, DATA_ID_LOWER, SECRET)); assertEquals(SignatureFailureReason.MISSING_SIGNATURE_HEADER, ex.getReason()); } // case 5 @Test void missingTsThrowsMissingTimestamp() { MPInvalidWebhookSignatureException ex = assertThrows(MPInvalidWebhookSignatureException.class, () -> WebhookSignatureValidator.validate("v1=" + validHash(), REQUEST_ID, DATA_ID_LOWER, SECRET)); assertEquals(SignatureFailureReason.MISSING_TIMESTAMP, ex.getReason()); } // case 6 @Test void missingV1ThrowsMissingHash() { MPInvalidWebhookSignatureException ex = assertThrows(MPInvalidWebhookSignatureException.class, () -> WebhookSignatureValidator.validate("ts=" + TS, REQUEST_ID, DATA_ID_LOWER, SECRET)); assertEquals(SignatureFailureReason.MISSING_HASH, ex.getReason()); assertEquals(TS, ex.getTimestamp()); } // case 7 @Test void tamperedHashThrowsSignatureMismatch() { String h = validHash(); String tampered = h.substring(0, h.length() - 2) + (h.endsWith("00") ? "ff" : "00"); MPInvalidWebhookSignatureException ex = assertThrows(MPInvalidWebhookSignatureException.class, () -> WebhookSignatureValidator.validate(buildHeader(tampered), REQUEST_ID, DATA_ID_LOWER, SECRET)); assertEquals(SignatureFailureReason.SIGNATURE_MISMATCH, ex.getReason()); } // case 8 @Test void timestampOutsideToleranceThrows() { String staleTs = String.valueOf(Instant.now().toEpochMilli() - 30 * 60 * 1000L); String h = computeHash(DATA_ID_LOWER, REQUEST_ID, staleTs, SECRET); MPInvalidWebhookSignatureException ex = assertThrows(MPInvalidWebhookSignatureException.class, () -> WebhookSignatureValidator.validate( buildHeader(h, staleTs), REQUEST_ID, DATA_ID_LOWER, SECRET, Duration.ofMinutes(5))); assertEquals(SignatureFailureReason.TIMESTAMP_OUT_OF_TOLERANCE, ex.getReason()); } @Test void timestampWithinTolerancePasses() { String currentTs = String.valueOf(Instant.now().toEpochMilli()); String h = computeHash(DATA_ID_LOWER, REQUEST_ID, currentTs, SECRET); assertDoesNotThrow(() -> WebhookSignatureValidator.validate( buildHeader(h, currentTs), REQUEST_ID, DATA_ID_LOWER, SECRET, Duration.ofMinutes(5))); } // case 9 @Test void dataIdAbsentExcludesIdPair() { String h = computeHash(null, REQUEST_ID, TS, SECRET); assertDoesNotThrow(() -> WebhookSignatureValidator.validate(buildHeader(h), REQUEST_ID, null, SECRET)); } // case 10 @Test void requestIdAbsentExcludesRequestIdPair() { String h = computeHash(DATA_ID_LOWER, null, TS, SECRET); assertDoesNotThrow(() -> WebhookSignatureValidator.validate(buildHeader(h), null, DATA_ID_LOWER, SECRET)); } // case 11 @Test void bothAbsentYieldsTsOnly() { String h = computeHash(null, null, TS, SECRET); assertDoesNotThrow(() -> WebhookSignatureValidator.validate(buildHeader(h), "", " ", SECRET)); } // case 12 @Test void nonPaymentTopicUsesSameAlgorithm() { String orderId = "ord01abc123"; String h = computeHash(orderId, REQUEST_ID, TS, SECRET); assertDoesNotThrow(() -> WebhookSignatureValidator.validate(buildHeader(h), REQUEST_ID, orderId, SECRET)); } @Test void supportsV1WhenBothPresent() { String header = "ts=" + TS + ",v1=" + validHash() + ",v2=aaaa"; assertDoesNotThrow(() -> WebhookSignatureValidator.validate( header, REQUEST_ID, DATA_ID_LOWER, SECRET, null, List.of("v1"), null)); } @Test void onlyV2InHeaderOnlyV1SupportedThrowsMissingHash() { String header = "ts=" + TS + ",v2=somehash"; MPInvalidWebhookSignatureException ex = assertThrows(MPInvalidWebhookSignatureException.class, () -> WebhookSignatureValidator.validate( header, REQUEST_ID, DATA_ID_LOWER, SECRET, null, List.of("v1"), null)); assertEquals(SignatureFailureReason.MISSING_HASH, ex.getReason()); } @Test void nullSecretThrowsNpe() { assertThrows(NullPointerException.class, () -> WebhookSignatureValidator.validate(buildHeader(validHash()), REQUEST_ID, DATA_ID_LOWER, null)); } }