Pagos P2P para apps
y agentes de IA

Integra envíos de dinero entre usuarios en minutos. API REST con autenticación por API key, webhooks y rate limiting listo para producción.

Quick start

Tres pasos para enviar tu primer pago.

1

Obtén un token JWT

# POST /auth/login
curl -X POST https://api.payg0.io/auth/login \
  -H 'Content-Type: application/json' \
  -d '{"email":"tu@email.com","password":"tu-password"}'
2

Crea una API key (modo desarrollador)

# Activa modo dev primero
curl -X PATCH https://api.payg0.io/users/developer-mode \
  -H 'Authorization: Bearer {token}' \
  -d '{"enabled": true}'

# Genera tu API key
curl -X POST https://api.payg0.io/keys \
  -H 'Authorization: Bearer {token}' \
  -d '{"name": "Mi app"}'
3

Envía un pago

# Enviar $100 MXN a un usuario
curl -X POST https://api.payg0.io/payments/send \
  -H 'X-API-Key: pyg0_test_xxxxxxxxxxxxx' \
  -H 'Content-Type: application/json' \
  -d '{"recipient": "@carlos", "amount": 100.00}'

# Response
{
  "id": "uuid...",
  "status": "COMPLETED",
  "reason": "transferred",
  "amount": "100.00"
}

Autenticación

Dos métodos según el contexto.

API Key X-API-Key

Ideal para integraciones server-to-server y agentes de IA. Genera tus keys en POST /keys.

X-API-Key: pyg0_test_a1b2c3d4e5f6g7h8

JWT Bearer

Para sesiones de usuario. Token de 24 horas obtenido en POST /auth/login.

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

Sandbox vs Producción: Las API keys de sandbox tienen prefijo pyg0_test_. En producción usarán pyg0_live_. En sandbox el dinero es simulado y no hay movimientos bancarios reales.

Endpoints

Todos los endpoints disponibles en la API.

Auth

MétodoRutaDescripciónRate limit
POST/auth/registerCrear cuenta10/min
POST/auth/loginObtener JWT10/min
GET/auth/mePerfil del usuario autenticado30/min

Wallet

MétodoRutaDescripciónRate limit
GET/wallet/balanceSaldo disponible, retenido y total30/min

Pagos

MétodoRutaDescripciónRate limit
POST/payments/sendEnviar pago a nickname o email5/min
GET/payments/historyHistorial paginado con filtros30/min
GET/payments/{id}Detalle de transacción30/min
POST/payments/{id}/cancelCancelar pago PENDING (solo emisor)30/min

Usuarios

MétodoRutaDescripciónRate limit
GET/users/lookup?q=Buscar usuario por nickname o email30/min
PATCH/users/developer-modeActivar/desactivar modo desarrollador30/min

API Keys (requiere modo dev)

MétodoRutaDescripciónRate limit
POST/keysCrear API key (full key solo en este response)30/min
GET/keysListar API keys activas30/min
DELETE/keys/{id}Revocar API key30/min

Webhooks (requiere modo dev)

MétodoRutaDescripciónRate limit
POST/webhooksRegistrar endpoint de webhook10/min
GET/webhooksListar webhooks activos30/min
DELETE/webhooks/{id}Eliminar webhook30/min

Webhooks

Recibe notificaciones en tiempo real cuando ocurre un evento de pago.

Eventos disponibles

Registrar un webhook

curl -X POST https://api.payg0.io/webhooks \
  -H 'X-API-Key: pyg0_test_xxxx' \
  -d '{
    "url": "https://tu-app.com/webhooks/payg0",
    "events": ["payment.completed", "payment.failed"]
  }'

Verificar la firma

Cada request incluye el header X-Payg0-Signature: sha256={hmac}. Verifica con el secret que recibiste al crear el webhook.

import hmac, hashlib

def verify_signature(payload: bytes, secret: str, signature: str) -> bool:
    expected = "sha256=" + hmac.new(
        secret.encode(), payload, hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

# En tu handler:
body = await request.body()
sig = request.headers["X-Payg0-Signature"]
if not verify_signature(body, WEBHOOK_SECRET, sig):
    raise HTTPException(401)

Ejemplos de código

Enviar un pago en distintos lenguajes.

Python
JavaScript
cURL
import httpx

client = httpx.Client(
    base_url="https://api.payg0.io",
    headers={"X-API-Key": "pyg0_test_xxxxxxxxxxxxx"},
)

# Consultar saldo
balance = client.get("/wallet/balance").json()
print(f"Disponible: ${balance['available_balance']} MXN")

# Enviar pago
response = client.post("/payments/send", json={
    "recipient": "@carlos",
    "amount": 150.00,
    "description": "Pago por servicio",
})
tx = response.json()
print(f"Transacción {tx['id']}: {tx['status']}")
const BASE = "https://api.payg0.io";
const HEADERS = {
  "X-API-Key": "pyg0_test_xxxxxxxxxxxxx",
  "Content-Type": "application/json",
};

// Consultar saldo
const balance = await fetch(`${BASE}/wallet/balance`, { headers: HEADERS })
  .then(r => r.json());
console.log(`Disponible: $${balance.available_balance} MXN`);

// Enviar pago
const tx = await fetch(`${BASE}/payments/send`, {
  method: "POST",
  headers: HEADERS,
  body: JSON.stringify({ recipient: "@carlos", amount: 150 }),
}).then(r => r.json());
console.log(`Transacción ${tx.id}: ${tx.status}`);
# Saldo
curl https://api.payg0.io/wallet/balance \
  -H "X-API-Key: pyg0_test_xxxxxxxxxxxxx"

# Enviar pago
curl -X POST https://api.payg0.io/payments/send \
  -H "X-API-Key: pyg0_test_xxxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"recipient":"@carlos","amount":150,"description":"Pago"}'

# Historial
curl "https://api.payg0.io/payments/history?status=COMPLETED&limit=10" \
  -H "X-API-Key: pyg0_test_xxxxxxxxxxxxx"

Rate limits

Los límites se aplican por API key, sesión JWT o IP.

OperaciónLímite
POST /payments/send5 por minuto
GET endpoints en general30 por minuto
POST /webhooks10 por minuto
GET /api/usage20 por minuto
Auth (login / register)10 por minuto

Al superar el límite recibirás 429 Too Many Requests. El header Retry-After indica cuándo reintentar.

Códigos de error

Todos los errores retornan JSON con el campo detail.

CódigoSignificado
400Bad Request — parámetros inválidos
401Unauthorized — token o API key inválida o expirada
403Forbidden — sin permisos (ej. modo dev no activo)
404Not Found — recurso no encontrado
409Conflict — email o nickname ya registrado
422Unprocessable — fondos insuficientes o datos inválidos
429Too Many Requests — rate limit excedido
500Internal Server Error — error interno inesperado