Skip to main content

Introducción a la API

Esta guía te ayudará a entender los conceptos básicos para integrar la API de GalioPay en tu aplicación.

URL Base​

Todas las peticiones a la API deben dirigirse a:

https://pay.galio.app/api

Autenticacion​

La API publica de GalioPay utiliza credenciales de cliente. Debes enviar API Key y Client ID en cada request autenticado.

Headers de autenticacion​

Authorization: Bearer {TU_API_KEY}
x-client-id: {TU_CLIENT_ID}

Ejemplo de autenticación​

const response = await fetch("https://pay.galio.app/api/payment-links", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer TU_API_KEY_AQUI",
"x-client-id": "TU_CLIENT_ID_AQUI",
},
body: JSON.stringify({
// ... datos de la petición
}),
});

Formatos de datos​

La API acepta y devuelve datos en formato JSON.

Content-Type​

Todas las peticiones deben incluir:

Content-Type: application/json

Códigos de respuesta HTTP​

CódigoSignificadoDescripción
200OKLa petición fue exitosa
201CreatedRecurso creado exitosamente
400Bad RequestDatos de entrada inválidos
401UnauthorizedAPI Key inválida o faltante
404Not FoundRecurso no encontrado
500Internal Server ErrorError interno del servidor

Manejo de errores​

Cuando ocurre un error, la API devuelve una respuesta con el siguiente formato:

{
"error": "Descripción del error"
}

Webhooks​

GalioPay envía webhooks con POST cuando cambia el estado del pago.

Destino del webhook (orden de prioridad):

  1. notificationUrl del payment link (si fue enviado en POST /api/payment-links o PUT /api/payment-links/{id})
  2. notificationUrl del cliente (fallback)

Si no hay URL configurada en ninguno de los dos niveles, no se envía webhook.

Firma HMAC opcional​

La firma de webhooks es opcional.

Cuando la firma HMAC está activada para tu cuenta, GalioPay agrega estos headers a cada webhook:

X-GalioPay-Event-Id: wh_evt_67a8f1b2c3d4e5f6a7b8c9d0_payment
X-GalioPay-Timestamp: 1768046400
X-GalioPay-Signature: v1=9f1c...

La firma se calcula con tu secreto de webhook:

HMAC_SHA256(timestamp + "." + raw_body, webhook_secret)

raw_body debe ser el body exacto recibido en la request, antes de parsearlo como JSON. No reconstruyas el JSON para validar la firma, porque puede cambiar el orden o formato de los campos.

Ejemplo de validación en Node.js/Express:

import crypto from "crypto";
import express from "express";

const app = express();

app.post(
"/webhooks/galiopay",
express.raw({ type: "application/json" }),
(req, res) => {
const webhookSecret = process.env.GALIOPAY_WEBHOOK_SECRET;
const timestamp = req.header("X-GalioPay-Timestamp");
const signatureHeader = req.header("X-GalioPay-Signature") || "";
const expectedSignature = crypto
.createHmac("sha256", webhookSecret)
.update(`${timestamp}.${req.body.toString("utf8")}`)
.digest("hex");

const receivedSignature = signatureHeader.replace("v1=", "");

if (receivedSignature !== expectedSignature) {
return res.status(401).send("Invalid signature");
}

const event = JSON.parse(req.body.toString("utf8"));

// Usa X-GalioPay-Event-Id para idempotencia.
res.sendStatus(200);
},
);

Recomendaciones:

  • Rechaza timestamps demasiado antiguos, por ejemplo mayores a 5 minutos.
  • Guarda X-GalioPay-Event-Id para no procesar dos veces el mismo evento.
  • Responde 200 si ya procesaste ese eventId, para evitar reintentos innecesarios.

Los POST posibles que puedes recibir​

CasostatusCuándo se envía
Pago aprobadoapprovedCuando un pago se acredita correctamente
Pago reembolsadorefundedCuando se completa un reembolso

Payload de pago (approved)​

{
"id": "67a8f1b2c3d4e5f6a7b8c9d0",
"paymentMethodId": "TRANSFER",
"amount": 15000,
"netAmount": 14650,
"moneyReleaseDate": "2026-02-12T00:00:00.000Z",
"currency": "ARS",
"status": "approved",
"sandbox": false,
"date": "2026-02-10T14:21:00.000Z",
"referenceId": "orden-456"
}

Payload de reembolso (refunded)​

{
"id": "67a8f1b2c3d4e5f6a7b8c9d0",
"paymentMethodId": "TRANSFER",
"amount_refunded": 15000,
"refund_type": "total",
"refund_reason": "Cliente solicito devolucion",
"status": "refunded",
"currency": "ARS",
"sandbox": false,
"date": "2026-02-12T10:30:00.000Z",
"referenceId": "orden-456"
}

Ejemplos de errores comunes​

Error de validación (400):

{
"error": "Items array is required"
}

API Key inválida (401):

{
"error": "Unauthorized"
}

Recurso no encontrado (404):

{
"error": "Payment link not found"
}

Ejemplo completo​

Aquí tienes un ejemplo completo de cómo hacer una petición autenticada:

cURL​

curl -X POST https://pay.galio.app/api/payment-links \
-H "Content-Type: application/json" \
-H "Authorization: Bearer TU_API_KEY_AQUI" \
-H "x-client-id: TU_CLIENT_ID_AQUI" \
-d '{
"items": [
{
"title": "Producto de ejemplo",
"quantity": 1,
"unitPrice": 1000,
"currencyId": "ARS"
}
],
"referenceId": "orden-123",
"backUrl": {
"success": "https://tusitio.com/exito",
"failure": "https://tusitio.com/error"
}
}'

JavaScript (Fetch)​

async function crearLinkDePago() {
const apiKey = "TU_API_KEY_AQUI";
const clientId = "TU_CLIENT_ID_AQUI";

const datos = {
items: [
{
title: "Producto de ejemplo",
quantity: 1,
unitPrice: 1000,
currencyId: "ARS",
},
],
referenceId: "orden-123",
backUrl: {
success: "https://tusitio.com/exito",
failure: "https://tusitio.com/error",
},
};

try {
const response = await fetch("https://pay.galio.app/api/payment-links", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
"x-client-id": clientId,
},
body: JSON.stringify(datos),
});

if (!response.ok) {
const error = await response.json();
throw new Error(error.error);
}

const resultado = await response.json();
console.log("Link creado:", resultado.url);
} catch (error) {
console.error("Error:", error.message);
}
}

Próximos pasos​