GatoPago Flow · API
Cobra en USDC desde tu servidor
Crea un cobro, comparte su link o QR y recibe un webhook firmado cuando se paga. Tu cliente paga desde GatoPago o desde cualquier wallet, y el dinero llega directo a tu cuenta: GatoPago nunca lo custodia.
Beta pública en redes de prueba: usa claves de prueba (sk_test_…) y USDC de prueba.
Primeros pasos
- Abre la consola con tu cuenta GatoPago y crea una clave API.
- Crea un cobro desde tu servidor y envía a tu cliente su
checkout_url. - Registra una URL de webhook y entrega el pedido cuando llegue
payment_intent.succeeded.
Autenticación
Cada solicitud lleva tu clave: Authorization: Bearer sk_test_…. Con ella se crean cobros a tu nombre: guárdala en tu servidor, nunca en una app ni en una página web. Si se filtra, revócala en la consola y crea otra.
Crear un cobro
Solo amount es obligatorio: un decimal en USDC con hasta 6 decimales. description (hasta 200 caracteres) la ve quien paga; metadata (hasta 20 valores de texto) es para ti; expires_in va en segundos, de 5 minutos a 7 días (24 horas por defecto).
curl -X POST https://api.gatopago.com/v1/payment_intents \
-H "Authorization: Bearer sk_test_…" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-1042" \
-d '{
"amount": "18.00",
"description": "Pedido 1042",
"metadata": { "order_id": "1042" },
"expires_in": 3600
}'{
"id": "pi_3f9c…",
"object": "payment_intent",
"amount": "18.00",
"currency": "USDC",
"status": "requires_payment",
"description": "Pedido 1042",
"metadata": { "order_id": "1042" },
"checkout_url": "https://gatopago.com/pay/pi_3f9c…",
"expires_at": 1767229200,
"created_at": 1767225600,
"livemode": false,
"payment": null
}Reintenta sin miedo: con la misma Idempotency-Key y los mismos datos recibes el mismo cobro, nunca uno segundo. Si la respuesta se perdió, repite la solicitud antes de crear otro.
Estados
requires_payment- Esperando el pago.
processing- Pagado desde otra red; Circle está entregando los USDC en tu red.
succeeded- Pagado: el dinero ya está en tu cuenta.
canceled- Lo cancelaste antes de que se pagara.
expired- Venció sin pagarse (por defecto, a las 24 horas).
En redes de prueba, POST /v1/payment_intents/:id/simulate marca un cobro como pagado, así pruebas tu webhook sin pagar.
Webhooks
Registra tu URL en la consola. GatoPago envía cada evento con un POST y reintenta las entregas fallidas hasta 10 veces; responde con un 2xx apenas lo recibas.
{
"id": "evt_…",
"object": "event",
"type": "payment_intent.succeeded",
"created_at": 1767226000,
"data": { "id": "pi_3f9c…", "status": "succeeded", "amount": "18.00", "…": "…" }
}payment_intent.created- Se creó un cobro.
payment_intent.processing- Se pagó desde otra red y está en camino.
payment_intent.succeeded- Se pagó: entrega el pedido.
payment_intent.duplicate_payment- Llegó un segundo pago para un cobro ya pagado.
payment_intent.canceled- Se canceló.
payment_intent.expired- Venció sin pagarse.
Verifica cada evento. El encabezado GatoPago-Signature es t=<unix>,v1=<hex>: un HMAC-SHA256 de <t>.<body> con el secreto de tu endpoint (whsec_…), que la consola muestra una sola vez.
import { createHmac, timingSafeEqual } from 'node:crypto';
// Usa el cuerpo crudo, tal como llegó.
export function verifyGatoPago(rawBody, header, secret) {
const { t, v1 } = Object.fromEntries(header.split(',').map((part) => part.split('=')));
// Rechaza entregas viejas (5 minutos).
if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex');
return v1.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}Referencia
URL base: https://api.gatopago.com
POST /v1/payment_intents | Crea un cobro. |
GET /v1/payment_intents | Lista los últimos 100. |
GET /v1/payment_intents/:id | Lee uno. |
POST /v1/payment_intents/:id/cancel | Cancela uno sin pagar. |
POST /v1/payment_intents/:id/simulate | Lo marca como pagado (solo en redes de prueba). |
GET /v1/events | Eventos y cómo fue cada entrega. |
POST /v1/events/:id/resend | Reenvía un evento. |
GET · POST /v1/webhook_endpoints | Lista o registra URLs de webhooks. |
DELETE /v1/webhook_endpoints/:id | Quita una URL. |
GET · POST /v1/api_keys | Claves API: solo desde la consola. |
Los errores responden con un estado HTTP y un código estable en error_code:
UNAUTHENTICATED- Falta la clave o no es válida (401).
INVALID_AMOUNT- El monto no es un decimal válido mayor a cero (400).
IDEMPOTENCY_KEY_REUSED- Usaste la misma Idempotency-Key con otros datos (409).
INTENT_NOT_CANCELABLE- El cobro ya se pagó, venció o se canceló (409).
RATE_LIMITED- Demasiadas solicitudes; reintenta luego (429).