API REST – OrionERP
Documentación oficial para integraciones de sistemas con OrionERP a través de la API REST.
Introducción
¡Bienvenido a la API de OrionERP! 👋 Aquí encontrará todo lo que necesita para usar nuestra API. Intentamos mantener la documentación lo más útil posible, pero si aún tiene problemas para entender algo, puede contactarnos a través de nuestro Helpdesk enviando un ticket en https://orionerp.cl/web/login como usuario registrado.
¡Respondemos rápido! ⚡️
Especificaciones
Resumen
-
Proporciona una API **RESTful** para OrionERP.
-
Soporta autenticación y acceso seguros, y permite operaciones **CRUD** (Crear, Leer, Actualizar, Eliminar) y llamadas personalizadas a los módulos de OrionERP.
Autenticación
-
Soporta **OAuth2** para la autenticación.
-
Basado en token: después de un flujo **OAuth** exitoso, recibe un token de acceso (**access token**).
-
Los tokens pueden ser revocados si es necesario.
Formato de Solicitud / Respuesta
-
La comunicación se realiza a través de **HTTP**.
-
**JSON** es el formato para las respuestas. Para las solicitudes, el formato es flexible siempre que cumpla con la estructura esperada del *endpoint* e incluya los encabezados de autenticación requeridos. Puede utilizar herramientas como `cURL`, Postman o cualquier librería cliente **HTTP** en su lenguaje de programación preferido para enviar solicitudes.
Seguridad
-
Los *endpoints* respetan el modelo de permisos de OrionERP (derechos de acceso, reglas de registro, reglas a nivel de campo).
Instalación y Configuración
-
Para entornos de prueba y producción, solicite al Helpdesk los parámetros adecuados como Client ID, Client Secret y Base URL.
Dependencias y Requisitos
-
Suscripción comercial activa a la API Rest de OrionERP
-
Parámetros Client ID, Client Secret y Base URL válidos actualmente
|
|
|
|
|
Autenticación
Para obtener un token **OAuth2** para cualquier solicitud posterior, debe solicitar uno al *endpoint* de autenticación **API** de su instancia **OrionERP** proporcionando su **Client ID** y **Client Secret**.
Ejemplo
Los siguientes parámetros no son válidos y se utilizan con fines ilustrativos. Para obtener parámetros funcionales, su empresa debe tener una suscripción activa a la **API Rest** de **OrionERP** y generarlos a través del módulo **API Rest** dentro de la instancia **OrionERP** de su empresa con la opcion Crear desde el Dashboard del modulo:
• **Base URL**: https://dominiocliente.orionerp.cl
• Auth endpoint: /api/authentication/oauth2/token
• Auth URL: https://dominiocliente.orionerp.cl/api/authentication/oauth2/token
• Client ID: CLIENT-ID-EXAMPLE
• Client Secret: CLIENT-SECRET-EXAMPLE
Todos estos parámetros son proporcionados por nuestro Helpdesk tanto para propósitos de prueba como de producción:
curl -X POST "https://dominiocliente.orionerp.cl/api/authentication/oauth2/token" \
-d "grant_type='client_credentials'" \
-d "client_id=CLIENT-ID" \
-d "client_secret=CLIENT-SECRET"
Ejemplo de Respuesta JSON:
{
"access_token": "XYZ...",
"token_type": "Bearer",
"expires_in": 3600
}
La clave 'access_token' dentro de la respuesta **JSON** es el token que debe usar posteriormente en cada solicitud como token **Bearer**
Notas de seguridad
• Keep your Client Secret confidential: Como su nombre lo indica.
• Client ID y Client Secret son válidos mientras la suscripción comercial de su empresa a la API de OrionERP esté activa y su empresa tenga la API habilitada dentro de su instancia. Ambos inclusive.
• Cada token OAuth2 es válido por 15 minutos: Aunque teóricamente podrías solicitar un nuevo token en cada transacción, **debes reutilizar el token mientras siga siendo válido** y solicitar uno nuevo solo después de que expire.
• La cantidad máxima de solicitudes HTTP a la API es de 300 por minuto. Si se supera el límite, se produce una prohibición temporal del Client ID que dura 60 segundos, por lo que todas las solicitudes que utilicen el Client ID prohibido serán inválidas.
Ejemplo en Python
Ejemplo de flujo: obtener token y crear un Lead usando el *endpoint* real.
import requests
import json
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
client_id = "CLIENT-ID"
client_secret = "CLIENT-SECRET"
base_url = "https://cliente.orionerp.cl"
token_url = f"{base_url}/api/authentication/oauth2/token"
type = 'POST'
data = {
"grant_type": "client_credentials",
"client_id": client_id,
"client_secret": client_secret
}
response = requests.post(token_url, data=data)
token_dict = response.json()
client = BackendApplicationClient(client_id)
oauth = OAuth2Session(client=client, token=token_dict)
method_endpoint = "/api/custom/crm/lead/create"
url = base_url + method_endpoint
params = {"subject": 'asunto',
"contact_name": "juan perez",
"email_from": 'correo@correo.cl',"phone": '123456789','partner_name': 'Empresa Test','description': 'una descripcion', 'company_id': 1}
if type == 'POST':
response = oauth.post(url, data=params)
print(response.text)
Listar Compañías
Endpoint (real)
GET /api/custom/company/list
Retorna la lista de compañías disponibles en la base de datos. El acceso a las compañías depende de los permisos del usuario autenticado.
Parámetros (consulta JSON en el cuerpo o query params según implementación)
{
"limit": 50,
"offset": 0
}
Los parámetros son opcionales. Si no se envían, se retornan todas las compañías accesibles al usuario autenticado.
Ejemplo de implementación en Python
import requests
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
CLIENT_ID = "aZ5o2q8KEiQ3452JEo6eyAi"
CLIENT_SECRET = "IKMnqnp123dexOCB1Fizwl23gb8n5"
BASE_URL = "https://cliente.orionerp.cl"
# -----------------------------
# Obtener token OAuth2
# -----------------------------
token_response = requests.post(
f"{BASE_URL}/api/authentication/oauth2/token",
data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
)
token_response.raise_for_status()
token = token_response.json()
client = BackendApplicationClient(client_id=CLIENT_ID)
oauth = OAuth2Session(client=client, token=token)
# -----------------------------
# Listar compañías (GET)
# -----------------------------
response = oauth.get(
f"{BASE_URL}/api/custom/company/list",
params={
"limit": 50,
"offset": 0
}
)
response.raise_for_status()
print(response.json())
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "Compañías encontradas",
"count": 2,
"companies": [
{
"id": 1,
"name": "Mi Empresa SPA",
"email": "contacto@miempresa.cl",
"phone": "+5621234567",
"document_number": "76.123.456-7",
"currency_id": 1,
},
{
"id": 2,
"name": "Mi Empresa SPA 2",
"email": "info@holding.com",
"phone": "+34912345678",
"document_number": "72.121.456-3",
"currency_id": 2,
}
]
}
Listar Productos
Obtiene el catálogo de productos activos del sistema. Este endpoint está orientado a
sincronización e integraciones externas (ERP, POS, eCommerce), retornando únicamente
los identificadores y datos básicos necesarios del producto.
Solo se listan productos activos y opcionalmente filtrados por compañía.
Endpoint (real)
POST /api/custom/product/product/list
Parámetros (JSON esperado)
{
"company_id": 1 // opcional: filtra productos de la compañía o globales (company_id = False)
}
Campos retornados
- id: ID interno del producto (product.product)
- name: Nombre del producto
- default_code: Código interno / SKU / referencia interna
- company_id: ID de la compañía propietaria o False si es global
Ejemplo de implementación con Python
import requests
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
# ------------------------------------------------------------------
# CONFIG
# ------------------------------------------------------------------
CLIENT_ID = "aZ5o2q8K1232FN0KsJEo6eyAi"
CLIENT_SECRET = "IKMnqnplI12311Fizwl23gb8n5"
BASE_URL = "https://cliente.orionerp.cl"
# ------------------------------------------------------------------
# AUTH
# ------------------------------------------------------------------
token_response = requests.post(
f"{BASE_URL}/api/authentication/oauth2/token",
data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
}
)
token = token_response.json()
client = BackendApplicationClient(client_id=CLIENT_ID)
oauth = OAuth2Session(client=client, token=token)
# ------------------------------------------------------------------
# CALL ENDPOINT
# ------------------------------------------------------------------
payload = {
"company_id": 1
}
response = oauth.post(
f"{BASE_URL}/api/custom/product/product/list",
json=payload
)
response.raise_for_status()
print(response.json())
Reglas Críticas de Negocio
- Solo activos: Se excluyen productos archivados (active = False).
- Sin paginación: El endpoint retorna el catálogo completo. Recomendado para sincronizaciones batch.
- Datos mínimos: Solo se retornan identificadores y datos básicos (nombre, código y compañía) para maximizar rendimiento y reducir payload.
- Multicompañía: Si se envía
company_id, se incluyen productos de esa compañía y globales. - Productos globales: Si
company_id = false, el producto se considera compartido y puede ser utilizado por todas las compañías del sistema. - company_id: ID de la compañía propietaria. Si retorna
false, el producto es global y compartido por todas las compañías.
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "Productos recuperados exitosamente",
"count": 3,
"records": [
{
"id": 10,
"name": "Producto A",
"default_code": "PROD-001",
"company_id": 1
},
{
"id": 11,
"name": "Servicio B",
"default_code": "SERV-002",
"company_id": false
},
{
"id": 15,
"name": "Kit C",
"default_code": "KIT-003",
"company_id": 1
}
]
}
Excepciones Específicas
- 400: Se enviaron parámetros no permitidos.
- 403: Usuario sin permisos de lectura sobre productos.
- 500: El modelo product.product no está disponible o error interno del servidor.
Crear Lead
Crea un nuevo lead en el CRM de OrionERP.
Endpoint (real)
POST /api/custom/crm/lead/create
Notas: el endpoint valida campos obligatorios, tipos de datos, permisos del usuario y existencia de relaciones (canal y compañía).
Parámetros (JSON esperado)
{
"subject": "Asunto del lead", // obligatorio
"contact_name": "Nombre contacto", // obligatorio
"email_from": "correo@dominio.cl", // obligatorio, formato simple validado
"phone": "+56912345678", // obligatorio, validación mínima
"partner_name": "Empresa S.A.", // obligatorio
"description": "Detalle del interés", // obligatorio
"company_id": 1, // obligatorio, debe existir en el sistema
"channel_id": "Nombre del canal" // opcional: resuelve crm.team por nombre,
// si no viene usa canal web por defecto
}
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "Lead con ID 3 creado exitosamente",
"lead_id": 3
}
Errores comunes
- 400 — Campos obligatorios faltantes, tipos de datos inválidos o campos no permitidos.
- 403 — El usuario autenticado no tiene permisos suficientes sobre el módulo CRM (create/read/write).
- 404 — La compañía indicada (
company_id) o el canal de ventas no existe. - 500 — Módulo CRM no instalado o error interno en OrionERP.
Listar Leads
Endpoint (real)
GET /api/custom/crm/lead/list
Soporta filtros y paginación (limit/offset).
El filtro filter_company_id es opcional y permite restringir
los resultados a una compañía específica.
Parámetros (consulta JSON en el cuerpo o query params según implementación)
{
"limit": 50,
"offset": 0,
"filter_company_id": 1,
"filter_name": "Empresa",
"filter_contact_name": "Juan",
"filter_email": "juan@",
"filter_phone": "+569",
"filter_user_id": 12,
"filter_stage_id": 5,
"filter_team_id": 3,
"filter_date_from": "2025-01-01",
"filter_date_to": "2025-12-31"
}
Todos los filtros son opcionales. Si no se envía ningún filtro, se retornan los leads accesibles al usuario autenticado.
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "Consulta ejecutada exitosamente",
"count": 1,
"records": [
{
"id": 123,
"name": "Asunto",
"contact_name": "Juan Perez",
"email_from": "juan@example.com",
"phone": "+56912345678",
"partner_name": "Empresa X",
"description": "Detalle",
"team_id": 2
}
]
}
Obtener Lead por ID
Endpoint (real)
GET /api/custom/crm/lead/get
Parámetro obligatorio: id (integer). :contentReference[oaicite:7]{index=7}
Carga útil (*Payload*)
{
"id": 123
}
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "Lead encontrado exitosamente",
"record": {
"id": 123,
"name": "Asunto",
"contact_name": "Juan Perez",
"email_from": "juan@example.com",
"phone": "+56912345678",
"partner_name": "Empresa",
"description": "Detalle",
"team_id": 2
}
}
Listar etapas del CRM
Obtiene el listado de las etapas configuradas en el módulo **CRM**.
Parámetros (JSON)
| Campo | Tipo | Requerido | Descripción |
|---|---|---|---|
limit
|
integer | No | Cantidad máxima de registros (por defecto: 50) |
offset
|
integer | No | Desde qué registro comenzar (por defecto: 0) |
domain
|
array | No | Dominio **Orion** para filtrar resultados |
Ejemplo de Solicitud (*request*)
{
"limit": 10,
"offset": 0,
"domain": [["fold", "=", false]]
}
Ejemplo de Respuesta (200)
{
"status": "success",
"http_code": 200,
"message": "Consulta ejecutada exitosamente",
"count": 2,
"records": [
{
"id": 1,
"name": "Nuevo",
"probability": 10,
"fold": false,
"sequence": 1,
"team_ids": [1, 2]
},
{
"id": 2,
"name": "Calificado",
"probability": 30,
"fold": false,
"sequence": 2,
"team_ids": []
}
]
}
Posibles errores
| HTTP | Mensaje | Descripción |
|---|---|---|
| 400 | Campos no permitidos / tipos inválidos | Se enviaron parámetros no admitidos o con formato incorrecto |
| 403 | Permisos insuficientes | El usuario no tiene acceso de lectura al modelo **crm.stage** |
| 500 | Error interno | El módulo **CRM** no está instalado o falló al consultar |
Crear Adjuntos para un Lead
Endpoint (real)
POST /api/custom/crm/attachment/create
Parámetros (JSON esperado)
{
"lead_id": 123, // obligatorio (int)
"filename": "contrato.pdf", // obligatorio (str)
"datas": "BASE64_ENCODED", // obligatorio (str)
"mimetype": "application/pdf",// opcional
"description": "Descripción"// opcional
}
Respuesta de éxito incluye attachment_id. Validaciones de tipos y existencia del *lead* aplican. :contentReference[oaicite:11]{index=11}
Registrar actividad en un Lead
Endpoint (real)
POST /api/custom/crm/activity/create
Parámetros (JSON esperado)
{
"lead_id": 123, // obligatorio (int)
"activity_type_id": 5, // obligatorio (int)
"summary": "Llamar cliente",// obligatorio (str)
"note": "Detalles", // opcional (str)
"due_date": "2025-12-01" // opcional (YYYY-MM-DD)
}
Respuesta incluye activity_id y validaciones de permisos/tipos aplican. :contentReference[oaicite:12]{index=12}
Buscar / Listar Vendedores
Endpoints (reales)
GET /api/custom/crm/user/find (buscar por email o name)
GET /api/custom/crm/user/list (listar usuarios comerciales)
El *endpoint* user/find requiere al menos email o name como criterio y construye un dominio contra los grupos comerciales. :contentReference[oaicite:14]{index=14}
Crear Nota Interna en Lead
Endpoint (real)
POST /api/custom/crm/note/create
Parámetros: lead_id (int), body (str), author_id (int opcional). Validaciones de existencia y permisos aplican. :contentReference[oaicite:15]{index=15}
Listar / Asignar Etiquetas
Endpoints (reales)
GET /api/custom/crm/tag/list
POST /api/custom/crm/lead/set_tags
Los *endpoints* permiten listar etiquetas y asignar un *array* de tag_ids a un *lead*. Validaciones de tipos y permisos aplican. :contentReference[oaicite:16]{index=16}
Crear DTE (Facturación Avanzada)
Crea un nuevo DTE en OrionERP. Este endpoint permite una gestión contable profunda, soportando multimoneda, centros de costos (cuentas analíticas) y validación automática de documentos de exportación.
Endpoint (real)
POST /api/custom/account/invoice/create
Parámetros (JSON esperado)
#valores para campo document_type_code y sii_code:
# 0: 'Sin impuesto declarado (Exento)'
# 14: 'IVA'
# 15: 'IVA retenido total'
# 17: 'IVA ANTICIPADO FAENAMIENTO CARNE'
# 18: 'IVA ANTICIPADO CARNE'
# 19: 'IVA ANTICIPADO HARINA'
# 30: 'IVA RETENIDO LEGUMBRES'
# 31: 'IVA RETENIDO SILVESTRES'
# 32: 'IVA RETENIDO GRANADO'
# 33: 'IVA RETENIDO MADERA'
# 34: 'IVA RETENIDO TRIGO'
# 36: 'IVA RETENIDO ARROZ'
# 37: 'IVA RETENIDO HIDROBIOLOGICAS'
# 38: 'IVA RETENIDO CHATARRA'
# 39: 'IVA RETENIDO PPA'
# 41: 'IVA RETENIDO CONSTRUCCION'
# 23: 'IMPUESTO ADICIONAL Art 37 Letras a,b,c'
# 44: 'IMPUESTO ADICIONAL Art 37 letras e,h,i,l'
# 45: 'IMPUESTO ADICIONAL Art 37 letras j'
# 24: 'IMPUESTO ART. 42, Ley 825/74 letra a'
# 25: 'IMPUESTO ART. 42, letra b'
# 26: 'IMPUESTO ART. 42, letra c'
# 27: 'IMPUESTO ART. 42, letra d y e'
# 28: 'Impuesto específico diesel'
# 29: 'Recuperación Impuesto Específico Diesel Transportistas'
# 35: 'Impuesto específico gasolina'
# 47: 'IVA RETENIDO CARTONES'
# 48: 'IVA RETENIDO FRAMBUESAS Y PASAS'
# 53: 'IMPUESTO RETENIDO SUPLEMENTEROS ART 74 N°5 LEY DE LA RENTA'
# 60: 'IMPUESTO RETENIDO FACTURA DE INICIO'
# 50: 'IVA DE MARGEN DE COMERCIALIZACIÓN DE INSTRUMENTOS DE PREPAGO'
# 51: 'IMPUESTO GAS NATURAL COMPRIMIDO'
# 52: 'IMPUESTO GAS LICUADO DE PETRÓLEO'
# 271: 'IMPUESTO ART. 42, LEY DE IVA LETRA A) PÁRRAFO 2°'
{
"company_id": 1, // obligatorio: ID de la compañía, obtenible con consulta Listar compañias
"partner_id": 10, // obligatorio: ID del cliente (res.partner), obtenible con consulta Listar clientes u obtener Cliente
"journal_id": 5, // obligatorio: ID exacto del diario, obtenible con consulta Listar Diarios
"document_type_code": "34", // obligatorio: Código SII (33, 34, 61, 56 u otro según listado de arriba)
"currency": "CLP", // opcional: CLP, USD, EUR (Default: CLP). No permite UF.
"date_invoice": "2023-10-27", // obligatorio: Fecha de emisión
"date_due": "2023-11-15", // obligatorio: Fecha de vencimiento
"folio": "1234", // opcional: Folio manual si aplica
"forma_pago": "1", // obligatorio: "1": Contado, "2": Crédito
"comment": "Precios según UF", // opcional: Comentario general de la factura para añadir debajo de las lineas
"do_validate": False, // opcional: Valida/timbra el DTE. En caso de fallar el timbraje, no se crea el DTE.
"lines": [ // obligatorio: Al menos una línea
{
"name": "Descripción", // opcional: descripción personalizada
"product_id": 1, // obligatorio: obtenible con consulta Listar Productos
"quantity": 2.0, // obligatorio
"price_unit": 1000.0, // obligatorio
"discount": 0.0, // opcional
"account_analytic_id": 12, // opcional: ID de cuenta analítica (centro de costo), obtenible con consulta Listar C.A.
"sii_code": 14 // opcional: Código SII de impuesto
}
],
"global_discounts": [ // opcional: Descuentos o Recargos Globales (GDR)
{
"type": "D", // 'D' Descuento, 'R' Recargo
"gdr_type": "percent", // 'percent' o 'amount'
"valor": 10.0,
"gdr_detail": "Dcto. Especial",
"impuesto": "afectos" // 'afectos' o 'exentos'
}
],
"references": [ // opcional: Referencias para NC/ND
{
"origen": "5678",
"tipo_de_documento": "801",
"codigo_nota_de_credito": "1", // nota: utilizar solo en caso de que el DTE emitido sea una Nota de Crédito Electrónica y se esté referenciando el documento anulado,
// "1": Anula Documento de Referencia, "2": Corrige texto Documento Referencia, "3": Corrige montos
"motivo": "OC5678",
"fecha_documento": "2026-10-20"
}
]
}
Ejemplo de implementación con Python
import requests
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
from datetime import date
# ------------------------------------------------------------------
# CONFIG
# ------------------------------------------------------------------
CLIENT_ID = "aZ5o2q8K1232FN0KsJEo6eyAi"
CLIENT_SECRET = "IKMnqnplI12311Fizwl23gb8n5"
BASE_URL = "https://cliente.orionerp.cl"
COMPANY_ID = 1 #valor obtenible con consulta GET Listar Compañias
# ------------------------------------------------------------------
# AUTH
# ------------------------------------------------------------------
token_response = requests.post(
f"{BASE_URL}/api/authentication/oauth2/token",
data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET,
}
)
token_response.raise_for_status()
token = token_response.json()
client = BackendApplicationClient(client_id=CLIENT_ID)
oauth = OAuth2Session(client=client, token=token)
# ------------------------------------------------------------------
# PARTNER HELPERS
# ------------------------------------------------------------------
def find_partner_by_rut(oauth, base_url, rut, company_id):
payload = {
"document_number": rut,
"company_id": company_id,
}
resp = oauth.post(
f"{base_url}/api/custom/res/partner/get",
json=payload
)
resp.raise_for_status()
result = resp.json()
# Expected responses:
# {} | [] | {"id": X} | [{"id": X, ...}]
if isinstance(result, dict) and result.get("id"):
return result["id"]
if isinstance(result, list) and result:
return result[0].get("id")
return None
def create_partner(oauth, base_url, partner_payload):
resp = oauth.post(
f"{base_url}/api/custom/res/partner/create",
json=partner_payload
)
resp.raise_for_status()
data = resp.json()
result = data.get("result") or data
if isinstance(result, dict) and result.get("id"):
return result["id"]
raise RuntimeError(f"Unexpected create partner response: {data}")
def get_or_create_partner(oauth, base_url, rut, partner_payload):
partner_id = find_partner_by_rut(
oauth,
base_url,
rut,
partner_payload["company_id"]
)
if partner_id:
return partner_id
return create_partner(oauth, base_url, partner_payload)
# ------------------------------------------------------------------
# PARTNER PAYLOAD
# ------------------------------------------------------------------
rut_to_find = "10.411.915-8"
partner_payload = {
"company_id": COMPANY_ID,
"name": "TECNOLOGIA S.A.",
"document_number": rut_to_find,
"giro_name": "Informatica",
"comuna_name": "Providencia",
"street": "Avenida Nueva Providencia 1234",
"email": "contacto@tecnologia.cl",
}
partner_id = get_or_create_partner(
oauth,
BASE_URL,
rut_to_find,
partner_payload
)
# ------------------------------------------------------------------
# DTE PAYLOAD
# ------------------------------------------------------------------
dte_payload = {
"company_id": COMPANY_ID,
"partner_id": partner_id,
"journal_id": 1, #valor obtenible con consulta GET Listar Diarios
"document_type_code": "34",
"currency": "CLP",
"date_invoice": date.today().isoformat(),
"date_due": date.today().isoformat(),
"folio": "1234",
"user_id": False,
"forma_pago": "2",
"comment": "Precios según UF al día %s" % str(date.today().isoformat()),
"do_validate": False,
"lines": [
{
"product_id": 1,
"name": "Producto de prueba",
"quantity": 2.0,
"price_unit": 1000.0,
"discount": 0.0,
"sii_code": 14,
}
],
"global_discounts": [
{
"type": "D",
"gdr_type": "percent",
"valor": 10.0,
"gdr_detail": "Dcto. Especial",
"impuesto": "afectos",
}
],
"references": [
{
"origen": "5678",
"sii_referencia_TpoDocRef": "801",
"motivo": "OC5678",
"fecha_documento": "2025-10-20",
}
],
}
# ------------------------------------------------------------------
# CREATE DTE
# ------------------------------------------------------------------
dte_response = oauth.post(
f"{BASE_URL}/api/custom/account/invoice/create",
json=dte_payload
)
dte_response.raise_for_status()
dte_result = dte_response.json()
print("DTE created successfully:")
print(dte_result)
Reglas Críticas de Negocio
- Validación de Moneda: Si
currencyes distinto a CLP, el sistema forzará el uso de documentos de exportación (SII 110, 111, 112). Si envía un código nacional con moneda extranjera, el sistema lo autocorregirá al tipo de exportación equivalente. - Diarios Contables: Es imperativo enviar el
journal_idcorrecto. Utilice el endpoint de/journal/listpara verificar qué diarios soportan qué tipos de documentos. - Analítica: El campo
account_analytic_idpermite la imputación directa de costos/ingresos a proyectos o departamentos desde la creación del documento.
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "DTE creado y validado exitosamente. Folio asignado: %s" % (invoice.number or "S/N"),
"record": {
"id": invoice.id,
"number": invoice.number,
"state": invoice.state,
"url_invoice": url_invoice
}
Excepciones Específicas
- 400 (Moneda): Si la moneda proporcionada no existe o es "UF" (moneda no permitida para emisión directa de DTE).
- 400 (Exportación): Si se intenta emitir un documento nacional con moneda extranjera y no hay mapeo de exportación disponible.
Listar Facturas
Permite consultar el histórico de facturas de venta, notas de crédito y notas de débito. Incluye filtros avanzados por RUT del cliente, Folio y Tipo de DTE según la localización chilena.
Endpoint (real)
POST /api/custom/account/invoice/list
Notas: La consulta devuelve por defecto las facturas ordenadas por fecha de emisión descendente. El parámetro filter_company_id es altamente recomendado en entornos multi-compañía para segmentar los resultados.
Parámetros de Filtro (JSON)
{
"filter_company_id": 1, // opcional: Filtrar por ID de compañía
"filter_rut": "12345678-9", // opcional: RUT del cliente (con o sin puntos/guión)
"filter_doc_type_code": "33", // opcional: Código SII (33: Factura, 61: NC, etc.)
"filter_folio": "5420", // opcional: Número de folio del DTE
"filter_state": "open", // opcional: draft, open (abierta), paid (pagada), cancel
"filter_date_from": "2023-01-01", // opcional: Fecha desde
"filter_date_to": "2023-12-31", // opcional: Fecha hasta
"limit": 20, // opcional: Cantidad de registros (defecto 50)
"offset": 0 // opcional: Desplazamiento para paginación
}
Estructura de la Respuesta
{
"status": "success",
"http_code": 200,
"count": 1,
"records": [
{
"id": 450,
"number": "INV/2023/001",
"folio": "5420",
"date": "2023-10-27",
"partner_rut": "12345678-9",
"partner_name": "Cliente Ejemplo S.A.",
"document_type": "Factura Electrónica",
"document_code": "33",
"amount_total": 119000.0,
"state": "open",
"currency": "CLP",
"url_invoice": "https://orionerp.cl/mail/view?model=account.invoice&62e32-9e03-46a6-8e8b-195522"
"sii_result": "Procesado",
"estado_aceptacion": "Aceptado",
"sii_send_ident": "123812783232",
"sii_message": "{'T110F586': {'status': 'Proceso', 'glosa': 'DTE Recibido', 'xml_resp': '<?xml version="1.0" encoding="UTF-8"?>\r\n<SII:RESPUESTA xmlns:SII="http://www.sii.cl/XMLSchema">\r\n <SII:RESP_HDR>\r\n <ESTADO>DOK</ESTADO>\r\n <GLOSA_ESTADO>DTE Recibido</GLOSA_ESTADO>\r\n <ERR_CODE>0</ERR_CODE>\r\n <GLOSA_ERR>Documento Recibido por el SII. Datos Coinciden con los Registrados</GLOSA_ERR>\r\n <NUM_ATENCION>11829304532</NUM_ATENCION>\r\n </SII:RESP_HDR>\r\n</SII:RESPUESTA>\r\n'}},
}
]
}
Errores comunes
- 400 — Se enviaron campos no permitidos o el formato de fecha es incorrecto (debe ser YYYY-MM-DD).
- 403 — El usuario no tiene permisos de lectura sobre el modelo de facturas (
account.invoice). - 404 — La compañía especificada en
filter_company_idno existe.
Consultar Factura por ID
Obtiene los detalles de una factura de venta (o rectificativa) existente en OrionERP. Este endpoint es útil para verificar el estado de un documento, obtener los montos totales tras el cálculo de impuestos y recuperar la URL pública del portal para el cliente.
Endpoint (real)
POST /api/custom/account/invoice/get
Notas: El sistema valida que el ID exista y que el usuario autenticado tenga permisos de lectura en el módulo contable. La respuesta incluye campos específicos de la localización chilena (SII).
Parámetros (JSON esperado)
{
"id": 450 // obligatorio: ID interno de la factura (Integer)
}
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "Factura encontrada",
"record": {
"id": 450,
"number": "FE/2023/0892", // Número de factura (asignado tras validar)
"state": "open", // open (abierta), paid (pagada), draft (borrador)
"date_invoice": "2023-10-27",
"partner_id": [10, "Empresa S.A."], // ID y Nombre del cliente
"amount_total": 11900.0, // Total con impuestos
"residual": 0.0, // Saldo pendiente de pago
"currency": "CLP",
"sii_document_class": "Factura Electrónica",
"sii_code": "33", // Código SII del documento
"url_invoice": "https://erp.tu-empresa.cl/mail/view?model=account.invoice...",
"sii_result": "Procesado",
"estado_aceptacion": "Aceptado",
"sii_send_ident": "123812783232",
"sii_message": "{'T110F586': {'status': 'Proceso', 'glosa': 'DTE Recibido', 'xml_resp': '<?xml version="1.0" encoding="UTF-8"?>\r\n<SII:RESPUESTA xmlns:SII="http://www.sii.cl/XMLSchema">\r\n <SII:RESP_HDR>\r\n <ESTADO>DOK</ESTADO>\r\n <GLOSA_ESTADO>DTE Recibido</GLOSA_ESTADO>\r\n <ERR_CODE>0</ERR_CODE>\r\n <GLOSA_ERR>Documento Recibido por el SII. Datos Coinciden con los Registrados</GLOSA_ERR>\r\n <NUM_ATENCION>11829304532</NUM_ATENCION>\r\n </SII:RESP_HDR>\r\n</SII:RESPUESTA>\r\n'}},
"lines": [
{
"product": "Servicio de Consultoría",
"quantity": 1.0,
"price_subtotal": 10000.0
}
]
}
}
Errores comunes
- 400 — El campo
idno fue enviado o no es un número entero válido. - 403 — El usuario no tiene permisos de lectura (Access Rights) en el modelo de facturas.
- 404 — No se encontró ningún registro con el ID proporcionado.
- 500 — Error interno al intentar procesar la consulta o módulo contable no instalado.
Validar DTE
Este endpoint procesa una factura que se encuentra actualmente en estado Borrador. Al validar, el sistema realiza el asiento contable, calcula impuestos finales y, en el caso de la localización chilena, solicita el folio al SII y genera el DTE correspondiente.
Endpoint (real)
POST /api/custom/account/invoice/validate
Parámetros (JSON esperado)
{
"id": 450 // ID interno de la factura en OrionERP (Integer)
}
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"message": "Factura validada exitosamente. Folio asignado: FE 1234",
"record": {
"id": 450,
"number": "FE/2023/1234",
"state": "open",
"url_invoice": "https://erp.tu-empresa.cl/mail/view?model=account.invoice&res_id=450..."
}
}
Excepciones y Errores Posibles
- 400 — Estado Inválido: La factura no está en estado 'draft'. Si la factura ya fue validada o está cancelada, no se puede volver a procesar.
- 403 — Permisos Insuficientes: El usuario de la API no tiene permisos de escritura (Write) en el módulo de Contabilidad.
- 404 — No Encontrado: El ID proporcionado no corresponde a ningún documento en la base de datos.
- 500 — Error de Validación SII:
Ocurre si hay problemas específicos con la localización chilena, tales como:
- No hay folios (CAF) disponibles para el tipo de documento.
- El RUT del cliente no es válido.
- Faltan datos mandatorios en las líneas de factura para generar el XML.
Listar Diarios de Venta (Journals)
Obtiene la lista de diarios contables de tipo 'Venta' para una compañía específica. Este endpoint es esencial para identificar qué journal_id enviar al crear una factura y qué tipos de documentos (DTE) permite cada uno.
Endpoint (real)
GET /api/custom/account/journal/list
Parámetros (JSON esperado)
{
"company_id": 1 // obligatorio: ID de la compañía a consultar
}
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"records": [
{
"id": 5,
"name": "Facturas de Venta Electrónicas",
"code": "INV",
"currency": "CLP",
"sii_supported_documents": [
{"sii_code": "33", "name": "Factura Electrónica"},
{"sii_code": "61", "name": "Nota de Crédito Electrónica"}
]
},
{
"id": 8,
"name": "Exportaciones USD",
"code": "EXP",
"currency": "USD",
"sii_supported_documents": [
{"sii_code": "110", "name": "Factura de Exportación Electrónica"}
]
}
]
}
Ejemplo de implementacion en Python
import requests
from requests_oauthlib import OAuth2Session
from oauthlib.oauth2 import BackendApplicationClient
CLIENT_ID = "aZ5o2q82424Er7F02FN0KsJEo6eyAi"
CLIENT_SECRET = "IKMn123123lIlHdexOCB1Fizwl23gb8n5"
BASE_URL = "https://cliente.orionerp.cl"
# -----------------------------
# 1. OAuth2 - obtener token
# -----------------------------
token_response = requests.post(
f"{BASE_URL}/api/authentication/oauth2/token",
data={
"grant_type": "client_credentials",
"client_id": CLIENT_ID,
"client_secret": CLIENT_SECRET
}
)
token_response.raise_for_status()
token = token_response.json()
client = BackendApplicationClient(client_id=CLIENT_ID)
oauth = OAuth2Session(client=client, token=token)
# -----------------------------
# 2. Listar compañías
# -----------------------------
companies_response = oauth.get(
f"{BASE_URL}/api/custom/company/list",
params={"limit": 50, "offset": 0}
)
companies_response.raise_for_status()
companies_data = companies_response.json()
companies = companies_data.get("result", {}).get("companies", [])
if not companies:
raise RuntimeError("No companies found")
first_company = companies[0]
company_id = first_company["id"]
# -----------------------------
# 3. Listar diarios de venta usando el company_id obtenido
# -----------------------------
journals_response = oauth.get(
f"{BASE_URL}/api/custom/account/journal/list",
params={"company_id": company_id}
)
journals_response.raise_for_status()
journals_data = journals_response.json()
journals = journals_data.get("result", {}).get("records", [])
if not journals:
raise RuntimeError("No sale journals found for company id {}".format(company_id))
first_journal = journals[0]
print(first_journal)
Notas de Integración
- Multimoneda: Si el diario tiene una moneda distinta a CLP (ej: USD), asegúrese de usar los códigos SII de exportación (110, 111, 112) al crear facturas.
- Filtros: El endpoint solo devuelve diarios de tipo 'venta' (sale) que son los aptos para emitir DTEs.
Listar Cuentas Analíticas
Obtiene el listado de Cuentas Analíticas (centros de costos o proyectos) disponibles para la compañía especificada. Estas cuentas se utilizan en las líneas de factura para la distribución de costos.
Endpoint (real)
GET /api/custom/account/analytic/list
Parámetros (JSON esperado)
{
"company_id": 1 // obligatorio: ID de la compañía
}
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"count": 2,
"records": [
{
"id": 10,
"name": "Proyecto Infraestructura Norte",
"code": "PIN001",
"display_name": "[PIN001] Proyecto Infraestructura Norte",
"company_id": 1,
"partner_id": [25, "Constructora Alpha"]
},
{
"id": 11,
"name": "Gastos Generales Administración",
"code": "ADM-GEN",
"display_name": "[ADM-GEN] Gastos Generales Administración",
"company_id": false,
"partner_id": false
}
]
}
Uso en Facturación
Para asignar una cuenta analítica a una factura, incluya el campo account_analytic_id dentro del objeto de cada línea en el endpoint de invoice/create.
Listar Clientes (res.partner)
Recupera el listado de contactos marcados como clientes en OrionERP, incluyendo datos de localización chilena (RUT, Giro, Comuna).
Endpoint
POST /api/custom/res/partner/list
Parámetros (JSON)
{
"company_id": 1 // Opcional: Filtra por empresa o globales
}
Respuesta (éxito)
{
"status": "success",
"http_code": 200,
"records": [
{
"id": 125,
"name": "IMPORTADORA Y EXPORTADORA LIMITADA",
"document_number": "76982853-2",
"giro": "VENTA AL POR MAYOR",
"comuna": "Santiago",
"is_company": true,
"user_id": [5, "Juan Pérez"]
}
]
}
Crear Cliente (res.partner)
Registra un nuevo cliente en el sistema. Soporta la vinculación automática de comunas y giros comerciales mediante búsqueda por nombre.
Endpoint
POST /api/custom/res/partner/create
Parámetros (JSON)
{
"company_id": 1,
"name": "TECNOLOGIA S.A.",
"document_number": "76982853-2", // RUT con formato SII
"giro_name": "Informatica", // El sistema buscará el ID del giro
"comuna_name": "Providencia", // El sistema buscará el ID de la comuna
"street": "Avenida Nueva Providencia 1234",
"email": "contacto@tecnologia.cl",
"user_id": 5, // ID del Vendedor asignado
}
Notas de Validación
- RUT Único: Se recomienda realizar una búsqueda previa por RUT para evitar duplicados.
- Vendedores: Utilice los IDs obtenidos del listado de vendedores para el campo
user_id.
Buscar Cliente por RUT
Permite localizar un cliente utilizando su RUT. Este método es ideal para verificar la existencia de un cliente antes de intentar crearlo.
Endpoint
POST /api/custom/res/partner/search
Parámetros (JSON)
{
"document_number": "76982853-2", // Formato debe ser XXXXXXXX-X
"company_id": 1 // Opcional pero recomendado para filtrar contexto
}
Lógica de Prioridad
Si existen dos registros con el mismo RUT (uno asignado a la compañía 1 y otro global), el sistema retornará siempre el específico de la compañía primero.