🛠️Guía de Integración: API Sale
🧩POST API Sale
Para cobrar a través de la aplicación de Payphone, usa API SALE, que te permite solicitar el pago y verificar el estado de la transacción.
🔗URL de la solicitud POST
https://pay.payphonetodoesposible.com/api/Sale
📦 Estructura del Cuerpo de la Solicitud:
El cuerpo de la solicitud debe ser un objeto JSON con la siguiente estructura:
{
"phoneNumber": "0984111222",
"countryCode": "593",
"amount": 315,
"amountWithoutTax": 200,
"amountWithTax": 100,
"tax": 15,
"service": 0,
"tip": 0,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"reference": "Motivo de cobro con Sale",
"storeId": "your_storeId",
"currency": "USD",
"timeZone": -5,
"lat": "-1.831239",
"lng": "-78.183406",
"clientUserId": "idUserClient.001",
"optionalParameter1": "Informacion Adicional 1",
"optionalParameter2": "Informacion Adicional 2",
"optionalParameter3": "Informacion Adicional 3",
"responseUrl": "https://your_domain.com/webhook/resultParameters",
//URL de respuesta donde nuestro servidor adjunta 2 parametros id y clientTransactionID
"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": [ //datos de productos o servicios
{
"productName": "Producto Vendido",
"unitPrice": 100,
"quantity": 1,
"totalAmount": 115,
"taxAmount": 15,
"productSKU": "3342.0004",
"productDescription": "Descripción Producto"
}
]
}
}
Este JSON completo describe un cobro mixto: 1 USD con impuesto del 15% y 2 USD 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 solicitudes mínimas
A continuación, se muestran ejemplos de objetos JSON con los campos mínimos para diferentes tipos de cobro:
Este objeto JSON define el cobro de $1 con un impuesto del 15%.
{
"phoneNumber": "0984111222",
"countryCode": "593",
"amount": 115,
"amountWithTax": 100,
"tax": 15,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"reference": "Motivo de cobro con Sale",
"storeId": "your_storeId",
"currency": "USD"
}
El objeto JSON define el cobro de $2 sin impuesto.
{
"phoneNumber": "0984111222",
"countryCode": "593",
"amount": 200,
"amountWithoutTax": 200,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"reference": "Motivo de cobro con Sale",
"storeId": "your_storeId",
"currency": "USD"
}
Este objeto JSON define el cobro de $3.15, divididos en $1 con un impuesto del 15% y $2 sin impuesto.
{
"phoneNumber": "0984111222",
"countryCode": "593",
"amount": 315,
"amountWithoutTax": 200,
"amountWithTax": 100,
"tax": 15,
"clientTransactionId": "ID_UNICO_X_TRANSACCION-001",
"reference": "Motivo de cobro con Sale",
"storeId": "your_storeId",
"currency": "USD"
}
Esta estructura permite una flexibilidad completa para manejar transacciones con impuestos, sin impuestos o mixtas, adaptándose a las necesidades del comercio.
📋Descripción de parámetros en la petición
A continuación se detallan los parámetros que puedes utilizar en una transacción, incluyendo los montos a cobrar, la moneda, los datos del cliente y otros campos opcionales que puedes incluir en la solicitud
Número de teléfono registrado en Payphone (ej: 0984111222)
Código de país estándar E.164 (ej: 593)
Valor total a cobrar. Debe ser igual a la suma de todos los montos individuales
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.
Url de respuesta donde nuestro servidor envía dos parámetros: id, clientTransactionID
latitud en formato decimal: -1.831239
longitud en formato decimal: -78.183406
Información adicional para la transacción.
Información adicional para la transacción.
Información adicional para la transacción.
Identificador del cliente otorgada por el comercio
Arreglos con datos de facturación y detalle de artículos o servicios.
🛑 Advertencia:
Campos obligatorios: Aunque muchos de los campos son opcionales, algunos parámetros como phoneNumber
, countryCode
, amount, currency
y clientTransactionId
son necesarios para procesar una transacción correctamente.
Formato de datos: Asegúrate de seguir el formato de datos especificado para cada campo.
📋 Desglose del campo order
El campo order
se divide en dos arreglos principales: BillTo
y LineItems
🧾BillTo (Datos de facturación):
El campo billTo
es un arreglo que contiene la información de facturación asociada a la transacció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 API Sale
A continuación, se presenta varios ejemplos de cómo realizar solicitudes POST:
<?php
date_default_timezone_set('America/Guayaquil');
//Funcion q ejecuta una solicitud http POST
function curlPost($urlAPI, $headers,$body) {
//Iniciar solicitud curl: POST
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $urlAPI);
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
curl_setopt($curl, CURLOPT_POSTFIELDS, $body);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$curl_response = curl_exec($curl);
//Finaliza solicitud curl: POST
curl_close($curl);
//Respuesta en formato JSON
return json_decode($curl_response);
}
/*## Credenciales como variables para la solicitud ##*/
$token="your_token";
$storeId="your_storeId";
//Datos de usuario de Payphone Personal
$phoneNumber = "0984111222";
$countryCode = "593";
//Dato Unico por transaccion
$clientTransactionID = substr((date("ymd-Hi-s").gettimeofday()["usec"]),0, 15);
/*## Preparar informacion para la solicitud POST ##*/
//URL del servicio payphone
$url="https://pay.payphonetodoesposible.com/api/Sale";
//Cabecera para la solicitud
$headers[] = 'Authorization: Bearer '.$token ;//CREDENCIALES DE CONFIGURACION
$headers[] = 'Content-Type: application/json' ;//TIPO DE APLICACION
//Preparar objeto JSON para solicitud
$data = array(
"phoneNumber"=> $phoneNumber,
"countryCode"=> $countryCode,
"amount" => 315,
"amountWithoutTax" => 200,
"amountWithTax" => 100,
"tax" => 15,
"storeId" => $storeId,
"clientTransactionId" => $clientTransactionID,
"currency" => "USD",
"reference" => "Pago con API Sale"
);
$bodyJSON = json_encode($data);
//realizar solicitud http POST
$result=curlPost($url, $headers,$bodyJSON);
//Mostrar Resultado en Pantalla
echo "<h1>Prueba de API Sale</h1> <br>";
echo "POST: <pre>".$url."</pre>";
echo "Cuerpo Solicitud : <pre>".json_encode($data,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT )."</pre>";
echo "Respuesta : <pre>".json_encode($result,JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT )."</pre>";
?>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Solicitud POST con jQuery</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
</head>
<body>
<h1>Solicitud POST con jQuery</h1>
<a>POST: <strong id="url"></strong></a><br><br>
<a><strong>Cuerpo: </strong></a><pre id="bodyJSON"></pre>
<a><strong>Respuesta : </strong></a><pre id="result"></pre>
<script>
//Credenciales de autorizacion
const token = "your_token";
const storeId="your_storeId";
//Datos de usuario de Payphone Personal
const phoneNumber = "0984112233";
const countryCode = "593";
//Dato Unico por transaccion
const clientTransactionID = Date.now();
/*## Preparar informacion para la solicitud POST ##*/
//URL del servicio payphone
const urlAPI="https://pay.payphonetodoesposible.com/api/Sale";
const headersAPI= {
"Content-Type": "application/json",
"Authorization": "Bearer "+token
};
const bodyJSON={
"phoneNumber": phoneNumber,
"countryCode": countryCode,
"amount" : 315,
"amountWithoutTax" : 200,
"amountWithTax" : 100,
"tax" : 15,
"storeId" : storeId,
"clientTransactionId" : clientTransactionID,
"currency" : "USD",
"reference" : "Pago con API Sale"
};
/*## Mostrar Datos en Pantalla ##*/
document.getElementById("url").innerHTML=urlAPI;
document.getElementById("bodyJSON").innerHTML=JSON.stringify(bodyJSON, null, 2);
/*## Solicitud POST con jQuery ##*/
$(document).ready(function() {
$.ajax({
url: urlAPI,
type: "POST",
headers: headersAPI,
data: JSON.stringify(bodyJSON),
success: function(response) {
$("#result").html(
"<pre>" + JSON.stringify(response, null, 2) + "</pre>"
);
},
error: function(error) {
$("#result").html(
"Error en la solicitud : <pre>" + JSON.stringify(error, null, 2) + "</pre>"
);
}
});
});
</script>
</body>
</html>
<html lang="es">
<head>
<meta charset="utf-8">
<title>Solicitud POST con Fetch</title>
</head>
<body>
<h1>Solicitud POST con Fetch</h1>
<a>POST: <strong id="url"></strong></a><br><br>
<a><strong>Cuerpo: </strong></a><pre id="bodyJSON"></pre>
<a><strong>Respuesta : </strong></a>
<script>
//Credenciales de autorizacion
const token = "your_token";
const storeId="your_storeId";
//Datos de usuario de Payphone Personal
const phoneNumber = "0984112233";
const countryCode = "593";
//Dato Unico por transaccion
const clientTransactionID = Date.now();
/*## Preparar informacion para la solicitud POST ##*/
//URL del servicio payphone
const urlAPI="https://pay.payphonetodoesposible.com/api/Sale";
const headersAPI= {
"Content-Type": "application/json",
"Authorization": "Bearer "+token
};
const bodyJSON={
"phoneNumber": phoneNumber,
"countryCode": countryCode,
"amount" : 315,
"amountWithoutTax" : 200,
"amountWithTax" : 100,
"tax" : 15,
"storeId" : storeId,
"clientTransactionId" : clientTransactionID,
"currency" : "USD",
"reference" : "Pago con API Sale"
};
/*## Mostrar Datos en Pantalla ##*/
document.getElementById("url").innerHTML=urlAPI;
document.getElementById("bodyJSON").innerHTML=JSON.stringify(bodyJSON, null, 2);
/*## Solicitud POST con Fetch ##*/
fetch(urlAPI, {
method: "POST",
headers: headersAPI,
body: JSON.stringify(bodyJSON)
})
.then((res) => res.json())
.catch((error) => {
const container = document.createElement("div");
const jsonResult = document.createElement("pre");
jsonResult.textContent = JSON.stringify(error, null, 2);
container.appendChild(jsonResult);
document.body.appendChild(container);
})
.then((data) => {
const container = document.createElement("div");
const jsonResult = document.createElement("pre");
jsonResult.textContent = JSON.stringify(data, null, 2);
container.appendChild(jsonResult);
document.body.appendChild(container);
});
</script>
</body>
</html>
📬Respuesta a la solicitud POST
Al realizar la solicitud POST, recibirás una respuesta en formato JSON con la siguiente estructura:
✅ Respuesta exitosa
{
"transactionId": 45441137
}
En caso de éxito, la respuesta incluirá el campo transactionId
, que es un identificador único para la transacción. Este identificador te permitirá consultar el estado de la transacción, el cual puede ser uno de los siguientes: Pendiente, Aceptado o Cancelado.
❌ Respuesta a error en la solicitud POST
Si la transacción no se puede crear, recibirás una respuesta de error con la siguiente estructura:
{
"message": "La transacción no pudo ser creada por favor inténtelo de nuevo",
"errorCode": 22,
"errors": [
{
"message": "El cliente tiene transacciones pendientes con su local",
"errorCode": 2061
}
]
}
Al manejar errores, muestra al usuario el mensaje específico contenido en el arreglo errors
, en lugar del mensaje general. Por ejemplo, deberías mostrar "El cliente tiene transacciones pendientes con su local" en lugar de "La transacción no pudo ser creada por favor inténtelo de nuevo".
🔔 Notificación en la aplicación de Payphone del usuario
Después de enviar la solicitud POST, el proceso para el usuario de Payphone continúa de la siguiente manera:
- El usuario de Payphone recibe una notificación push en su aplicación móvil.
- La notificación contiene los detalles de la transacción, incluyendo el monto a pagar y el comercio solicitante.
- Al abrir la notificación, el usuario puede seleccionar su método de pago preferido.
- Para confirmar el pago, el usuario debe autenticarse utilizando uno de los métodos biométricos o de seguridad (Huella dactilar, Reconocimiento facial o Contraseña)
📌 Consideraciones
La solicitud de pago desde la aplicación Payphone tiene una ventana de tiempo de 5 minutos para completarse. Si transcurre este tiempo, la solicitud expirará y la transacción será cancelada
🌐 Uso del campo responseUrl
(Webhook)
Si configuras el campo responseUrl
en la solicitud inicial, nuestro servidor enviará una respuesta a esa URL con dos parámetros:
id
: Identificador de la transacciónclientTransactionID
: Identificador de la transacción proporcionado por el comercio
Esta respuesta solo se enviará en dos casos de acción:
- Cuando el usuario aprueba el pago
- Cuando el usuario rechaza el pago
Es importante que tu servidor esté preparado para recibir y procesar esta respuesta en la URL especificada.