# MD for: https://www.mercadopago.com.br/developers/en/docs/apple-pay/attached-model-integration/web-integration.md
\# Mercado Pago integration for websites This model lets you offer Apple Pay on your website without managing payment certificates or decrypting tokens on your server. You can integrate \*\*via SDK\*\*, using the Mercado Pago JavaScript SDK in the frontend to display the Apple Pay button, or \*\*via API\*\*, implementing the flow in your backend. In both cases, Mercado Pago handles validation with Apple and returns a token ready to create the payment.
sequenceDiagram
title How it works
participant C as Buyer
participant V as Website (frontend)
participant MP as Mercado Pago
participant A as Apple
V->>MP: Initialize Apple Pay
MP->>A: Validate merchant and domain
A-->>V: Apple Pay button available
C->>V: Click Apple Pay
V->>A: Payment request (Touch ID/Face ID)
A-->>MP: Apple Pay token
MP-->>V: Mercado Pago token (callback)
V->>V: Send token to backend
V->>MP: Create payment (token + data)
MP-->>V: Payment response
:::::TabsComponent ::::TabComponent{title="Via SDK"} In this integration you use the Mercado Pago JavaScript SDK in the frontend to display the Apple Pay button. Mercado Pago validates the session with Apple and returns a token ready to create the payment in your backend. Follow the steps below to integrate. :::AccordionComponent{title="Include the SDK and initialize Apple Pay" pill="1"} Having obtained and configured the \[required Apple Developer certificates\](https://www.mercadopago.com.br/developers/en/docs/apple-pay/obtain-apple-developer-certificates), include the \[MercadoPago.js\](https://www.mercadopago.com/developers/en/docs/sdks-library/client-side/mp-js-v2) SDK on your page:
* [html ](#editor%5F1)
html
```
```
Copiar
Then, initialize the library with your :toolTipComponent\[test Public Key\]{content="Public key of the application created in Mercado Pago, used in the frontend. You can access it in \*Your integrations > Application details > Test > Test credentials\*."}: \`\`\`javascript const mp = new MercadoPago('YOUR\_PUBLIC\_KEY'); const quickCheckoutBuilder = mp.quickCheckout(); \`\`\` ::: :::AccordionComponent{title="Configure and render the Apple Pay button" pill="2"} 1\. Configure the payment and Apple Pay session data in your frontend. Below, you can see a configuration example and a description of the parameters necessary to do so.
* [javascript ](#editor%5F2)
javascript
```
const renderApplePayBrick = async (quickCheckoutBuilder) => {
const settings = {
checkoutTypes: ['applePay'],
applePay: {
paymentRequest: {
countryCode: 'BR',
currencyCode: 'BRL',
merchantCapabilities: ['supports3DS'],
supportedNetworks: ['visa', 'masterCard'],
total: {
label: 'My product',
amount: '10.00'
}
},
sessionRequest: {
id: 'PUBLIC_HASH_FROM_MERCADO_PAGO',
merchantIdentifier: 'merchant.your-identifier',
domainName: 'your-domain.com',
displayName: 'My store',
initiative: 'web',
initiativeContext: 'your-domain.com'
},
customization: {
locale: 'en-US'
},
callbacks: {
onReady: async () => {
console.log('Apple Pay ready');
},
onTokenGenerated: async (token, bin, paymentMethodId) => {
// Send token, bin and paymentMethodId to your backend to create the payment
const response = await fetch('/your-endpoint/pay', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ token, bin, paymentMethodId })
});
const result = await response.json();
// Redirect or display result according to result
},
onCancel: async () => {
console.log('Payment cancelled');
},
onError: async (error) => {
console.error('Apple Pay error:', error);
}
}
}
};
window.applePayBrickController = await quickCheckoutBuilder.create(
'payment-container',
settings
);
};
renderApplePayBrick(quickCheckoutBuilder);
```
Copiar
| Parameter | Description | | --- | --- | | \`paymentRequest.merchantCapabilities\` | Merchant capabilities for the payment. Must include \`supports3DS\` to enable 3D Secure authentication in Apple Pay transactions. | | \`paymentRequest.supportedNetworks\` | Payment networks supported in the checkout. Only the \`visa\` and/or \`masterCard\` card brands are supported. | | \`sessionRequest.id\` | Public \_hash\_ that Mercado Pago provides after you configure and submit the certificates in the Apple Developer Portal. It identifies your Apple Pay session with Mercado Pago. | | \`sessionRequest.merchantIdentifier\` | Unique identifier of your business in Apple Pay. Must match the Merchant ID you created and configured in the Apple Developer Portal. | | \`sessionRequest.domainName\` | Domain of your site where the Apple Pay button is displayed. Must match the domain you verified in the Apple Developer Portal and where the verification file is published in \`.well-known\`. | | \`sessionRequest.displayName\` | Merchant name shown to the user during the Apple Pay payment flow, for example on the Touch ID or Face ID authorization screen. | | \`sessionRequest.initiativeContext\` | Web payment initiative context. Must have the same value as \`domainName\` for the Apple Pay session to validate correctly. | 2\. After creating the configuration, define the container in your HTML where the Apple Pay button will be rendered and add the code below. \`\`\`html \`\`\` The rendered component should look similar to the image below. !\[Apple Pay button\](https://www.mercadopago.com.br/images/apple-pay/applepay-button-pt.png) ### Button visual customization You can customize the button style, text type, and language in the \`customization\` object of your configuration: \`\`\`javascript customization: { buttonStyle: 'black', // 'black' | 'white' | 'white-outline' buttonType: 'pay', // 'pay' | 'buy' | 'check-out' | 'plain' | etc. locale: 'en-US' // The default is the language and region currently configured in the browser } \`\`\` | Option | Description | | --- | --- | | \`buttonStyle\` | Button style. Values can be: \`black\`, \`white\`, or \`white-outline\`. | | \`buttonType\` | Button type displayed. Values can be: \`pay\`, \`buy\`, \`check-out\`, \`plain\`, among others. | | \`locale\` | Language code. Values can be: \`es-ES\`, \`pt-BR\`, \`en-US\`, among others. | ::: :::AccordionComponent{title="Create the payment" pill="3"} When the buyer authorizes the payment with Apple Pay, the \`onTokenGenerated\` callback delivers the \`token\`, \`bin\`, and \`paymentMethodId\` to your frontend. Send these values in the payment to Mercado Pago through our SDKs. Use your :toolTipComponent\[test Access Token\]{content="Private key of the application created in Mercado Pago, used in the backend. You can access it in \*Your integrations > Application details > Test > Test credentials\*."}.
* [csharp ](#editor%5F7)
* [java ](#editor%5F5)
* [node ](#editor%5F4)
* [php ](#editor%5F3)
* [python ](#editor%5F8)
* [ruby ](#editor%5F6)
php node java ruby csharp python
```
setCustomHeaders(["X-Idempotency-Key: "]);
$payment = $client->create([
"transaction_amount" => (float) $_POST[''],
"token" => $_POST[''],
"description" => $_POST[''],
"installments" => $_POST[''],
"payment_method_id" => $_POST[''],
"issuer_id" => $_POST[''],
"payer" => [
"email" => $_POST[''],
"identification" => [
"type" => $_POST[''],
"number" => $_POST['']
]
]
], $request_options);
echo implode($payment);
?>
```
Copiar
```
import { MercadoPagoConfig, Payment } from '@src/index';
const client = new MercadoPagoConfig({ accessToken: '', options: { timeout: 5000 } });
const payment = new Payment(client);
payment
.create({
body: {
transaction_amount: 100,
token: '',
description: '',
installments: 1,
payment_method_id: '',
issuer_id: 310,
payer: {
email: '',
identification: {
number: '12345678909',
type: 'CPF',
},
},
},
}).then(console.log).catch(console.log);
```
Copiar
```
Map customHeaders = new HashMap<>();
customHeaders.put("x-idempotency-key", );
MPRequestOptions requestOptions = MPRequestOptions.builder()
.customHeaders(customHeaders)
.build();
MercadoPagoConfig.setAccessToken("YOUR_ACCESS_TOKEN");
PaymentClient client = new PaymentClient();
PaymentCreateRequest paymentCreateRequest =
PaymentCreateRequest.builder()
.transactionAmount(request.getTransactionAmount())
.token(request.getToken())
.description(request.getDescription())
.installments(request.getInstallments())
.paymentMethodId(request.getPaymentMethodId())
.payer(
PaymentPayerRequest.builder()
.email(request.getPayer().getEmail())
.firstName(request.getPayer().getFirstName())
.identification(
IdentificationRequest.builder()
.type(request.getPayer().getIdentification().getType())
.number(request.getPayer().getIdentification().getNumber())
.build())
.build())
.build();
client.create(paymentCreateRequest, requestOptions);
```
Copiar
```
require 'mercadopago'
sdk = Mercadopago::SDK.new('YOUR_ACCESS_TOKEN')
custom_headers = {
'x-idempotency-key': ''
}
custom_request_options = Mercadopago::RequestOptions.new(custom_headers: custom_headers)
payment_data = {
transaction_amount: params[:transactionAmount].to_f,
token: params[:token],
description: params[:description],
installments: params[:installments].to_i,
payment_method_id: params[:paymentMethodId],
payer: {
email: params[:cardholderEmail],
identification: {
type: params[:identificationType],
number: params[:identificationNumber]
},
first_name: params[:cardholderName]
}
}
payment_response = sdk.payment.create(payment_data, custom_request_options)
payment = payment_response[:response]
puts payment
```
Copiar
```
using System;
using MercadoPago.Client.Common;
using MercadoPago.Client.Payment;
using MercadoPago.Config;
using MercadoPago.Resource.Payment;
MercadoPagoConfig.AccessToken = "YOUR_ACCESS_TOKEN";
var requestOptions = new RequestOptions();
requestOptions.CustomHeaders.Add("x-idempotency-key", "");
var paymentRequest = new PaymentCreateRequest
{
TransactionAmount = decimal.Parse(Request["transactionAmount"]),
Token = Request["token"],
Description = Request["description"],
Installments = int.Parse(Request["installments"]),
PaymentMethodId = Request["paymentMethodId"],
Payer = new PaymentPayerRequest
{
Email = Request["cardholderEmail"],
Identification = new IdentificationRequest
{
Type = Request["identificationType"],
Number = Request["identificationNumber"],
},
FirstName = Request["cardholderName"]
},
};
var client = new PaymentClient();
Payment payment = await client.CreateAsync(paymentRequest, requestOptions);
Console.WriteLine(payment.Status);
```
Copiar
```
import mercadopago
sdk = mercadopago.SDK("ACCESS_TOKEN")
request_options = mercadopago.config.RequestOptions()
request_options.custom_headers = {
'x-idempotency-key': ''
}
payment_data = {
"transaction_amount": float(request.POST.get("transaction_amount")),
"token": request.POST.get("token"),
"description": request.POST.get("description"),
"installments": int(request.POST.get("installments")),
"payment_method_id": request.POST.get("payment_method_id"),
"payer": {
"email": request.POST.get("cardholderEmail"),
"identification": {
"type": request.POST.get("identificationType"),
"number": request.POST.get("identificationNumber")
},
"first_name": request.POST.get("cardholderName")
}
}
payment_response = sdk.payment().create(payment_data, request_options)
payment = payment_response["response"]
print(payment)
```
Copiar
| Element | Description | Required | | --- | --- | --- | | \`Authorization\` | Header with your :toolTipComponent\[test Access Token\]{content="Private key of the application created in Mercado Pago, used in the backend. You can access it in \*Your integrations > Application details > Test > Test credentials\*."}. | Required | | \`X-Idempotency-Key\` | Unique value per request (for example, UUID v4) to avoid duplicate payments. | Required | | \`token\` | Card token received in the \`onTokenGenerated\` callback. | Required | | \`payment\_method\_id\` | Payment method identifier: \`visa\` or \`master\`. | Required | | \`transaction\_amount\` | Transaction amount. | Required | | \`installments\` | Number of installments. | Required | | \`payer\` | Buyer data. | Required | | \`description\` | Payment description. | Required | | \`issuer\_id\` | Card issuer ID. | Optional | The API returns a response with a structure similar to the following example: \`\`\`json { "status": "approved", "status\_detail": "accredited", "id": 3055677, "date\_approved": "2019-02-23T00:01:10.000-04:00", "payer": { ... }, "payment\_method\_id": "visa", "payment\_type\_id": "credit\_card", "refunds": \[\], ... } \`\`\` ::: :::AccordionComponent{title="Test the integration" pill="4"} You can simulate different payment scenarios in the test environment using the \`testStatus\` property in the Apple Pay configuration. It only takes effect when you use a :toolTipComponent\[test Public Key\]{content="Public key of the application created in Mercado Pago, used in the frontend. You can access it in \*Your integrations > Application details > Test > Test credentials\*."}. > WARNING > > The \`testStatus\` property is optional and should be used for testing only. In production, do not include this configuration. 1\. Add the \`testStatus\` property inside \`applePay\` in your configuration. Use the different values detailed in the table to simulate payment scenarios. \`\`\`javascript const settings = { checkoutTypes: \['applePay'\], applePay: { paymentRequest: { /\* ... \*/ }, sessionRequest: { /\* ... \*/ }, callbacks: { /\* ... \*/ }, testStatus: 'APRO' // Optional: for testing only } }; \`\`\` | \`testStatus\` value | Payment scenario | | --- | --- | | \`APRO\` | Payment approved | | \`OTHE\` | Rejected due to general error | | \`CONT\` | Pending payment | | \`CALL\` | Rejected with validation to authorize | | \`FUND\` | Rejected due to insufficient funds | | \`SECU\` | Rejected due to invalid security code | | \`EXPI\` | Rejected due to expiration date | | \`FORM\` | Rejected due to form error | | \`CARD\` | Rejected due to missing \`card\_number\` | | \`INST\` | Rejected due to invalid installments | | \`DUPL\` | Rejected due to duplicate payment | | \`LOCK\` | Rejected due to disabled card | | \`CTNA\` | Rejected due to card type not allowed | | \`ATTE\` | Rejected due to PIN attempts exceeded | | \`BLAC\` | Rejected due to blacklist | | \`UNSU\` | Not supported | | \`TEST\` | Used to apply amount rule | ::: :::: ::::TabComponent{title="Via API"} In this integration you implement the Apple Pay flow without using the Mercado Pago SDK in the frontend. Your backend validates the session with Apple and obtains the token through Mercado Pago APIs to create the payment. Follow the steps below to integrate. :::AccordionComponent{title="Validate the session for tokenization flow" pill="1"} Having obtained and configured the \[required Apple Developer certificates\](https://www.mercadopago.com.br/developers/en/docs/apple-pay/obtain-apple-developer-certificates), before starting tokenization with Apple, your backend must validate the Apple Pay session with the \*merchant\* certificate \`certificate\_id\` and the data Apple sends to the frontend. To do so, send a \*\*POST\*\* with your :toolTipComponent\[test Public Key\]{content="Public key used in the frontend to access information and encrypt data. You can access it through \*Your integrations > Integration data > Tests > Test credentials\*."} to the endpoint :TagComponent{tag="API" text="/applepay/v1/session" href="https://api.mercadopago.com/applepay/v1/session"}. \`\`\`curl curl --location 'https://api.mercadopago.com/applepay/v1/session' \\ --header 'X-Product-ID: YOUR\_PRODUCT\_ID' \\ --header 'Content-Type: application/json' \\ --header 'X-Public-key: YOUR\_PUBLIC\_KEY' \\ --data '{ "id": "CERTIFICATE\_ID\_MERCHANT", "merchantIdentifier": "merchant.your-identifier", "domainName": "your-domain.com", "displayName": "My store", "initiative": "web", "initiativeContext": "your-domain.com", "validationURL": "https://apple-pay-gateway.apple.com/paymentservices/startSession" }' \`\`\` | Element | Description | | --- | --- | | \`X-Product-ID\` | Product identifier. | | \`X-Public-key\` | Header with your :toolTipComponent\[test Public Key\]{content="Public key used in the frontend to access information and encrypt data. You can access it through \*Your integrations > Integration data > Tests > Test credentials\*."}. | | \`id\` | Certificate ID of the \*merchant\* certificate obtained in the previous steps. | | \`merchantIdentifier\` | Merchant ID configured in Apple. | | \`domainName\` | Domain of your site where the Apple Pay button is displayed. Must match the domain you verified in the Apple Developer Portal and where the verification file is published in \`.well-known\`. | | \`displayName\` | Name of your merchant or store shown to the user in the Apple Pay payment flow. | | \`initiative\` | Fixed value \`web\`. | | \`initiativeContext\` | Must match \`domainName\`. | | \`validationURL\` | URL that Apple sends to your frontend when starting the flow; send it here unchanged. | The API returns a response with a structure similar to the following example. It includes \`merchantSessionIdentifier\` and other data that your frontend will use to complete the flow with Apple: \`\`\`json { "epochTimestamp": 1768253984908, "expiresAt": 1768257584908, "merchantSessionIdentifier": "SSH1920C0C97402...7B1B1A97F33C9C3", "nonce": "124074e7", "merchantIdentifier": "10DDB60D113BB4...CDF76292133", "domainName": "your-domain.com", "displayName": "My store", "signature": "308006092...2f5d0c8000000000000" } \`\`\` ::: :::AccordionComponent{title="Payment tokenization" pill="2"} When the buyer authorizes the payment with Apple Pay, Apple returns the encrypted payment data in the frontend. Send that data to your backend and, from there, send a \*\*POST\*\* with your :toolTipComponent\[test Public Key\]{content="Public key used in the frontend to access information and encrypt data. You can access it through \*Your integrations > Integration data > Tests > Test credentials\*."} to the endpoint :TagComponent{tag="API" text="/platforms/pci/applepay/v1/tokenize" href="https://api.mercadopago.com/platforms/pci/applepay/v1/tokenize"} to obtain a card token from Mercado Pago. \`\`\`curl curl --location 'https://api.mercadopago.com/platforms/pci/applepay/v1/tokenize' \\ --header 'X-Product-ID: YOUR\_PRODUCT\_ID' \\ --header 'Content-Type: application/json' \\ --header 'X-Public-key: YOUR\_PUBLIC\_KEY' \\ --data '{ "payment\_method": { "type": "applepay", "payment\_data": "PAYMENT\_DATA\_FROM\_APPLE\_BASE64" }, "transaction\_identifier": "TRANSACTION\_ID\_FROM\_APPLE", "device": { "meli": { "session\_id": "SESSION\_ID\_DEVICE" } } }' \`\`\` | Element | Description | | --- | --- | | \`X-Product-ID\` | Product identifier. | | \`X-Public-key\` | Header with your :toolTipComponent\[test Public Key\]{content="Public key used in the frontend to access information and encrypt data. You can access it through \*Your integrations > Integration data > Tests > Test credentials\*."}. | | \`payment\_method.type\` | Fixed value \`applepay\`. | | \`payment\_method.payment\_data\` | Payment data that Apple sends to the frontend, returned in \_Base64\_ format. When the user authorizes the payment on an Apple device, the browser triggers the \`onpaymentauthorized\` event and, from that point on, within \`payment.token.paymentData\` there will be a \`JavaScript\` object containing the card data encrypted by Apple. The returned object must be converted to a \`JSON\` string and then encoded in \_Base64\_. | | \`transaction\_identifier\` | Transaction identifier that Apple sends to the frontend. It is a unique hexadecimal string generated by Apple for each transaction. | | \`device.meli.session\_id\` | Device session identifier. It must be initialized on the page before clicking the Apple Pay button. The value is available in the global variable \`window.MP\_DEVICE\_SESSION\_ID\` and comes from Mercado Pago’s device fingerprint SDK (Armor). | The API returns a response with a structure similar to the following example: \`\`\`json { "id": "5c055ff0d...00b888c85c64e", "bin": "44...49" } \`\`\` | Field | Description | | --- | --- | | \`id\` | Card token. Use it as \`token\` when creating the payment in the payments API. | | \`bin\` | First digits of the card. | ::: :::AccordionComponent{title="Create the payment" pill="3"} Create the payment by sending a \*\*POST\*\* with your :toolTipComponent\[test Access Token\]{content="Private key of the application created in Mercado Pago, that must be used in the backend. You can access it through \*Your integrations > Integration data > Tests > Test credentials\*."} to the endpoint :TagComponent{tag="API" text="Create payment" href="/developers/en/reference/payments/\_payments/post"} with your :toolTipComponent\[test Access Token\]{content="Private key of the application created in Mercado Pago, used in the backend. You can access it in \*Your integrations > Application details > Test > Test credentials\*."}. Add the \`id\` obtained in the previous step as the value of the \`token\` field and the body with the fields described in the table below. \`\`\`curl curl --location 'https://api.mercadopago.com/v1/payments' \\ --header 'Content-Type: application/json' \\ --header 'Authorization: Bearer YOUR\_ACCESS\_TOKEN' \\ --header 'X-Idempotency-Key: SOME\_UNIQUE\_VALUE' \\ --data '{ "token": "ID\_RETURNED\_BY\_TOKENIZATION", "payment\_method\_id": "visa", "transaction\_amount": 100, "installments": 1, "description": "Payment description", "payer": { "email": "buyer@email.com", "identification": { "type": "CPF", "number": "12345678909" } } }' \`\`\` | Field | Description | | --- | --- | | \`Authorization\` | Header with your :toolTipComponent\[test Access Token\]{content="Private key of the application created in Mercado Pago, that must be used in the backend. You can access it through \*Your integrations > Integration data > Tests > Test credentials\*."}. | | \`X-Idempotency-Key\` | Unique value per request (for example, UUID v4) to avoid duplicate payments. | | \`token\` | \`id\` value returned by tokenization in the previous step. | | \`payment\_method\_id\` | Payment method identifier: \`visa\` or \`master\`. | | \`transaction\_amount\` | Transaction amount. | | \`installments\` | Number of installments. | | \`payer\` | Buyer data (email, identification, etc.). | | \`description\` | Payment description. | | \`issuer\_id\` | Card issuer ID. \*\*Optional\*\*. | ::: :::: ::::: > NOTE > > If you encounter an error in your Apple Pay integration, see \[Frequent errors\](https://www.mercadopago.com.br/developers/en/docs/apple-pay/additional-content/frequent-errors).