🛠️Preparar la transacción
Este método permite preparar los montos e información adicional necesarios para iniciar una transacción de pago a través del botón Payphone.
🧩 API Button/Prepare
Para preparar una transacción, debes realizar una solicitud POST como se muestra a continuacion:
🔗 URL de la solicitud POST
https://pay.payphonetodoesposible.com/api/button/Prepare
📦 Estructura del Cuerpo de la Solicitud:
El cuerpo de la solicitud debe ser un objeto JSON con la siguiente estructura:
{
"amount": 315,
"amountWithoutTax": 200,
"amountWithTax": 100,
"tax": 15,
"service": 0,
"tip": 0,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"reference": "Motivo de cobro con Boton",
"storeId": "your_storeId",
"currency": "USD",
"responseUrl": "https://your_domain.com/webhook/resultParameters",
"cancellationUrl": "https://tu-dominio.com/",
"timeZone": -5,
"lat": "-1.831239",
"lng": "-78.183406",
"order": {
"billTo": { //datos de facturacion
"billToId": 12,
"address1": "Colorado Springs",
"address2": "Denver",
"country": "EC",
"state": "Azuay",
"locality": "Cuenca",
"firstName": "Elisabeth",
"lastName": "Sobeck",
"phoneNumber": "+593999999999",
"email": "aloy@mail.com",
"postalCode": "EC090108",
"customerId": "idUserClient.001",
"ipAddress": "127.0.0.1"
},
"lineItems": [
{
"productName": "Producto Vendido",
"unitPrice": 100,
"quantity": 1,
"totalAmount": 115,
"taxAmount": 15,
"productSKU": "3342.0004",
"productDescription": "Descripción Producto"
},
{
"productName": "Servicio Entregado",
"unitPrice": 100,
"quantity": 2,
"totalAmount": 200,
"taxAmount": 0,
"productSKU": "5342.0054",
"productDescription": "Descripción Servicio"
}
]
},
"documentId": null,
"phoneNumber": null,
"email": null,
"optionalParameter": "Descripción Extra"
}
El objeto JSON mostrado define el cobro de $3.15, divididos en $1 con un impuesto del 15% y $2 sin impuesto.
🔐 Es fundamental incluir las siguientes cabeceras en la solicitud:
Authorization: bearer TU_TOKEN
(Token de autenticación de la aplicación, precedido por la palabra "Bearer").Content-type: application/json
(Formato de los datos: JSON).
📌 Importante:
📟 Cálculo del monto total (amount
)
El campo amount
debe ser la suma de todos los valores monetarios
amount = amountWithoutTax + amountWithTax + tax + service + tip
Aunque los campos individuales son opcionales, debe haber al menos uno presente que respalde el valor total amount
💵 Valores monetarios en centavos:
Todos los montos deben expresarse como enteros. Multiplica el valor en dólares por 100:
💵 Valor en USD |
🪙 Valor en centavos |
$ 1.00 |
100 |
$ 1.50 |
150 |
$ 10.00 |
1000 |
$ 12.68 |
1268 |
🔸Ejemplos de cuerpos de solicitudes con campos mínimos
A continuación, se muestran ejemplos de objetos JSON con los campos mínimos para diferentes tipos de cobro:
{
"amount": 115,
"amountWithTax": 100,
"tax": 15,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"currency": "USD",
"storeId": "your_storeId",
"reference": "Pago con API Link",
"responseUrl":"https://tu-dominio.com/ConfirmacionPago"
}
El objeto JSON mostrado define el cobro de $1 con un impuesto del 15%.
{
"amount": 200,
"amountWithoutTax": 200,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"currency": "USD",
"storeId": "your_storeId",
"reference": "Pago con API Link",
"responseUrl":"https://tu-dominio.com/ConfirmacionPago"
}
El objeto JSON mostrado define el cobro de $2 sin impuesto.
{
"amount": 315,
"amountWithoutTax": 200,
"amountWithTax": 100,
"tax": 15,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"currency": "USD",
"storeId": "your_storeId",
"reference": "Pago con API Link",
"responseUrl":"https://tu-dominio.com/ConfirmacionPago"
}
El objeto JSON mostrado define el cobro de $3.15, divididos en $1 con un impuesto del 15% y $2 sin impuesto.
📋Descripción de parámetros en la petición
A continuación se detallan todos los parámetros que se pueden usar para una transacción como montos a cobra, moneda, datos del cliente y otros campos que puedes enviar.
Valor total a cobrar.
Debe ser igual a la suma de todos los montos individuales ( amountWithoutTax, amountWithTax, Tax, service y tip ).
Monto que no está sujeto a impuestos.
Monto que incluye el valor sujeto a impuestos, excluyendo el propio impuesto.
Monto del impuesto aplicado a la transacción.
Monto asociado al servicio proporcionado.
Monto de la propina otorgada por el cliente.
Código de moneda ISO 4217. (ej:USD)
Identificador único asignado a la transacción para su seguimiento.
Identificador de la sucursal que efectúa el cobro (se obtiene en Payphone Developer).
Motivo o referencia específica del pago.
Número de teléfono del titular; se solicitará si no se proporciona.Formato: Símbolo(+) + Código País + numero telefónico.Ej. +593984111222
Correo electrónico del cliente; se solicitará si no se proporciona.
Número de identificación del cliente; se solicitará si no se proporciona.
Url de respuesta a donde se redirecciona luego del pago.
Url a donde se redirecciona si se cancela la transacción desde el icono X en el formulario.
Información adicional para la transacción.
Arreglos con datos de facturación y detalle de artículos o servicios.
Idioma de Formulario:
inglés (en),
español (es).
Por defecto en español.
latitud en formato decimal: -1.831239
longitud en formato decimal: -78.183406
🛑 Advertencia:
Al utilizar los campos phoneNumber
, email
y documentId
en las solicitudes a los servicios de Payphone, es crucial que se ingresen los datos del titular de la tarjeta para cada transacción individual. No se permite el uso de datos "quemados" o estáticos, ya que esto puede resultar en el rechazo de sus transacciones y el bloqueo de sus usuarios. El uso de datos falsos o repetitivos puede generar sospechas de fraude.
Payphone se compromete a proteger la seguridad y privacidad de los datos, por lo que es fundamental cumplir con esta política para garantizar un proceso de pago seguro y confiable.
📋 Desglose del campo order
El campo order se divide en dos arreglos: BillTo, LineItems
🧾BillTo (Datos de facturación):
El campo billTo es un arreglo que contiene información de facturación
Identificador para los datos de facturación (Opcional)
Dirección de facturación 1
Dirección de facturación 2
El código de país según la norma ISO 3166-1 alfa-2.
(EJ: EC)
Número de teléfono del titular; se solicitará si no se proporciona.
Formato: Símbolo(+) + Código País + numero telefónico.
Ej. +593984111222
Correo electrónico del cliente.
Código Postal: dirección numérica de un lugar específico.
Identificador del cliente otorgada por el comercio
Dirección IP del dispositivo
📦 LineItems (Detalle del pedido):
El campo lineItems es un conjunto de arreglos que contiene la información de los servicios o productos entregados
Nombre del producto o servicio
Total a pagar por este servicio
Identificador del producto o servicio
Descripcion corta del producto
🧱 Ejemplos de solicitud POST a Buttom/Prepare
A continuación, se presenta varios ejemplos de cómo realizar solicitudes POST:
<?php
date_default_timezone_set('America/Guayaquil');
//Preparar cabecera para la solicitud
$headers[] = 'Authorization: Bearer your_token' ;//CREDENCIALES DE CONFIGURACION
$headers[] = 'Content-Type: application/json' ;//TIPO DE APLICACION
//Genera Dato Unico por transacción
$clientTransactionID = substr((date("ymd-Hi-s").gettimeofday()["usec"]),0, 16);
//Preparar objeto JSON para solicitud
$data = array(
"amount" => 215,
"amountWithoutTax" => 100,
"amountWithTax" => 100,
"tax" => 15,
"service" => 0,
"tip" => 0,
"storeId" => "your_storeId",
"clientTransactionId" => $clientTransactionID,
"currency" => "USD",
"responseUrl" => "https://your_domain.com/confirm.php",
"reference" => "Prueba Boton por redireccion"
);
$objetoJSON = json_encode($data);
//Iniciar solicitud curl: POST
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://pay.payphonetodoesposible.com/api/button/Prepare");
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $objetoJSON);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
//Respuesta en formato JSON
$curl_response = curl_exec($curl);
//Finaliza solicitud curl: POST
curl_close($curl);
//Mostrar Resultado en Pantalla
echo "<h1>Prueba Botón por redirección</h1> <br><br>";
$result= json_decode($curl_response);
if(isset($result->paymentId) ) {
echo "<a href='".$result->payWithPayPhone."'>PAGAR CON PAYPHONE</a> <br><br>";
echo "<a href='" .$result->payWithCard."'>PAGAR CON TARJETA VISA/MASTERCARD</a>";
}else{
echo "<pre>".json_encode($result,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT )."</pre>";
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Ejemplo de Solicitud POST con jQuery</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
//Genera un Dato Unico por transacción
const redirectClientTraxID =Date.now();
//Se realiza solicitud POST: Se prepara objeto JSON, header y presenta resultado o error
$(document).ready(function() {
$.ajax({
url: "https://pay.payphonetodoesposible.com/api/button/Prepare",
type: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer your_token"
},
data: JSON.stringify({
"amount": 155,
"amountWithoutTax": 155,
"amountWithTax": 0,
"tax": 0,
"reference": "Pago mediante Boton payphone",
"currency": "USD",
"clientTransactionId": redirectClientTraxID,
"storeId": "your_storeId",
"ResponseUrl": "https://your-domain.com/Confirm"
}),
success: function(response) {
$("#resultado").html(
"<a href='" + response.payWithPayPhone + "' target='_blank'>Pagar con payphone</a><br><br>" +
"<a href='" + response.payWithCard + "' target='_blank'>Pagar con Tarjeta Visa/MasterCard</a><br><br>"+
"Respuesta : <pre>" + JSON.stringify(response, null, 2) + "</pre>"
);
},
error: function(error) {
$("#resultado").html(
"Error en la solicitud : <pre>" + JSON.stringify(error, null, 2) + "</pre>"
);
}
});
});
</script>
</head>
<body>
<h1>Ejemplo de Solicitud POST</h1>
<div id="resultado"></div>
</body>
</html>
<!DOCTYPE html>
<html lang="es">
<head>
<title>Ejemplo de Solicitud POST con fetch</title>
<script>
//Genera un Dato Unico por transacción
const redirectClientTraxID =Date.now();
//Preparar cabecera para la solicitud
const headers = {
"Content-Type": "application/json",
"Authorization": "Bearer your_token",
"Referer": document.referrer
};
//Preparar objeto JSON para solicitud
const bodyJSON = {
"amount": 180,//monto total
"amountWithoutTax": 180,//monto que no cobrar impuestos
"amountWithTax": 0,//monto que cobrar impuestos excluido el impuesto
"tax": 0,//monto del impuestos
"reference": "Prueba Boton fetch", //motivo de transaccion opcional
"currency": "USD",//ISO DE MONEDA
"clientTransactionId": redirectClientTraxID,//id unico proporcionado por el comercio
"storeId": "your_storeId",
"ResponseUrl": "https://your-domain.com/Confirm"
};
//Iniciar solicitud: POST
const url = "https://pay.payphonetodoesposible.com/api/button/Prepare";
fetch(url, {
method: "POST",
headers: headers,
body: JSON.stringify(bodyJSON)
})
.then((res) => res.json())
.catch((error) => {
// Se crea etiqueta <pre> que contiene el error
const jsonResult = document.createElement("pre");
jsonResult.textContent = JSON.stringify(error, null, 2);
// Mostrar los enlaces en el documento con un salto de línea entre ellos
const container = document.createElement("div");
container.appendChild(jsonResult);
// Agregar los enlaces al body del documento o a un contenedor específico
document.body.appendChild(container);
})
.then((data) => {
// Se procesa la respuesta JSON
const payWithPayPhone = data.payWithPayPhone;
const payWithCard = data.payWithCard;
// Se crea etiquetas <a> con los enlaces hacia el formulario
const payWithPayPhoneLink = document.createElement("a");
payWithPayPhoneLink.href = payWithPayPhone;
payWithPayPhoneLink.textContent = "Pagar con PayPhone";
const payWithCardLink = document.createElement("a");
payWithCardLink.href = payWithCard;
payWithCardLink.textContent = "Pagar con Tarjeta Visa/MasterCard";
// Se crea etiqueta <pre> que contiene el json de respuesta
const jsonResult = document.createElement("pre");
jsonResult.textContent = JSON.stringify(data, null, 2);
// Mostrar los enlaces en el documento con un salto de línea entre ellos
const container = document.createElement("div");
container.appendChild(payWithPayPhoneLink);
container.appendChild(document.createElement("br")); // Salto de línea
container.appendChild(document.createElement("br")); // Salto de línea
container.appendChild(payWithCardLink);
container.appendChild(document.createElement("br")); // Salto de línea
container.appendChild(document.createElement("br")); // Salto de línea
container.appendChild(jsonResult);
// Agregar los enlaces al body del documento o a un contenedor específico
document.body.appendChild(container);
});
</script>
</head>
<body>
<h1>Ejemplo de Solicitud POST con Fetch</h1>
<div id="resultado"></div>
</body>
</html>
📬Respuesta a la solicitud POST
Al realizar la solicitud POST, recibirás un objeto JSON que incluye los siguientes parámetros:
{
"paymentId": "GSizecyUkIAkxTj3SQ",
"payWithPayPhone": "https://pay.payphonetodoesposible.com/PayPhone/Index?paymentId=GSizecyUkIAkxTj3SQ",
"payWithCard": "https://pay.payphonetodoesposible.com/Anonymous/Index?paymentId=GSizecyUkIAkxTj3SQ"
}
- paymentId: Identificador del pago.
- payWithPayPhone: URL del formulario para realizar el pago mediante la app de Payphone.
- payWithCard: URL del formulario para realizar el pago directamente con su tarjeta de crédito o débito.
Al redireccionar desde el dominio hacia los enlaces del formulario se mostrará de la siguiente forma:
Los clientes pueden pagar con tarjetas de crédito y débito (Visa , MasterCard), así como con saldo Payphone. Independientemente del método de pago, recibirás la misma respuesta de transacción, ya sea aprobada o rechazada.
❌ Respuesta a error en la solicitud POST
Si algun campo no cumple con las reglas o formato en la solicitud POST, recibirás un objeto JSON que incluye el detalle del error:
{
"message": "Validaciones fallidas",
"errorCode": 800,
"errors": [
{
"message": "Amount",
"errorCode": 0,
"errorDescriptions": [
"El campo Amount no es igual a la suma de AmountWithTax, AmountWithoutTax, Tax, Service, Tip"
]
}
]
}
📌 Consideraciones
⏱️ Tiempo de vida del formulario
- Cada enlace como el formulario del botón de Pagos tiene una vigencia de 10 minutos desde su carga.
- Si el usuario no completa el pago en ese tiempo, el formulario expirará y se deberá generar uno nuevo.
🚫 Error de "No Autorizado"

¿Por qué ocurre este error?
El mensaje de “Acceso denegado o dominio no permitido” al intentar cargar o ejecutar el boton de Pagos puede deberse a una de las siguientes razones:
1. 🌐 Dominio no autorizado
- Los Formularios del Botón de Pagos solo funcionaran si son redireccionados desde el dominio registrado en tu configuración de desarrollador en Payphone Developer.
- Si intentas redireccionar desde otro dominio o abrir el enlace directamente, se bloqueará por motivos de seguridad.
- ✅ Solución: Asegúrate de que la redirección hacia el formulario de pago se realice desde el mismo dominio que configuraste en tu cuenta de Payphone.
2. 🛡️ Falta de identidad del sitio (Referrer-Policy)
En algunos frameworks o servidores, existe una configuración por defecto que no comparte la identidad del sitio web desde donde se hace la redirección al formulario de pago.
Esto impide que Payphone verifique el origen de la solicitud y provoca el error de acceso denegado.
La configuración detectada que puede causar el error:
- Referrer-Policy: en las plataformas mas comunes como C# / ASP.NET, WordPress, entre otras
- SECURE_REFERRER_POLICY: Desde Django 3.1 en adelante
📘 ¿Qué es la Referrer-Policy?
La Referrer-Policy es una política de seguridad del navegador que define qué información del origen (referencia) se envía al hacer peticiones a otros recursos.
A continuación, se muestran las opciones más comunes:
- no-referrer: No se envía ninguna referencia. Máxima privacidad, pero puede romper funcionalidades.
- no-referrer-when-downgrade: Envía la referencia solo si ambos sitios usan HTTPS.
- origin: Envía solo el esquema y host del sitio (sin ruta). Nivel medio de privacidad.
- origin-when-cross-origin: Como
origin
, pero solo en solicitudes entre sitios distintos. - strict-origin: Similar a
origin
, pero restringido a HTTPS. - strict-origin-when-cross-origin: Mayor control sobre envíos entre orígenes cruzados.
- no-referrer: No se envía ninguna referencia. Máxima privacidad, pero puede romper funcionalidades.
✅ Recomendación de Payphone
Para garantizar el correcto funcionamiento de Boton de Pagos, recomendamos usar:
- origin
- origin-when-cross-origin
Esto proporciona el equilibrio ideal entre funcionalidad y privacidad, y permite a Payphone validar correctamente el origen de la solicitud.