Integraciones

API REST para código propio

Tres pasos: crear un cobro, enviar al comprador a la página de pago y recibir el aviso firmado cuando se confirma.

Base
https://pagosbi.com/api/v1
Autenticación
Cabecera Authorization: Bearer <clave de API>
Formato
JSON. Importes como cadenas decimales ("15.00").

1. Crear un cobro

POST /cobros

curl -X POST https://pagosbi.com/api/v1/cobros \
  -H "Authorization: Bearer pgd_live_7Kq2mXv9RtLpW4nB" \
  -H "Content-Type: application/json" \
  -d '{
    "importe": "15.00",
    "referencia": "Pedido #4821",
    "descripcion": "Aceite de coco 500 ml x2",
    "url_retorno": "https://tutienda.com/gracias?pedido=4821",
    "caducidad_min": 15,
    "meta": { "pedido_id": 4821, "cliente_email": "ana.r@gmail.com" }
  }'

Respuesta 201 Created:

{
  "id": "PGD-2026-000512",
  "estado": "esperando",
  "importe_pedido": "15.00",
  "importe_unico": "15.23",
  "moneda": "USDT",
  "url_pago": "https://pagosbi.com/p/PGD-2026-000512",
  "caduca_en": "2026-09-04T15:57:12Z",
  "creado_en": "2026-09-04T15:42:12Z",
  "referencia": "Pedido #4821"
}

Redirige al comprador a url_pago. Si prefieres mostrar el QR en tu propia página, la respuesta incluye también tu qr_url y el pay_id.

2. Consultar un cobro

GET /cobros/{id}

{
  "id": "PGD-2026-000512",
  "estado": "pagado",
  "importe_pedido": "15.00",
  "importe_unico": "15.23",
  "importe_recibido": "15.23",
  "pagado_en": "2026-09-04T15:44:03Z",
  "transaccion": {
    "binance_tx_id": "1847392018273645",
    "pagador": { "nombre": "Ana R.", "pay_id": "***45 218" }
  },
  "avisos": [
    { "intento": 1, "enviado_en": "2026-09-04T15:44:05Z", "codigo": 200, "estado": "entregado" }
  ]
}

Estados posibles: esperando, detectado, pagado, caducado.

3. Recibir el aviso

Cuando el cobro pasa a pagado (y también al pasar a caducado), hacemos un POST a tu dirección de avisos:

POST /pgd/aviso HTTP/1.1
Host: tutienda.com
Content-Type: application/json
X-PGD-Firma: sha256=3f7a9c...e21b
X-PGD-Marca-Tiempo: 1788554643
X-PGD-Evento: cobro.pagado

{
  "evento": "cobro.pagado",
  "cobro": { "id": "PGD-2026-000512", "estado": "pagado", "importe_unico": "15.23",
             "importe_recibido": "15.23", "referencia": "Pedido #4821",
             "meta": { "pedido_id": 4821 } }
}

Responde 200 en menos de 10 segundos. Si no, reintentamos hasta 6 veces (1, 5, 15, 60, 240 y 720 minutos). Cada aviso es idempotente: usa el id del cobro para no entregar dos veces.

Verificar la firma

La firma es HMAC-SHA256(secreto, marca_tiempo + "." + cuerpo_crudo), en hexadecimal. Rechaza avisos con marca de tiempo de más de 5 minutos.

# Python (Flask)
import hmac, hashlib, time
from flask import request, abort

SECRETO = "whsec_9a4Ff2ZkQ8mT1vLr6Dp3Xc"

@app.post("/pgd/aviso")
def aviso():
    ts = request.headers.get("X-PGD-Marca-Tiempo", "")
    firma = request.headers.get("X-PGD-Firma", "").replace("sha256=", "")
    if abs(time.time() - int(ts or 0)) > 300:
        abort(400)
    esperada = hmac.new(SECRETO.encode(), f"{ts}.".encode() + request.get_data(), hashlib.sha256).hexdigest()
    if not hmac.compare_digest(esperada, firma):
        abort(401)
    datos = request.get_json()
    if datos["evento"] == "cobro.pagado":
        marcar_pedido_pagado(datos["cobro"]["meta"]["pedido_id"])
    return "", 200
// PHP
$ts = $_SERVER['HTTP_X_PGD_MARCA_TIEMPO'] ?? '';
$firma = str_replace('sha256=', '', $_SERVER['HTTP_X_PGD_FIRMA'] ?? '');
$cuerpo = file_get_contents('php://input');
$esperada = hash_hmac('sha256', $ts . '.' . $cuerpo, $SECRETO);
if (!hash_equals($esperada, $firma)) { http_response_code(401); exit; }

Errores

CódigoMotivo
401Clave de API inválida o regenerada.
402Suscripción impagada o suspendida.
409 sin_importes_libresYa hay 90 cobros abiertos en esa cuenta. Espera a que caduque alguno.
422Cuerpo inválido (importe no numérico, caducidad fuera de 5–60 min).
429Más de 60 peticiones por minuto.

Otros puntos de acceso

MétodoRutaUso
GET/cobros?estado=pagado&desde=2026-09-01Listar cobros con filtros y paginación (pagina, por_pagina).
POST/cobros/{id}/cancelarCancelar un cobro en espera y liberar su importe.
POST/cobros/{id}/reenviar-avisoVolver a enviar el aviso a tu tienda.
GET/tiendasTus tiendas conectadas (plan Negocio).