Express Checkout
El express checkout te permite recopilar direcciones de envío y facturación directamente desde las interfaces de Apple Pay, Google Pay o PayPal, sin necesidad de un formulario de dirección independiente.
Disponible en los componentes PaymentRequest (Apple Pay / Google Pay) y PayPal.
Antes de empezar
- Necesitarás una cuenta MONEI y tus claves de API (de prueba o de producción). Encuéntralas en tu MONEI Dashboard.
- Usa tus claves en modo de prueba para las pruebas de integración.
- Apple Pay requiere verificación de dominio tanto en desarrollo como en producción.
- Google Pay requiere al menos un procesador de tarjetas configurado.
- PayPal requiere una cuenta de empresa PayPal conectada.
Cómo funciona
- El navegador abre la interfaz de cartera (Apple Pay, Google Pay o PayPal) con tu ID de cuenta y el importe inicial
- El cliente selecciona las opciones de envío/facturación — tus callbacks actualizan los importes de forma dinámica
- Tras la aprobación, el token y los detalles se envían a tu backend
- Tu backend crea el pago con el token — no es necesario crear el pago previamente
- MONEI envía el estado final del pago mediante webhook
Express checkout con envío
Con envío, el importe autorizado por la cartera puede diferir del importe inicial cuando cambian los costes de envío. Este flujo usa el enfoque de accountId — no es necesario crear el pago previamente. El pago se crea en el servidor una vez que el cliente confirma en la interfaz de cartera.
1. Incluir monei.js (lado del cliente)
Añade la etiqueta script al head de tu archivo HTML.
<head>
<script src="https://js.monei.com/v3/monei.js"></script>
</head>
<body>
<!-- Use "payment_request" for Apple Pay / Google Pay, "paypal_container" for PayPal -->
<div id="payment_request"></div>
<div id="paypal_container"></div>
<script src="client.js"></script>
</body>
2. Inicializar el Component con express checkout (lado del cliente)
- Apple Pay / Google Pay
- PayPal
const paymentRequest = monei.PaymentRequest({
accountId: 'your_account_id',
sessionId: 'unique_session_id',
amount: 1099, // base amount in minor units (before shipping)
currency: 'EUR',
requestShipping: true,
requestBilling: true,
shippingOptions: [
{id: 'standard', label: 'Standard Shipping', amount: 500},
{id: 'express', label: 'Express Shipping', amount: 1200, description: '1-2 business days'}
],
onShippingAddressChange(address) {
// Called when the customer changes their shipping address.
// address contains: country, city, state, zip (no street-level data mid-flow).
// Return updated shipping options and/or amount based on the address.
if (address.country !== 'ES') {
return {
shippingOptions: [{id: 'intl', label: 'International', amount: 2000}],
amount: 3099 // product (1099) + intl shipping (2000)
};
}
return {shippingOptions: [{id: 'standard', label: 'Standard', amount: 500}], amount: 1599};
},
onShippingOptionChange(option) {
// Called when the customer selects a different shipping option.
// Return updated total amount.
return {amount: 1099 + option.amount};
},
async onSubmit(result) {
// Called when the customer approves the payment in the wallet UI.
// Create the payment server-side (see Step 3).
await fetch('/create-payment', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
amount: result.finalAmount,
currency: 'EUR',
sessionId: 'unique_session_id',
paymentToken: result.token,
billingDetails: result.billingDetails,
shippingDetails: result.shippingDetails
})
});
},
onError(error) {
console.error(error);
}
});
paymentRequest.render('#payment_request');
const paypal = monei.PayPal({
accountId: 'your_account_id',
sessionId: 'unique_session_id',
amount: 1099,
currency: 'EUR',
requestShipping: true,
shippingOptions: [
{id: 'standard', label: 'Standard Shipping', amount: 500, selected: true},
{id: 'express', label: 'Express Shipping', amount: 1200}
],
onShippingAddressChange(address) {
return {
shippingOptions: [{id: 'standard', label: 'Standard', amount: 500, selected: true}],
amount: 1599
};
},
onShippingOptionChange(option) {
return {amount: 1099 + option.amount};
},
async onSubmit(result) {
// PayPal always returns payer info (name, email) in billingDetails.
// Create the payment server-side (see Step 3).
await fetch('/create-payment', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
amount: result.finalAmount,
currency: 'EUR',
sessionId: 'unique_session_id',
paymentToken: result.token,
billingDetails: result.billingDetails,
shippingDetails: result.shippingDetails
})
});
},
onError(error) {
console.error(error);
}
});
paypal.render('#paypal_container');
PayPal siempre devuelve la información del pagador (nombre, email) independientemente de la configuración — no existe una propiedad requestBilling independiente.
Opciones principales:
- accountId
string: Tu ID de cuenta MONEI. - sessionId
string: Un identificador de sesión único. Debe coincidir con elsessionIdpasado al crear el pago en el servidor. - amount
number: Importe inicial en la unidad monetaria más pequeña (p. ej., 1099 = 10,99 EUR). - requestShipping
boolean: Activa la recopilación de la dirección de envío en la interfaz de cartera. - requestBilling
boolean: Activa la recopilación de la dirección de facturación (solo PaymentRequest — PayPal siempre devuelve la información de facturación). - shippingOptions
ShippingOption[]: Opciones de envío disponibles.
Consulta las opciones de PaymentRequest y PayPal para la lista completa.
3. Crear el pago (lado del servidor)
Cuando el cliente confirma en la interfaz de cartera, tu manejador onSubmit envía el resultado a tu servidor. Crea el pago pasando el paymentToken — esto confirma el pago automáticamente.
Debes pasar el mismo sessionId utilizado para inicializar el componente en el frontend. Esto garantiza que el cliente que generó el token sea el mismo que realiza el pago.
- cURL
- Node.js
- PHP
- Python
curl --request POST 'https://api.monei.com/v1/payments' \
--header 'Authorization: YOUR_API_KEY' \
--header 'Content-Type: application/json' \
--data-raw '{
"amount": 1599,
"currency": "EUR",
"orderId": "14379133960355",
"description": "Test Shop - #14379133960355",
"sessionId": "unique_session_id",
"paymentToken": "token_from_client",
"callbackUrl": "https://example.com/checkout/callback",
"customer": {
"email": "email@example.com"
},
"billingDetails": {},
"shippingDetails": {}
}'
import {Monei} from '@monei-js/node-sdk';
const monei = new Monei('YOUR_API_KEY');
// In your /create-payment route handler:
app.post('/create-payment', async (req, res) => {
const {amount, currency, sessionId, paymentToken, billingDetails, shippingDetails} = req.body;
const payment = await monei.payments.create({
amount,
currency,
orderId: '14379133960355',
description: 'Test Shop - #14379133960355',
sessionId,
paymentToken,
callbackUrl: 'https://example.com/checkout/callback',
customer: {email: billingDetails?.email},
billingDetails,
shippingDetails
});
res.json({status: payment.status});
});
<?php
require_once 'vendor/autoload.php';
use Monei\Model\CreatePaymentRequest;
use Monei\MoneiClient;
$monei = new MoneiClient('YOUR_API_KEY');
$body = json_decode(file_get_contents('php://input'), true);
$payment = $monei->payments->create(
new CreatePaymentRequest([
'amount' => $body['amount'],
'currency' => $body['currency'],
'order_id' => '14379133960355',
'description' => 'Test Shop - #14379133960355',
'session_id' => $body['sessionId'],
'payment_token' => $body['paymentToken'],
'callback_url' => 'https://example.com/checkout/callback',
'billing_details' => $body['billingDetails'],
'shipping_details' => $body['shippingDetails']
])
);
echo json_encode(['status' => $payment->getStatus()]);
?>
import Monei
from Monei import CreatePaymentRequest
monei = Monei.MoneiClient(api_key="YOUR_API_KEY")
# In your /create-payment route handler:
payment = monei.payments.create(
CreatePaymentRequest(
amount=body["amount"],
currency=body["currency"],
order_id="14379133960355",
description="Test Shop - #14379133960355",
session_id=body["sessionId"],
payment_token=body["paymentToken"],
callback_url="https://example.com/checkout/callback",
billing_details=body["billingDetails"],
shipping_details=body["shippingDetails"]
)
)
Consulta todos los parámetros de la solicitud disponibles.
4. Procesar la notificación de webhook (lado del servidor)
MONEI envía el estado final y definitivo del pago mediante una solicitud HTTP POST asíncrona a la callbackUrl que proporcionaste en el Paso 3. El cuerpo de la solicitud contiene el objeto Payment completo en formato JSON.
Este webhook es la única forma fiable de confirmar el resultado definitivo del pago.
- Verifica la cabecera
MONEI-Signaturepara confirmar que el webhook proviene realmente de MONEI. Consulta la guía de verificación de firmas para los detalles de implementación. - Devuelve un código de estado HTTP
200 OKinmediatamente para confirmar la recepción.
Si MONEI no recibe un 200 OK, reintentará el envío del webhook.
Checkout solo con facturación
Si solo necesitas la dirección de facturación (sin envío), el flujo es más sencillo — usa paymentId en lugar de accountId y confirma en el lado del cliente con confirmPayment. Sigue los mismos pasos que en Crea un checkout personalizado, pero añade requestBilling: true para recopilar la dirección de facturación desde la cartera:
const paymentRequest = monei.PaymentRequest({
paymentId: '{{payment_id}}',
requestBilling: true,
async onSubmit(result) {
await monei.confirmPayment({
paymentId: '{{payment_id}}',
paymentToken: result.token,
billingDetails: result.billingDetails
});
},
onError(error) {
console.error(error);
}
});
paymentRequest.render('#payment_request');
Referencia de tipos
Consulta las definiciones de tipos completas en la Referencia:
SubmitResult— devuelto por todos los callbacksonSubmitShippingOption— configuración de opciones de envíoShippingAddressChangeResult— tipo de retorno paraonShippingAddressChangeShippingOptionChangeResult— tipo de retorno paraonShippingOptionChangeBillingDetails— detalles de facturación/envíoAddress— dirección postal
Antes de pasar a producción
- Asegúrate de usar el ID de cuenta y la clave de API en modo de producción (live).
- Asegúrate de tener los métodos de pago relevantes configurados y habilitados en modo de producción.
- Para Apple Pay, verifica tu dominio de producción.