Odoo, ERP y marketplaces
Dos puertas de entrada, un mismo motor de facturación:
- Orden normalizada (
/hooks/orden): para Odoo, cualquier ERP, y para Falabella o Ripley a través de tu middleware. Tú envías la venta en un JSON simple; BillerPro emite. - Notificaciones de Mercado Libre (
/hooks/mercadolibre/webhook): Mercado Libre avisa; BillerPro trae la orden con tu token y emite.
Odoo u otro ERP
1. Genera tu URL privada
En tu panel: Conectar canal → Odoo / ERP, elige el sistema, pon un nombre y pulsa Generar URL de conexión. Obtienes algo como:
https://billerpro.store/hooks/orden?token=XXXXXXXX
Trátala como una contraseña: quien la tenga puede emitir con tu RUC. Si se filtra, genera otra desde el panel y la anterior deja de funcionar.
2. Envía cada venta
Cada vez que confirmes una venta o factura en tu ERP, haz un POST JSON a esa URL:
{
"origen": "odoo",
"origen_id": "INV/2026/00042",
"tipo_comprobante": "01",
"documento": "20601234567",
"razon_social": "Cliente SAC",
"moneda": "PEN",
"lineas": [
{ "codigo": "SKU-1", "descripcion": "Consultoría", "cantidad": 1, "precio_unitario": 590.00, "afectacion": "10", "unidad": "ZZ" },
{ "descripcion": "Mouse", "cantidad": 2, "precio_unitario": 59.90 }
],
"envio": { "precio": 15.00, "descripcion": "Envío Lima" }
}
| Campo | Obligatorio | Notas |
|---|---|---|
origen_id |
Recomendado | Tu número de venta. Evita duplicados: si lo repites, no se emite dos veces. |
tipo_comprobante |
No | 01 factura, 03 boleta. Si falta, se deduce del documento. |
documento |
No | RUC (11) → factura; DNI (8) → boleta; vacío → boleta a "Cliente varios". |
razon_social |
No | Nombre del cliente. |
moneda |
No | PEN por defecto; USD usa el tipo de cambio de SUNAT del día. |
lineas[].precio_unitario |
Sí | Con IGV incluido (precio que paga el cliente). |
lineas[].afectacion |
No | 10 gravado (defecto), 20 exonerado, 30 inafecto, 15 bonificación. |
lineas[].unidad |
No | NIU (unidad) por defecto; ZZ para servicios. |
envio |
No | Se agrega como línea gravada. |
Respuesta:
{ "emitido": true, "numero": "F001-00000042", "estado": "aceptado" }
Odoo: dónde engancharlo
La forma más simple es una acción automatizada (Ajustes → Técnico → Acciones automatizadas) sobre account.move al pasar a Publicado, que haga la petición con requests. Si usas Odoo.sh o SaaS sin código Python, un webhook de Odoo (v17+) hacia la URL con un pequeño middleware que reordene los campos también funciona. Si prefieres, te damos el módulo listo: escríbenos.
Falabella y Ripley
Ambos marketplaces exponen sus ventas por API (Falabella Seller Center / Ripley Seller). Lo habitual es que tu integrador o middleware ya lea las órdenes; añade una llamada más: por cada orden pagada, envía la orden normalizada de arriba a tu URL privada con origen: "falabella" o "ripley" y el número de orden del marketplace como origen_id.
Como el marketplace suele vender a persona natural, casi todo saldrá como boleta. Si el comprador pidió factura en el marketplace, manda documento con su RUC.
Mercado Libre
1. Consigue el access token
- Crea una aplicación en developers.mercadolibre.com.pe con permisos de lectura de órdenes.
- Autoriza tu cuenta vendedora y obtén el access token (
APP_USR-…). Recuerda que expira cada 6 horas: usa el refresh token para renovarlo y, si cambia, vuelve a vincular en el panel.
2. Vincula en BillerPro
En tu panel: Conectar canal → Mercado Libre, pega el token y pulsa Vincular. Te devolvemos la URL de notificaciones.
3. Registra la URL en tu app de Mercado Libre
En la configuración de tu aplicación, campo URL de notificaciones, pega la URL y activa el tema orders_v2.
Desde ese momento, cada orden pagada se factura como boleta al comprador (nombre y apellido de Mercado Libre). El origen_id es el número de orden de Mercado Libre, así que nunca se factura dos veces aunque lleguen varias notificaciones.
Problemas comunes
401 Falta el token / Token no válido: la URL está incompleta o fue regenerada. Copia la nueva desde el panel.
400 La orden no tiene líneas con precio: cada línea necesita precio_unitario.
No se emitió y respondió {"emitido": false, "motivo": …} (Mercado Libre): el motivo lo explica: no era una orden, el estado no es paid o el token expiró.
Quiero probar sin emitir de verdad: usa un origen_id de prueba y luego anula el comprobante desde el panel.