Uso multi-compañía
Una API key puede tener acceso a varias compañías. Cómo elegir sobre cuál opera cada llamada y cómo leer las respuestas.
Una API key no siempre corresponde a una sola compañía. En los grupos empresariales
con varias razones sociales, una misma key puede tener acceso a varias compañías,
cada una identificada por su uniqueCode. Esta guía explica qué hace cada endpoint en ese
caso y cómo indicar sobre qué compañía quieres operar.
Reglas en breve
- Consulta
GET /api/public/v1/companiespara conocer las compañías a las que tiene acceso tu key. El valor que va en todo parámetro o campocompanyCodees eluniqueCodede la compañía (en el objeto de la compañía,companyCodetiene ese mismo valor). Para ubicar una compañía por su identificación fiscal, filtra contaxIdentificationValue. - Envía siempre
companyCodeen los endpoints que lo aceptan, también en las lecturas. Así el resultado no depende de cómo esté configurada la key. - Sin
companyCode, las lecturas devuelven datos de todas tus compañías juntas. Usa elcompanyCodede cada elemento para distinguirlos. - En las altas, la API no elige una compañía por ti: la mayoría responde
400si no la indicas. Algunas tienen reglas propias, detalladas más abajo. - Un filtro
companyCodesobre una compañía a la que la key no tiene acceso devuelve una página vacía, no un error. En la mayoría de las altas devuelve403. - Las consultas por
{code}encuentran recursos de cualquiera de tus compañías. Si el recurso es de otra, la respuesta es404, igual que si no existiera.
Conocer tus compañías
GET /companies devuelve todas las compañías a las que tiene acceso tu key.
Guarda el uniqueCode de cada una: es el valor que vas a usar como companyCode en
el resto de la API.
curl -X GET 'https://{HOST}/api/public/v1/companies' \
-H 'X-API-KEY: tu_api_key_aqui'Si en tu sistema ya identificas a cada compañía por su identificación fiscal (RFC,
CUIT, RUT), búscala directamente por ese valor con taxIdentificationValue. Es la
forma más simple de mapear tus compañías a sus uniqueCode:
curl -X GET 'https://{HOST}/api/public/v1/companies?taxIdentificationValue=XAXX010101000' \
-H 'X-API-KEY: tu_api_key_aqui'La búsqueda es por coincidencia exacta y solo devuelve compañías a las que tu key tiene
acceso. Si varias compañías comparten la identificación fiscal y se diferencian por
sucursal, agrega branchCode para quedarte con una. La identificación fiscal de cada
compañía viene en legalInformation.taxIdentificationValue y su sucursal en
legalInformation.branchCode.
Para traer solo algunas compañías que ya conoces, pasa sus uniqueCode en include
(se puede repetir).
Cómo queda asociada una key a sus compañías
Las compañías de una API key se fijan cuando se crea, a partir de las compañías a las que tiene acceso la persona que la genera. Hay dos variantes:
| Tipo de key | Cómo se comporta |
|---|---|
| Con compañía principal | Las lecturas y las altas operan, por defecto, sobre esa compañía. |
| Multi-compañía (sin compañía principal) | Las lecturas consolidan todas sus compañías; las altas necesitan que indiques la compañía. |
Ningún endpoint indica de qué tipo es tu key: si no lo sabes, consulta con tu contacto
de onboarding. Esta guía describe el comportamiento de una key multi-compañía. Si
envías siempre companyCode, como recomienda la regla 2, tu integración funciona igual
con los dos tipos.
Las compañías de la key no se actualizan solas
Si la persona que creó la key gana o pierde acceso a una compañía, la key no lo refleja: conserva las compañías que tenía al crearse, y renovarla no lo cambia. Para operar sobre una compañía nueva, genera una key nueva. Los cambios sobre una key, como deshabilitarla, pueden tardar unos minutos en aplicarse.
No existe un header ni un parámetro global para elegir la compañía de una llamada. La
única forma es el companyCode de los endpoints que lo aceptan, en el query o en el
body según el caso.
Lecturas: la vista consolidada
Los listados no se limitan a una compañía: devuelven los elementos de todas las compañías de la key en una sola colección. La paginación y el orden son globales, así que una misma página puede mezclar compañías.
# Todas las transacciones de todas tus compañías
curl -X GET 'https://{HOST}/api/public/v1/purchases?page=0&size=50' \
-H 'X-API-KEY: tu_api_key_aqui'
# Solo las de una compañía
curl -X GET 'https://{HOST}/api/public/v1/purchases?companyCode=CODIGO_COMPANIA' \
-H 'X-API-KEY: tu_api_key_aqui'
# Las de dos compañías: repite el parámetro
curl -X GET 'https://{HOST}/api/public/v1/purchases?companyCode=CODIGO_A&companyCode=CODIGO_B' \
-H 'X-API-KEY: tu_api_key_aqui'Para ordenar y recorrer las páginas, sigue la guía de
Paginación: el orden se envía con la forma indexada
sort[0].property=…&sort[0].direction=….
| Endpoint | Sin companyCode | Para filtrar | Cada elemento trae companyCode |
|---|---|---|---|
GET /purchases | Todas tus compañías | companyCode (admite varios) | Sí |
GET /statements | Todas tus compañías | companyCode | Sí |
GET /budgets | Todas tus compañías | companyCode | Sí |
GET /projects | Todas tus compañías | companyCode | Sí |
GET /cost-centers | Todas tus compañías | companyCode | Sí |
GET /people | Todas tus compañías | companyCode (admite varios) | Sí |
GET /cost-center-account-types | Todas tus compañías | No admite filtro | No |
GET /purchase-approval-workflows | Todas tus compañías | No admite filtro | Sí |
GET /purchase-approval-workflows/events | Todas tus compañías | No admite filtro | Sí |
GET /purchases/files | Todas tus compañías | Por purchaseCodes | No: usa purchaseCode |
GET /billing-documents | Las transacciones que pidas, si son de tus compañías | purchaseCodes, obligatorio (hasta 100) | No: usa purchaseUniqueCode |
GET /companies | Todas tus compañías | — | Es la compañía misma |
En las respuestas, el companyCode de cada elemento es el uniqueCode de su
compañía. Cuando los elementos de transacciones no traen companyCode, como en archivos y documentos
de facturación, cruza el purchaseCode con GET /purchases para saber a qué compañía
pertenece cada uno.
Endpoints que necesitan una compañía
Algunos catálogos son propios de cada compañía y no se pueden consolidar:
| Endpoint | Comportamiento |
|---|---|
GET /account-types | companyCode es obligatorio. Sin él responde 400. |
GET /account-types/selectable | companyCode es obligatorio. Sin él responde 400. |
GET /company-custom-fields | Envía companyCode. Sin él, una key multi-compañía recibe una página vacía. Con una key de compañía principal se devuelven los campos de esa compañía. |
GET /merchant-categories | No admite companyCode. Una key multi-compañía recibe el catálogo general de categorías, sin las categorías propias de cada compañía. |
GET /people y la compañía principal de cada persona
Una persona puede pertenecer a varias compañías, pero tiene una compañía principal.
El filtro companyCode de GET /people, los filtros por identificación fiscal de la
compañía y la búsqueda por {code} usan esa compañía principal. Una persona cuya
compañía principal no está entre las de tu key no aparece, aunque también pertenezca a
una compañía que sí lo está.
Consultas por {code}
GET, PATCH y DELETE sobre un recurso concreto encuentran el recurso en
cualquiera de las compañías de tu key, sin que indiques cuál. Si el recurso es de
una compañía a la que la key no tiene acceso, la API responde como si no existiera.
Esto evita revelar recursos de otras compañías.
| Caso | Respuesta |
|---|---|
La mayoría de los recursos (/purchases/{code}, /budgets/{code}, /projects/{code}, …) | 404 |
GET /purchases/{code}/files | 200 con listas vacías |
DELETE /cost-center-account-types/{code} | 400 |
PATCH /projects/bulk, PATCH /cost-centers/bulk | Cada elemento ajeno se informa en failed con NOT_FOUND; un mismo lote puede incluir elementos de varias de tus compañías |
Altas: indica siempre la compañía
Al crear recursos, la API no elige una compañía por ti. Con una key multi-compañía, indica en cuál se crea cada recurso:
| Endpoint | Dónde va la compañía | Sin compañía | Compañía sin acceso |
|---|---|---|---|
POST /projects (JSON) | companyCode en el body | 400 | 403 |
POST /cost-centers (JSON) | companyCode en el body | 400 | 403 |
POST /budgets (JSON) | companyCode en el body | 400 | Error (valida antes contra GET /companies) |
POST /cost-center-account-types | companyCode en el body | 400 | 403 |
POST /projects (CSV) | companyCode en el query | 400 | 403 |
POST /cost-centers (CSV) | companyCode en el query | 400 | 403 |
curl -X POST 'https://{HOST}/api/public/v1/projects' \
-H 'X-API-KEY: tu_api_key_aqui' \
-H 'Content-Type: application/json' \
-d '{ "companyCode": "CODIGO_COMPANIA", "name": "Expansión regional" }'En POST /cost-center-account-types, la cuenta contable y el centro de costos que
vinculas tienen que pertenecer a la misma compañía que indicas.
Altas con reglas propias
Estos endpoints no deciden la compañía con companyCode:
POST /people(JSON): con una key multi-compañía, la persona queda asociada a todas las compañías de la key.companyCodesen el body no restringe ese conjunto. No hay forma de elegir su compañía principal.POST /people(CSV): la compañía de cada fila sale de la columnaNRO_IDENTIFICADOR_FISCAL_EMPRESA(oRFC_EMPRESA), que tiene que coincidir con una de tus compañías. Una fila sin coincidencia se rechaza. Las personas que ya existen conservan sus compañías.POST /account-types(CSV): la compañía de cada fila sale deNRO_IDENTIFICADOR_FISCAL_EMPRESAy, si hace falta distinguir sucursales, deCODIGO_IDENTIFICADOR. El parámetrocompanyCodeno decide en qué compañía se crean las cuentas. Con una key multi-compañía, incluye esas columnas en todas las filas: si una fila no identifica su compañía, se rechaza el archivo entero.POST /account-types(JSON) yPOST /budgets(CSV): no permiten elegir compañía, así que hoy no están disponibles para keys multi-compañía. Usa la carga por CSV de cuentas contables y el alta JSON de presupuestos.
Miembros de presupuestos
POST /budgets/{code}/members no valida que las personas que agregas pertenezcan a la
compañía del presupuesto, y los personCode que la key no puede ver se omiten sin
error. Con una key multi-compañía, verifica la compañía de cada persona con
GET /people/{code} antes de agregarla.
Recorrido recomendado
Este es el flujo que conviene seguir para leer datos de varias compañías sin mezclarlos ni perder ninguno:
Mapea tus compañías
Llama a GET /companies (o búscalas por taxIdentificationValue) y guarda el
uniqueCode de cada una junto con el identificador que usas en tu sistema.
Consulta compañía por compañía
Para cada uniqueCode, llama al endpoint con companyCode=<uniqueCode> y recorre
todas sus páginas. Si el endpoint acepta varios companyCode, puedes pedir varias
compañías en una sola consulta.
Asigna cada elemento por su companyCode
Guarda cada elemento según el companyCode que trae, no según la consulta que lo
devolvió. Usa su uniqueCode como clave para no duplicarlo.
Crea siempre con la compañía explícita
En las altas, envía el companyCode de la compañía destino, aunque la key tenga una
sola compañía.
Errores y resultados vacíos
| Lo que recibes | Qué significa |
|---|---|
400 con el campo companyCode | La operación necesita una compañía y no la indicaste, o no se pudo determinar. |
403 | Indicaste una compañía a la que tu key no tiene acceso. |
200 con una página vacía al filtrar por companyCode | No hay datos o la key no tiene acceso a esa compañía. La API no distingue los dos casos. |
404 en una consulta por {code} | El recurso no existe o es de una compañía a la que la key no tiene acceso. |
Un 400 por falta de compañía señala el campo companyCode en key cuando el
parámetro es obligatorio:
{
"errors": [
{ "category": "must not be blank", "key": "companyCode", "parameters": [] }
],
"status": 400
}Cuando la compañía es necesaria pero no se puede determinar, el campo viaja en
parameters:
{
"errors": [
{ "category": "AppErrorType", "key": "INVALID_REQUEST", "parameters": ["companyCode"] }
]
}En los dos casos, la solución es la misma: envía companyCode.
Como una página vacía no indica si tienes acceso, valida los companyCode contra
GET /companies antes de usarlos en filtros. Así un código mal escrito no pasa por
"esa compañía no tiene datos".