FINORA Pago · Guía
Verificar el aviso firmado
Si tu caja pide los cobros sin esperar la respuesta, o usa la dirección finora-pago://, el veredicto le llega por un
aviso: un POST de FINORA Pago a una dirección de tu caja. El aviso va firmado para que tu caja sepa que lo mandó
FINORA Pago y no otro programa del equipo.
Los pasos
Sección titulada «Los pasos»-
Pide el cobro con la dirección del aviso:
"callbackUrl": "http://127.0.0.1:5000/pago"en la API local, ocallback=(codificado) en la direcciónfinora-pago://. -
En tu caja, al recibir el
POST, lee el cuerpo crudo, tal como llegó, antes de convertirlo en objeto. -
Calcula
HMAC-SHA256de ese cuerpo crudo con el token local como clave, en hexadecimal, y antepónsha256=. -
Compáralo con la cabecera
X-Pago-Firma, con una comparación de tiempo constante. Si no coinciden, responde401y descarta el aviso. -
Si coinciden, lee
estadoy actúa:APROBADAcierra la venta,EN_DUDAla retiene, el resto la deja sin pagar. -
Responde
200enseguida. FINORA Pago reintenta tres veces (a los 0, 2 y 8 segundos) si no recibe un2xx.
Prueba tu cálculo con el vector
Sección titulada «Prueba tu cálculo con el vector»Antes de conectar nada, comprueba que tu código firma igual que FINORA Pago:
| Dato | Valor |
|---|---|
| Token local | secreto |
| Cuerpo crudo (7 bytes, sin espacios ni salto de línea) | {"a":1} |
X-Pago-Firma esperada | sha256=87c6bf752c360faf8b89e2d9ed15dcc45e947f9ecdf9c4b637c8fa62d691c598 |
Si tu resultado es otro, estás firmando otra cosa: espacios añadidos, un salto de línea al final o el JSON vuelto a serializar.
$hmac = [System.Security.Cryptography.HMACSHA256]::new([Text.Encoding]::UTF8.GetBytes("secreto"))$firma = $hmac.ComputeHash([Text.Encoding]::UTF8.GetBytes('{"a":1}'))"sha256=" + -join ($firma | ForEach-Object { $_.ToString("x2") })import { createHmac, timingSafeEqual } from "node:crypto";
// Vector de pruebaconsole.log("sha256=" + createHmac("sha256", "secreto").update('{"a":1}').digest("hex"));
// En tu caja (Express): el cuerpo se lee crudo, sin convertirapp.post("/pago", express.raw({ type: "application/json" }), (req, res) => { const esperada = Buffer.from("sha256=" + createHmac("sha256", process.env.PAGO_TOKEN ?? "").update(req.body).digest("hex")); const recibida = Buffer.from(req.get("X-Pago-Firma") ?? ""); if (esperada.length !== recibida.length || !timingSafeEqual(esperada, recibida)) return res.sendStatus(401); const cobro = JSON.parse(req.body.toString("utf8")); // decide por cobro.estado res.sendStatus(200);});import hmac, hashlib
firma = "sha256=" + hmac.new(b"secreto", b'{"a":1}', hashlib.sha256).hexdigest()print(firma)
# En tu caja: compara con la cabecera usando hmac.compare_digest(firma_calculada, cabecera)Si algo sale mal
Sección titulada «Si algo sale mal»| Lo que ves | Qué hacer |
|---|---|
| La firma nunca coincide | Prueba el vector. Casi siempre es el cuerpo reserializado o un token distinto al de Configuración |
| El aviso no llega | Comprueba que tu caja escucha en esa dirección y puerto. El veredicto sigue disponible en GET /v1/cobros/{cobroId} |
| Llegan avisos repetidos | Son los reintentos: responde 2xx más rápido. Procesa cada cobroId una sola vez |