Salir a producción
Lo que separa una integración que funciona en tu portátil de una que aguanta el lunes por la mañana. Ninguno de estos puntos es teórico: todos son formas de perder dinero o clientes que hemos visto de cerca.
Antes del primer cobro real
Credenciales
- Una credencial por sistema, con los alcances mínimos. Si un solo secreto está repartido entre tu tienda, tu ERP y tres terminales, no puedes revocar ninguno sin tumbar los cinco.
- El secreto vive en tu gestor de secretos o en variables de entorno.
Nunca en el repositorio, nunca en el navegador, nunca en un
.envcommiteado. - Restringe por IP si tu integración sale siempre desde las mismas.
- Tienes escrito cómo rotar. El día que haga falta no es el día de averiguarlo.
Idempotencia
- Toda llamada que crea o modifica manda
Idempotency-Key. Es obligatoria, así que si no lo haces ya lo sabes — pero asegúrate de que la clave sea tu identificador de negocio (el número de pedido, el de ticket), no un aleatorio nuevo en cada intento. Un aleatorio no protege de nada: el reintento genera otra clave y otro cobro. - Tus reintentos de
5xxreusan la misma clave.
Webhooks
- Verificas la firma antes de procesar nada. → Cómo
- Firmas el cuerpo crudo, no el objeto re-serializado. Es el error número uno y el síntoma no apunta a la causa.
- Respondes
2xxrápido y haces el trabajo pesado aparte. Cada intento tiene 10 segundos. - Guardas los
idde evento y descartas los repetidos. La entrega es «al menos una vez». - Tu servidor no sigue redirecciones: un
3xxcuenta como fallo y no lo seguimos.
Conciliación
- No dependes sólo de los webhooks. Para cuadrar contabilidad,
GET /v1/transactionsyGET /v1/payment_linksson el estado real. - Comparas contra el
amountdel enlace, no contra lo que mandó el pagador. En un pago cruzado son cifras distintas y sólo la primera es predecible. → Pagos cruzados - Registras el
request_idde cada llamada en tus propios logs.
Interfaz
- El importe a pagar se enseña con todos sus decimales y no se puede editar. Una transferencia por otro importe no se acredita.
-
processingse lee como «estamos confirmando tu pago», no como error. En cadena hay confirmaciones y en un pago cruzado hay una conversión. - Si construyes tu propia pantalla de cobro, escuchas
payment_link:quotes_updated: la CLABE puede cambiar mientras el pagador la mira. - Enseñas sólo los métodos disponibles para ese importe, no la lista completa.
Los cinco errores que más caro salen
1 · Firmar el cuerpo re-serializado. Todas las firmas fallan y el mensaje no dice por qué. Guarda los bytes tal cual llegan, antes de parsear el JSON.
2 · Usar un aleatorio como clave de idempotencia. Parece que cumples y no proteges nada: cada reintento lleva una clave distinta y crea un cobro nuevo. La clave tiene que ser tu identificador de pedido.
3 · Mandar amount como número. JSON.parse pierde precisión antes de que
lo veamos. Devolvemos 400 a propósito, pero si tu capa intermedia lo convierte
en cadena por su cuenta, cobrarás una cifra que no es la tuya.
4 · Dar por bueno un webhook sin verificar. Es un POST a una URL pública.
Cualquiera que la adivine puede inventarte un cobro pagado.
5 · Tratar processing como fallo. El cliente pagó, tú le dices que falló, y
paga otra vez. El doble cobro se lo comes tú.
Qué vigilar una vez en marcha
| Señal | Dónde | Qué significa |
|---|---|---|
429 en aumento | Tus logs | Te estás acercando al tope. Mira RateLimit-Remaining |
| Destino de webhooks apagado | GET /v1/webhook_endpoints → disabled_at | Cinco entregas fallidas seguidas. Arregla tu servidor antes de reactivarlo |
Enlaces atascados en processing | GET /v1/payment_links?status=processing | Si pasan horas, escríbenos con el code |
| Cobros de QR generados ≫ pagados | GET /v1/qr/stats | Suele ser problema de mostrador, no de la API |
Cuando algo se rompe
En este orden, porque cada paso descarta la mitad de los casos:
GET /v1/ping— ¿tu credencial sigue viva y con los alcances que crees?GET /v1/request_logs— ¿nos llegó tu llamada? Si no aparece ahí, el problema está entre tu servidor y nosotros.- El
codedel error — busca en el catálogo qué lo provoca. - Escríbenos con el
request_id. Con él localizamos la llamada exacta en segundos; sin él, empezamos preguntando.
Lo que todavía no hay
Por transparencia, para que no lo descubras a mitad de la integración:
- No hay entorno de pruebas separado. Las credenciales pertenecen al entorno donde se emiten. Prueba con importes pequeños.
- Las devoluciones no están en la API. Se hacen desde el panel.
- Dar de alta un destino bancario de retiro se hace desde el panel. Ordenar el retiro sí está en la API, y sólo a destinos ya dados de alta — es lo que impide que un fallo mande tu saldo a una cuenta que nadie aprobó. → Retiros
- El QR de mostrador se puede dar de alta por API desde
POST /v1/qr, pero su ciclo de vida completo —revocarlo, por ejemplo— sigue en el panel.
Si algo de esto te bloquea, dínoslo: saber quién lo necesita es lo que decide qué se construye antes.