Skip to main content
Antes de habilitar la salida a producción de tu compañía, OnePay revisa tu integración de facturas contra un conjunto de criterios conocidos. Esta página es ese conjunto: si tu integración los cumple, la homologación se cierra sin devoluciones. El proceso tiene dos etapas: primero validamos cada endpoint por separado sobre tu tráfico de sandbox, y después corres la misma secuencia de punta a punta con tu llave de producción.
En ninguna de las dos etapas trabajas contra un guion nuestro. La etapa 1 no te pide preparar nada: OnePay la hace sobre el tráfico que ya generaste en sandbox, revisando tus llamadas reales.La etapa 2 la corres por tu cuenta, con tu llave de producción, cuando estés listo. Al terminar nos entregas los id y nosotros analizamos el flujo de peticiones y el del pago del lado de OnePay. No hace falta agendar nada ni esperar a que estemos conectados.
En las tablas de criterios distinguimos dos tipos:
  • Requisito — sin esto no se homologa.
  • Recomendación — no bloquea la homologación, pero es lo que hace que la integración aguante en producción.

Prerrequisitos

Tu llave sk_live_ la generas tú desde el panel de administración. La homologación no te la retiene: la necesitas para correr la etapa 2.Lo que sí depende de este proceso es la salida a producción de la compañía: OnePay la habilita cuando la homologación queda aprobada, así que conviene cerrarla antes de planear la fecha de salida.

Etapa 1 · Validación por endpoint

Crear factura — POST /v1/invoices

provider_id debe ser único por documento y en el tiempo. Cada factura lleva el suyo y no se reutiliza nunca: ni en el siguiente ciclo, ni para el mismo cliente, ni para el mismo contrato. Para identificar al cliente el campo es reference.Reenviar un provider_id ya usado no crea la factura nueva. Mientras la anterior siga en estado CREATED, OnePay la reconoce como el mismo documento y responde 201 con esa factura: el cobro nuevo no se genera y el cliente sigue viendo el monto anterior. La respuesta es exitosa, así que tu sistema no se entera.
Un due_date de año-mes nace vencido. Un valor como "2026-05" es aceptado por la validación y se guarda como el día 1 de ese mes: la factura nace vencida y las reglas de cobranza disparan mora desde el primer día.Si manejas una fecha de pago oportuno distinta del vencimiento, va en timely_payment_date, no en due_date.
Sin datos de contacto no hay cobro. Una factura sin phone ni email se crea igual y responde 201, pero el cobro no sale por ningún canal: ni WhatsApp ni correo. El cliente nunca se entera de que tiene algo que pagar.
Por qué el reintento va con el mismo cuerpo: si repites el POST con un cuerpo idéntico, la deduplicación te devuelve el mismo id y no se duplica el cobro. Un reintento con datos cambiados no es un reintento — crea un cobro nuevo.

Actualizar factura — PUT /v1/invoices/{id}

El contacto se hereda. Si el PUT no trae phone ni email, el cobro de reemplazo conserva los del cobro anterior. Enviarlos sirve para actualizarlos; no es obligatorio para que el cobro llegue.

Cancelar factura — DELETE /v1/invoices/{id}

Los dos motivos de cancelación no son intercambiables: cada uno corresponde a una situación real distinta.
Para qué sirve payment_method: es el medio con el que el cliente pagó por fuera de OnePay. Texto libre de hasta 60 caracteres — Efectivo, Nequi, Consignación Bancolombia. Sin él, OnePay sabe que la factura se pagó afuera pero no sabe cómo.
El endpoint masivo no es para el flujo diario. DELETE /v1/invoices borra todas las facturas pendientes de la empresa. Es una herramienta de limpieza puntual y no debe quedar cableada al flujo de anulación de tu sistema de gestión.
El 404 de desajuste de ambiente aparece cuando consultas una factura de sandbox con la llave de producción o al revés. Es terminal: reintentarlo no cambia nada, hay que revisar qué llave está usando el proceso.

Webhooks

Por qué invoice.paid es el mínimo: es el evento que cierra el ciclo de cobro. Sin él no te enteras de que una factura se pagó en OnePay y tu sistema queda desincronizado.
Un evento agotado se pierde. OnePay entrega cada evento en 6 intentos como máximo, con un backoff que se agota en poco menos de 10 minutos. Después del sexto intento fallido el evento deja de reintentarse por esa vía. Ver Entrega y reintentos para el calendario completo.
La firma se calcula sobre el cuerpo crudo. Signature es un HMAC-SHA256 sobre los bytes tal como llegaron. Deserializar el JSON y volver a serializarlo antes de calcular el HMAC cambia el cuerpo y rompe la firma, aunque el contenido sea equivalente. Ver Verificar la firma.
Por qué la idempotencia importa: los reintentos pueden entregarte el mismo evento dos veces. Sin idempotencia por invoice.id + tipo de evento, un reintento se convierte en un pago registrado dos veces en tu sistema.

Etapa 2 · Corrida integral

Es la misma secuencia de la etapa 1, pero ejecutada de punta a punta con tu llave sk_live_ y sobre facturas nuevas. Al correr en producción son facturas reales de tus clientes: el dinero se mueve y los mensajes salen normalmente. Al terminar nos entregas el id de OnePay de cada paso, y nosotros revisamos el flujo de peticiones y el del pago para confirmar que cada resultado esperado se dio.
1

Crear la factura, dos veces con el mismo cuerpo

POST /v1/invoices con el payload completo, enviado dos veces con el mismo cuerpo. Usa un monto bajo: esta factura se paga de verdad en el paso 2.Esperado: ambas respuestas 201 y con el mismo id. Si el segundo 201 trae un id distinto, hay un cobro duplicado.
2

Pagar la factura

Paga el payment.payment_link. Es un pago real: el dinero se mueve y se liquida como cualquier otro cobro, con su comisión.Esperado: llega invoice.paid con el pago aprobado, la factura queda en CONCILIATED, y en tu sistema queda marcada como pagada. Este último punto se verifica con evidencia de tu lado: es el paso que demuestra que el webhook no solo llega, sino que cierra el ciclo.
3

Actualizar otra factura

PUT /v1/invoices/{id} cambiando el monto de otra factura.Esperado: 200 con un payment_id nuevo. El cobro conserva el teléfono de la factura original y llega por WhatsApp.
4

Cancelar por pago externo

DELETE /v1/invoices/{id} con reason: PAID_FROM_PROVIDER, provider_payment_id y payment_method.Esperado: 204. La factura sobrevive en estado PAID_FROM_PROVIDER con el método registrado — no se borra. Si la factura tiene teléfono, el cliente recibe el recibo en PDF por WhatsApp.
5

Cancelar por anulación

DELETE /v1/invoices/{id} con reason: DELETE_FROM_PROVIDER sobre otra factura.Esperado: 204. La factura se elimina.
6

Intentar cancelar la factura ya pagada

DELETE /v1/invoices/{id} sobre la factura que pagaste en el paso 2.Esperado: 409, registrado en tu sistema como “ya pagada en OnePay” y sin reintentos.
Los pasos 4 y 5 son los que más seguido revelan un problema: son el mismo endpoint con dos comportamientos distintos, y una integración que trata los dos motivos por igual falla ahí.

Salida a producción

Con las etapas 1 y 2 cerradas:
  1. Salida a producción habilitada por OnePay, y tu webhook de producción configurado con secret y los mismos eventos que homologaste.
  2. Primera factura real acompañada de punta a punta: creación, envío, pago y conciliación, con OnePay presente.
  3. Retiro de las facturas de prueba que hayan quedado en sandbox.
  4. Monitoreo de las primeras 72 horas: entregas de webhook, tasa de 422 y cobros duplicados.