Cobros por SPEI para tu plataforma
Integra cobro por transferencia SPEI para tus clientes. Pides una CLABE por cada cliente tuyo, recibes un webhook firmado cuando cae un pago, y consultas pagos para reconciliar. Tus datos siguen siendo tuyos: nos mandas tu propia referencia y te la regresamos en cada evento.
Concepto
Tú operas la relación con tus clientes; nosotros somos la infraestructura de cobro. El puente entre ambos mundos es external_ref: el identificador de tu cliente en tu sistema. Lo guardamos junto a la CLABE que emitimos y te lo devolvemos en cada webhook y consulta — así nunca necesitas importar tus datos a nuestro sistema.
| Paso | Qué haces |
|---|---|
| 1 | Por cada cliente tuyo, pides una CLABE con tu external_ref. |
| 2 | Le das esa CLABE a tu cliente para que te pague por SPEI. |
| 3 | Cuando cae el pago, te llega un payment.received firmado con el external_ref. |
| 4 | Reconcilias (o haces backfill) con GET /v1/payments. |
Autenticación
Cada solicitud lleva tu token en el header. El business_id y los permisos salen siempre del token, nunca del cuerpo del request. Guardamos solo el hash del token, nunca el token en claro.
Authorization: Bearer <tu_token>01 Emitir / obtener una CLABE
Si ya existe la CLABE de ese cliente, te la devuelve — no crea otra. Puedes reintentar sin duplicar.
curl -X POST https://hailanerp.site/api/finaxapay/v1/clabes \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "external_ref": "CLI-4821", "name": "Cliente Ejemplo SA" }'
{ "clabe": "646180157000000004", "external_ref": "CLI-4821", "status": "active" }| Campo | Req. | Notas |
|---|---|---|
external_ref | sí | El id de tu cliente en tu sistema (1–128 caracteres). Es la llave: úsalo consistente. |
name | no | Alias legible del cliente (≤160). |
02 Consultar CLABEs
Una CLABE por tu referencia. Responde 404 si no existe.
Lista paginada de tus CLABEs.
# una CLABE por external_ref (404 si no existe) GET /v1/clabes/CLI-4821 # lista de tus CLABEs GET /v1/clabes?limit=100&offset=0
03 Webhook: payment.received
Cuando cae un pago a una de tus CLABEs, hacemos POST a la URL que configuraste, con firma HMAC. Es la vía principal para enterarte de los cobros en tiempo real.
{
"event": "payment.received",
"payment_id": "c8be760d-…",
"external_ref": "CLI-4821",
"clabe": "646180157000000004",
"amount_cents": 150000,
"currency": "MXN",
"tracking_key": "…",
"transaction_date": "2026-08-02T18:04:00Z",
"cep_url": "https://…/cep"
}Verificar la firma OBLIGATORIO
Header Finaxa-Signature: t=<unix>,v1=<hmac_hex>. La firma es HMAC-SHA256(secret, "<t>.<rawBody>") en hex, donde rawBody es el cuerpo crudo tal como llegó (no lo re-serialices).
import crypto from 'crypto' function verify(rawBody, header, secret, toleranceSec = 300) { const parts = Object.fromEntries(header.split(',').map(kv => kv.split('='))) const t = Number(parts.t) // anti-replay: rechaza firmas viejas if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex') return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1)) }
Reglas de entrega
- Responde 2xx rápido. Si no, reintentamos con backoff: 2, 4, 8, 16, 32 min, hasta 6 intentos.
- Idempotencia: la entrega es at-least-once — puedes recibir el mismo
payment.receivedmás de una vez. Deduplica porpayment_id(es estable por pago). - Si perdiste un webhook, reconcilia con
GET /v1/payments.
04 Consultar pagos
Para reconciliar o hacer backfill si perdiste un webhook.
GET /v1/payments?external_ref=CLI-4821&since=2026-08-01T00:00:00Z&limit=100&offset=0
{ "data": [ {
"payment_id": "…", "external_ref": "CLI-4821", "clabe": "…",
"amount_cents": 150000, "currency": "MXN", "status": "succeeded",
"tracking_key": "…", "transaction_date": "…", "cep_url": "…"
} ] }Filtros opcionales: external_ref, since (ISO 8601), limit (1–200), offset.
05 Errores y límites
| Código | Significado |
|---|---|
| 400 | Datos inválidos (revisa el campo error). |
| 401 | Token faltante, inválido o revocado. |
| 403 | El token no tiene permiso para esa operación. |
| 404 | El recurso no existe (o no es tuyo). |
| 429 | Demasiadas solicitudes — reintenta con backoff. |
| 502 | No pudimos emitir la CLABE en ese momento — reintenta. |
06 Alta (onboarding)
El alta la hacemos nosotros. Te entregamos:
- Tu token (Bearer) de acceso.
- Configuramos tu URL de webhook y te damos su secret de firma — se muestra una sola vez.
- Acceso al ambiente de pruebas (sandbox) para integrar de punta a punta antes de producción.
07 Notas de seguridad
- Nunca publiques el token ni el secret del webhook.
- Los montos son centavos. No los dividas antes de firmar/verificar.
- Los datos de tus clientes se quedan en tu sistema; nosotros solo guardamos
external_refy te lo regresamos. - Verifica siempre la firma del webhook antes de confiar en el payload.