This is the abridged developer documentation for ERP # Introducción a la API > Cómo está armada la API del ERP y por dónde empezar. La API del ERP es la misma que usa la pantalla. Cada botón que tocás en el ERP llama a una de estas operaciones, con las mismas reglas y los mismos permisos. Una integración no tiene atajos: lo que una persona no puede hacer, su integración tampoco. ## Cómo es una operación [Sección titulada «Cómo es una operación»](#cómo-es-una-operación) Cada operación tiene una ruta `/api/v1//`: * **Las lecturas** usan `GET` y reciben sus filtros en la consulta: `GET /api/v1/items/list?search=tornillo`. * **Las escrituras** usan `POST` con un cuerpo JSON y una `Idempotency-Key`: `POST /api/v1/sales-orders/create`. * **Las descargas** (PDF, Excel, adjuntos) usan `POST` y responden el archivo. Todas responden JSON, salvo las descargas, y todos los rechazos usan el mismo formato de [errores](/api/errores/). ## La dirección [Sección titulada «La dirección»](#la-dirección) Cada cliente tiene su propia instalación del ERP, con su propia dirección. La API está en esa misma dirección, debajo de `/api/v1`. En los ejemplos usamos la variable `$ERP_URL`: ```bash export ERP_URL="https://erp.tuempresa.com.ar" ``` ## Empresas [Sección titulada «Empresas»](#empresas) Una instalación tiene una o varias empresas legales que nunca comparten datos. Casi todas las operaciones trabajan sobre una empresa y piden el encabezado `X-Expected-Company`. Ver [Empresa activa](/api/empresa-activa/). ## Por dónde seguir [Sección titulada «Por dónde seguir»](#por-dónde-seguir) [Autenticación](/api/autenticacion/)Cómo se identifica la integración. [Errores](/api/errores/)El formato de los rechazos y sus códigos. [Idempotencia](/api/idempotencia/)Reintentar sin duplicar un pedido o un pago. [Referencia](/api/referencia/)Todas las operaciones, agrupadas como el menú. # Autenticación > Cómo se identifica una integración ante la API. Toda llamada a la API actúa en nombre de un usuario real del ERP. La integración nunca tiene más permisos que ese usuario, y la auditoría registra cada operación como hecha por la API. ## Sesión de un usuario [Sección titulada «Sesión de un usuario»](#sesión-de-un-usuario) Hoy una integración entra con el correo y la contraseña de un usuario creado para ella, y manda la cookie de sesión que recibe en cada llamada. Es lo que usan los ejemplos de la referencia. 1. Creá un usuario para la integración, con un rol que tenga sólo los permisos que necesita. 2. Iniciá la sesión y guardá la cookie en `sesion.txt`: ```bash curl -c sesion.txt -X POST "$ERP_URL/api/auth/sign-in/email" \ -H "Content-Type: application/json" \ -d '{"email": "integracion@tuempresa.com.ar", "password": "…"}' ``` 3. Elegí la empresa activa de esa sesión ([Elegir la empresa activa](/api/referencia/empresa/elegir-la-empresa-activa/)): ```bash curl -b sesion.txt -X POST "$ERP_URL/api/v1/companies/select-active" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d "{\"companyId\": \"$ERP_EMPRESA\"}" ``` 4. Mandá la cookie en cada llamada: ```bash curl -b sesion.txt "$ERP_URL/api/v1/items/list" \ -H "X-Expected-Company: $ERP_EMPRESA" ``` Desde código, la cookie va en el encabezado `Cookie`. En los ejemplos de TypeScript está en la variable `ERP_SESION`, con su nombre y su valor: `__Secure-erp.session_token=…`. Una llamada sin sesión, o con la sesión vencida, responde `401` con el código `session.required`. ## Clave API [Sección titulada «Clave API»](#clave-api) En preparación La clave API todavía no está habilitada. Hasta entonces, usá la sesión de un usuario. La clave API va a ser una credencial que un usuario crea desde su ficha para una integración: elige la empresa, qué permisos suyos le delega y hasta cuándo vale (90 días como máximo, según la política de la empresa). Se va a mandar como `Authorization: Bearer ` en lugar de la cookie, y el usuario la va a poder revocar cuando quiera. # Errores > El formato de los rechazos y los códigos comunes a todas las operaciones. Todo rechazo responde con el formato [RFC 9457](https://www.rfc-editor.org/rfc/rfc9457) (`Content-Type: application/problem+json`) y un `code` estable que podés usar en tu código. El `title` está en castellano y se puede mostrar tal cual a una persona. ```json { "type": "urn:erp:problem:input.invalid", "title": "Hay datos inválidos", "status": 422, "code": "input.invalid", "errors": [{ "field": "lines.0.quantity", "message": "La cantidad tiene que ser mayor que cero." }] } ``` | Campo | Qué es | | ------------------- | --------------------------------------------------------------------------------- | | `code` | Código estable `módulo.motivo`. Es lo que tu integración compara. | | `status` | El mismo código HTTP de la respuesta. | | `title` | Qué pasó, en castellano, para mostrar. | | `detail` | Más contexto, cuando lo hay. | | `errors` | En datos inválidos, el campo y el mensaje de cada error. | | `retryAfterSeconds` | En un rechazo transitorio, cuántos segundos esperar. También va en `Retry-After`. | ## Códigos comunes [Sección titulada «Códigos comunes»](#códigos-comunes) | Código | HTTP | Qué pasó | Qué hacer | | --------------------------- | ---- | -------------------------------------------------------- | ------------------------------------------------ | | `session.required` | 401 | Falta la credencial o venció. | Volvé a autenticarte. | | `permission.denied` | 403 | La credencial no tiene el permiso de la operación. | Pedí el permiso al administrador. | | `operation.unavailable` | 404 | La operación no se ofrece por este canal. | Usá otra operación. | | `idempotency.key-required` | 400 | Falta la `Idempotency-Key` en una escritura. | Mandá una clave por intento. | | `idempotency.key-reused` | 422 | La clave ya se usó con otra operación o con otros datos. | Generá una clave nueva. | | `input.invalid` | 422 | Hay datos inválidos; el detalle está en `errors`. | Corregí los campos indicados. | | `company.expected-required` | 428 | Falta `X-Expected-Company`. | Mandá el id de la empresa. | | `company.no-active` | 409 | La sesión no tiene empresa activa. | Elegí la empresa activa. | | `company.mismatch` | 409 | La empresa activa no es la esperada. | Revisá la empresa y volvé a leer. | | `record.stale` | 409 | Otra persona cambió el registro desde que lo leíste. | Volvé a leerlo y reintentá con la versión nueva. | | `database.busy` | 503 | El sistema está ocupado. | Reintentá después de `Retry-After`. | | `internal` | 500 | Error interno, sin detalle. | Reintentá; si sigue, avisá a soporte. | ## Reglas de negocio [Sección titulada «Reglas de negocio»](#reglas-de-negocio) Cuando una operación rompe una regla del negocio, el código es del módulo: por ejemplo `sales-orders.not-found` (404) o un conflicto de estado (409). El `title` siempre explica qué pasó en palabras. # Guía para agentes > Cómo trabaja un agente con el ERP por MCP y qué herramientas tiene. Esta página es para quien arma un agente o un flujo automático sobre el ERP. ## Reglas que el agente tiene que conocer [Sección titulada «Reglas que el agente tiene que conocer»](#reglas-que-el-agente-tiene-que-conocer) * **Una empresa por conexión.** La empresa es la de la delegación; las herramientas no reciben empresa. * **Mismos permisos que la persona**, recortados a lo que ella delegó. Un rechazo por permiso es definitivo: no tiene sentido reintentarlo. * **Las escrituras son idempotentes.** Cada llamada que escribe lleva una clave en `_meta["erp/idempotency-key"]`; si el agente reintenta con la misma clave, el ERP devuelve el resultado original y marca `_meta["erp/replayed"]`. * **Los rechazos vienen en castellano**, con el mismo `code` que en la [API](/api/errores/). El agente puede mostrarle el `title` a la persona. * **Todo queda auditado** como «persona, vía el asistente». ## Herramientas [Sección titulada «Herramientas»](#herramientas) Cada herramienta es una operación del ERP, con el mismo nombre que su ruta en la API (`items.list` es `GET /api/v1/items/list`) y el mismo esquema de entrada y salida. Hoy están disponibles éstas; se suman más con cada versión. | Herramienta | Qué hace | Tipo | | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------- | ------- | | `companies.get` | [Ver la empresa activa](/api/referencia/empresa/ver-la-empresa-activa/) | Lee | | `reference-catalog.list-units` | [Listar unidades de medida](/api/referencia/datos-de-referencia/listar-unidades-de-medida/) | Lee | | `reference-catalog.list-tax-rates` | [Listar alícuotas de IVA](/api/referencia/datos-de-referencia/listar-alicuotas-de-iva/) | Lee | | `reference-catalog.list-jurisdictions` | [Listar jurisdicciones](/api/referencia/datos-de-referencia/listar-jurisdicciones/) | Lee | | `reference-catalog.list-national-holidays` | [Listar feriados nacionales](/api/referencia/datos-de-referencia/listar-feriados-nacionales/) | Lee | | `brands.list` | [Listar marcas](/api/referencia/marcas-y-familias/listar-marcas/) | Lee | | `families.list` | [Listar familias](/api/referencia/marcas-y-familias/listar-familias/) | Lee | | `warehouses.list` | [Listar depósitos](/api/referencia/depositos/listar-depositos/) | Lee | | `warehouses.get` | [Ver un depósito](/api/referencia/depositos/ver-un-deposito/) | Lee | | `payment-terms.list` | [Listar condiciones de pago](/api/referencia/condiciones-de-pago/listar-condiciones-de-pago/) | Lee | | `payment-terms.get` | [Ver una condición de pago](/api/referencia/condiciones-de-pago/ver-una-condicion-de-pago/) | Lee | | `payment-terms.simulate` | [Simular vencimientos](/api/referencia/condiciones-de-pago/simular-vencimientos/) | Lee | | `customers.list` | [Listar clientes](/api/referencia/clientes/listar-clientes/) | Lee | | `customers.get` | [Ver un cliente](/api/referencia/clientes/ver-un-cliente/) | Lee | | `suppliers.list` | [Listar proveedores](/api/referencia/proveedores/listar-proveedores/) | Lee | | `suppliers.get` | [Ver un proveedor](/api/referencia/proveedores/ver-un-proveedor/) | Lee | | `items.list` | [Listar artículos](/api/referencia/articulos/listar-articulos/) | Lee | | `items.get` | [Ver un artículo](/api/referencia/articulos/ver-un-articulo/) | Lee | | `price-lists.list` | [Listar listas de precios](/api/referencia/listas-de-precios/listar-listas-de-precios/) | Lee | | `price-lists.get` | [Ver una lista de precios](/api/referencia/listas-de-precios/ver-una-lista-de-precios/) | Lee | | `price-lists.list-prices` | [Listar los precios de una lista](/api/referencia/listas-de-precios/listar-los-precios-de-una-lista/) | Lee | | `price-lists.resolve-price` | [Resolver el precio para un cliente](/api/referencia/listas-de-precios/resolver-el-precio-para-un-cliente/) | Lee | | `price-lists.list-customer-prices` | [Listar precios especiales](/api/referencia/listas-de-precios/listar-precios-especiales/) | Lee | | `stock.list-balances` | [Listar saldos de stock](/api/referencia/stock/listar-saldos-de-stock/) | Lee | | `stock.get-valuation` | [Valuar el stock](/api/referencia/stock/valuar-el-stock/) | Lee | | `stock.count-by-warehouse` | [Contar artículos por depósito](/api/referencia/stock/contar-articulos-por-deposito/) | Lee | | `stock-movements.list` | [Listar movimientos de stock](/api/referencia/movimientos/listar-movimientos-de-stock/) | Lee | | `stock-movements.get` | [Ver un movimiento](/api/referencia/movimientos/ver-un-movimiento/) | Lee | | `stock-movements.list-counts` | [Listar recuentos](/api/referencia/recuentos/listar-recuentos/) | Lee | | `stock-movements.get-count` | [Ver un recuento](/api/referencia/recuentos/ver-un-recuento/) | Lee | | `accounting.list-accounts` | [Listar cuentas contables](/api/referencia/plan-de-cuentas/listar-cuentas-contables/) | Lee | | `accounting.assign-role-account` | [Asignar una cuenta a un rol](/api/referencia/plan-de-cuentas/asignar-una-cuenta-a-un-rol/) | Escribe | | `accounting.list-role-accounts` | [Listar cuentas por rol](/api/referencia/plan-de-cuentas/listar-cuentas-por-rol/) | Lee | | `accounting.list-entries` | [Listar asientos](/api/referencia/diario/listar-asientos/) | Lee | | `accounting.get-entry` | [Ver un asiento](/api/referencia/diario/ver-un-asiento/) | Lee | | `accounting.list-source-entries` | [Listar asientos de un documento](/api/referencia/diario/listar-asientos-de-un-documento/) | Lee | | `accounting.get-account-ledger` | [Ver el mayor de una cuenta](/api/referencia/diario/ver-el-mayor-de-una-cuenta/) | Lee | | `accounting.get-reconciliation` | [Conciliar con los auxiliares](/api/referencia/diario/conciliar-con-los-auxiliares/) | Lee | | `accounting.list-x-operations` | [Ver las operaciones X del mes](/api/referencia/diario/ver-las-operaciones-x-del-mes/) | Lee | | `document-flow.search` | [Buscar un documento](/api/referencia/flujo-de-documentos/buscar-un-documento/) | Lee | | `document-flow.of` | [Ver el flujo de un documento](/api/referencia/flujo-de-documentos/ver-el-flujo-de-un-documento/) | Lee | Además hay 15 herramientas de administración (usuarios, roles y configuración) que no están en la referencia pública. # Empresa activa > Sobre qué empresa opera cada llamada y para qué sirve X-Expected-Company. Una instalación del ERP puede tener varias empresas legales. Sus clientes, artículos, comprobantes y saldos nunca se mezclan: cada llamada opera sobre una sola empresa. ## La empresa de la llamada [Sección titulada «La empresa de la llamada»](#la-empresa-de-la-llamada) La empresa la fija la credencial: la de la clave API, o la empresa activa de la sesión. Además, cada operación de empresa pide el encabezado `X-Expected-Company` con el id de la empresa sobre la que creés estar operando: ```bash -H "X-Expected-Company: 3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" ``` Si no coincide con la de la credencial, la llamada se rechaza con `409` y no hace nada. Así, una integración que quedó apuntando a otra empresa nunca carga un pedido donde no corresponde. | Situación | Respuesta | Código | | --------------------------------- | --------- | --------------------------- | | Falta el encabezado | `428` | `company.expected-required` | | La sesión no tiene empresa activa | `409` | `company.no-active` | | La empresa no coincide | `409` | `company.mismatch` | ## Cómo saber el id [Sección titulada «Cómo saber el id»](#cómo-saber-el-id) [Listar empresas](/api/referencia/empresa/listar-empresas/) devuelve las empresas a las que accede el usuario, con su id. Las operaciones que no dependen de una empresa, como [Listar alícuotas de IVA](/api/referencia/datos-de-referencia/listar-alicuotas-de-iva/), no lo piden. # Idempotencia > Cómo reintentar una escritura sin duplicar un pedido, un recibo o un pago. Toda operación que escribe pide el encabezado `Idempotency-Key`: una clave que generás vos, única por intento, de hasta 255 caracteres. Un UUID nuevo por operación es lo más simple. ```bash -H "Idempotency-Key: 0f8c1a2e-9b4d-4c7e-8a1f-3d2b6e5c4a90" ``` ## Qué garantiza [Sección titulada «Qué garantiza»](#qué-garantiza) Si la red se corta y no sabés si la llamada llegó, repetila **con la misma clave y los mismos datos**. El ERP no repite la operación: devuelve el resultado de la primera vez, con el encabezado `Idempotent-Replayed: true`. | Reintento | Resultado | | ----------------------------------------- | ------------------------------------------- | | Misma clave, mismos datos | El resultado original, sin volver a operar. | | Misma clave, otros datos u otra operación | `422 idempotency.key-reused`. | | Sin clave | `400 idempotency.key-required`. | Las lecturas no la necesitan: repetir una lectura nunca cambia nada. ## La versión del registro [Sección titulada «La versión del registro»](#la-versión-del-registro) Las operaciones que modifican un registro existente piden también la `version` que leíste. Si otra persona lo cambió en el medio, la llamada responde `409 record.stale` en lugar de pisar su cambio. Volvé a leer el registro y decidí con los datos nuevos. # Listados y filtros > Cómo paginar, buscar y ordenar en las operaciones que listan. Las operaciones que listan registros reciben sus filtros en la consulta y devuelven una página de resultados con el total. ## Paginación [Sección titulada «Paginación»](#paginación) | Parámetro | Qué hace | Por defecto | | ---------- | ----------------------------------------- | --------------------------------------------------------------- | | `page` | Número de página, desde 1. | `1` | | `pageSize` | Cuántos registros por página, de 1 a 100. | `50` en casi todos; la referencia de cada listado dice el suyo. | La respuesta trae los registros de la página y el `total` de lo que cumple los filtros. Para recorrer todo, pedí páginas hasta que la cantidad leída llegue al total: ```ts let page = 1; const todos = []; while (true) { const r = await fetch(`${process.env.ERP_URL}/api/v1/customers/list?page=${page}&pageSize=100`, { headers }); const { customers, total } = await r.json(); todos.push(...customers); if (todos.length >= total || customers.length === 0) break; page += 1; } ``` ## Búsqueda, filtros y orden [Sección titulada «Búsqueda, filtros y orden»](#búsqueda-filtros-y-orden) * `search` busca por texto en los campos que indica cada operación (nombre, código, número, documento). * Cada listado tiene sus filtros propios, con sus valores posibles en la referencia: por ejemplo `status` (`active`, `inactive` o `all`). * `sort` elige el orden, entre los valores que admite cada listado. Algunos listados chicos, como los datos de referencia, devuelven todo de una vez y no paginan. La referencia de cada operación dice qué parámetros acepta. # Referencia de la API > Las 260 operaciones públicas del ERP, agrupadas como el menú. Cada operación tiene su página con la ruta, el permiso que exige, los parámetros o el cuerpo, la respuesta campo por campo y ejemplos listos para copiar. Están agrupadas por área, en el mismo orden que el menú del ERP. ## Empresa y referencias [Sección titulada «Empresa y referencias»](#empresa-y-referencias) | Grupo | Para qué | Operaciones | | ----------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ----------- | | [Empresa](/api/referencia/empresa/) | Las empresas a las que accede la credencial y la ficha de la empresa activa. | 5 | | [Datos de referencia](/api/referencia/datos-de-referencia/) | Alícuotas de IVA, unidades, jurisdicciones y feriados oficiales, comunes a toda la instalación. | 4 | | [Flujo de documentos](/api/referencia/flujo-de-documentos/) | Buscar un documento por cualquiera de sus números y recorrer todo lo que tiene vinculado. | 2 | ## Ventas [Sección titulada «Ventas»](#ventas) | Grupo | Para qué | Operaciones | | --------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------- | | [Pedidos](/api/referencia/pedidos/) | El compromiso de venta: se arma en borrador, se confirma y fija precios y condiciones. | 15 | | [Entregas](/api/referencia/entregas/) | Remitos que sacan la mercadería del depósito contra los pedidos confirmados, con su COT cuando corresponde. | 17 | | [Facturación](/api/referencia/facturacion/) | Facturas y notas de crédito autorizadas por ARCA, desde los pedidos o los remitos. | 16 | | [Cuentas corrientes](/api/referencia/cuentas-corrientes/) | Saldo, vencido y antigüedad de la deuda de cada cliente, con sus partidas. | 3 | | [Clientes](/api/referencia/clientes/) | La ficha del cliente con su situación fiscal, lugares de entrega, contactos y condiciones comerciales. | 14 | | [Listas de precios](/api/referencia/listas-de-precios/) | Listas, precios con vigencia, precios especiales por cliente y promociones por cantidad. | 26 | ## Finanzas [Sección titulada «Finanzas»](#finanzas) | Grupo | Para qué | Operaciones | | ----------------------------------------------------------- | -------------------------------------------------------------------------------------------- | ----------- | | [Cobranzas](/api/referencia/cobranzas/) | Recibos de clientes con sus medios de cobro, su imputación a cuotas y lo que queda a cuenta. | 12 | | [Pagos](/api/referencia/pagos/) | Órdenes de pago a proveedores con sus medios de pago, su imputación y lo que queda a favor. | 10 | | [Condiciones de pago](/api/referencia/condiciones-de-pago/) | Las condiciones de pago con sus cuotas, para clientes y proveedores. | 8 | ## Compras [Sección titulada «Compras»](#compras) | Grupo | Para qué | Operaciones | | ----------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------- | | [Órdenes de compra](/api/referencia/ordenes-de-compra/) | El pedido al proveedor: se arma en borrador, se emite y se modifica mientras tenga pendiente. | 15 | | [Recepciones](/api/referencia/recepciones/) | La mercadería que llega contra una orden de compra y entra al depósito al costo de la orden. | 9 | | [Facturas de proveedor](/api/referencia/facturas-de-proveedor/) | Facturas, notas y despachos de proveedores, con sus controles, su lectura con IA y su verificación en ARCA. | 15 | | [Cuentas de proveedores](/api/referencia/cuentas-de-proveedores/) | Lo que la empresa debe a cada proveedor por moneda, con sus partidas. | 3 | | [Proveedores](/api/referencia/proveedores/) | La ficha del proveedor local o del exterior, con sus contactos y cuentas bancarias. | 13 | ## Inventario [Sección titulada «Inventario»](#inventario) | Grupo | Para qué | Operaciones | | ------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------- | | [Stock](/api/referencia/stock/) | Saldos por artículo y depósito, su valuación y el último costo de compra. | 4 | | [Movimientos](/api/referencia/movimientos/) | Movimientos de stock, saldos iniciales y cambios de condición. | 6 | | [Recuentos](/api/referencia/recuentos/) | Recuentos de un depósito, a ciegas o no, con el ajuste de sus diferencias. | 7 | | [Artículos](/api/referencia/articulos/) | La ficha del artículo con su unidad, IVA, embalajes, componentes de kit y proveedores. | 11 | | [Depósitos](/api/referencia/depositos/) | Depósitos con sus ubicaciones y la ubicación habitual de cada artículo. | 14 | | [Marcas y familias](/api/referencia/marcas-y-familias/) | Las marcas y el árbol de familias que clasifican los artículos. | 8 | ## Impuestos [Sección titulada «Impuestos»](#impuestos) | Grupo | Para qué | Operaciones | | --------------------------------------- | -------------------------------------------------------------------------------- | ----------- | | [Impuestos](/api/referencia/impuestos/) | Padrones de ARCA y ARBA, percepciones practicadas y sufridas, y posición de IVA. | 8 | ## Contabilidad [Sección titulada «Contabilidad»](#contabilidad) | Grupo | Para qué | Operaciones | | --------------------------------------------------- | ------------------------------------------------------------------------------- | ----------- | | [Plan de cuentas](/api/referencia/plan-de-cuentas/) | Las cuentas contables y qué cuenta usa cada rol del sistema y cada artículo. | 9 | | [Diario](/api/referencia/diario/) | Asientos, mayor de una cuenta, conciliación con los auxiliares y operaciones X. | 6 | # Artículos > La ficha del artículo con su unidad, IVA, embalajes, componentes de kit y proveedores. La ficha del artículo con su unidad, IVA, embalajes, componentes de kit y proveedores. | Operación | Ruta | | ------------------------------------------------------------------------------------------------------- | ----------------------------------------- | | [Listar artículos](/api/referencia/articulos/listar-articulos/) | GET `/api/v1/items/list` | | [Ver un artículo](/api/referencia/articulos/ver-un-articulo/) | GET `/api/v1/items/get` | | [Crear un artículo](/api/referencia/articulos/crear-un-articulo/) | POST `/api/v1/items/create` | | [Modificar un artículo](/api/referencia/articulos/modificar-un-articulo/) | POST `/api/v1/items/update` | | [Cambiar la alícuota de IVA](/api/referencia/articulos/cambiar-la-alicuota-de-iva/) | POST `/api/v1/items/set-vat-rate` | | [Reemplazar los componentes de un kit](/api/referencia/articulos/reemplazar-los-componentes-de-un-kit/) | POST `/api/v1/items/set-kit-components` | | [Reemplazar los niveles de embalaje](/api/referencia/articulos/reemplazar-los-niveles-de-embalaje/) | POST `/api/v1/items/set-packaging-levels` | | [Desactivar o reactivar un artículo](/api/referencia/articulos/desactivar-o-reactivar-un-articulo/) | POST `/api/v1/items/set-status` | | [Cargar el artículo de un proveedor](/api/referencia/articulos/cargar-el-articulo-de-un-proveedor/) | POST `/api/v1/items/set-supplier-item` | | [Retirar un proveedor del artículo](/api/referencia/articulos/retirar-un-proveedor-del-articulo/) | POST `/api/v1/items/retire-supplier-item` | | [Ver el historial de un artículo](/api/referencia/articulos/ver-el-historial-de-un-articulo/) | GET `/api/v1/items/get-history` | # Cambiar la alícuota de IVA > Fija la alícuota de IVA de un artículo; tiene que estar vigente hoy. POST`/api/v1/items/set-vat-rate` * Permiso `items.set-vat-rate` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemId`uuidrequerido * `version`enterorequerido mínimo 1 * `vatRateId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `description`cualquierarequerido * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `gtin`cualquierarequerido * `ncmCode`cualquierarequerido * `arbaCategory`cualquierarequerido * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o norequerido * `tracksLotAndExpiry`sí o norequerido * `requiresQualityControl`sí o norequerido * `netWeightKg`cualquierarequerido * `grossWeightKg`cualquierarequerido * `palletLayers`enterorequeridoadmite null * `lengthCm`cualquierarequerido * `widthCm`cualquierarequerido * `heightCm`cualquierarequerido * `brandId`uuidrequeridoadmite null * `familyId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.set-vat-rate`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/set-vat-rate" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/set-vat-rate`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "description": null, "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "gtin": null, "ncmCode": null, "arbaCategory": null, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isImported": false, "tracksLotAndExpiry": false, "requiresQualityControl": false, "netWeightKg": null, "grossWeightKg": null, "palletLayers": 1, "lengthCm": null, "widthCm": null, "heightCm": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Cargar el artículo de un proveedor > Agrega, edita o reactiva cómo llama un proveedor a un artículo: su código y descripción, la unidad de compra, el último precio y la demora. POST`/api/v1/items/set-supplier-item` * Permiso `items.manage-supplier-data` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemId`uuidrequerido * `supplierId`uuidrequerido * `version`enterorequerido mínimo 0 * `supplierCode`textoadmite null hasta 40 caracteres * `supplierDescription`textoadmite null hasta 120 caracteres * `purchaseLevel`opciónrequerido Valores: `unit` `primary_box` `secondary_box` `pallet` * `lastPrice`númeroadmite null mínimo 0, máximo 999999999999 * `currencyCode`textoadmite null formato \`^\[A-Z]{3}$\` * `lastPriceDate`fechaadmite null * `leadTimeDays`enteroadmite null mínimo 0, máximo 3650 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `supplierId`uuidrequerido * `supplier`objetorequerido * `supplierCode`cualquierarequerido * `supplierDescription`cualquierarequerido * `purchaseLevel`opciónrequerido Valores: `unit` `primary_box` `secondary_box` `pallet` * `lastPrice`cualquierarequerido * `currencyCode`cualquierarequerido * `lastPriceDate`fecharequeridoadmite null * `leadTimeDays`enterorequeridoadmite null * `retiredAt`fecha y horarequeridoadmite null * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.manage-supplier-data`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/set-supplier-item" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "purchaseLevel": "unit" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/set-supplier-item`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "purchaseLevel": "unit" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplier": { "name": "texto", "code": 1, "status": "active" }, "supplierCode": null, "supplierDescription": null, "purchaseLevel": "unit", "lastPrice": null, "currencyCode": null, "lastPriceDate": "2026-10-23", "leadTimeDays": 1, "retiredAt": "2026-10-23T14:30:00.000Z", "version": 1 } ``` # Crear un artículo > Crea un artículo con su tipo, vistas, unidad, alícuota de IVA, niveles de embalaje y, en un kit, sus componentes. POST`/api/v1/items/create` * Permiso `items.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `code`textorequerido de 1 a 30 caracteres, formato \`^\S+$\` * `name`textorequerido de 1 a 120 caracteres * `description`textoadmite null hasta 2000 caracteres * `gtin`cualquiera * `ncmCode`cualquiera * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o no Por defecto: `false` * `tracksLotAndExpiry`sí o no Por defecto: `false` * `requiresQualityControl`sí o no Por defecto: `false` * `netWeightKg`númeroadmite null mayor que 0, máximo 999999999 * `grossWeightKg`númeroadmite null mayor que 0, máximo 999999999 * `palletLayers`enteroadmite null mayor que 0, máximo 999999999 * `lengthCm`númeroadmite null mayor que 0, máximo 99999999.99 * `widthCm`númeroadmite null mayor que 0, máximo 99999999.99 * `heightCm`númeroadmite null mayor que 0, máximo 99999999.99 * `packagingLevels`lista de objeto hasta 3 * `components`lista de objeto Por defecto: `[]`hasta 100 * `brandId`uuidadmite null * `familyId`uuidadmite null * `sourceItemId`uuidadmite null ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `description`cualquierarequerido * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `gtin`cualquierarequerido * `ncmCode`cualquierarequerido * `arbaCategory`cualquierarequerido * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o norequerido * `tracksLotAndExpiry`sí o norequerido * `requiresQualityControl`sí o norequerido * `netWeightKg`cualquierarequerido * `grossWeightKg`cualquierarequerido * `palletLayers`enterorequeridoadmite null * `lengthCm`cualquierarequerido * `widthCm`cualquierarequerido * `heightCm`cualquierarequerido * `brandId`uuidrequeridoadmite null * `familyId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "code": "ARS", "name": "texto", "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "code": "ARS", "name": "texto", "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "description": null, "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "gtin": null, "ncmCode": null, "arbaCategory": null, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isImported": false, "tracksLotAndExpiry": false, "requiresQualityControl": false, "netWeightKg": null, "grossWeightKg": null, "palletLayers": 1, "lengthCm": null, "widthCm": null, "heightCm": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar un artículo > Desactiva un artículo con un motivo opcional, o lo reactiva. POST`/api/v1/items/set-status` * Permiso `items.set-status` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemId`uuidrequerido * `version`enterorequerido mínimo 1 * `status`opciónrequerido Valores: `active` `inactive` * `reason`textoadmite null hasta 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `description`cualquierarequerido * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `gtin`cualquierarequerido * `ncmCode`cualquierarequerido * `arbaCategory`cualquierarequerido * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o norequerido * `tracksLotAndExpiry`sí o norequerido * `requiresQualityControl`sí o norequerido * `netWeightKg`cualquierarequerido * `grossWeightKg`cualquierarequerido * `palletLayers`enterorequeridoadmite null * `lengthCm`cualquierarequerido * `widthCm`cualquierarequerido * `heightCm`cualquierarequerido * `brandId`uuidrequeridoadmite null * `familyId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.set-status`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/set-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/set-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "description": null, "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "gtin": null, "ncmCode": null, "arbaCategory": null, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isImported": false, "tracksLotAndExpiry": false, "requiresQualityControl": false, "netWeightKg": null, "grossWeightKg": null, "palletLayers": 1, "lengthCm": null, "widthCm": null, "heightCm": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Listar artículos > Lista los artículos por código con búsqueda por nombre, código o código de barras y filtros de estado, tipo, vistas, alícuota de IVA, marca y familia. GET`/api/v1/items/list` * Permiso `items.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 120 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `itemType`opciónadmite null Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o no * `isPurchased`sí o no * `tracksStock`sí o no * `vatRateId`uuidadmite null * `brandId`uuidadmite null * `familyId`uuidadmite null * `sort`opción Valores: `code` `relevance`Por defecto: `code` * `countTotal`sí o no * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `25`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `items`lista de objetorequerido * `total`entero mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/items/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "items": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitName": "texto", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRatePercentage": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "brandName": null, "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyPath": null, "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ], "total": 1 } ``` # Modificar un artículo > Edita una sección de un artículo: identificación, tipo y vistas, unidad, clasificación, comercio exterior, control o logística. POST`/api/v1/items/update` * Permiso `items.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `respuesta`uno derequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `description`cualquierarequerido * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `gtin`cualquierarequerido * `ncmCode`cualquierarequerido * `arbaCategory`cualquierarequerido * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o norequerido * `tracksLotAndExpiry`sí o norequerido * `requiresQualityControl`sí o norequerido * `netWeightKg`cualquierarequerido * `grossWeightKg`cualquierarequerido * `palletLayers`enterorequeridoadmite null * `lengthCm`cualquierarequerido * `widthCm`cualquierarequerido * `heightCm`cualquierarequerido * `brandId`uuidrequeridoadmite null * `familyId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "section": "identification", "code": "ARS", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "section": "identification", "code": "ARS", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "description": null, "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "gtin": null, "ncmCode": null, "arbaCategory": null, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isImported": false, "tracksLotAndExpiry": false, "requiresQualityControl": false, "netWeightKg": null, "grossWeightKg": null, "palletLayers": 1, "lengthCm": null, "widthCm": null, "heightCm": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Reemplazar los componentes de un kit > Reemplaza los componentes de un kit con sus cantidades. POST`/api/v1/items/set-kit-components` * Permiso `items.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemId`uuidrequerido * `version`enterorequerido mínimo 1 * `components`lista de objetorequerido hasta 100 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `description`cualquierarequerido * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `gtin`cualquierarequerido * `ncmCode`cualquierarequerido * `arbaCategory`cualquierarequerido * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o norequerido * `tracksLotAndExpiry`sí o norequerido * `requiresQualityControl`sí o norequerido * `netWeightKg`cualquierarequerido * `grossWeightKg`cualquierarequerido * `palletLayers`enterorequeridoadmite null * `lengthCm`cualquierarequerido * `widthCm`cualquierarequerido * `heightCm`cualquierarequerido * `brandId`uuidrequeridoadmite null * `familyId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `components`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/set-kit-components" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "components": [ { "componentItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/set-kit-components`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "components": [ { "componentItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "description": null, "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "gtin": null, "ncmCode": null, "arbaCategory": null, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isImported": false, "tracksLotAndExpiry": false, "requiresQualityControl": false, "netWeightKg": null, "grossWeightKg": null, "palletLayers": 1, "lengthCm": null, "widthCm": null, "heightCm": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "components": [ { "componentItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "quantity": 100, "status": "active", "itemType": "resale_product", "tracksStock": false, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ] } ``` # Reemplazar los niveles de embalaje > Reemplaza los niveles de embalaje de un artículo: caja primaria, caja secundaria y pallet, con su contenido y código de barras. POST`/api/v1/items/set-packaging-levels` * Permiso `items.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemId`uuidrequerido * `version`enterorequerido mínimo 1 * `packagingLevels`lista de objetorequerido hasta 3 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `description`cualquierarequerido * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `gtin`cualquierarequerido * `ncmCode`cualquierarequerido * `arbaCategory`cualquierarequerido * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o norequerido * `tracksLotAndExpiry`sí o norequerido * `requiresQualityControl`sí o norequerido * `netWeightKg`cualquierarequerido * `grossWeightKg`cualquierarequerido * `palletLayers`enterorequeridoadmite null * `lengthCm`cualquierarequerido * `widthCm`cualquierarequerido * `heightCm`cualquierarequerido * `brandId`uuidrequeridoadmite null * `familyId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `packagingLevels`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/set-packaging-levels" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "packagingLevels": [ { "level": "primary_box", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/set-packaging-levels`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "packagingLevels": [ { "level": "primary_box", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "description": null, "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "gtin": null, "ncmCode": null, "arbaCategory": null, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isImported": false, "tracksLotAndExpiry": false, "requiresQualityControl": false, "netWeightKg": null, "grossWeightKg": null, "palletLayers": 1, "lengthCm": null, "widthCm": null, "heightCm": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "packagingLevels": [ { "level": "primary_box", "quantity": 100, "barcode": null, "totalStockUnits": 100 } ] } ``` # Retirar un proveedor del artículo > Retira un proveedor de un artículo; agregarlo otra vez reactiva el mismo registro. POST`/api/v1/items/retire-supplier-item` * Permiso `items.manage-supplier-data` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemId`uuidrequerido * `supplierId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `supplierId`uuidrequerido * `supplier`objetorequerido * `supplierCode`cualquierarequerido * `supplierDescription`cualquierarequerido * `purchaseLevel`opciónrequerido Valores: `unit` `primary_box` `secondary_box` `pallet` * `lastPrice`cualquierarequerido * `currencyCode`cualquierarequerido * `lastPriceDate`fecharequeridoadmite null * `leadTimeDays`enterorequeridoadmite null * `retiredAt`fecha y horarequeridoadmite null * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.manage-supplier-data`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/items/retire-supplier-item" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/retire-supplier-item`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplier": { "name": "texto", "code": 1, "status": "active" }, "supplierCode": null, "supplierDescription": null, "purchaseLevel": "unit", "lastPrice": null, "currencyCode": null, "lastPriceDate": "2026-10-23", "leadTimeDays": 1, "retiredAt": "2026-10-23T14:30:00.000Z", "version": 1 } ``` # Ver el historial de un artículo > Lista los cambios de un artículo, sus embalajes y sus componentes, del más nuevo al más viejo, campo por campo. GET`/api/v1/items/get-history` * Permiso `items.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `itemId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/items/get-history?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/get-history?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un artículo > Devuelve un artículo con sus niveles de embalaje, sus componentes de kit, los kits que lo usan y sus proveedores. GET`/api/v1/items/get` * Permiso `items.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `itemId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `description`cualquierarequerido * `itemType`opciónrequerido Valores: `resale_product` `finished_product` `productive_input` `non_productive_input` `service` `kit` * `isSold`sí o norequerido * `isPurchased`sí o norequerido * `tracksStock`sí o norequerido * `gtin`cualquierarequerido * `ncmCode`cualquierarequerido * `arbaCategory`cualquierarequerido * `stockUnitId`uuidrequerido * `vatRateId`uuidrequerido * `isImported`sí o norequerido * `tracksLotAndExpiry`sí o norequerido * `requiresQualityControl`sí o norequerido * `netWeightKg`cualquierarequerido * `grossWeightKg`cualquierarequerido * `palletLayers`enterorequeridoadmite null * `lengthCm`cualquierarequerido * `widthCm`cualquierarequerido * `heightCm`cualquierarequerido * `brandId`uuidrequeridoadmite null * `familyId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `packagingLevels`lista de objetorequerido * `components`lista de objetorequerido * `usedInKits`lista de objetorequerido * `supplierItems`lista de objetorequerido * `enabledCurrencies`lista de textorequerido * `vatRateExpired`sí o norequerido * `brandName`cualquierarequerido * `familyPath`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `items.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/items/get?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/items/get?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "description": null, "itemType": "resale_product", "isSold": false, "isPurchased": false, "tracksStock": false, "gtin": null, "ncmCode": null, "arbaCategory": null, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "vatRateId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isImported": false, "tracksLotAndExpiry": false, "requiresQualityControl": false, "netWeightKg": null, "grossWeightKg": null, "palletLayers": 1, "lengthCm": null, "widthCm": null, "heightCm": null, "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "packagingLevels": [ { "level": "primary_box", "quantity": 100, "barcode": null, "totalStockUnits": 100 } ], "components": [ { "componentItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "quantity": 100, "status": "active", "itemType": "resale_product", "tracksStock": false, "stockUnitId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ], "usedInKits": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" } ], "supplierItems": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplier": { "name": "texto", "code": 1, "status": "active" }, "supplierCode": null, "supplierDescription": null, "purchaseLevel": "unit", "lastPrice": null, "currencyCode": null, "lastPriceDate": "2026-10-23", "leadTimeDays": 1, "retiredAt": "2026-10-23T14:30:00.000Z", "version": 1 } ], "enabledCurrencies": [ "tex" ], "vatRateExpired": false, "brandName": null, "familyPath": null } ``` # Clientes > La ficha del cliente con su situación fiscal, lugares de entrega, contactos y condiciones comerciales. La ficha del cliente con su situación fiscal, lugares de entrega, contactos y condiciones comerciales. | Operación | Ruta | | ------------------------------------------------------------------------------------------------------------------ | --------------------------------------------- | | [Listar clientes](/api/referencia/clientes/listar-clientes/) | GET `/api/v1/customers/list` | | [Ver un cliente](/api/referencia/clientes/ver-un-cliente/) | GET `/api/v1/customers/get` | | [Crear un cliente](/api/referencia/clientes/crear-un-cliente/) | POST `/api/v1/customers/create` | | [Modificar un cliente](/api/referencia/clientes/modificar-un-cliente/) | POST `/api/v1/customers/update` | | [Modificar las condiciones comerciales](/api/referencia/clientes/modificar-las-condiciones-comerciales/) | POST `/api/v1/customers/update-commercial` | | [Desactivar o reactivar un cliente](/api/referencia/clientes/desactivar-o-reactivar-un-cliente/) | POST `/api/v1/customers/set-status` | | [Aplicar los datos de ARCA a un cliente](/api/referencia/clientes/aplicar-los-datos-de-arca-a-un-cliente/) | POST `/api/v1/customers/apply-taxpayer-data` | | [Agregar un lugar de entrega](/api/referencia/clientes/agregar-un-lugar-de-entrega/) | POST `/api/v1/customers/create-recipient` | | [Modificar un lugar de entrega](/api/referencia/clientes/modificar-un-lugar-de-entrega/) | POST `/api/v1/customers/update-recipient` | | [Desactivar o reactivar un lugar de entrega](/api/referencia/clientes/desactivar-o-reactivar-un-lugar-de-entrega/) | POST `/api/v1/customers/set-recipient-status` | | [Agregar un contacto](/api/referencia/clientes/agregar-un-contacto/) | POST `/api/v1/customers/create-contact` | | [Modificar un contacto](/api/referencia/clientes/modificar-un-contacto/) | POST `/api/v1/customers/update-contact` | | [Desactivar o reactivar un contacto](/api/referencia/clientes/desactivar-o-reactivar-un-contacto/) | POST `/api/v1/customers/set-contact-status` | | [Ver el historial de un cliente](/api/referencia/clientes/ver-el-historial-de-un-cliente/) | GET `/api/v1/customers/get-history` | # Agregar un contacto > Agrega un contacto a un cliente; puede ser el principal. POST`/api/v1/customers/create-contact` * Permiso `customers.manage-contacts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `name`textorequerido de 1 a 120 caracteres * `role`textoadmite null hasta 80 caracteres * `email`textoadmite null hasta 254 caracteres * `phone`textoadmite null hasta 40 caracteres * `isPrimary`sí o no Por defecto: `false` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `name`textorequerido * `role`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.manage-contacts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/create-contact" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/create-contact`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "version": 1 } ``` # Agregar un lugar de entrega > Agrega un lugar de entrega a un cliente; puede ser el predeterminado. POST`/api/v1/customers/create-recipient` * Permiso `customers.manage-recipients` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `name`textorequerido de 1 a 120 caracteres * `street`textorequerido de 1 a 120 caracteres * `streetNumber`textoadmite null hasta 20 caracteres * `city`textorequerido de 1 a 120 caracteres * `provinceId`uuidrequerido * `postalCode`textoadmite null hasta 8 caracteres * `receiverName`textoadmite null hasta 120 caracteres * `receiverPhone`textoadmite null hasta 40 caracteres * `receivingHours`textoadmite null hasta 200 caracteres * `carrierTaxId`cualquiera * `isDefault`sí o no Por defecto: `false` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `name`textorequerido * `street`textorequerido * `streetNumber`cualquierarequerido * `city`textorequerido * `provinceId`uuidrequerido * `postalCode`cualquierarequerido * `receiverName`cualquierarequerido * `receiverPhone`cualquierarequerido * `receivingHours`cualquierarequerido * `carrierTaxId`cualquierarequerido * `isDefault`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.manage-recipients`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/create-recipient" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/create-recipient`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "streetNumber": null, "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "receiverName": null, "receiverPhone": null, "receivingHours": null, "carrierTaxId": null, "isDefault": false, "status": "active", "version": 1 } ``` # Aplicar los datos de ARCA a un cliente > Aplica a un cliente los datos fiscales que ARCA guardó para su CUIT en la fecha revisada: razón social, condición de IVA, ingresos brutos y domicilio fiscal. POST`/api/v1/customers/apply-taxpayer-data` * Permiso `customers.apply-taxpayer-data` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `version`enterorequerido mínimo 1 * `taxDataConsultedAt`fecha y horarequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `documentType`opciónrequerido Valores: `CUIT` `CUIL` `DNI` * `documentNumber`textorequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequerido Valores: `registered` `monotributo` `exempt` `final_consumer` * `iibbCondition`cualquierarequerido * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `salesMode`opciónrequerido Valores: `cash` `account` * `paymentTerm`objetorequeridoadmite null * `priceList`objetorequeridoadmite null * `generalDiscountPercent`textorequerido * `creditLimit`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `recipients`lista de objetorequerido * `contacts`lista de objetorequerido * `apocryphal`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.apply-taxpayer-data`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/apply-taxpayer-data" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "taxDataConsultedAt": "2026-10-23T14:30:00.000Z" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/apply-taxpayer-data`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "taxDataConsultedAt": "2026-10-23T14:30:00.000Z" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "tradeName": null, "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": null, "iibbNumber": null, "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "salesMode": "cash", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "generalDiscountPercent": "texto", "creditLimit": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "recipients": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "streetNumber": null, "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "receiverName": null, "receiverPhone": null, "receivingHours": null, "carrierTaxId": null, "isDefault": false, "status": "active", "version": 1 } ], "contacts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "version": 1 } ], "apocryphal": { "listedOn": "2026-10-23", "checkedAt": "2026-10-23T14:30:00.000Z" } } ``` # Crear un cliente > Crea un cliente con su documento, razón social y condición de IVA y, opcionales, nombre de fantasía, contacto, ingresos brutos, domicilio fiscal y perfil comercial. Con la fecha de una consulta a ARCA completa el domicilio fiscal y los ingresos brutos que se dejen vacíos. POST`/api/v1/customers/create` * Permiso `customers.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentType`opciónrequerido Valores: `CUIT` `CUIL` `DNI` * `documentNumber`textorequerido * `legalName`textorequerido * `vatCondition`opciónrequerido Valores: `registered` `monotributo` `exempt` `final_consumer` * `taxDataConsultedAt`fecha y hora * `tradeName`textoadmite null hasta 200 caracteres * `email`textoadmite null hasta 254 caracteres * `phone`textoadmite null hasta 40 caracteres * `iibbCondition`opciónadmite null Valores: `local` `multilateral` `exempt` `unregistered` * `iibbNumber`textoadmite null hasta 30 caracteres * `street`textoadmite null hasta 120 caracteres * `streetNumber`textoadmite null hasta 20 caracteres * `city`textoadmite null hasta 120 caracteres * `provinceId`uuidadmite null * `postalCode`textoadmite null hasta 8 caracteres * `commercial`objeto ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `documentType`opciónrequerido Valores: `CUIT` `CUIL` `DNI` * `documentNumber`textorequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequerido Valores: `registered` `monotributo` `exempt` `final_consumer` * `iibbCondition`cualquierarequerido * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `salesMode`opciónrequerido Valores: `cash` `account` * `paymentTerm`objetorequeridoadmite null * `priceList`objetorequeridoadmite null * `generalDiscountPercent`textorequerido * `creditLimit`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `recipients`lista de objetorequerido * `contacts`lista de objetorequerido * `apocryphal`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "vatCondition": "registered" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "vatCondition": "registered" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "tradeName": null, "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": null, "iibbNumber": null, "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "salesMode": "cash", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "generalDiscountPercent": "texto", "creditLimit": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "recipients": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "streetNumber": null, "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "receiverName": null, "receiverPhone": null, "receivingHours": null, "carrierTaxId": null, "isDefault": false, "status": "active", "version": 1 } ], "contacts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "version": 1 } ], "apocryphal": { "listedOn": "2026-10-23", "checkedAt": "2026-10-23T14:30:00.000Z" } } ``` # Desactivar o reactivar un cliente > Desactiva un cliente con un motivo, o lo reactiva. Nunca uno con documentos abiertos. POST`/api/v1/customers/set-status` * Permiso `customers.change-status` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `respuesta`uno derequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `documentType`opciónrequerido Valores: `CUIT` `CUIL` `DNI` * `documentNumber`textorequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequerido Valores: `registered` `monotributo` `exempt` `final_consumer` * `iibbCondition`cualquierarequerido * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `salesMode`opciónrequerido Valores: `cash` `account` * `paymentTerm`objetorequeridoadmite null * `priceList`objetorequeridoadmite null * `generalDiscountPercent`textorequerido * `creditLimit`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.change-status`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/set-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "inactive", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/set-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "inactive", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "tradeName": null, "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": null, "iibbNumber": null, "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "salesMode": "cash", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "generalDiscountPercent": "texto", "creditLimit": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar un contacto > Desactiva o reactiva un contacto de un cliente; desactivar el principal deja al cliente sin ninguno. POST`/api/v1/customers/set-contact-status` * Permiso `customers.manage-contacts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `contactId`uuidrequerido * `version`enterorequerido mínimo 1 * `status`opciónrequerido Valores: `active` `inactive` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `name`textorequerido * `role`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.manage-contacts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/set-contact-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/set-contact-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "version": 1 } ``` # Desactivar o reactivar un lugar de entrega > Desactiva o reactiva un lugar de entrega de un cliente; desactivar el predeterminado deja al cliente sin ninguno. POST`/api/v1/customers/set-recipient-status` * Permiso `customers.manage-recipients` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `recipientId`uuidrequerido * `version`enterorequerido mínimo 1 * `status`opciónrequerido Valores: `active` `inactive` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `name`textorequerido * `street`textorequerido * `streetNumber`cualquierarequerido * `city`textorequerido * `provinceId`uuidrequerido * `postalCode`cualquierarequerido * `receiverName`cualquierarequerido * `receiverPhone`cualquierarequerido * `receivingHours`cualquierarequerido * `carrierTaxId`cualquierarequerido * `isDefault`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.manage-recipients`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/set-recipient-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/set-recipient-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "streetNumber": null, "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "receiverName": null, "receiverPhone": null, "receivingHours": null, "carrierTaxId": null, "isDefault": false, "status": "active", "version": 1 } ``` # Listar clientes > Lista los clientes con búsqueda por nombre, documento o código y filtros de estado, condición de IVA, modalidad de venta y lista de precios. GET`/api/v1/customers/list` * Permiso `customers.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `vatCondition`uno deadmite null * `salesMode`uno deadmite null * `priceListId`uno deadmite null * `sort`opción Valores: `name` `code`Por defecto: `name` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `customers`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/customers/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "customers": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "tradeName": null, "vatCondition": "registered", "salesMode": "cash", "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "city": null, "status": "active", "version": 1 } ], "total": 1 } ``` # Modificar las condiciones comerciales > Cambia la modalidad de venta, la lista de precios, la condición de pago, la bonificación general y el límite de crédito de un cliente. POST`/api/v1/customers/update-commercial` * Permiso `customers.update-commercial` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `version`enterorequerido mínimo 1 * `salesMode`opción Valores: `cash` `account`Por defecto: `account` * `paymentTermsId`uuidadmite null * `priceListId`uuidadmite null * `generalDiscountPercent`cualquiera * `creditLimit`cualquiera ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `documentType`opciónrequerido Valores: `CUIT` `CUIL` `DNI` * `documentNumber`textorequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequerido Valores: `registered` `monotributo` `exempt` `final_consumer` * `iibbCondition`cualquierarequerido * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `salesMode`opciónrequerido Valores: `cash` `account` * `paymentTerm`objetorequeridoadmite null * `priceList`objetorequeridoadmite null * `generalDiscountPercent`textorequerido * `creditLimit`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.update-commercial`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/update-commercial" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/update-commercial`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "tradeName": null, "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": null, "iibbNumber": null, "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "salesMode": "cash", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "generalDiscountPercent": "texto", "creditLimit": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Modificar un cliente > Edita un bloque de un cliente: datos generales, situación fiscal o domicilio fiscal. POST`/api/v1/customers/update` * Permiso `customers.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `respuesta`uno derequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `documentType`opciónrequerido Valores: `CUIT` `CUIL` `DNI` * `documentNumber`textorequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequerido Valores: `registered` `monotributo` `exempt` `final_consumer` * `iibbCondition`cualquierarequerido * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `salesMode`opciónrequerido Valores: `cash` `account` * `paymentTerm`objetorequeridoadmite null * `priceList`objetorequeridoadmite null * `generalDiscountPercent`textorequerido * `creditLimit`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "block": "general", "legalName": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "block": "general", "legalName": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "tradeName": null, "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": null, "iibbNumber": null, "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "salesMode": "cash", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "generalDiscountPercent": "texto", "creditLimit": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Modificar un contacto > Edita un contacto de un cliente; marcarlo principal le saca la marca al anterior. POST`/api/v1/customers/update-contact` * Permiso `customers.manage-contacts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `contactId`uuidrequerido * `version`enterorequerido mínimo 1 * `name`textorequerido de 1 a 120 caracteres * `role`textoadmite null hasta 80 caracteres * `email`textoadmite null hasta 254 caracteres * `phone`textoadmite null hasta 40 caracteres * `isPrimary`sí o norequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `name`textorequerido * `role`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.manage-contacts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/update-contact" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto", "isPrimary": false }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/update-contact`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto", "isPrimary": false }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "version": 1 } ``` # Modificar un lugar de entrega > Edita un lugar de entrega de un cliente; marcarlo predeterminado le saca la marca al anterior. POST`/api/v1/customers/update-recipient` * Permiso `customers.manage-recipients` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `recipientId`uuidrequerido * `version`enterorequerido mínimo 1 * `name`textorequerido de 1 a 120 caracteres * `street`textorequerido de 1 a 120 caracteres * `streetNumber`textoadmite null hasta 20 caracteres * `city`textorequerido de 1 a 120 caracteres * `provinceId`uuidrequerido * `postalCode`textoadmite null hasta 8 caracteres * `receiverName`textoadmite null hasta 120 caracteres * `receiverPhone`textoadmite null hasta 40 caracteres * `receivingHours`textoadmite null hasta 200 caracteres * `carrierTaxId`cualquiera * `isDefault`sí o norequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `name`textorequerido * `street`textorequerido * `streetNumber`cualquierarequerido * `city`textorequerido * `provinceId`uuidrequerido * `postalCode`cualquierarequerido * `receiverName`cualquierarequerido * `receiverPhone`cualquierarequerido * `receivingHours`cualquierarequerido * `carrierTaxId`cualquierarequerido * `isDefault`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.manage-recipients`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/customers/update-recipient" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto", "street": "texto", "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isDefault": false }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/update-recipient`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto", "street": "texto", "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "isDefault": false }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "streetNumber": null, "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "receiverName": null, "receiverPhone": null, "receivingHours": null, "carrierTaxId": null, "isDefault": false, "status": "active", "version": 1 } ``` # Ver el historial de un cliente > Lista los cambios de un cliente, sus lugares de entrega y sus contactos, del más nuevo al más viejo, campo por campo. GET`/api/v1/customers/get-history` * Permiso `customers.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/customers/get-history?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/get-history?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un cliente > Devuelve un cliente con sus lugares de entrega y sus contactos. GET`/api/v1/customers/get` * Permiso `customers.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `documentType`opciónrequerido Valores: `CUIT` `CUIL` `DNI` * `documentNumber`textorequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequerido Valores: `registered` `monotributo` `exempt` `final_consumer` * `iibbCondition`cualquierarequerido * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `salesMode`opciónrequerido Valores: `cash` `account` * `paymentTerm`objetorequeridoadmite null * `priceList`objetorequeridoadmite null * `generalDiscountPercent`textorequerido * `creditLimit`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `recipients`lista de objetorequerido * `contacts`lista de objetorequerido * `apocryphal`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/customers/get?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/customers/get?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "documentType": "CUIT", "documentNumber": "texto", "legalName": "texto", "tradeName": null, "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": null, "iibbNumber": null, "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "salesMode": "cash", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "generalDiscountPercent": "texto", "creditLimit": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "recipients": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "street": "texto", "streetNumber": null, "city": "texto", "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "receiverName": null, "receiverPhone": null, "receivingHours": null, "carrierTaxId": null, "isDefault": false, "status": "active", "version": 1 } ], "contacts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "version": 1 } ], "apocryphal": { "listedOn": "2026-10-23", "checkedAt": "2026-10-23T14:30:00.000Z" } } ``` # Cobranzas > Recibos de clientes con sus medios de cobro, su imputación a cuotas y lo que queda a cuenta. Recibos de clientes con sus medios de cobro, su imputación a cuotas y lo que queda a cuenta. | Operación | Ruta | | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | | [Listar recibos](/api/referencia/cobranzas/listar-recibos/) | GET `/api/v1/collections/list` | | [Ver un recibo](/api/referencia/cobranzas/ver-un-recibo/) | GET `/api/v1/collections/get` | | [Listar cuotas abiertas de un cliente](/api/referencia/cobranzas/listar-cuotas-abiertas-de-un-cliente/) | GET `/api/v1/collections/list-open-items` | | [Registrar un recibo](/api/referencia/cobranzas/registrar-un-recibo/) | POST `/api/v1/collections/register` | | [Registrar un recibo fiscal y uno X juntos](/api/referencia/cobranzas/registrar-un-recibo-fiscal-y-uno-x-juntos/) | POST `/api/v1/collections/register-together` | | [Proponer la aplicación de saldos a cuenta](/api/referencia/cobranzas/proponer-la-aplicacion-de-saldos-a-cuenta/) | GET `/api/v1/collections/propose-credit-application` | | [Aplicar saldos a cuenta](/api/referencia/cobranzas/aplicar-saldos-a-cuenta/) | POST `/api/v1/collections/apply-credit` | | [Deshacer una aplicación](/api/referencia/cobranzas/deshacer-una-aplicacion/) | POST `/api/v1/collections/undo-clearing` | | [Anular un recibo](/api/referencia/cobranzas/anular-un-recibo/) | POST `/api/v1/collections/void` | | [Descargar el PDF de un recibo](/api/referencia/cobranzas/descargar-el-pdf-de-un-recibo/) | POST `/api/v1/collections/download-pdf` | | [Resumir las cobranzas del mes](/api/referencia/cobranzas/resumir-las-cobranzas-del-mes/) | GET `/api/v1/collections/summarize-month` | | [Ver el historial de un recibo](/api/referencia/cobranzas/ver-el-historial-de-un-recibo/) | GET `/api/v1/collections/get-history` | # Anular un recibo > Anula un recibo con un motivo y la versión leída: revierte lo imputado y lo aplicado desde su saldo a cuenta, en un solo acto. POST`/api/v1/collections/void` * Permiso `collections.void` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `receiptId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`enterorequerido * `name`textorequerido * `circuit`opciónrequerido Valores: `fiscal` `x` * `status`opciónrequerido Valores: `issued` `voided` * `receiptDate`fecharequerido * `customer`objetorequerido * `kinds`lista de opciónrequerido Valores: `cash` `transfer` `check` `echeq` `withholding` * `methodsText`textorequerido * `advanceBalance`textorequerido * `total`textorequerido * `version`enterorequerido mínimo 1 * `allocatedTotal`textorequerido * `advanceTotal`textorequerido * `isAdvance`sí o norequerido * `notes`cualquierarequerido * `methods`lista de objetorequerido * `allocations`lista de objetorequerido * `registeredAt`fecha y horarequerido * `registeredBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `account`objetorequeridoadmite null * `registeredWith`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.void`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/collections/void" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "receiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/void`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "receiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "circuit": "fiscal", "status": "issued", "receiptDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "address": "texto" }, "kinds": [ "cash" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "version": 1, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "notes": null, "methods": [ { "kind": "cash", "amount": "texto", "bankName": null, "reference": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "paymentDate": "2026-10-23", "tax": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "certificateNumber": null, "certificateDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "receipt", "allocatedOn": "2026-10-23", "amount": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "createdBy": { "id": "texto", "name": null } } ], "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidReason": null, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "account": { "balance": "texto", "openDocuments": 1 }, "registeredWith": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "total": "texto" } } ``` # Aplicar saldos a cuenta > Aplica lo que los recibos de un cliente dejaron a cuenta a sus cuotas abiertas, tal como se confirmó. Cada aplicación llega hasta el saldo de la cuota y del crédito, controlado bajo bloqueo. POST`/api/v1/collections/apply-credit` * Permiso `collections.apply-credit` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `applications`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `applications`lista de objetorequerido * `receipts`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.apply-credit`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/collections/apply-credit" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": null } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/apply-credit`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": null } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": "texto" } ], "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "advanceBalance": "texto" } ] } ``` # Descargar el PDF de un recibo > Descarga el PDF de un recibo para entregar al cliente: la empresa, el cliente, cada medio de cobro, la imputación, lo que quedó a cuenta y el total. POST`/api/v1/collections/download-pdf` * Permiso `collections.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta un PDF ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `receiptId`uuidrequerido ## Respuesta `200` con un PDF y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/collections/download-pdf" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "receiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/download-pdf`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "receiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Deshacer una aplicación > Deshace la cancelación entre un crédito del cliente (de un recibo o una nota de crédito) y una cuota sin anular ninguno de los dos documentos: ambos quedan abiertos otra vez por su importe. POST`/api/v1/collections/undo-clearing` * Permiso `collections.apply-credit` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `allocationId`uuidrequerido * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `allocationId`uuidrequerido * `receipts`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.apply-credit`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/collections/undo-clearing" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "allocationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/undo-clearing`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "allocationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "allocationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "advanceBalance": "texto" } ] } ``` # Listar cuotas abiertas de un cliente > Lista las cuotas abiertas de un cliente que puede imputar un recibo de una fecha, por vencimiento, con la imputación propuesta de un importe, el saldo del cliente y lo que tiene a cuenta. GET`/api/v1/collections/list-open-items` * Permiso `collections.create` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `fiscal` * `receiptDate`fechaadmite null * `amount`cualquiera ## Respuesta `200` con este JSON. * `customer`objetorequerido * `balance`textorequerido * `onAccount`textorequerido * `items`lista de objetorequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/collections/list-open-items?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/list-open-items?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "status": "active" }, "balance": "texto", "onAccount": "texto", "items": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "installment": null, "documentDate": "2026-10-23", "dueDate": "2026-10-23", "amount": "texto", "balance": "texto", "daysOverdue": 1, "circuit": "fiscal", "proposed": "texto" } ], "today": "2026-10-23" } ``` # Listar recibos > Lista los recibos, del más nuevo al más viejo, con búsqueda por número o cliente y filtros de estado (emitidos por defecto, anulados, con saldo a cuenta), medio de cobro, cliente y fechas. GET`/api/v1/collections/list` * Permiso `collections.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `status`opción Valores: `issued` `voided` `with-advance` `all`Por defecto: `issued` * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` * `kind`opciónadmite null Valores: `cash` `transfer` `check` `echeq` `withholding` * `customerId`uuidadmite null * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `page`entero Por defecto: `1`mínimo 1, máximo 100000 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `receipts`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/collections/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "circuit": "fiscal", "status": "issued", "receiptDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto" }, "kinds": [ "cash" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto" } ], "total": 1 } ``` # Proponer la aplicación de saldos a cuenta > Propone cómo aplicar lo que los recibos de un cliente dejaron a cuenta a sus cuotas abiertas: primero las de importe exacto, después del recibo más viejo y por vencimiento. No graba nada. GET`/api/v1/collections/propose-credit-application` * Permiso `collections.apply-credit` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido * `documentId`uuidadmite null ## Respuesta `200` con este JSON. * `customer`objetorequerido * `credits`lista de objetorequerido * `items`lista de objetorequerido * `applications`lista de objetorequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.apply-credit`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/collections/propose-credit-application?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/propose-credit-application?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto" }, "credits": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "receipt", "label": "texto" }, "receiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "documentDate": "2026-10-23", "circuit": "fiscal", "balance": "texto" } ], "items": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "installment": null, "documentDate": "2026-10-23", "dueDate": "2026-10-23", "amount": "texto", "balance": "texto", "daysOverdue": 1, "circuit": "fiscal" } ], "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": "texto" } ], "today": "2026-10-23" } ``` # Registrar un recibo > Registra un recibo de un cliente, fiscal o X, con sus medios de cobro (efectivo, transferencia, cheque, echeq y retenciones sufridas) y lo imputa a sus cuotas abiertas del mismo circuito. Lo que no se imputa queda a cuenta. POST`/api/v1/collections/register` * Permiso `collections.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `circuit`opción Valores: `fiscal` `x`Por defecto: `fiscal` * `receiptDate`fechaadmite null * `total`cualquierarequerido * `methods`lista de objetorequerido al menos 1, hasta 50 * `allocations`lista de objeto hasta 200 * `notes`textoadmite null hasta 1000 caracteres * `isAdvance`sí o no Por defecto: `false` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`enterorequerido * `name`textorequerido * `circuit`opciónrequerido Valores: `fiscal` `x` * `status`opciónrequerido Valores: `issued` `voided` * `receiptDate`fecharequerido * `customer`objetorequerido * `kinds`lista de opciónrequerido Valores: `cash` `transfer` `check` `echeq` `withholding` * `methodsText`textorequerido * `advanceBalance`textorequerido * `total`textorequerido * `version`enterorequerido mínimo 1 * `allocatedTotal`textorequerido * `advanceTotal`textorequerido * `isAdvance`sí o norequerido * `notes`cualquierarequerido * `methods`lista de objetorequerido * `allocations`lista de objetorequerido * `registeredAt`fecha y horarequerido * `registeredBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `account`objetorequeridoadmite null * `registeredWith`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/collections/register" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "total": null, "methods": [ { "kind": "cash", "amount": null } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/register`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "total": null, "methods": [ { "kind": "cash", "amount": null } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "circuit": "fiscal", "status": "issued", "receiptDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "address": "texto" }, "kinds": [ "cash" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "version": 1, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "notes": null, "methods": [ { "kind": "cash", "amount": "texto", "bankName": null, "reference": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "paymentDate": "2026-10-23", "tax": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "certificateNumber": null, "certificateDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "receipt", "allocatedOn": "2026-10-23", "amount": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "createdBy": { "id": "texto", "name": null } } ], "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidReason": null, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "account": { "balance": "texto", "openDocuments": 1 }, "registeredWith": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "total": "texto" } } ``` # Registrar un recibo fiscal y uno X juntos > Registra en una sola transacción un recibo fiscal y uno X del mismo cliente y fecha, cada uno con sus medios y sus imputaciones. Se graban los dos o ninguno, con el X vinculado al fiscal. POST`/api/v1/collections/register-together` * Permiso `collections.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `receiptDate`fechaadmite null * `fiscal`objetorequerido * `x`objetorequerido ## Respuesta `200` con este JSON. * `fiscal`objetorequerido * `x`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/collections/register-together" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fiscal": { "total": null, "methods": [ { "kind": "cash", "amount": null } ] }, "x": { "total": null, "methods": [ { "kind": "cash", "amount": null } ] } }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/register-together`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fiscal": { "total": null, "methods": [ { "kind": "cash", "amount": null } ] }, "x": { "total": null, "methods": [ { "kind": "cash", "amount": null } ] } }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "fiscal": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "circuit": "fiscal", "status": "issued", "receiptDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "address": "texto" }, "kinds": [ "cash" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "version": 1, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "notes": null, "methods": [ { "kind": "cash", "amount": "texto", "bankName": null, "reference": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "paymentDate": "2026-10-23", "tax": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "certificateNumber": null, "certificateDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "receipt", "allocatedOn": "2026-10-23", "amount": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "createdBy": { "id": "texto", "name": null } } ], "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidReason": null, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "account": { "balance": "texto", "openDocuments": 1 }, "registeredWith": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "total": "texto" } }, "x": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "circuit": "fiscal", "status": "issued", "receiptDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "address": "texto" }, "kinds": [ "cash" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "version": 1, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "notes": null, "methods": [ { "kind": "cash", "amount": "texto", "bankName": null, "reference": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "paymentDate": "2026-10-23", "tax": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "certificateNumber": null, "certificateDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "receipt", "allocatedOn": "2026-10-23", "amount": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "createdBy": { "id": "texto", "name": null } } ], "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidReason": null, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "account": { "balance": "texto", "openDocuments": 1 }, "registeredWith": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "total": "texto" } } } ``` # Resumir las cobranzas del mes > Devuelve el total de los recibos emitidos de un mes y cuántos son. GET`/api/v1/collections/summarize-month` * Permiso `collections.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `month`texto formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` ## Respuesta `200` con este JSON. * `month`textorequerido * `total`textorequerido * `count`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/collections/summarize-month" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/summarize-month`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "month": "texto", "total": "texto", "count": 1 } ``` # Ver el historial de un recibo > Lista los cambios de un recibo, sus medios de cobro y lo imputado o aplicado, del más nuevo al más viejo, campo por campo. GET`/api/v1/collections/get-history` * Permiso `collections.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `receiptId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/collections/get-history?receiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/get-history?receiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un recibo > Devuelve un recibo con su cliente tal como se registró, sus medios de cobro, lo imputado, lo que dejó a cuenta y sus aplicaciones posteriores, y su anulación. GET`/api/v1/collections/get` * Permiso `collections.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `receiptId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`enterorequerido * `name`textorequerido * `circuit`opciónrequerido Valores: `fiscal` `x` * `status`opciónrequerido Valores: `issued` `voided` * `receiptDate`fecharequerido * `customer`objetorequerido * `kinds`lista de opciónrequerido Valores: `cash` `transfer` `check` `echeq` `withholding` * `methodsText`textorequerido * `advanceBalance`textorequerido * `total`textorequerido * `version`enterorequerido mínimo 1 * `allocatedTotal`textorequerido * `advanceTotal`textorequerido * `isAdvance`sí o norequerido * `notes`cualquierarequerido * `methods`lista de objetorequerido * `allocations`lista de objetorequerido * `registeredAt`fecha y horarequerido * `registeredBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `account`objetorequeridoadmite null * `registeredWith`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `collections.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/collections/get?receiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/collections/get?receiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "circuit": "fiscal", "status": "issued", "receiptDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "address": "texto" }, "kinds": [ "cash" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "version": 1, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "notes": null, "methods": [ { "kind": "cash", "amount": "texto", "bankName": null, "reference": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "paymentDate": "2026-10-23", "tax": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "certificateNumber": null, "certificateDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "receipt", "allocatedOn": "2026-10-23", "amount": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "createdBy": { "id": "texto", "name": null } } ], "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidReason": null, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "account": { "balance": "texto", "openDocuments": 1 }, "registeredWith": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "total": "texto" } } ``` # Condiciones de pago > Las condiciones de pago con sus cuotas, para clientes y proveedores. Las condiciones de pago con sus cuotas, para clientes y proveedores. | Operación | Ruta | | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | [Listar condiciones de pago](/api/referencia/condiciones-de-pago/listar-condiciones-de-pago/) | GET `/api/v1/payment-terms/list` | | [Ver una condición de pago](/api/referencia/condiciones-de-pago/ver-una-condicion-de-pago/) | GET `/api/v1/payment-terms/get` | | [Crear una condición de pago](/api/referencia/condiciones-de-pago/crear-una-condicion-de-pago/) | POST `/api/v1/payment-terms/create` | | [Modificar una condición de pago](/api/referencia/condiciones-de-pago/modificar-una-condicion-de-pago/) | POST `/api/v1/payment-terms/update` | | [Reemplazar las cuotas](/api/referencia/condiciones-de-pago/reemplazar-las-cuotas/) | POST `/api/v1/payment-terms/update-installments` | | [Desactivar o reactivar una condición](/api/referencia/condiciones-de-pago/desactivar-o-reactivar-una-condicion/) | POST `/api/v1/payment-terms/set-status` | | [Simular vencimientos](/api/referencia/condiciones-de-pago/simular-vencimientos/) | GET `/api/v1/payment-terms/simulate` | | [Ver el historial de una condición](/api/referencia/condiciones-de-pago/ver-el-historial-de-una-condicion/) | GET `/api/v1/payment-terms/get-history` | # Crear una condición de pago > Crea una condición de pago con su nombre, su uso y sus cuotas. POST`/api/v1/payment-terms/create` * Permiso `payment-terms.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `name`textorequerido de 1 a 80 caracteres * `usage`opciónrequerido Valores: `customers` `suppliers` `both` * `prepaid`sí o no Por defecto: `false` * `installmentPlan`sí o norequerido * `installments`lista de objetorequerido al menos 1, hasta 36 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `usage`opciónrequerido Valores: `customers` `suppliers` `both` * `prepaid`sí o norequerido * `installmentPlan`sí o norequerido * `installments`lista de objetorequerido * `planSummary`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `usedAt`fecha y horarequeridoadmite null * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payment-terms/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "texto", "usage": "customers", "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "texto", "usage": "customers", "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "usage": "customers", "prepaid": false, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ], "planSummary": "texto", "status": "active", "statusReason": null, "usedAt": "2026-10-23T14:30:00.000Z", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar una condición > Desactiva o reactiva una condición de pago con un motivo opcional. POST`/api/v1/payment-terms/set-status` * Permiso `payment-terms.set-status` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `paymentTermId`uuidrequerido * `status`opciónrequerido Valores: `active` `inactive` * `reason`textoadmite null hasta 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `usage`opciónrequerido Valores: `customers` `suppliers` `both` * `prepaid`sí o norequerido * `installmentPlan`sí o norequerido * `installments`lista de objetorequerido * `planSummary`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `usedAt`fecha y horarequeridoadmite null * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.set-status`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payment-terms/set-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/set-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "usage": "customers", "prepaid": false, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ], "planSummary": "texto", "status": "active", "statusReason": null, "usedAt": "2026-10-23T14:30:00.000Z", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Listar condiciones de pago > Lista las condiciones de pago con búsqueda por nombre o código y filtros de estado y uso. GET`/api/v1/payment-terms/list` * Permiso `payment-terms.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `usage`opción Valores: `customers` `suppliers` `all`Por defecto: `all` * `sort`opción Valores: `name` `code`Por defecto: `name` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `paymentTerms`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payment-terms/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "paymentTerms": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "usage": "customers", "prepaid": false, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ], "planSummary": "texto", "status": "active", "statusReason": null, "usedAt": "2026-10-23T14:30:00.000Z", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ], "total": 1 } ``` # Modificar una condición de pago > Cambia el nombre, el uso y la marca de contado anticipado de una condición, con la versión leída. POST`/api/v1/payment-terms/update` * Permiso `payment-terms.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `paymentTermId`uuidrequerido * `version`enterorequerido mínimo 1 * `name`textorequerido de 1 a 80 caracteres * `usage`opciónrequerido Valores: `customers` `suppliers` `both` * `prepaid`sí o norequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `usage`opciónrequerido Valores: `customers` `suppliers` `both` * `prepaid`sí o norequerido * `installmentPlan`sí o norequerido * `installments`lista de objetorequerido * `planSummary`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `usedAt`fecha y horarequeridoadmite null * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payment-terms/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto", "usage": "customers", "prepaid": false }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto", "usage": "customers", "prepaid": false }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "usage": "customers", "prepaid": false, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ], "planSummary": "texto", "status": "active", "statusReason": null, "usedAt": "2026-10-23T14:30:00.000Z", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Reemplazar las cuotas > Reemplaza las cuotas de una condición de pago con la versión leída. POST`/api/v1/payment-terms/update-installments` * Permiso `payment-terms.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `paymentTermId`uuidrequerido * `version`enterorequerido mínimo 1 * `installmentPlan`sí o norequerido * `installments`lista de objetorequerido al menos 1, hasta 36 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `usage`opciónrequerido Valores: `customers` `suppliers` `both` * `prepaid`sí o norequerido * `installmentPlan`sí o norequerido * `installments`lista de objetorequerido * `planSummary`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `usedAt`fecha y horarequeridoadmite null * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payment-terms/update-installments" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/update-installments`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "usage": "customers", "prepaid": false, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ], "planSummary": "texto", "status": "active", "statusReason": null, "usedAt": "2026-10-23T14:30:00.000Z", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Simular vencimientos > Devuelve los vencimientos e importes de una condición para una fecha y un total de prueba, sin grabar nada. GET`/api/v1/payment-terms/simulate` * Permiso `payment-terms.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `paymentTermId`uuidrequerido * `invoiceDate`textorequerido * `total`númerorequerido mayor que 0, máximo 100000000000 ## Respuesta `200` con este JSON. * `invoiceDate`fecharequerido * `total`textorequerido * `currency`textorequerido * `installments`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payment-terms/simulate?paymentTermId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&invoiceDate=texto&total=100" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/simulate?paymentTermId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&invoiceDate=texto&total=100`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "invoiceDate": "2026-10-23", "total": "texto", "currency": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ] } ``` # Ver el historial de una condición > Lista los cambios de una condición de pago, del más nuevo al más viejo, campo por campo. GET`/api/v1/payment-terms/get-history` * Permiso `payment-terms.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `paymentTermId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payment-terms/get-history?paymentTermId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/get-history?paymentTermId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver una condición de pago > Devuelve una condición de pago con sus cuotas y cuántos registros la tienen asignada. GET`/api/v1/payment-terms/get` * Permiso `payment-terms.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `paymentTermId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `usage`opciónrequerido Valores: `customers` `suppliers` `both` * `prepaid`sí o norequerido * `installmentPlan`sí o norequerido * `installments`lista de objetorequerido * `planSummary`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `usedAt`fecha y horarequeridoadmite null * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `assignedCustomers`enterorequerido mínimo 0 * `assignedSuppliers`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payment-terms.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payment-terms/get?paymentTermId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payment-terms/get?paymentTermId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "usage": "customers", "prepaid": false, "installmentPlan": false, "installments": [ { "percent": 100, "dueDays": 1 } ], "planSummary": "texto", "status": "active", "statusReason": null, "usedAt": "2026-10-23T14:30:00.000Z", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "assignedCustomers": 1, "assignedSuppliers": 1 } ``` # Cuentas corrientes > Saldo, vencido y antigüedad de la deuda de cada cliente, con sus partidas. Saldo, vencido y antigüedad de la deuda de cada cliente, con sus partidas. | Operación | Ruta | | -------------------------------------------------------------------------------------------------- | ---------------------------------- | | [Listar cuentas de clientes](/api/referencia/cuentas-corrientes/listar-cuentas-de-clientes/) | GET `/api/v1/ledger/list-accounts` | | [Ver la cuenta de un cliente](/api/referencia/cuentas-corrientes/ver-la-cuenta-de-un-cliente/) | GET `/api/v1/ledger/get-account` | | [Listar partidas de un cliente](/api/referencia/cuentas-corrientes/listar-partidas-de-un-cliente/) | GET `/api/v1/ledger/list-items` | # Listar cuentas de clientes > Lista las cuentas de los clientes con partidas: saldo, antigüedad en cinco tramos (a vencer, 1 a 30, 31 a 60, 61 a 90 y más de 90 días) y lo que tienen a cuenta, con los totales de lo filtrado. Por defecto, los deudores con lo más vencido primero. GET`/api/v1/ledger/list-accounts` * Permiso `ledger.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `balance`opción Valores: `debtors` `overdue` `in-favor` `all`Por defecto: `debtors` * `sort`opción Valores: `overdue` `customer` `balance`Por defecto: `overdue` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` * `page`entero Por defecto: `1`mínimo 1, máximo 100000 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `accounts`lista de objetorequerido * `total`enterorequerido mínimo 0 * `totals`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `ledger.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/ledger/list-accounts" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/ledger/list-accounts`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "accounts": [ { "balance": "texto", "overdue": "texto", "onAccount": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" }, "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto" } } ], "total": 1, "totals": { "balance": "texto", "overdue": "texto", "onAccount": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" } } } ``` # Listar partidas de un cliente > Lista las partidas de un cliente, abiertas, canceladas o todas, cada una con su saldo, el saldo de la cuenta después de ella, cuánto está vencida, cómo se canceló y el número de su asiento. GET`/api/v1/ledger/list-items` * Permiso `ledger.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido * `status`opción Valores: `open` `cleared` `all`Por defecto: `open` * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` * `page`entero Por defecto: `1`mínimo 1, máximo 100000 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `items`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `ledger.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/ledger/list-items?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/ledger/list-items?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "items": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "debit", "source": { "kind": "invoice", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "number": null, "detail": null, "documentDate": "2026-10-23", "dueDate": "2026-10-23", "amount": "texto", "balance": "texto", "daysOverdue": 1, "runningBalance": "texto", "entryNumber": 1, "isAdvance": false, "entryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "allocatedOn": "2026-10-23", "amount": "texto", "source": { "kind": "invoice", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "detail": null }, "undoable": false, "undone": { "reason": "texto" }, "difference": null } ] } ], "total": 1 } ``` # Ver la cuenta de un cliente > Devuelve la cuenta de un cliente: saldo, vencido, a cuenta, antigüedad en cinco tramos, límite de crédito y si tiene partidas. GET`/api/v1/ledger/get-account` * Permiso `ledger.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido ## Respuesta `200` con este JSON. * `balance`textorequerido * `overdue`textorequerido * `onAccount`textorequerido * `advances`textorequerido * `aging`objetorequerido * `customer`objetorequerido * `creditLimit`cualquierarequerido * `hasItems`sí o norequerido * `circuits`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `ledger.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/ledger/get-account?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/ledger/get-account?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "balance": "texto", "overdue": "texto", "onAccount": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" }, "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto" }, "creditLimit": null, "hasItems": false, "circuits": { "fiscal": { "balance": "texto", "overdue": "texto", "onAccount": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" } }, "x": { "balance": "texto", "overdue": "texto", "onAccount": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" } } } } ``` # Cuentas de proveedores > Lo que la empresa debe a cada proveedor por moneda, con sus partidas. Lo que la empresa debe a cada proveedor por moneda, con sus partidas. | Operación | Ruta | | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------- | | [Listar cuentas de proveedores](/api/referencia/cuentas-de-proveedores/listar-cuentas-de-proveedores/) | GET `/api/v1/ledger/list-supplier-accounts` | | [Ver la cuenta de un proveedor](/api/referencia/cuentas-de-proveedores/ver-la-cuenta-de-un-proveedor/) | GET `/api/v1/ledger/get-supplier-account` | | [Listar partidas de un proveedor](/api/referencia/cuentas-de-proveedores/listar-partidas-de-un-proveedor/) | GET `/api/v1/ledger/list-supplier-items` | # Listar cuentas de proveedores > Lista lo que la empresa debe a cada proveedor, una fila por proveedor y moneda: saldo, antigüedad en cinco tramos y lo que hay a favor, con los totales por moneda. GET`/api/v1/ledger/list-supplier-accounts` * Permiso `ledger.view-suppliers` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `balance`opción Valores: `payable` `overdue` `in-favor` `all`Por defecto: `payable` * `currencyCode`textoadmite null formato \`^\[A-Z]{3}$\` * `sort`opción Valores: `overdue` `supplier` `balance`Por defecto: `overdue` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `page`entero Por defecto: `1`mínimo 1, máximo 100000 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `accounts`lista de objetorequerido * `total`enterorequerido mínimo 0 * `totals`lista de objetorequerido * `currencies`lista de textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `ledger.view-suppliers`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/ledger/list-supplier-accounts" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/ledger/list-supplier-accounts`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "accounts": [ { "currencyCode": "texto", "balance": "texto", "overdue": "texto", "inFavor": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "status": "active" } } ], "total": 1, "totals": [ { "currencyCode": "texto", "balance": "texto", "overdue": "texto", "inFavor": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" } } ], "currencies": [ "texto" ] } ``` # Listar partidas de un proveedor > Lista las partidas de un proveedor, abiertas, canceladas o todas, cada una con su moneda, su saldo, el saldo después de ella, cuánto está vencida y cómo se canceló. GET`/api/v1/ledger/list-supplier-items` * Permiso `ledger.view-suppliers` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido * `status`opción Valores: `open` `cleared` `all`Por defecto: `open` * `currencyCode`textoadmite null formato \`^\[A-Z]{3}$\` * `page`entero Por defecto: `1`mínimo 1, máximo 100000 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `items`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `ledger.view-suppliers`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/ledger/list-supplier-items?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/ledger/list-supplier-items?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "items": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "debit", "status": "active", "source": { "kind": "supplier-invoice", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "number": null, "detail": null, "documentDate": "2026-10-23", "dueDate": "2026-10-23", "currencyCode": "texto", "exchangeRate": null, "amount": "texto", "balance": "texto", "daysOverdue": 1, "runningBalance": null, "entryNumber": 1, "isAdvance": false, "entryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "allocatedOn": "2026-10-23", "amount": "texto", "source": { "kind": "texto", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "detail": null }, "reversal": { "reason": "texto", "undone": false }, "undoable": false, "difference": null } ] } ], "total": 1 } ``` # Ver la cuenta de un proveedor > Devuelve lo que la empresa debe a un proveedor en cada moneda: saldo, vencido, a favor y antigüedad en cinco tramos. GET`/api/v1/ledger/get-supplier-account` * Permiso `ledger.view-suppliers` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido ## Respuesta `200` con este JSON. * `supplier`objetorequerido * `accounts`lista de objetorequerido * `hasItems`sí o norequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `ledger.view-suppliers`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/ledger/get-supplier-account?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/ledger/get-supplier-account?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "status": "active" }, "accounts": [ { "currencyCode": "texto", "balance": "texto", "overdue": "texto", "inFavor": "texto", "advances": "texto", "aging": { "current": "texto", "days1to30": "texto", "days31to60": "texto", "days61to90": "texto", "over90": "texto" } } ], "hasItems": false } ``` # Datos de referencia > Alícuotas de IVA, unidades, jurisdicciones y feriados oficiales, comunes a toda la instalación. Alícuotas de IVA, unidades, jurisdicciones y feriados oficiales, comunes a toda la instalación. | Operación | Ruta | | --------------------------------------------------------------------------------------------- | ------------------------------------------------------ | | [Listar alícuotas de IVA](/api/referencia/datos-de-referencia/listar-alicuotas-de-iva/) | GET `/api/v1/reference-catalog/list-tax-rates` | | [Listar unidades de medida](/api/referencia/datos-de-referencia/listar-unidades-de-medida/) | GET `/api/v1/reference-catalog/list-units` | | [Listar jurisdicciones](/api/referencia/datos-de-referencia/listar-jurisdicciones/) | GET `/api/v1/reference-catalog/list-jurisdictions` | | [Listar feriados nacionales](/api/referencia/datos-de-referencia/listar-feriados-nacionales/) | GET `/api/v1/reference-catalog/list-national-holidays` | # Listar alícuotas de IVA > Lista las alícuotas oficiales de IVA de la instalación por código y vigencia, con su código de ARCA cuando está verificado y su fuente. GET`/api/v1/reference-catalog/list-tax-rates` * Permiso `reference-catalog.view` * Empresa No depende de la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). ## Respuesta `200` con este JSON. * `taxRates`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `reference-catalog.view`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/reference-catalog/list-tax-rates" \ -b sesion.txt ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/reference-catalog/list-tax-rates`, { headers: { Cookie: process.env.ERP_SESION!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "taxRates": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "tax": "texto", "code": "texto", "percentage": 100, "arcaId": 1, "validFrom": "2026-10-23", "validTo": "2026-10-23", "source": "texto", "sourceDate": "2026-10-23" } ] } ``` # Listar feriados nacionales > Lista los feriados y días no laborables nacionales de un año, por fecha, con su categoría oficial y su fuente. GET`/api/v1/reference-catalog/list-national-holidays` * Permiso `reference-catalog.view` * Empresa No depende de la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). ## Parámetros de la consulta * `year`enterorequerido mínimo 2000, máximo 2100 ## Respuesta `200` con este JSON. * `year`enterorequerido * `holidays`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `reference-catalog.view`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/reference-catalog/list-national-holidays?year=2000" \ -b sesion.txt ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/reference-catalog/list-national-holidays?year=2000`, { headers: { Cookie: process.env.ERP_SESION!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "year": 1, "holidays": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "date": "2026-10-23", "name": "texto", "category": "fixed", "originalDate": "2026-10-23", "source": "texto", "sourceDate": "2026-10-23" } ] } ``` # Listar jurisdicciones > Lista las jurisdicciones del Convenio Multilateral por código, con su fuente. GET`/api/v1/reference-catalog/list-jurisdictions` * Permiso `reference-catalog.view` * Empresa No depende de la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). ## Respuesta `200` con este JSON. * `jurisdictions`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `reference-catalog.view`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/reference-catalog/list-jurisdictions" \ -b sesion.txt ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/reference-catalog/list-jurisdictions`, { headers: { Cookie: process.env.ERP_SESION!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "jurisdictions": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": null, "name": "texto", "authority": null, "arbaLetter": null, "source": "texto", "sourceDate": "2026-10-23" } ] } ``` # Listar unidades de medida > Lista las unidades de medida estándar de la instalación por código, con si admiten decimales y su fuente. GET`/api/v1/reference-catalog/list-units` * Permiso `reference-catalog.view` * Empresa No depende de la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). ## Respuesta `200` con este JSON. * `units`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `reference-catalog.view`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/reference-catalog/list-units" \ -b sesion.txt ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/reference-catalog/list-units`, { headers: { Cookie: process.env.ERP_SESION!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "units": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "allowsDecimals": false, "arcaCode": null, "arbaCode": null, "source": "texto", "sourceDate": "2026-10-23" } ] } ``` # Depósitos > Depósitos con sus ubicaciones y la ubicación habitual de cada artículo. Depósitos con sus ubicaciones y la ubicación habitual de cada artículo. | Operación | Ruta | | ------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | | [Listar depósitos](/api/referencia/depositos/listar-depositos/) | GET `/api/v1/warehouses/list` | | [Ver un depósito](/api/referencia/depositos/ver-un-deposito/) | GET `/api/v1/warehouses/get` | | [Crear un depósito](/api/referencia/depositos/crear-un-deposito/) | POST `/api/v1/warehouses/create` | | [Modificar un depósito](/api/referencia/depositos/modificar-un-deposito/) | POST `/api/v1/warehouses/update` | | [Marcar el depósito general](/api/referencia/depositos/marcar-el-deposito-general/) | POST `/api/v1/warehouses/set-general` | | [Desactivar un depósito](/api/referencia/depositos/desactivar-un-deposito/) | POST `/api/v1/warehouses/deactivate` | | [Reactivar un depósito](/api/referencia/depositos/reactivar-un-deposito/) | POST `/api/v1/warehouses/reactivate` | | [Agregar una ubicación](/api/referencia/depositos/agregar-una-ubicacion/) | POST `/api/v1/warehouses/create-location` | | [Modificar una ubicación](/api/referencia/depositos/modificar-una-ubicacion/) | POST `/api/v1/warehouses/update-location` | | [Desactivar o reactivar una ubicación](/api/referencia/depositos/desactivar-o-reactivar-una-ubicacion/) | POST `/api/v1/warehouses/set-location-status` | | [Fijar la ubicación habitual](/api/referencia/depositos/fijar-la-ubicacion-habitual/) | POST `/api/v1/warehouses/set-usual-location` | | [Listar ubicaciones habituales](/api/referencia/depositos/listar-ubicaciones-habituales/) | GET `/api/v1/warehouses/list-usual-locations` | | [Descargar etiquetas de ubicaciones](/api/referencia/depositos/descargar-etiquetas-de-ubicaciones/) | POST `/api/v1/warehouses/print-location-labels` | | [Ver el historial de un depósito](/api/referencia/depositos/ver-el-historial-de-un-deposito/) | GET `/api/v1/warehouses/get-history` | # Agregar una ubicación > Agrega una ubicación a un depósito activo: código, nombre y si es la predeterminada. POST`/api/v1/warehouses/create-location` * Permiso `warehouses.manage-locations` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `code`textorequerido de 1 a 20 caracteres, formato \`^\[A-Z0-9.-]+$\` * `name`textorequerido de 1 a 80 caracteres * `isDefault`sí o no Por defecto: `false` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `warehouseId`uuidrequerido * `code`textorequerido * `name`textorequerido * `isDefault`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `usualItems`entero mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.manage-locations`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/create-location" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "ARS", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/create-location`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "ARS", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isDefault": false, "status": "texto", "version": 1, "usualItems": 1 } ``` # Crear un depósito > Crea un depósito con su primera ubicación. El primer depósito de la empresa es el general. POST`/api/v1/warehouses/create` * Permiso `warehouses.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `code`textorequerido de 1 a 10 caracteres, formato \`^\[A-Z0-9-]+$\` * `name`textorequerido de 1 a 80 caracteres * `street`textoadmite null hasta 200 caracteres * `streetNumber`textoadmite null hasta 20 caracteres * `city`textoadmite null hasta 120 caracteres * `provinceId`uuidadmite null * `postalCode`cualquiera * `firstLocationName`textoadmite null hasta 80 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `isGeneral`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `locations`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "code": "ARS", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "code": "ARS", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "isGeneral": false, "status": "texto", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "locations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isDefault": false, "status": "texto", "version": 1, "usualItems": 1 } ] } ``` # Desactivar o reactivar una ubicación > Desactiva o reactiva una ubicación de un depósito activo; nunca la predeterminada. POST`/api/v1/warehouses/set-location-status` * Permiso `warehouses.manage-locations` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `locationId`uuidrequerido * `version`enterorequerido mínimo 1 * `status`opciónrequerido Valores: `active` `inactive` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `warehouseId`uuidrequerido * `code`textorequerido * `name`textorequerido * `isDefault`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `usualItems`entero mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.manage-locations`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/set-location-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "locationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/set-location-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "locationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isDefault": false, "status": "texto", "version": 1, "usualItems": 1 } ``` # Desactivar un depósito > Desactiva un depósito con un motivo; nunca el general ni uno en uso. POST`/api/v1/warehouses/deactivate` * Permiso `warehouses.set-status` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `isGeneral`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.set-status`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/deactivate" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/deactivate`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "isGeneral": false, "status": "texto", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Descargar etiquetas de ubicaciones > Descarga un PDF con una etiqueta por ubicación activa de un depósito, con el QR de los códigos de depósito y ubicación. POST`/api/v1/warehouses/print-location-labels` * Permiso `warehouses.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta un PDF ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido ## Respuesta `200` con un PDF y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/print-location-labels" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/print-location-labels`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Fijar la ubicación habitual > Fija o quita la ubicación habitual de un artículo en un depósito sin WMS. POST`/api/v1/warehouses/set-usual-location` * Permiso `warehouses.manage-locations` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `itemId`uuidrequerido * `locationId`uuidrequeridoadmite null * `version`enterorequerido mínimo 0 ## Respuesta `200` con este JSON. * `warehouseId`uuidrequerido * `itemId`uuidrequerido * `locationId`uuidrequeridoadmite null * `version`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.manage-locations`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/set-usual-location" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "locationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/set-usual-location`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "locationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "locationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 } ``` # Listar depósitos > Lista los depósitos con búsqueda por código, nombre, calle, localidad o código postal y filtro de estado. GET`/api/v1/warehouses/list` * Permiso `warehouses.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `warehouses`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/warehouses/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "warehouses": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "address": null, "isGeneral": false, "status": "texto", "version": 1, "activeLocations": 1 } ], "total": 1 } ``` # Listar ubicaciones habituales > Lista los depósitos activos con sus ubicaciones activas y la ubicación habitual de un artículo en cada uno. GET`/api/v1/warehouses/list-usual-locations` * Permiso `warehouses.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `itemId`uuidrequerido ## Respuesta `200` con este JSON. * `warehouses`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/warehouses/list-usual-locations?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/list-usual-locations?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "warehouses": [ { "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isGeneral": false, "locations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" } ], "usual": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "version": 1 } ] } ``` # Marcar el depósito general > Hace general a un depósito y le saca la marca al anterior. POST`/api/v1/warehouses/set-general` * Permiso `warehouses.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `isGeneral`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/set-general" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/set-general`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "isGeneral": false, "status": "texto", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Modificar un depósito > Edita el código, el nombre y el domicilio de un depósito. POST`/api/v1/warehouses/update` * Permiso `warehouses.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `version`enterorequerido mínimo 1 * `code`textorequerido de 1 a 10 caracteres, formato \`^\[A-Z0-9-]+$\` * `name`textorequerido de 1 a 80 caracteres * `street`textoadmite null hasta 200 caracteres * `streetNumber`textoadmite null hasta 20 caracteres * `city`textoadmite null hasta 120 caracteres * `provinceId`uuidadmite null * `postalCode`cualquiera ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `isGeneral`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "code": "ARS", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "code": "ARS", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "isGeneral": false, "status": "texto", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Modificar una ubicación > Edita el código y el nombre de una ubicación y puede hacerla la predeterminada de su depósito. POST`/api/v1/warehouses/update-location` * Permiso `warehouses.manage-locations` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `locationId`uuidrequerido * `version`enterorequerido mínimo 1 * `code`textorequerido de 1 a 20 caracteres, formato \`^\[A-Z0-9.-]+$\` * `name`textorequerido de 1 a 80 caracteres * `isDefault`sí o no ## Respuesta `200` con este JSON. * `id`uuidrequerido * `warehouseId`uuidrequerido * `code`textorequerido * `name`textorequerido * `isDefault`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `usualItems`entero mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.manage-locations`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/update-location" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "locationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "code": "ARS", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/update-location`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "locationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "code": "ARS", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isDefault": false, "status": "texto", "version": 1, "usualItems": 1 } ``` # Reactivar un depósito > Reactiva un depósito inactivo. POST`/api/v1/warehouses/reactivate` * Permiso `warehouses.set-status` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `isGeneral`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.set-status`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/warehouses/reactivate" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/reactivate`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "isGeneral": false, "status": "texto", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Ver el historial de un depósito > Lista los cambios de un depósito y sus ubicaciones, del más nuevo al más viejo, campo por campo. GET`/api/v1/warehouses/get-history` * Permiso `warehouses.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `warehouseId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/warehouses/get-history?warehouseId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/get-history?warehouseId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un depósito > Devuelve un depósito con sus ubicaciones. GET`/api/v1/warehouses/get` * Permiso `warehouses.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `warehouseId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `isGeneral`sí o norequerido * `status`textorequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `locations`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `warehouses.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/warehouses/get?warehouseId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/warehouses/get?warehouseId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "isGeneral": false, "status": "texto", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "locations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isDefault": false, "status": "texto", "version": 1, "usualItems": 1 } ] } ``` # Diario > Asientos, mayor de una cuenta, conciliación con los auxiliares y operaciones X. Asientos, mayor de una cuenta, conciliación con los auxiliares y operaciones X. | Operación | Ruta | | ------------------------------------------------------------------------------------------ | -------------------------------------------- | | [Listar asientos](/api/referencia/diario/listar-asientos/) | GET `/api/v1/accounting/list-entries` | | [Ver un asiento](/api/referencia/diario/ver-un-asiento/) | GET `/api/v1/accounting/get-entry` | | [Listar asientos de un documento](/api/referencia/diario/listar-asientos-de-un-documento/) | GET `/api/v1/accounting/list-source-entries` | | [Ver el mayor de una cuenta](/api/referencia/diario/ver-el-mayor-de-una-cuenta/) | GET `/api/v1/accounting/get-account-ledger` | | [Conciliar con los auxiliares](/api/referencia/diario/conciliar-con-los-auxiliares/) | GET `/api/v1/accounting/get-reconciliation` | | [Ver las operaciones X del mes](/api/referencia/diario/ver-las-operaciones-x-del-mes/) | GET `/api/v1/accounting/list-x-operations` | # Conciliar con los auxiliares > Concilia a una fecha el valor del stock y las cuentas de clientes y proveedores contra sus cuentas del diario, con lo que explica cada diferencia. GET`/api/v1/accounting/get-reconciliation` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `date`fecha * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` ## Respuesta `200` con este JSON. * `date`fecharequerido * `circuit`opciónrequerido Valores: `all` `fiscal` `x` * `lines`lista de objetorequerido * `stock`lista de objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/get-reconciliation" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/get-reconciliation`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "date": "2026-10-23", "circuit": "all", "lines": [ { "key": "stock", "label": "texto", "accounts": "texto", "subledger": "texto", "account": "texto", "difference": "texto", "pending": "texto", "beforeOpening": "texto", "unexplained": "texto" } ], "stock": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "value": "texto" } ] } ``` # Listar asientos > Lista los asientos del diario, del más nuevo al más viejo, con filtros de fecha, hecho, estado, cuenta y circuito. GET`/api/v1/accounting/list-entries` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`texto hasta 80 caracteres * `from`fecha * `to`fecha * `fact`texto hasta 60 caracteres * `status`opción Valores: `registered` `pending` * `accountId`uuid * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `entries`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/list-entries" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/list-entries`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "entries": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "numberText": "texto", "accountingDate": "2026-10-23", "source": { "kind": "texto", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "fact": "texto", "status": "registered", "fiscalMark": "fiscal", "reversesEntryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reversedByEntryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedBy": "texto", "recordedByName": null, "recordedChannel": "texto", "recordedAt": "2026-10-23T14:30:00.000Z", "total": "texto" } ], "total": 1 } ``` # Listar asientos de un documento > Lista los asientos que dejó un documento y los que los revierten, cada uno con sus líneas. GET`/api/v1/accounting/list-source-entries` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `sourceKind`textorequerido de 1 a 60 caracteres * `sourceId`uuidrequerido ## Respuesta `200` con este JSON. * `entries`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/list-source-entries?sourceKind=texto&sourceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/list-source-entries?sourceKind=texto&sourceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "entries": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "numberText": "texto", "accountingDate": "2026-10-23", "source": { "kind": "texto", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "fact": "texto", "status": "registered", "fiscalMark": "fiscal", "reversesEntryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reversedByEntryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedBy": "texto", "recordedByName": null, "recordedChannel": "texto", "recordedAt": "2026-10-23T14:30:00.000Z", "total": "texto", "lines": [ { "position": 1, "role": "texto", "key": null, "account": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "partyName": null, "debit": "texto", "credit": "texto", "currencyCode": null, "foreignAmount": null, "exchangeRate": null, "description": "texto" } ] } ] } ``` # Ver el mayor de una cuenta > Devuelve el mayor de una cuenta entre dos fechas, con el saldo acumulado de cada línea. GET`/api/v1/accounting/get-account-ledger` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `accountId`uuidrequerido * `from`fecha * `to`fecha * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `account`objetorequerido * `openingBalance`textorequerido * `lines`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/get-account-ledger?accountId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/get-account-ledger?accountId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "account": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "type": "asset", "postable": false, "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" }, "openingBalance": "texto", "lines": [ { "entryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "numberText": "texto", "position": 1, "accountingDate": "2026-10-23", "source": { "kind": "texto", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "fact": "texto", "description": "texto", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "debit": "texto", "credit": "texto", "balance": "texto" } ], "total": 1 } ``` # Ver las operaciones X del mes > Devuelve las operaciones X de un mes separadas de las fiscales (ventas y notas de crédito a su neto, cobranzas y salidas de stock), con los totales de cada circuito, desde los asientos. GET`/api/v1/accounting/list-x-operations` * Permiso `documents.view-x` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `month`textorequerido formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` ## Respuesta `200` con este JSON. * `month`textorequerido * `from`fecharequerido * `to`fecharequerido * `totals`objetorequerido * `operations`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.view-x`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/list-x-operations?month=2026-10" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/list-x-operations?month=2026-10`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "month": "texto", "from": "2026-10-23", "to": "2026-10-23", "totals": { "fiscal": { "sales": "texto", "credit-notes": "texto", "collections": "texto", "stock-exits": "texto" }, "x": { "sales": "texto", "credit-notes": "texto", "collections": "texto", "stock-exits": "texto" } }, "operations": [ { "category": "sales", "accountingDate": "2026-10-23", "entry": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "numberText": "texto" }, "source": { "kind": "texto", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto" }, "amount": "texto" } ] } ``` # Ver un asiento > Devuelve un asiento, por id o por número, con sus líneas. GET`/api/v1/accounting/get-entry` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `entryId`uuid * `number`entero mínimo 1 ## Respuesta `200` con este JSON. * `entry`objetorequerido * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/get-entry" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/get-entry`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "entry": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "numberText": "texto", "accountingDate": "2026-10-23", "source": { "kind": "texto", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto" }, "fact": "texto", "status": "registered", "fiscalMark": "fiscal", "reversesEntryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reversedByEntryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedBy": "texto", "recordedByName": null, "recordedChannel": "texto", "recordedAt": "2026-10-23T14:30:00.000Z", "total": "texto" }, "lines": [ { "position": 1, "role": "texto", "key": null, "account": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "partyName": null, "debit": "texto", "credit": "texto", "currencyCode": null, "foreignAmount": null, "exchangeRate": null, "description": "texto" } ] } ``` # Empresa > Las empresas a las que accede la credencial y la ficha de la empresa activa. Las empresas a las que accede la credencial y la ficha de la empresa activa. | Operación | Ruta | | --------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | | [Listar empresas](/api/referencia/empresa/listar-empresas/) | GET `/api/v1/companies/list` | | [Elegir la empresa activa](/api/referencia/empresa/elegir-la-empresa-activa/) | POST `/api/v1/companies/select-active` | | [Ver la empresa activa](/api/referencia/empresa/ver-la-empresa-activa/) | GET `/api/v1/companies/get` | | [Ver la identidad en impresos](/api/referencia/empresa/ver-la-identidad-en-impresos/) | GET `/api/v1/companies/get-branding` | | [Ver la inscripción como agente de ARBA](/api/referencia/empresa/ver-la-inscripcion-como-agente-de-arba/) | GET `/api/v1/companies/get-agent-registration` | # Elegir la empresa activa > Fija la empresa activa de la sesión, si el usuario tiene acceso a ella. Las operaciones de empresa trabajan sobre esa empresa. POST`/api/v1/companies/select-active` * Permiso `companies.select-active` * Empresa No depende de la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `companyId`uuidrequerido ## Respuesta `200` con este JSON. * `activeCompanyId`uuidrequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `companies.select-active`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/companies/select-active" \ -b sesion.txt \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "companyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/companies/select-active`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "companyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "activeCompanyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Listar empresas > Lista las empresas de la instalación a las que accede el usuario, con búsqueda por razón social o CUIT y filtro por estado. GET`/api/v1/companies/list` * Permiso `companies.list` * Empresa No depende de la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `companies`lista de objetorequerido * `total`enterorequerido mínimo 0 * `counts`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `companies.list`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/companies/list" \ -b sesion.txt ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/companies/list`, { headers: { Cookie: process.env.ERP_SESION!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "companies": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "cuit": "texto", "vatCondition": null, "status": "texto", "activePointsOfSale": 1 } ], "total": 1, "counts": { "active": 1, "inactive": 1, "all": 1 } } ``` # Ver la empresa activa > Devuelve la ficha de la empresa activa: identificación, condición fiscal, ingresos brutos, domicilio fiscal, contacto, puntos de venta y monedas. GET`/api/v1/companies/get` * Permiso `companies.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Respuesta `200` con este JSON. * `id`uuidrequerido * `cuit`textorequerido * `legalName`textorequerido * `status`textorequerido * `createdAt`fecha y horarequerido * `version`enterorequerido mínimo 1 * `vatCondition`cualquierarequerido * `fiscalYearStartMonth`enterorequeridoadmite null mínimo 1, máximo 12 * `tradeName`cualquierarequerido * `activityStartDate`fecharequeridoadmite null * `registryNumber`cualquierarequerido * `iibbCondition`cualquierarequerido * `iibbNumber`cualquierarequerido * `iibbJurisdictionId`uuidrequeridoadmite null * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `website`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `pointsOfSale`lista de objetorequerido * `currencies`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `companies.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/companies/get" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/companies/get`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cuit": "texto", "legalName": "texto", "status": "texto", "createdAt": "2026-10-23T14:30:00.000Z", "version": 1, "vatCondition": null, "fiscalYearStartMonth": 1, "tradeName": null, "activityStartDate": "2026-10-23", "registryNumber": null, "iibbCondition": null, "iibbNumber": null, "iibbJurisdictionId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "email": null, "phone": null, "website": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "pointsOfSale": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto", "issuanceType": "texto", "address": null, "isDefault": false, "status": "texto", "deliveryNoteCai": null, "deliveryNoteCaiExpiry": "2026-10-23", "deliveryNotePrinter": null, "version": 1 } ], "currencies": [ { "currencyCode": "tex", "status": "texto", "enabledAt": "2026-10-23T14:30:00.000Z" } ] } ``` # Ver la identidad en impresos > Devuelve cómo se ve la empresa activa en sus impresos: logo, color, si se muestra el logo y el formato. Es nulo mientras no tenga ninguna. GET`/api/v1/companies/get-branding` * Permiso `companies.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Respuesta `200` con este JSON. * `branding`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `companies.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/companies/get-branding" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/companies/get-branding`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "branding": { "hasLogo": false, "logoType": null, "logoDataUrl": null, "color": null, "showLogo": false, "printLayout": "standard", "version": 1 } } ``` # Ver la inscripción como agente de ARBA > Devuelve desde qué fecha la empresa activa percibe como agente de percepción de ARBA, o nada si no es agente. GET`/api/v1/companies/get-agent-registration` * Permiso `companies.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Respuesta `200` con este JSON. * `registration`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `companies.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/companies/get-agent-registration" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/companies/get-agent-registration`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "registration": { "regime": "arba-perception", "validFrom": "2026-10-23", "version": 1 } } ``` # Entregas > Remitos que sacan la mercadería del depósito contra los pedidos confirmados, con su COT cuando corresponde. Remitos que sacan la mercadería del depósito contra los pedidos confirmados, con su COT cuando corresponde. | Operación | Ruta | | ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | [Listar remitos](/api/referencia/entregas/listar-remitos/) | GET `/api/v1/deliveries/list` | | [Ver un remito](/api/referencia/entregas/ver-un-remito/) | GET `/api/v1/deliveries/get` | | [Listar lo pendiente de entregar](/api/referencia/entregas/listar-lo-pendiente-de-entregar/) | GET `/api/v1/deliveries/list-pending` | | [Listar líneas para entregar de un cliente](/api/referencia/entregas/listar-lineas-para-entregar-de-un-cliente/) | GET `/api/v1/deliveries/list-deliverable-lines` | | [Preparar un remito](/api/referencia/entregas/preparar-un-remito/) | POST `/api/v1/deliveries/prepare` | | [Modificar un remito en borrador](/api/referencia/entregas/modificar-un-remito-en-borrador/) | POST `/api/v1/deliveries/update` | | [Ver qué falta para emitir un remito](/api/referencia/entregas/ver-que-falta-para-emitir-un-remito/) | GET `/api/v1/deliveries/issue-readiness` | | [Emitir un remito](/api/referencia/entregas/emitir-un-remito/) | POST `/api/v1/deliveries/issue` | | [Descartar un remito](/api/referencia/entregas/descartar-un-remito/) | POST `/api/v1/deliveries/discard` | | [Revertir un remito](/api/referencia/entregas/revertir-un-remito/) | POST `/api/v1/deliveries/revert` | | [Listar pedidos para entregar (backorders)](/api/referencia/entregas/listar-pedidos-para-entregar-backorders/) | GET `/api/v1/deliveries/list-deliverable-orders` | | [Ver qué falta para generar remitos](/api/referencia/entregas/ver-que-falta-para-generar-remitos/) | GET `/api/v1/deliveries/generate-readiness` | | [Generar remitos de backorders](/api/referencia/entregas/generar-remitos-de-backorders/) | POST `/api/v1/deliveries/generate` | | [Reintentar el COT](/api/referencia/entregas/reintentar-el-cot/) | POST `/api/v1/deliveries/retry-cot` | | [Registrar un COT sacado a mano](/api/referencia/entregas/registrar-un-cot-sacado-a-mano/) | POST `/api/v1/deliveries/record-cot` | | [Descargar el PDF de un remito](/api/referencia/entregas/descargar-el-pdf-de-un-remito/) | POST `/api/v1/deliveries/print` | | [Ver el historial de un remito](/api/referencia/entregas/ver-el-historial-de-un-remito/) | GET `/api/v1/deliveries/get-history` | # Descargar el PDF de un remito > Descarga el PDF de un remito emitido con su CAI, en el formulario que eligió la empresa: el estándar sin precios en original y duplicado, o el clásico valorizado en tres copias. POST`/api/v1/deliveries/print` * Permiso `deliveries.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta un PDF ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `deliveryId`uuidrequerido ## Respuesta `200` con un PDF y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/print" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/print`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Descartar un remito > Descarta un remito en borrador con un motivo: libera su reserva y lo que retenía de los pedidos. Conserva su número interno. POST`/api/v1/deliveries/discard` * Permiso `deliveries.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `deliveryId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/discard" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/discard`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] } } ``` # Emitir un remito > Emite un remito en borrador con la versión leída: toma el número legal, saca el stock al costo promedio consumiendo la reserva y entrega lo retenido de los pedidos. Con la política de COT y un tramo en Buenos Aires, pide el COT a ARBA y responde el resultado. POST`/api/v1/deliveries/issue` * Permiso `deliveries.issue` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `deliveryId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null * `cotOutcome`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `cotOutcomeMessage`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/issue" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/issue`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] }, "cotOutcome": "not-required", "cotOutcomeMessage": "texto" } ``` # Generar remitos de backorders > Genera los remitos de backorders, todos o ninguno: uno por cliente con sus líneas pendientes, desde un depósito y con una fecha. Cada uno se prepara y se emite como un remito suelto, y después se pide el COT de los que lo necesitan. POST`/api/v1/deliveries/generate` * Permiso `deliveries.issue` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuid * `documentDate`fecha * `deliveries`lista de objetorequerido al menos 1, hasta 30 ## Respuesta `200` con este JSON. * `deliveries`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/generate" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "deliveries": [ { "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryMethod": "transport", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/generate`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "deliveries": [ { "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryMethod": "transport", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "deliveries": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": null, "item": null, "quantity": null } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] }, "cotOutcome": "not-required", "cotOutcomeMessage": "texto" } ] } ``` # Listar líneas para entregar de un cliente > Lista las líneas con inventario de los pedidos confirmados de un cliente pendientes de entrega, con lo entregado, lo retenido por remitos sin emitir y lo disponible en el depósito. GET`/api/v1/deliveries/list-deliverable-lines` * Permiso `deliveries.prepare` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido * `warehouseId`uuid * `salesOrderIds`lista de uuidadmite null * `deliveryId`uuidadmite null ## Respuesta `200` con este JSON. * `lines`lista de objetorequerido * `warehouse`objetorequerido * `warehouses`lista de objetorequerido * `pointsOfSale`lista de objetorequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/list-deliverable-lines?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/list-deliverable-lines?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "lines": [ { "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "confirmedAt": "2026-10-23" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "position": 1, "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "lineKind": "sale", "quantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "heldByDelivery": 100, "pendingQuantity": 100, "availableQuantity": 100 } ], "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "warehouses": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isGeneral": false } ], "pointsOfSale": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto", "isDefault": false, "x": false, "cai": "valid" } ], "today": "2026-10-23" } ``` # Listar lo pendiente de entregar > Lista lo pendiente de entrega de los pedidos confirmados, por línea y en orden de entrega (fecha de confirmación), con lo que retienen los remitos sin emitir y el stock disponible de un depósito. GET`/api/v1/deliveries/list-pending` * Permiso `deliveries.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `customerId`uuidadmite null * `itemId`uuidadmite null * `warehouseId`uuidadmite null * `confirmedFrom`fechaadmite null * `confirmedTo`fechaadmite null * `sort`opción Valores: `confirmed` `customer` `item`Por defecto: `confirmed` * `direction`opción Valores: `asc` `desc`Por defecto: `asc` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `lines`lista de objetorequerido * `total`enterorequerido mínimo 0 * `warehouse`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/list-pending" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/list-pending`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "lines": [ { "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "confirmedAt": "2026-10-23" }, "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "pendingQuantity": 100, "inDeliveryQuantity": 100, "availableQuantity": 100 } ], "total": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" } } ``` # Listar pedidos para entregar (backorders) > Lista los pedidos confirmados con algo pendiente de entrega, en orden de confirmación, con el destino del cliente, las unidades pendientes y cuántas posiciones cubre el stock disponible de un depósito, asignado primero a los pedidos más viejos. GET`/api/v1/deliveries/list-deliverable-orders` * Permiso `deliveries.prepare` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `customerId`uuidadmite null * `warehouseId`uuidadmite null * `confirmedFrom`fechaadmite null * `confirmedTo`fechaadmite null ## Respuesta `200` con este JSON. * `orders`lista de objetorequerido * `warehouse`objetorequerido * `warehouses`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/list-deliverable-orders" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/list-deliverable-orders`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "orders": [ { "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "confirmedAt": "2026-10-23" }, "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto" }, "destination": { "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "city": "texto" }, "partiallyDelivered": false, "pendingQuantity": 100, "deliveredPercent": 1, "positions": 1, "coveredPositions": 1, "coveredPercent": 1, "coverage": "complete" } ], "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "warehouses": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isGeneral": false } ] } ``` # Listar remitos > Lista los remitos de la empresa activa con búsqueda por número o cliente y filtros de estado, reversión, facturación, forma de entrega, depósito, cliente, pedido y fechas. Por defecto trae todos menos los descartados. GET`/api/v1/deliveries/list` * Permiso `deliveries.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `status`lista de opciónadmite null Valores: `draft` `issued` `discarded` * `reversal`lista de opciónadmite null Valores: `partial` `total` * `invoicing`opciónadmite null Valores: `pending` * `deliveryMethod`lista de opciónadmite null Valores: `transport` `own-fleet` `customer-pickup` * `cot`lista de opciónadmite null Valores: `pending` `rejected` * `warehouseId`uuidadmite null * `customerId`uuidadmite null * `salesOrderId`uuidadmite null * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `sort`opción Valores: `number` `date` `customer`Por defecto: `date` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `deliveries`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "deliveries": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal" } ], "total": 1 } ``` # Modificar un remito en borrador > Edita un remito en borrador con la versión leída: sus datos y líneas. Se reemplazan su reserva y lo que retiene de los pedidos. POST`/api/v1/deliveries/update` * Permiso `deliveries.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `deliveryId`uuidrequerido * `version`enterorequerido mínimo 1 * `customerId`uuidrequerido * `warehouseId`uuid * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `recipientId`uuidadmite null * `pointOfSaleId`uuid * `documentDate`fecha * `notes`textoadmite null hasta 500 caracteres * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryMethod": "transport", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryMethod": "transport", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] } } ``` # Preparar un remito > Prepara un remito en borrador con líneas pendientes de pedidos confirmados de un cliente, desde un depósito, con su forma de entrega y su destino. El borrador reserva el stock que lleva. POST`/api/v1/deliveries/prepare` * Permiso `deliveries.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `warehouseId`uuid * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `recipientId`uuidadmite null * `pointOfSaleId`uuid * `documentDate`fecha * `notes`textoadmite null hasta 500 caracteres * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/prepare" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryMethod": "transport", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/prepare`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryMethod": "transport", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] } } ``` # Registrar un COT sacado a mano > Registra el COT obtenido en la web de ARBA para un remito con el COT pendiente o rechazado, con un motivo. No llama a ARBA. POST`/api/v1/deliveries/record-cot` * Permiso `deliveries.issue` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `deliveryId`uuidrequerido * `cotNumber`textorequerido * `reason`textorequerido de 1 a 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null * `cotOutcome`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `cotOutcomeMessage`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/record-cot" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cotNumber": "texto", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/record-cot`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cotNumber": "texto", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] }, "cotOutcome": "not-required", "cotOutcomeMessage": "texto" } ``` # Reintentar el COT > Vuelve a pedir a ARBA el COT de un remito emitido con el COT pendiente o rechazado, con los datos maestros actuales y el destino con que se emitió. POST`/api/v1/deliveries/retry-cot` * Permiso `deliveries.issue` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `deliveryId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null * `cotOutcome`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `cotOutcomeMessage`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/retry-cot" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/retry-cot`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] }, "cotOutcome": "not-required", "cotOutcomeMessage": "texto" } ``` # Revertir un remito > Revierte un remito emitido, total o por líneas, con un motivo: el stock vuelve a entrar al costo de su salida y las cantidades revertidas quedan otra vez pendientes de entrega. POST`/api/v1/deliveries/revert` * Permiso `deliveries.revert` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `deliveryId`uuidrequerido * `reason`textorequerido de 1 a 300 caracteres * `lines`lista de objeto al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.revert`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/deliveries/revert" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/revert`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] } } ``` # Ver el historial de un remito > Lista los cambios de un remito, su entrega, sus líneas y sus reversiones, del más nuevo al más viejo, campo por campo. GET`/api/v1/deliveries/get-history` * Permiso `deliveries.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `deliveryId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/get-history?deliveryId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/get-history?deliveryId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver qué falta para emitir un remito > Dice todo lo que falta para emitir un remito en borrador, en el orden en que lo controla la emisión: el CAI del punto de venta, los datos de la empresa, el domicilio del cliente y, si pide COT, su clave y datos. GET`/api/v1/deliveries/issue-readiness` * Permiso `deliveries.issue` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `deliveryId`uuidrequerido ## Respuesta `200` con este JSON. * `cotRequired`sí o norequerido * `hasKey`sí o norequerido * `missing`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/issue-readiness?deliveryId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/issue-readiness?deliveryId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "cotRequired": false, "hasKey": false, "missing": [ { "text": "texto", "href": null } ] } ``` # Ver qué falta para generar remitos > Dice todo lo que le falta a un remito de backorders, todavía no generado, para poder emitirse: el CAI del punto de venta, los datos de la empresa, el domicilio del cliente y, si pide COT, su clave y datos. GET`/api/v1/deliveries/generate-readiness` * Permiso `deliveries.issue` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `recipientId`uuidadmite null * `pointOfSaleId`uuidadmite null * `warehouseId`uuidadmite null * `documentDate`fechaadmite null * `salesOrderLineIds`lista de uuidadmite null ## Respuesta `200` con este JSON. * `cotRequired`sí o norequerido * `hasKey`sí o norequerido * `missing`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/generate-readiness?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&deliveryMethod=transport" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/generate-readiness?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&deliveryMethod=transport`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "cotRequired": false, "hasKey": false, "missing": [ { "text": "texto", "href": null } ] } ``` # Ver un remito > Devuelve un remito con su cliente, destino, depósito, líneas con lo revertido y facturado, sus reversiones y las facturas que lo toman. GET`/api/v1/deliveries/get` * Permiso `deliveries.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `deliveryId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `deliveryNoteId`uuidrequerido * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `status`opciónrequerido Valores: `draft` `issued` `discarded` * `deliveryStatus`opciónrequerido Valores: `open` `closed` `annulled` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `documentDate`fecharequerido * `customer`objetorequerido * `deliveryMethod`opciónrequerido Valores: `transport` `own-fleet` `customer-pickup` * `destination`objetorequerido * `warehouse`objetorequerido * `pendingInvoice`sí o norequerido * `cotStatus`opciónrequerido Valores: `not-required` `pending` `granted` `rejected` * `circuit`opciónrequerido Valores: `fiscal` `x` * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `cai`cualquierarequerido * `caiExpiry`fecharequeridoadmite null * `notes`cualquierarequerido * `lines`lista de objetorequerido * `reversals`lista de objetorequerido * `invoices`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `cot`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `deliveries.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/deliveries/get?deliveryId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/deliveries/get?deliveryId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1, "legalNumber": 1, "status": "draft", "deliveryStatus": "open", "reversal": "none", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "deliveryMethod": "transport", "destination": { "kind": "recipient", "recipientId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "address": "texto", "city": "texto", "receiverName": null, "carrierTaxId": null }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "pendingInvoice": false, "cotStatus": "not-required", "circuit": "fiscal", "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto" }, "cai": null, "caiExpiry": "2026-10-23", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "description": "texto", "quantity": 100, "revertedQuantity": 100, "invoicedQuantity": 100, "pendingInvoiceQuantity": 100 } ], "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "quantity": 100 } ] } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto" } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "cot": { "status": "not-required", "number": null, "source": "arba", "message": null, "inProgress": false, "submissions": [ { "attempt": 1, "result": "granted", "cotNumber": null, "message": null, "createdAt": "2026-10-23T14:30:00.000Z" } ] } } ``` # Facturación > Facturas y notas de crédito autorizadas por ARCA, desde los pedidos o los remitos. Facturas y notas de crédito autorizadas por ARCA, desde los pedidos o los remitos. | Operación | Ruta | | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | | [Listar comprobantes](/api/referencia/facturacion/listar-comprobantes/) | GET `/api/v1/documents/list` | | [Ver un comprobante](/api/referencia/facturacion/ver-un-comprobante/) | GET `/api/v1/documents/get` | | [Listar el pool de facturación](/api/referencia/facturacion/listar-el-pool-de-facturacion/) | GET `/api/v1/documents/list-billable` | | [Generar facturas desde el pool](/api/referencia/facturacion/generar-facturas-desde-el-pool/) | POST `/api/v1/documents/generate-invoices` | | [Listar lo facturable de un cliente](/api/referencia/facturacion/listar-lo-facturable-de-un-cliente/) | GET `/api/v1/documents/list-invoiceable-lines` | | [Preparar una factura](/api/referencia/facturacion/preparar-una-factura/) | POST `/api/v1/documents/create-invoice` | | [Preparar una nota de crédito](/api/referencia/facturacion/preparar-una-nota-de-credito/) | POST `/api/v1/documents/create-credit-note` | | [Modificar un comprobante en borrador](/api/referencia/facturacion/modificar-un-comprobante-en-borrador/) | POST `/api/v1/documents/update-draft` | | [Emitir una factura](/api/referencia/facturacion/emitir-una-factura/) | POST `/api/v1/documents/issue-invoice` | | [Emitir una nota de crédito](/api/referencia/facturacion/emitir-una-nota-de-credito/) | POST `/api/v1/documents/issue-credit-note` | | [Reintentar comprobantes pendientes](/api/referencia/facturacion/reintentar-comprobantes-pendientes/) | POST `/api/v1/documents/retry` | | [Descartar un comprobante en borrador](/api/referencia/facturacion/descartar-un-comprobante-en-borrador/) | POST `/api/v1/documents/discard` | | [Modificar las notas de un comprobante](/api/referencia/facturacion/modificar-las-notas-de-un-comprobante/) | POST `/api/v1/documents/update-notes` | | [Descargar el PDF de un comprobante](/api/referencia/facturacion/descargar-el-pdf-de-un-comprobante/) | POST `/api/v1/documents/download-pdf` | | [Resumir las ventas del mes](/api/referencia/facturacion/resumir-las-ventas-del-mes/) | GET `/api/v1/documents/summarize-sales` | | [Ver el historial de un comprobante](/api/referencia/facturacion/ver-el-historial-de-un-comprobante/) | GET `/api/v1/documents/get-history` | # Descargar el PDF de un comprobante > Descarga el PDF de una factura o nota de crédito autorizada en el formato de ARCA (RG 1415) con su QR, el logo de la empresa y el formulario que eligió la empresa. POST`/api/v1/documents/download-pdf` * Permiso `documents.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta un PDF ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido ## Respuesta `200` con un PDF y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/download-pdf" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/download-pdf`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Descartar un comprobante en borrador > Descarta una factura o nota de crédito en borrador con la versión leída: conserva su número interno y libera lo que retenía de los pedidos. POST`/api/v1/documents/discard` * Permiso `documents.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/discard" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/discard`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" } } ``` # Emitir una factura > Emite una factura en borrador con la versión leída: fija cliente, alícuotas y vencimientos, pide a ARCA el CAE y el número legal, y responde la factura con el resultado: autorizada, rechazada (vuelve a borrador) o pendiente de autorización. POST`/api/v1/documents/issue-invoice` * Permiso `documents.issue` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null * `outcome`opciónrequerido Valores: `authorized` `rejected` `pending` * `message`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/issue-invoice" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/issue-invoice`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" }, "outcome": "authorized", "message": "texto" } ``` # Emitir una nota de crédito > Emite una nota de crédito en borrador con la versión leída, controla otra vez que no acredite más de lo que le queda a la factura y pide a ARCA su CAE. POST`/api/v1/documents/issue-credit-note` * Permiso `documents.issue-credit-note` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null * `outcome`opciónrequerido Valores: `authorized` `rejected` `pending` * `message`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.issue-credit-note`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/issue-credit-note" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/issue-credit-note`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" }, "outcome": "authorized", "message": "texto" } ``` # Generar facturas desde el pool > Genera las facturas del pool de facturación, todas o ninguna: una por cliente con líneas de sus remitos y pedidos, con una fecha y un punto de venta. Cada una se prepara y se emite como una factura suelta y después se pide el CAE de cada una. POST`/api/v1/documents/generate-invoices` * Permiso `documents.issue` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentDate`fecha * `invoices`lista de objetorequerido al menos 1, hasta 30 ## Respuesta `200` con este JSON. * `invoices`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/generate-invoices" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "invoices": [ { "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ] } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/generate-invoices`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "invoices": [ { "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ] } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": null, "number": null } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" }, "outcome": "authorized", "message": "texto" } ] } ``` # Listar comprobantes > Lista las facturas y notas de crédito con búsqueda por número o cliente y filtros de tipo, estado, cliente y fechas. Por defecto trae todos menos los descartados. GET`/api/v1/documents/list` * Permiso `documents.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`texto hasta 100 caracteres * `kind`opción Valores: `invoice` `credit-note` * `status`opción Valores: `draft` `pending-authorization` `authorized` `discarded` * `customerId`uuid * `salesOrderId`uuid * `dateFrom`fecha * `dateTo`fecha * `sort`opción Valores: `date` `number` `customer` `total`Por defecto: `date` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `circuit`opción Valores: `all` `fiscal` `x`Por defecto: `all` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `documents`lista de objetorequerido * `total`enterorequerido mínimo 0 * `pending`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/documents/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "documents": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } } ], "total": 1, "pending": 1 } ``` # Listar el pool de facturación > Lista todo lo pendiente de facturar, de lo más viejo a lo más nuevo: cada remito emitido con algo sin facturar y cada pedido confirmado con líneas nunca remitidas, con su cliente, condiciones congeladas y líneas. GET`/api/v1/documents/list-billable` * Permiso `documents.prepare` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Respuesta `200` con este JSON. * `rows`lista de objetorequerido * `pointsOfSale`lista de objetorequerido * `issuerProblems`lista de textorequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/documents/list-billable" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/list-billable`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "rows": [ { "kind": "delivery-note", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "letter": "A", "needsCuit": false, "address": "texto" }, "x": false, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "xPointOfSaleId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "itemType": "texto", "vatRate": null }, "pendingQuantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100 } ] } ], "pointsOfSale": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto", "isDefault": false } ], "issuerProblems": [ "texto" ], "today": "2026-10-23" } ``` # Listar lo facturable de un cliente > Sin cliente, lista los clientes con pedidos confirmados por facturar. Con un cliente, lista las líneas de sus pedidos confirmados con su precio, bonificación y cuotas congelados. GET`/api/v1/documents/list-invoiceable-lines` * Permiso `documents.prepare` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `source`opción Valores: `sales-orders` `delivery-notes` * `deliveryId`uuid * `customerId`uuid * `documentId`uuid * `salesOrderId`uuid ## Respuesta `200` con este JSON. * `customers`lista de objetorequerido * `lines`lista de objetorequerido * `deliveryNoteLines`lista de objetorequerido * `hasDeliveryNotes`sí o norequerido * `pointsOfSale`lista de objetorequerido * `issuerProblems`lista de textorequerido * `canPrepare`sí o norequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/documents/list-invoiceable-lines" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/list-invoiceable-lines`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "customers": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "letter": "A", "needsCuit": false, "address": "texto" } ], "lines": [ { "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "documentDate": "2026-10-23" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "itemType": "texto", "vatRate": null }, "quantity": 100, "invoicedQuantity": 100, "pendingQuantity": 100, "heldByDocument": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentPlan": [ { "percent": 100, "dueDays": 1 } ] } ], "deliveryNoteLines": [ { "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "documentDate": "2026-10-23", "x": false }, "deliveryNoteLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "itemType": "texto", "vatRate": null }, "quantity": 100, "invoicedQuantity": 100, "pendingQuantity": 100, "heldByDocument": 100, "preselected": false, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentPlan": [ { "percent": 100, "dueDays": 1 } ] } ], "hasDeliveryNotes": false, "pointsOfSale": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "description": "texto", "isDefault": false } ], "issuerProblems": [ "texto" ], "canPrepare": false, "today": "2026-10-23" } ``` # Modificar las notas de un comprobante > Edita sólo las notas de una factura o nota de crédito, también una vez emitida, con la versión leída. POST`/api/v1/documents/update-notes` * Permiso `documents.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `version`enterorequerido mínimo 1 * `notes`textorequeridoadmite null hasta 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/update-notes" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "notes": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/update-notes`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "notes": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" } } ``` # Modificar un comprobante en borrador > Edita una factura o nota de crédito en borrador con la versión leída: punto de venta, fecha, período de servicio, notas y la cantidad y descripción de sus líneas. Los precios y bonificaciones quedan congelados. POST`/api/v1/documents/update-draft` * Permiso `documents.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `version`enterorequerido mínimo 1 * `pointOfSaleId`uuid * `documentDate`fecha * `servicePeriod`objetoadmite null * `notes`textoadmite null hasta 500 caracteres * `lines`lista de objeto al menos 1, hasta 200 * `creditLines`lista de objeto al menos 1, hasta 200 * `reason`texto de 1 a 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/update-draft" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/update-draft`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" } } ``` # Preparar una factura > Prepara una factura en borrador con líneas de pedidos confirmados de un cliente, con su precio, bonificación y cuotas congelados. Toma su número interno y retiene lo que factura de cada línea. POST`/api/v1/documents/create-invoice` * Permiso `documents.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `pointOfSaleId`uuid * `documentDate`fecha * `servicePeriod`objetoadmite null * `notes`textoadmite null hasta 500 caracteres * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/create-invoice" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/create-invoice`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" } } ``` # Preparar una nota de crédito > Prepara una nota de crédito en borrador de una factura autorizada, por líneas y cantidades al mismo precio y bonificación, con un motivo. Nunca acredita más de lo que le queda a cada línea. POST`/api/v1/documents/create-credit-note` * Permiso `documents.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `invoiceId`uuidrequerido * `documentDate`fecha * `reason`textorequerido de 1 a 300 caracteres * `notes`textoadmite null hasta 500 caracteres * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/create-credit-note" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "invoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "lines": [ { "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/create-credit-note`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "invoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "lines": [ { "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" } } ``` # Reintentar comprobantes pendientes > Resuelve los comprobantes pendientes de autorización: primero pregunta a ARCA si ya tiene cada uno y sólo lo vuelve a enviar si no. Sin un comprobante, toma todos los pendientes que el usuario puede emitir, por punto de venta y tipo, en orden. POST`/api/v1/documents/retry` * Permiso `documents.view` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuid ## Respuesta `200` con este JSON. * `results`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/documents/retry" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{}' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/retry`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({}), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "results": [ { "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } }, "outcome": "authorized", "message": "texto" } ] } ``` # Resumir las ventas del mes > Devuelve el neto de las facturas autorizadas de un mes menos sus notas de crédito, por semana, y el neto del mes anterior. GET`/api/v1/documents/summarize-sales` * Permiso `documents.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `month`texto formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` ## Respuesta `200` con este JSON. * `month`textorequerido * `net`textorequerido * `previousNet`textorequerido * `weeks`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/documents/summarize-sales" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/summarize-sales`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "month": "texto", "net": "texto", "previousNet": "texto", "weeks": [ { "from": "2026-10-23", "to": "2026-10-23", "net": "texto" } ] } ``` # Ver el historial de un comprobante > Lista los cambios de una factura o nota de crédito y de sus líneas, del más nuevo al más viejo, campo por campo. GET`/api/v1/documents/get-history` * Permiso `documents.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `documentId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/documents/get-history?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/get-history?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un comprobante > Devuelve una factura o nota de crédito con su cliente, líneas con su pedido, IVA por alícuota, totales, vencimientos, CAE, envíos a ARCA y, en una factura, sus notas de crédito y su cobranza. GET`/api/v1/documents/get` * Permiso `documents.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `documentId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `kind`opciónrequerido Valores: `invoice` `credit-note` * `status`opciónrequerido Valores: `draft` `pending-authorization` `authorized` `discarded` * `number`textorequerido * `internalNumber`enterorequerido * `legalNumber`enterorequeridoadmite null * `letter`opciónrequerido Valores: `A` `B` `X` * `documentDate`fecharequerido * `customer`objetorequerido * `total`textorequerido * `lastSubmission`objetorequeridoadmite null * `version`enterorequerido mínimo 1 * `pointOfSale`objetorequerido * `concept`opciónrequerido Valores: `products` `services` `products-and-services` * `servicePeriod`objetorequeridoadmite null * `paymentDueDate`fecharequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `orderDiscounts`lista de objetorequerido * `perception`objetorequeridoadmite null * `perceptionSkip`opciónrequeridoadmite null Valores: `excluded` `not-listed` `no-cuit` `zero-rate` `below-minimum` `x-circuit` * `perceptionEstimate`uno derequeridoadmite null * `cae`cualquierarequerido * `caeExpiry`fecharequeridoadmite null * `authorizedAt`fecha y horarequeridoadmite null * `arcaObservations`cualquierarequerido * `submissions`lista de objetorequerido * `corrects`objetorequeridoadmite null * `reason`cualquierarequerido * `creditNotes`lista de objetorequerido * `notes`cualquierarequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `collection`objetorequeridoadmite null * `application`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `documents.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/documents/get?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/documents/get?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "invoice", "status": "draft", "number": "texto", "internalNumber": 1, "legalNumber": 1, "letter": "A", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "documentType": "texto", "documentNumber": "texto", "vatCondition": "texto", "address": "texto" }, "total": "texto", "lastSubmission": { "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" }, "version": 1, "pointOfSale": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "text": "texto" }, "concept": "products", "servicePeriod": { "from": "2026-10-23", "to": "2026-10-23" }, "paymentDueDate": "2026-10-23", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "percent": 100, "dueDate": "2026-10-23", "amount": "texto" } ], "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "salesOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "salesOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "invoiceLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "unitCode": "texto", "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "headerDiscountPercent": 100, "lineKind": "sale", "vatPercentage": 100, "netAmount": "texto", "creditedQuantity": null, "creditableQuantity": null, "deliveryNoteLine": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "deliveryNote": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" } } } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "orderDiscounts": [ { "percent": 100, "amount": "texto", "text": "texto" } ], "perception": { "rateHundredths": 1, "base": "texto", "amount": "texto", "source": "arba" }, "perceptionSkip": "excluded", "perceptionEstimate": { "kind": "estimated", "rateHundredths": 1, "amount": "texto", "total": "texto" }, "cae": null, "caeExpiry": "2026-10-23", "authorizedAt": "2026-10-23T14:30:00.000Z", "arcaObservations": null, "submissions": [ { "attempt": 1, "kind": "send", "result": "authorized", "message": null, "recordedAt": "2026-10-23T14:30:00.000Z" } ], "corrects": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "internalNumber": 1 }, "reason": null, "creditNotes": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "total": "texto" } ], "notes": null, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "collection": { "state": "pending", "balance": "texto", "dueDate": "2026-10-23" }, "application": { "state": "pending", "balance": "texto", "invoiceBalance": null, "invoiceDueDate": "2026-10-23" } } ``` # Facturas de proveedor > Facturas, notas y despachos de proveedores, con sus controles, su lectura con IA y su verificación en ARCA. Facturas, notas y despachos de proveedores, con sus controles, su lectura con IA y su verificación en ARCA. | Operación | Ruta | | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | | [Listar facturas de proveedor](/api/referencia/facturas-de-proveedor/listar-facturas-de-proveedor/) | GET `/api/v1/supplier-invoices/list` | | [Ver una factura de proveedor](/api/referencia/facturas-de-proveedor/ver-una-factura-de-proveedor/) | GET `/api/v1/supplier-invoices/get` | | [Cargar una factura de proveedor](/api/referencia/facturas-de-proveedor/cargar-una-factura-de-proveedor/) | POST `/api/v1/supplier-invoices/create` | | [Modificar una factura en borrador](/api/referencia/facturas-de-proveedor/modificar-una-factura-en-borrador/) | POST `/api/v1/supplier-invoices/update` | | [Revisar los controles](/api/referencia/facturas-de-proveedor/revisar-los-controles/) | GET `/api/v1/supplier-invoices/preview` | | [Listar lo facturable de un proveedor](/api/referencia/facturas-de-proveedor/listar-lo-facturable-de-un-proveedor/) | GET `/api/v1/supplier-invoices/list-invoiceable-lines` | | [Leer el archivo con IA](/api/referencia/facturas-de-proveedor/leer-el-archivo-con-ia/) | POST `/api/v1/supplier-invoices/read-file` | | [Verificar en ARCA](/api/referencia/facturas-de-proveedor/verificar-en-arca/) | POST `/api/v1/supplier-invoices/verify` | | [Registrar una factura de proveedor](/api/referencia/facturas-de-proveedor/registrar-una-factura-de-proveedor/) | POST `/api/v1/supplier-invoices/register` | | [Anular una factura de proveedor](/api/referencia/facturas-de-proveedor/anular-una-factura-de-proveedor/) | POST `/api/v1/supplier-invoices/void` | | [Descartar una factura en borrador](/api/referencia/facturas-de-proveedor/descartar-una-factura-en-borrador/) | POST `/api/v1/supplier-invoices/discard` | | [Modificar las notas](/api/referencia/facturas-de-proveedor/modificar-las-notas/) | POST `/api/v1/supplier-invoices/update-notes` | | [Descargar el archivo](/api/referencia/facturas-de-proveedor/descargar-el-archivo/) | POST `/api/v1/supplier-invoices/get-file` | | [Resumir las compras](/api/referencia/facturas-de-proveedor/resumir-las-compras/) | GET `/api/v1/supplier-invoices/summarize-purchases` | | [Ver el historial de una factura](/api/referencia/facturas-de-proveedor/ver-el-historial-de-una-factura/) | GET `/api/v1/supplier-invoices/get-history` | # Anular una factura de proveedor > Anula un comprobante registrado con un motivo, salvo que tenga notas que lo corrigen o partidas aplicadas: se deshacen sus partidas, su crédito de IVA, sus percepciones y lo facturado de cada recepción. POST`/api/v1/supplier-invoices/void` * Permiso `supplier-invoices.void` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.void`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/void" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/void`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Cargar una factura de proveedor > Crea en borrador una factura, nota de débito, nota de crédito o despacho de un proveedor con todos sus datos, o sólo con el archivo del papel para leerlo después. POST`/api/v1/supplier-invoices/create` * Permiso `supplier-invoices.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `supplierId`uuidadmite null * `letter`opciónadmite null Valores: `A` `B` `C` `M` * `pointOfSale`enteroadmite null mínimo 1, máximo 99999 * `legalNumber`textoadmite null de 1 a 30 caracteres * `documentDate`fechaadmite null * `accountingDate`fechaadmite null * `authorizationMode`opciónadmite null Valores: `cae` `caea` `cai` * `authorizationCode`textoadmite null formato \`^\d{14}$\` * `authorizationExpiry`fechaadmite null * `currencyCode`texto formato \`^\[A-Za-z]{3}$\` * `exchangeRate`cualquiera * `paymentTermId`uuidadmite null * `correctsInvoiceId`uuidadmite null * `creditDestination`opciónadmite null Valores: `apply-to-invoice` `on-account` * `reason`textoadmite null hasta 300 caracteres * `total`cualquiera * `notes`textoadmite null hasta 1000 caracteres * `lines`lista de objeto hasta 200 * `vat`lista de objetoadmite null hasta 20 * `perceptions`lista de objeto hasta 20 * `file`objeto * `confirmedFields`lista de opción Valores: `supplier` `kind` `letter` `pointOfSale` `legalNumber` `documentDate` `authorizationMode` `authorizationCode` `authorizationExpiry` `currencyCode` `exchangeRate` `correctsInvoice` `vat` `perceptions` `total` `lines`hasta 16 * `ignoredReadingLines`lista de entero hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "kind": "invoice" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "kind": "invoice" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Descargar el archivo > Devuelve el archivo de un comprobante de proveedor (PDF, JPEG, PNG o WebP) para verlo o descargarlo. POST`/api/v1/supplier-invoices/get-file` * Permiso `supplier-invoices.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta el archivo ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `disposition`opción Valores: `inline` `attachment`Por defecto: `inline` ## Respuesta `200` con el archivo y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/get-file" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/get-file`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Descartar una factura en borrador > Descarta un comprobante en borrador con un motivo. Conserva su número interno. POST`/api/v1/supplier-invoices/discard` * Permiso `supplier-invoices.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/discard" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/discard`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Leer el archivo con IA > Lee el archivo de un comprobante en borrador con IA y propone lo leído en los campos vacíos, marcando los dudosos para revisar. Nunca registra. Requiere la política de la empresa activa; una lectura a la vez por borrador y hasta 200 por día. POST`/api/v1/supplier-invoices/read-file` * Permiso `supplier-invoices.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/read-file" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/read-file`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Listar facturas de proveedor > Lista los comprobantes de proveedor con búsqueda por número o proveedor y filtros de estado, tipo, proveedor, diferencias, verificación en ARCA, saldo y fechas. Por defecto trae todos menos los descartados. GET`/api/v1/supplier-invoices/list` * Permiso `supplier-invoices.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `status`lista de opciónadmite null Valores: `draft` `registered` `void` `discarded` * `kind`lista de opciónadmite null Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `supplierId`uuidadmite null * `hasDifferences`cualquiera * `verification`lista de opciónadmite null Valores: `verified` `unverified` `rejected` * `withBalance`cualquiera * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `sort`opción Valores: `date` `number` `supplier` `total`Por defecto: `date` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `supplierInvoices`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/supplier-invoices/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "supplierInvoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false } ], "total": 1 } ``` # Listar lo facturable de un proveedor > Lista las líneas de recepciones cerradas de un proveedor y las posiciones de sus órdenes de servicios, con lo recibido u ordenado, lo facturado y lo pendiente de facturar. GET`/api/v1/supplier-invoices/list-invoiceable-lines` * Permiso `supplier-invoices.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido * `currencyCode`textoadmite null formato \`^\[A-Za-z]{3}$\` * `supplierInvoiceId`uuidadmite null * `includeInvoiced`cualquiera ## Respuesta `200` con este JSON. * `lines`lista de objetorequerido * `orderLines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/supplier-invoices/list-invoiceable-lines?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/list-invoiceable-lines?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "lines": [ { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receipt": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "supplierDeliveryNote": null }, "order": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "currencyCode": "texto", "paymentPlanText": "texto" }, "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null, "inDrafts": [ "texto" ] } ], "orderLines": [ { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "order": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "orderDate": "2026-10-23", "currencyCode": "texto", "paymentPlanText": "texto" }, "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false }, "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "inDrafts": [ "texto" ] } ] } ``` # Modificar las notas > Cambia las notas de un comprobante registrado o anulado, con la versión leída. POST`/api/v1/supplier-invoices/update-notes` * Permiso `supplier-invoices.update-notes` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `version`enterorequerido mínimo 1 * `notes`textoadmite null hasta 1000 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.update-notes`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/update-notes" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/update-notes`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Modificar una factura en borrador > Edita un comprobante en borrador con la versión leída: datos, líneas, IVA, percepciones y total. Un archivo nuevo reemplaza al anterior. POST`/api/v1/supplier-invoices/update` * Permiso `supplier-invoices.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `version`enterorequerido mínimo 1 * `kind`opción Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `supplierId`uuidadmite null * `letter`opciónadmite null Valores: `A` `B` `C` `M` * `pointOfSale`enteroadmite null mínimo 1, máximo 99999 * `legalNumber`textoadmite null de 1 a 30 caracteres * `documentDate`fechaadmite null * `accountingDate`fechaadmite null * `authorizationMode`opciónadmite null Valores: `cae` `caea` `cai` * `authorizationCode`textoadmite null formato \`^\d{14}$\` * `authorizationExpiry`fechaadmite null * `currencyCode`texto formato \`^\[A-Za-z]{3}$\` * `exchangeRate`cualquiera * `paymentTermId`uuidadmite null * `correctsInvoiceId`uuidadmite null * `creditDestination`opciónadmite null Valores: `apply-to-invoice` `on-account` * `reason`textoadmite null hasta 300 caracteres * `total`cualquiera * `notes`textoadmite null hasta 1000 caracteres * `lines`lista de objeto hasta 200 * `vat`lista de objetoadmite null hasta 20 * `perceptions`lista de objeto hasta 20 * `file`objeto * `confirmedFields`lista de opción Valores: `supplier` `kind` `letter` `pointOfSale` `legalNumber` `documentDate` `authorizationMode` `authorizationCode` `authorizationExpiry` `currencyCode` `exchangeRate` `correctsInvoice` `vat` `perceptions` `total` `lines`hasta 16 * `ignoredReadingLines`lista de entero hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Registrar una factura de proveedor > Registra un borrador completo cuya suma coincide con el total del papel, que no está duplicado y con las advertencias aceptadas: la deuda en la cuenta del proveedor, el crédito de IVA, las percepciones sufridas, lo facturado de cada recepción y el último precio de cada artículo. POST`/api/v1/supplier-invoices/register` * Permiso `supplier-invoices.register` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `version`enterorequerido mínimo 1 * `acceptWarnings`lista de opción Valores: `letter-mismatch` `letter-m` `vat-differs` `arca-rejected` `unverified` `authorization-expired` `apocryphal` `quantity-difference` `price-difference` `occasional-supplier` `reading-unreviewed` `same-file`Por defecto: `[]`hasta 24 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.register`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/register" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/register`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Resumir las compras > Devuelve el neto en pesos de las facturas y notas de débito registradas menos sus notas de crédito, de los cuatro meses que terminan en el pedido. GET`/api/v1/supplier-invoices/summarize-purchases` * Permiso `supplier-invoices.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `month`texto formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` ## Respuesta `200` con este JSON. * `months`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/supplier-invoices/summarize-purchases" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/summarize-purchases`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "months": [ { "month": "texto", "net": "texto" } ] } ``` # Revisar los controles > Devuelve, sin grabar, un comprobante guardado con sus controles (errores, advertencias e información), el IVA que proponen las líneas, las diferencias con recepciones y órdenes y las cuotas que dejaría. GET`/api/v1/supplier-invoices/preview` * Permiso `supplier-invoices.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierInvoiceId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/supplier-invoices/preview?supplierInvoiceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/preview?supplierInvoiceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Ver el historial de una factura > Lista los cambios de un comprobante, sus líneas, IVA y percepciones, del más nuevo al más viejo, campo por campo. GET`/api/v1/supplier-invoices/get-history` * Permiso `supplier-invoices.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierInvoiceId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/supplier-invoices/get-history?supplierInvoiceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/get-history?supplierInvoiceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver una factura de proveedor > Devuelve un comprobante de proveedor con su número, autorización, moneda, condición y cuotas, líneas con sus recepciones, órdenes y diferencias, IVA, percepciones, totales, verificación en ARCA, saldo, notas que lo corrigen, archivo y lectura con IA. GET`/api/v1/supplier-invoices/get` * Permiso `supplier-invoices.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierInvoiceId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/supplier-invoices/get?supplierInvoiceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/get?supplierInvoiceId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Verificar en ARCA > Pregunta a ARCA (WSCDC) si un comprobante con letra existe tal como se cargó. La respuesta se guarda sólo si el comprobante no cambió mientras tanto. POST`/api/v1/supplier-invoices/verify` * Permiso `supplier-invoices.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierInvoiceId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `label`textorequerido * `kind`opciónrequerido Valores: `invoice` `debit-note` `credit-note` `customs-entry` * `status`opciónrequerido Valores: `draft` `registered` `void` `discarded` * `origin`opciónrequerido Valores: `domestic` `foreign` * `documentDate`fecharequeridoadmite null * `supplier`objetorequeridoadmite null * `currencyCode`textorequerido * `total`cualquierarequerido * `balance`cualquierarequerido * `verification`opciónrequerido Valores: `unverified` `verified` `rejected` `unavailable` `not-applicable` * `hasDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `accountingDate`fecharequeridoadmite null * `letter`opciónrequeridoadmite null Valores: `A` `B` `C` `M` * `arcaVoucherType`enterorequeridoadmite null * `pointOfSale`enterorequeridoadmite null * `legalNumber`cualquierarequerido * `authorizationMode`opciónrequeridoadmite null Valores: `cae` `caea` `cai` * `authorizationCode`cualquierarequerido * `authorizationExpiry`fecharequeridoadmite null * `exchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlanText`textorequerido * `installments`lista de objetorequerido * `correctsInvoice`objetorequeridoadmite null * `creditDestination`opciónrequeridoadmite null Valores: `apply-to-invoice` `on-account` * `reason`cualquierarequerido * `lines`lista de objetorequerido * `vat`lista de objetorequerido * `proposedVat`lista de objetorequerido * `perceptions`lista de objetorequerido * `totals`objetorequerido * `controls`lista de objetorequerido * `warningsAccepted`lista de textorequerido * `verificationMessage`cualquierarequerido * `verifiedAt`fecha y horarequeridoadmite null * `notes`cualquierarequerido * `file`objetorequeridoadmite null * `reading`objetorequeridoadmite null * `payable`sí o norequerido * `readingAvailable`sí o norequerido * `readFields`lista de textorequerido * `ignoredReadingLines`lista de enterorequerido * `reviewFields`lista de objetorequerido * `corrections`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `registeredAt`fecha y horarequeridoadmite null * `registeredBy`objetorequeridoadmite null * `voidedAt`fecha y horarequeridoadmite null * `voidedBy`objetorequeridoadmite null * `voidReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `supplier-invoices.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/supplier-invoices/verify" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/supplier-invoices/verify`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "kind": "invoice", "status": "draft", "origin": "domestic", "documentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "taxId": "texto", "origin": "domestic", "status": "active", "vatCondition": null, "isOccasional": false, "apocryphalSince": "2026-10-23" }, "currencyCode": "texto", "total": null, "balance": null, "verification": "unverified", "hasDifferences": false, "version": 1, "accountingDate": "2026-10-23", "letter": "A", "arcaVoucherType": 1, "pointOfSale": 1, "legalNumber": null, "authorizationMode": "cae", "authorizationCode": null, "authorizationExpiry": "2026-10-23", "exchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "paymentPlanText": "texto", "installments": [ { "number": 1, "dueDate": "2026-10-23", "amount": "texto" } ], "correctsInvoice": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto" }, "creditDestination": "apply-to-invoice", "reason": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lineKind": "receipt", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "allowsDecimals": false, "status": "active" }, "description": "texto", "quantity": 100, "unitPrice": "texto", "discountPercent": 100, "vatRateId": null, "vatPercentage": null, "netAmount": "texto", "creditedQuantity": 100, "quantityDifference": null, "priceDifference": null, "correctsLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fromReading": false, "receipt": { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "receiptNumber": 1, "receiptDate": "2026-10-23", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "received": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null, "unitCost": null }, "orderLine": { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orderNumber": 1, "orderCurrency": "texto", "ordered": 100, "invoiced": 100, "pending": 100, "orderUnitPrice": null, "orderDiscountPercent": null } } ], "vat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "proposedVat": [ { "vatRateId": "texto", "vatPercentage": 100, "base": "texto", "amount": "texto" } ], "perceptions": [ { "perceptionKind": "vat", "jurisdiction": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "base": null, "rate": null, "amount": "texto" } ], "totals": { "net": "texto", "vat": "texto", "perceptions": "texto", "sum": "texto", "gap": null }, "controls": [ { "code": "texto", "level": "error", "text": "texto", "field": null } ], "warningsAccepted": [ "texto" ], "verificationMessage": null, "verifiedAt": "2026-10-23T14:30:00.000Z", "notes": null, "file": { "fileName": "texto", "mediaType": "texto", "sizeBytes": 1, "pageCount": 1, "uploadedAt": "2026-10-23T14:30:00.000Z" }, "reading": { "status": "running", "failure": "unreadable", "startedAt": "2026-10-23T14:30:00.000Z", "finishedAt": "2026-10-23T14:30:00.000Z", "unassignedLines": [ { "index": 1, "code": null, "description": "texto", "quantity": null, "unitPrice": null, "amount": null } ] }, "payable": false, "readingAvailable": false, "readFields": [ "texto" ], "ignoredReadingLines": [ 1 ], "reviewFields": [ { "field": "texto", "label": "texto", "reason": "texto" } ], "corrections": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "label": "texto", "number": "texto", "kind": "invoice", "status": "draft", "total": null } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "voidedAt": "2026-10-23T14:30:00.000Z", "voidedBy": { "id": "texto", "name": null }, "voidReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Flujo de documentos > Buscar un documento por cualquiera de sus números y recorrer todo lo que tiene vinculado. Buscar un documento por cualquiera de sus números y recorrer todo lo que tiene vinculado. | Operación | Ruta | | ------------------------------------------------------------------------------------------------- | ---------------------------------- | | [Buscar un documento](/api/referencia/flujo-de-documentos/buscar-un-documento/) | GET `/api/v1/document-flow/search` | | [Ver el flujo de un documento](/api/referencia/flujo-de-documentos/ver-el-flujo-de-un-documento/) | GET `/api/v1/document-flow/of` | # Buscar un documento > Encuentra los documentos de la empresa activa que nombra un texto: un número comercial con prefijo (PED-4, FAC-12, REC-3, OP-7, OC-2, RCP-5, FPR-1, ENT-9, SAL-4, AS-231), un número interno, un número legal con o sin letra, un CAE de 14 dígitos o un número de cheque. Sólo devuelve lo que el usuario puede ver. GET`/api/v1/document-flow/search` * Permiso `document-flow.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `text`textorequerido de 1 a 100 caracteres ## Respuesta `200` con este JSON. * `query`textorequerido * `results`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `document-flow.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/document-flow/search?text=texto" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/document-flow/search?text=texto`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "query": "texto", "results": [ { "kind": "sales-order", "id": "texto", "label": "texto", "number": "texto", "legal": null, "party": null, "date": null, "amount": { "value": "texto", "currency": "texto" }, "status": "active", "entry": { "id": "texto", "number": "texto" } } ] } ``` # Ver el flujo de un documento > Devuelve todos los documentos vinculados a uno, desde el pedido o la orden de compra hasta entregas, facturas, notas de crédito, recibos, órdenes de pago y movimientos de stock, con el estado de cada uno y lo que queda pendiente. Un documento de un módulo que el usuario no ve aparece oculto y el recorrido se corta ahí. GET`/api/v1/document-flow/of` * Permiso `document-flow.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `kind`opciónrequerido Valores: `sales-order` `delivery-note` `sales-document` `receipt` `receipt-method` `purchase-order` `goods-receipt` `supplier-invoice` `payment-order` `payment-method` `stock-movement` * `id`uuidrequerido ## Respuesta `200` con este JSON. * `focus`textorequerido * `nodes`lista de uno derequerido * `links`lista de objetorequerido * `positions`lista de enterorequerido * `truncated`sí o norequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `document-flow.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/document-flow/of?kind=sales-order&id=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/document-flow/of?kind=sales-order&id=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "focus": "texto", "nodes": [ { "node": "document", "kind": "sales-order", "id": "texto", "label": "texto", "number": "texto", "legal": null, "party": null, "date": null, "amount": { "value": "texto", "currency": "texto" }, "stage": "purchase-order", "progress": "pending", "status": "active", "badge": null, "quantity": { "value": "texto", "unit": "texto" }, "dueDate": null, "drawer": null, "warehouse": null, "positions": [ 1 ], "distance": 1, "entry": { "id": "texto", "number": "texto" } } ], "links": [ { "from": "texto", "to": "texto" } ], "positions": [ 1 ], "truncated": false } ``` # Impuestos > Padrones de ARCA y ARBA, percepciones practicadas y sufridas, y posición de IVA. Padrones de ARCA y ARBA, percepciones practicadas y sufridas, y posición de IVA. | Operación | Ruta | | ----------------------------------------------------------------------------------------------- | ---------------------------------------------- | | [Consultar un CUIT en ARCA](/api/referencia/impuestos/consultar-un-cuit-en-arca/) | POST `/api/v1/taxes/lookup-taxpayer` | | [Consultar la alícuota de ARBA](/api/referencia/impuestos/consultar-la-alicuota-de-arba/) | POST `/api/v1/taxes/lookup-arba-rate` | | [Ver la percepción de un cliente](/api/referencia/impuestos/ver-la-percepcion-de-un-cliente/) | GET `/api/v1/taxes/get-customer-perception` | | [Cargar un ajuste de percepción](/api/referencia/impuestos/cargar-un-ajuste-de-percepcion/) | POST `/api/v1/taxes/set-perception-adjustment` | | [Terminar un ajuste de percepción](/api/referencia/impuestos/terminar-un-ajuste-de-percepcion/) | POST `/api/v1/taxes/end-perception-adjustment` | | [Listar percepciones practicadas](/api/referencia/impuestos/listar-percepciones-practicadas/) | GET `/api/v1/taxes/list-perceptions` | | [Listar percepciones sufridas](/api/referencia/impuestos/listar-percepciones-sufridas/) | GET `/api/v1/taxes/list-suffered-perceptions` | | [Ver la posición de IVA](/api/referencia/impuestos/ver-la-posicion-de-iva/) | GET `/api/v1/taxes/get-vat-position` | # Cargar un ajuste de percepción > Carga para un cliente su propia alícuota de percepción o «No percibir», con un motivo y sus fechas. Prevalece sobre ARBA sólo en esta empresa. POST`/api/v1/taxes/set-perception-adjustment` * Permiso `taxes.adjust-perception` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `kind`opciónrequerido Valores: `rate` `exclude` * `rateHundredths`entero mínimo 0, máximo 9999 * `reason`textorequerido de 1 a 300 caracteres * `validFrom`fecharequerido * `validUntil`fechaadmite null Por defecto: `null` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `kind`opciónrequerido Valores: `rate` `exclude` * `rateHundredths`enterorequeridoadmite null * `reason`textorequerido * `validFrom`fecharequerido * `validUntil`fecharequeridoadmite null * `version`enterorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `taxes.adjust-perception`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/taxes/set-perception-adjustment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "rate", "reason": "texto", "validFrom": "2026-10-23" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/set-perception-adjustment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "rate", "reason": "texto", "validFrom": "2026-10-23" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "rate", "rateHundredths": 1, "reason": "texto", "validFrom": "2026-10-23", "validUntil": "2026-10-23", "version": 1 } ``` # Consultar la alícuota de ARBA > Consulta en el padrón de ARBA la alícuota de percepción de ingresos brutos de un cliente para un mes, siempre preguntando otra vez. Si ARBA no responde, devuelve la guardada. POST`/api/v1/taxes/lookup-arba-rate` * Permiso `taxes.lookup-arba-rate` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `period`texto formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` ## Respuesta `200` con este JSON. * `cuit`textorequerido formato \`^\d{11}$\` * `period`fecharequerido * `listed`sí o norequerido * `rateHundredths`enterorequeridoadmite null * `consultedAt`fecha y horarequerido * `unavailable`sí o norequerido * `fromPeriod`fecharequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `taxes.lookup-arba-rate`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/taxes/lookup-arba-rate" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/lookup-arba-rate`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "cuit": "30715742426", "period": "2026-10-23", "listed": false, "rateHundredths": 1, "consultedAt": "2026-10-23T14:30:00.000Z", "unavailable": false, "fromPeriod": "2026-10-23" } ``` # Consultar un CUIT en ARCA > Consulta un CUIT en el padrón de ARCA (Alcance 4) y en su base de contribuyentes apócrifos con el certificado de la empresa activa. Responde razón social, domicilio fiscal y condición de IVA, con la fecha y la fuente del dato. POST`/api/v1/taxes/lookup-taxpayer` * Permiso `taxes.lookup-taxpayer` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `cuit`textorequerido * `refresh`sí o no Por defecto: `false` ## Respuesta `200` con este JSON. * `cuit`textorequerido formato \`^\d{11}$\` * `legalName`textorequerido * `personType`opciónrequerido Valores: `legal` `natural` * `vatCondition`opciónrequeridoadmite null Valores: `registered` `monotributo` `exempt` `not_reached` `final_consumer` * `iibbCondition`opciónrequeridoadmite null Valores: `multilateral` * `iibbNumber`cualquierarequeridoadmite null * `fiscalAddress`objetorequeridoadmite null * `environment`opciónrequerido Valores: `homologation` `production` * `source`opciónrequerido Valores: `arca` * `consultedAt`fecha y horarequerido * `unavailable`sí o norequerido * `apocryphal`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `taxes.lookup-taxpayer`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/taxes/lookup-taxpayer" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "cuit": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/lookup-taxpayer`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "cuit": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "cuit": "30715742426", "legalName": "texto", "personType": "legal", "vatCondition": "registered", "iibbCondition": "multilateral", "iibbNumber": null, "fiscalAddress": { "street": null, "streetNumber": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null }, "environment": "homologation", "source": "arca", "consultedAt": "2026-10-23T14:30:00.000Z", "unavailable": false, "apocryphal": { "status": "listed", "listedOn": "2026-10-23", "checkedAt": "2026-10-23T14:30:00.000Z" } } ``` # Listar percepciones practicadas > Lista lo que la empresa percibió en un mes, opcionalmente de un cliente, con el total del mes y las notas de crédito restadas. GET`/api/v1/taxes/list-perceptions` * Permiso `taxes.view-perceptions` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `period`texto formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` * `customerId`uuid * `search`texto hasta 200 caracteres ## Respuesta `200` con este JSON. * `agent`sí o norequerido * `period`fecharequerido * `rows`lista de objetorequerido * `total`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `taxes.view-perceptions`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/taxes/list-perceptions" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/list-perceptions`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "agent": false, "period": "2026-10-23", "rows": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "documentDate": "2026-10-23", "documentLabel": "texto", "kind": "invoice", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerName": "texto", "cuit": "texto", "base": "texto", "rateHundredths": 1, "amount": "texto", "rateSource": "arba" } ], "total": "texto" } ``` # Listar percepciones sufridas > Lista las percepciones que sufrió la empresa en un mes en los comprobantes de sus proveedores, en pesos, con los totales por tipo y jurisdicción. GET`/api/v1/taxes/list-suffered-perceptions` * Permiso `taxes.view-suffered-perceptions` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `period`texto formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` * `kind`opción Valores: `vat` `income-tax` `gross-income` * `supplierId`uuid ## Respuesta `200` con este JSON. * `period`fecharequerido * `rows`lista de objetorequerido * `totals`lista de objetorequerido * `total`textorequerido * `suppliers`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `taxes.view-suffered-perceptions`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/taxes/list-suffered-perceptions" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/list-suffered-perceptions`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "period": "2026-10-23", "rows": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierInvoiceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "documentDate": "2026-10-23", "voucherLabel": "texto", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "supplierName": "texto", "supplierCuit": null, "kind": "vat", "jurisdictionId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "jurisdictionName": null, "amount": "texto", "voided": false } ], "totals": [ { "kind": "vat", "jurisdictionId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "jurisdictionName": null, "amount": "texto" } ], "total": "texto", "suppliers": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" } ] } ``` # Terminar un ajuste de percepción > Termina un ajuste de un cliente en una fecha, con un motivo y la versión leída. POST`/api/v1/taxes/end-perception-adjustment` * Permiso `taxes.adjust-perception` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `adjustmentId`uuidrequerido * `validUntil`fecharequerido * `reason`textorequerido de 1 a 300 caracteres * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `kind`opciónrequerido Valores: `rate` `exclude` * `rateHundredths`enterorequeridoadmite null * `reason`textorequerido * `validFrom`fecharequerido * `validUntil`fecharequeridoadmite null * `version`enterorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `taxes.adjust-perception`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/taxes/end-perception-adjustment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "adjustmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "validUntil": "2026-10-23", "reason": "texto", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/end-perception-adjustment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "adjustmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "validUntil": "2026-10-23", "reason": "texto", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "rate", "rateHundredths": 1, "reason": "texto", "validFrom": "2026-10-23", "validUntil": "2026-10-23", "version": 1 } ``` # Ver la percepción de un cliente > Devuelve si la empresa es agente, la alícuota del mes guardada de ARBA con cuándo se consultó y los ajustes vigentes o posteriores del cliente. GET`/api/v1/taxes/get-customer-perception` * Permiso `customers.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido ## Respuesta `200` con este JSON. * `agent`sí o norequerido * `cuit`cualquierarequerido * `period`fecharequerido * `rate`objetorequeridoadmite null * `adjustments`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `customers.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/taxes/get-customer-perception?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/get-customer-perception?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "agent": false, "cuit": null, "period": "2026-10-23", "rate": { "listed": false, "rateHundredths": 1, "consultedAt": "2026-10-23T14:30:00.000Z" }, "adjustments": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "rate", "rateHundredths": 1, "reason": "texto", "validFrom": "2026-10-23", "validUntil": "2026-10-23", "version": 1 } ] } ``` # Ver la posición de IVA > Devuelve la posición de IVA de un mes: el débito de los comprobantes autorizados menos el crédito fiscal y las percepciones de IVA sufridas. Positivo es a pagar. GET`/api/v1/taxes/get-vat-position` * Permiso `taxes.view-vat-position` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `month`texto formato \`^\d{4}-(0\[1-9]|1\[0-2])$\` ## Respuesta `200` con este JSON. * `month`textorequerido * `debit`textorequerido * `credit`textorequerido * `perceptions`textorequerido * `balance`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `taxes.view-vat-position`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/taxes/get-vat-position" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/taxes/get-vat-position`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "month": "texto", "debit": "texto", "credit": "texto", "perceptions": "texto", "balance": "texto" } ``` # Listas de precios > Listas, precios con vigencia, precios especiales por cliente y promociones por cantidad. Listas, precios con vigencia, precios especiales por cliente y promociones por cantidad. | Operación | Ruta | | ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | | [Listar listas de precios](/api/referencia/listas-de-precios/listar-listas-de-precios/) | GET `/api/v1/price-lists/list` | | [Ver una lista de precios](/api/referencia/listas-de-precios/ver-una-lista-de-precios/) | GET `/api/v1/price-lists/get` | | [Crear una lista de precios](/api/referencia/listas-de-precios/crear-una-lista-de-precios/) | POST `/api/v1/price-lists/create` | | [Renombrar una lista de precios](/api/referencia/listas-de-precios/renombrar-una-lista-de-precios/) | POST `/api/v1/price-lists/update` | | [Marcar la lista general](/api/referencia/listas-de-precios/marcar-la-lista-general/) | POST `/api/v1/price-lists/set-general` | | [Desactivar o reactivar una lista](/api/referencia/listas-de-precios/desactivar-o-reactivar-una-lista/) | POST `/api/v1/price-lists/set-status` | | [Listar los precios de una lista](/api/referencia/listas-de-precios/listar-los-precios-de-una-lista/) | GET `/api/v1/price-lists/list-prices` | | [Listar los precios de un artículo](/api/referencia/listas-de-precios/listar-los-precios-de-un-articulo/) | GET `/api/v1/price-lists/list-item-prices` | | [Ver la historia de precios de un artículo](/api/referencia/listas-de-precios/ver-la-historia-de-precios-de-un-articulo/) | GET `/api/v1/price-lists/get-price-history` | | [Cargar un precio](/api/referencia/listas-de-precios/cargar-un-precio/) | POST `/api/v1/price-lists/set-price` | | [Cargar precios en lote](/api/referencia/listas-de-precios/cargar-precios-en-lote/) | POST `/api/v1/price-lists/set-prices-batch` | | [Quitar un precio programado](/api/referencia/listas-de-precios/quitar-un-precio-programado/) | POST `/api/v1/price-lists/remove-scheduled-price` | | [Previsualizar un ajuste porcentual](/api/referencia/listas-de-precios/previsualizar-un-ajuste-porcentual/) | GET `/api/v1/price-lists/preview-adjustment` | | [Aplicar un ajuste porcentual](/api/referencia/listas-de-precios/aplicar-un-ajuste-porcentual/) | POST `/api/v1/price-lists/apply-adjustment` | | [Resolver el precio para un cliente](/api/referencia/listas-de-precios/resolver-el-precio-para-un-cliente/) | GET `/api/v1/price-lists/resolve-price` | | [Listar precios especiales](/api/referencia/listas-de-precios/listar-precios-especiales/) | GET `/api/v1/price-lists/list-customer-prices` | | [Cargar un precio especial](/api/referencia/listas-de-precios/cargar-un-precio-especial/) | POST `/api/v1/price-lists/set-customer-price` | | [Terminar un precio especial](/api/referencia/listas-de-precios/terminar-un-precio-especial/) | POST `/api/v1/price-lists/end-customer-price` | | [Quitar un precio especial programado](/api/referencia/listas-de-precios/quitar-un-precio-especial-programado/) | POST `/api/v1/price-lists/remove-scheduled-customer-price` | | [Listar promociones por cantidad](/api/referencia/listas-de-precios/listar-promociones-por-cantidad/) | GET `/api/v1/price-lists/list-promotions` | | [Ver una promoción](/api/referencia/listas-de-precios/ver-una-promocion/) | GET `/api/v1/price-lists/get-promotion` | | [Crear una promoción](/api/referencia/listas-de-precios/crear-una-promocion/) | POST `/api/v1/price-lists/create-promotion` | | [Guardar una promoción](/api/referencia/listas-de-precios/guardar-una-promocion/) | POST `/api/v1/price-lists/save-promotion` | | [Activar o desactivar una promoción](/api/referencia/listas-de-precios/activar-o-desactivar-una-promocion/) | POST `/api/v1/price-lists/set-promotion-status` | | [Ver el historial de una lista](/api/referencia/listas-de-precios/ver-el-historial-de-una-lista/) | GET `/api/v1/price-lists/get-history` | | [Ver el historial de una promoción](/api/referencia/listas-de-precios/ver-el-historial-de-una-promocion/) | GET `/api/v1/price-lists/get-promotion-history` | # Activar o desactivar una promoción > Activa una promoción en borrador cuando su regla está completa, o desactiva o reactiva una, con su versión y un motivo opcional. POST`/api/v1/price-lists/set-promotion-status` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `promotionId`uuidrequerido * `version`enterorequerido mínimo 1 * `status`opciónrequerido Valores: `active` `inactive` * `reason`textoadmite null hasta 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `priceListId`uuidrequerido * `priceListName`textorequerido * `name`textorequerido * `scope`opciónrequerido Valores: `item` `items` `family` `list` * `family`objetorequeridoadmite null * `items`lista de objetorequerido * `measure`opciónrequerido Valores: `unit` `package` * `benefit`opciónrequerido Valores: `percent` `price` * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null * `status`opciónrequerido Valores: `draft` `active` `inactive` * `statusReason`cualquierarequerido * `validity`opciónrequerido Valores: `current` `scheduled` `expired` * `version`enterorequerido mínimo 1 * `tiers`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/set-promotion-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "promotionId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/set-promotion-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "promotionId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListName": "texto", "name": "texto", "scope": "item", "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "path": "texto" }, "items": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitName": "texto", "level": "primary_box", "levelUnits": 100, "counts": false } ], "measure": "unit", "benefit": "percent", "validFrom": "2026-10-23", "validTo": "2026-10-23", "status": "draft", "statusReason": null, "validity": "current", "version": 1, "tiers": [ { "fromQuantity": 100, "discountPercent": null, "freeQuantity": null, "prices": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitPrice": "texto" } ] } ] } ``` # Aplicar un ajuste porcentual > Confirma un ajuste porcentual ya revisado, todo o nada. Se rechaza si los precios cambiaron desde la revisión. POST`/api/v1/price-lists/apply-adjustment` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `priceListId`uuidrequerido * `percent`númerorequerido mínimo -90, máximo 1000 * `validFrom`textorequerido * `familyId`uuidadmite null * `brandId`uuidadmite null * `previewCount`enterorequerido mínimo 1 * `previewHash`textorequerido formato \`^\[0-9a-f]{64}$\` ## Respuesta `200` con este JSON. * `priceListId`uuidrequerido * `adjusted`enterorequerido mínimo 1 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/apply-adjustment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "percent": 100, "validFrom": "texto", "previewCount": 1, "previewHash": "0000000000000000000000000000000000000000000000000000000000000000" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/apply-adjustment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "percent": 100, "validFrom": "texto", "previewCount": 1, "previewHash": "0000000000000000000000000000000000000000000000000000000000000000" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "adjusted": 1 } ``` # Cargar precios en lote > Carga de una vez los precios sin IVA de varios artículos de una lista desde una fecha, todos o ninguno. Rechaza el lote si un precio cambió desde que se leyó. POST`/api/v1/price-lists/set-prices-batch` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `priceListId`uuidrequerido * `validFrom`textorequerido * `validTo`cualquiera * `rows`lista de objetorequerido al menos 1, hasta 500 ## Respuesta `200` con este JSON. * `saved`enterorequerido mínimo 1 * `prices`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/set-prices-batch" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "validFrom": "texto", "rows": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": 100, "basedOn": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 } } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/set-prices-batch`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "validFrom": "texto", "rows": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": 100, "basedOn": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 } } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "saved": 1, "prices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 } ] } ``` # Cargar un precio > Carga el precio sin IVA de un artículo en una lista, desde hoy o una fecha posterior, con una fecha de fin opcional. POST`/api/v1/price-lists/set-price` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `priceListId`uuidrequerido * `itemId`uuidrequerido * `price`númerorequerido mayor que 0, máximo 100000000000 * `validFrom`textorequerido * `validTo`cualquiera ## Respuesta `200` con este JSON. * `id`uuidrequerido * `price`textorequerido * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null * `priceListId`uuidrequerido * `itemId`uuidrequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/set-price" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": 100, "validFrom": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/set-price`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": 100, "validFrom": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Cargar un precio especial > Carga el precio especial sin IVA de un cliente para un artículo, desde hoy o una fecha posterior, con una fecha de fin opcional. POST`/api/v1/price-lists/set-customer-price` * Permiso `price-lists.set-customer-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `itemId`uuidrequerido * `price`númerorequerido mayor que 0, máximo 100000000000 * `currencyCode`textorequerido formato \`^\[A-Z]{3}$\` * `validFrom`textorequerido * `validTo`cualquiera * `reason`textoadmite null hasta 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `itemId`uuidrequerido * `price`textorequerido * `currencyCode`textorequerido * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null * `reason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-customer-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/set-customer-price" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": 100, "currencyCode": "ARS", "validFrom": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/set-customer-price`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": 100, "currencyCode": "ARS", "validFrom": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "currencyCode": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "reason": null } ``` # Crear una lista de precios > Crea una lista de precios con su nombre y su moneda. La primera de la empresa es la general. POST`/api/v1/price-lists/create` * Permiso `price-lists.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `name`textorequerido de 1 a 80 caracteres * `currencyCode`textorequerido formato \`^\[A-Z]{3}$\` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `currencyCode`textorequerido * `isGeneral`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "texto", "currencyCode": "ARS" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "texto", "currencyCode": "ARS" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "currencyCode": "texto", "isGeneral": false, "status": "active", "statusReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Crear una promoción > Crea una promoción por cantidad en borrador con su nombre y vigencia. Su regla se guarda después y al activarla entra en vigencia. POST`/api/v1/price-lists/create-promotion` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `priceListId`uuidrequerido * `name`textorequerido de 1 a 80 caracteres * `validFrom`cualquiera * `validTo`cualquiera ## Respuesta `200` con este JSON. * `id`uuidrequerido * `priceListId`uuidrequerido * `priceListName`textorequerido * `name`textorequerido * `scope`opciónrequerido Valores: `item` `items` `family` `list` * `family`objetorequeridoadmite null * `items`lista de objetorequerido * `measure`opciónrequerido Valores: `unit` `package` * `benefit`opciónrequerido Valores: `percent` `price` * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null * `status`opciónrequerido Valores: `draft` `active` `inactive` * `statusReason`cualquierarequerido * `validity`opciónrequerido Valores: `current` `scheduled` `expired` * `version`enterorequerido mínimo 1 * `tiers`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/create-promotion" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/create-promotion`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListName": "texto", "name": "texto", "scope": "item", "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "path": "texto" }, "items": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitName": "texto", "level": "primary_box", "levelUnits": 100, "counts": false } ], "measure": "unit", "benefit": "percent", "validFrom": "2026-10-23", "validTo": "2026-10-23", "status": "draft", "statusReason": null, "validity": "current", "version": 1, "tiers": [ { "fromQuantity": 100, "discountPercent": null, "freeQuantity": null, "prices": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitPrice": "texto" } ] } ] } ``` # Desactivar o reactivar una lista > Desactiva o reactiva una lista de precios con un motivo opcional. La lista general no se desactiva. POST`/api/v1/price-lists/set-status` * Permiso `price-lists.set-status` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `priceListId`uuidrequerido * `status`opciónrequerido Valores: `active` `inactive` * `reason`textoadmite null hasta 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `currencyCode`textorequerido * `isGeneral`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-status`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/set-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/set-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "currencyCode": "texto", "isGeneral": false, "status": "active", "statusReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Guardar una promoción > Crea o edita, con su versión, una promoción por cantidad: alcance, medida, beneficio, escalas con su regalo y vigencia. POST`/api/v1/price-lists/save-promotion` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `promotionId`uuidadmite null * `version`enteroadmite null mínimo 1 * `priceListId`uuidrequerido * `name`textorequerido de 1 a 80 caracteres * `scope`opciónrequerido Valores: `item` `items` `family` `list` * `familyId`uuidadmite null * `items`lista de objeto hasta 200 * `measure`opciónrequerido Valores: `unit` `package` * `benefit`opciónrequerido Valores: `percent` `price` * `validFrom`cualquiera * `validTo`cualquiera * `tiers`lista de objetorequerido hasta 100 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `priceListId`uuidrequerido * `priceListName`textorequerido * `name`textorequerido * `scope`opciónrequerido Valores: `item` `items` `family` `list` * `family`objetorequeridoadmite null * `items`lista de objetorequerido * `measure`opciónrequerido Valores: `unit` `package` * `benefit`opciónrequerido Valores: `percent` `price` * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null * `status`opciónrequerido Valores: `draft` `active` `inactive` * `statusReason`cualquierarequerido * `validity`opciónrequerido Valores: `current` `scheduled` `expired` * `version`enterorequerido mínimo 1 * `tiers`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/save-promotion" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "scope": "item", "measure": "unit", "benefit": "percent", "tiers": [ { "fromQuantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/save-promotion`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "scope": "item", "measure": "unit", "benefit": "percent", "tiers": [ { "fromQuantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListName": "texto", "name": "texto", "scope": "item", "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "path": "texto" }, "items": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitName": "texto", "level": "primary_box", "levelUnits": 100, "counts": false } ], "measure": "unit", "benefit": "percent", "validFrom": "2026-10-23", "validTo": "2026-10-23", "status": "draft", "statusReason": null, "validity": "current", "version": 1, "tiers": [ { "fromQuantity": 100, "discountPercent": null, "freeQuantity": null, "prices": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitPrice": "texto" } ] } ] } ``` # Listar listas de precios > Lista las listas de precios con búsqueda por nombre o código y filtro de estado. GET`/api/v1/price-lists/list` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `sort`opción Valores: `name` `code`Por defecto: `name` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `priceLists`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "priceLists": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "currencyCode": "texto", "isGeneral": false, "status": "active", "statusReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "itemsWithPrice": 1, "assignedCustomers": 1 } ], "total": 1 } ``` # Listar los precios de un artículo > Lista el precio de un artículo en cada lista activa en una fecha, con el próximo precio programado y las promociones que lo alcanzan. GET`/api/v1/price-lists/list-item-prices` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `itemId`uuidrequerido * `date`cualquiera ## Respuesta `200` con este JSON. * `date`fecharequerido * `lists`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/list-item-prices?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/list-item-prices?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "date": "2026-10-23", "lists": [ { "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "currencyCode": "texto", "isGeneral": false, "price": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23" }, "next": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23" }, "promotions": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "tiers": "texto" } ] } ] } ``` # Listar los precios de una lista > Lista los precios de una lista en una fecha: por artículo, el precio vigente, el próximo programado y las promociones por cantidad que lo alcanzan. GET`/api/v1/price-lists/list-prices` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `priceListId`uuidrequerido * `search`textoadmite null hasta 80 caracteres * `itemIds`uno deadmite null * `priceStatus`opción Valores: `with-price` `without-price` `all`Por defecto: `with-price` * `familyId`uuidadmite null * `brandId`uuidadmite null * `date`cualquiera * `sort`opción Valores: `code` `name`Por defecto: `code` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `date`fecharequerido * `currencyCode`textorequerido * `prices`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/list-prices?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/list-prices?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "date": "2026-10-23", "currencyCode": "texto", "prices": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitName": "texto", "status": "active", "isSold": false }, "price": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "version": 1 }, "next": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23" }, "promotions": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "tiers": "texto" } ] } ], "total": 1 } ``` # Listar precios especiales > Lista los precios especiales de un cliente o de un artículo, vigentes y programados o todos. GET`/api/v1/price-lists/list-customer-prices` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidadmite null * `itemId`uuidadmite null * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `current` `all`Por defecto: `current` * `sort`opción Valores: `customer` `item`Por defecto: `customer` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `customerPrices`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/list-customer-prices" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/list-customer-prices`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "customerPrices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "currencyCode": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "reason": null, "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "code": 1, "status": "active" }, "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "scheduled": false } ], "total": 1 } ``` # Listar promociones por cantidad > Lista las promociones por cantidad de una lista por nombre: borradores, vigentes y programadas, o todas, con búsqueda por nombre o por artículo. GET`/api/v1/price-lists/list-promotions` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `priceListId`uuidrequerido * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `current` `all`Por defecto: `current` * `itemId`uuidadmite null * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `promotions`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/list-promotions?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/list-promotions?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "promotions": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "scope": "item", "scopeText": "texto", "measure": "unit", "tiersText": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "status": "draft", "validity": "current" } ], "total": 1 } ``` # Marcar la lista general > Marca una lista activa como la general; la anterior deja de serlo. POST`/api/v1/price-lists/set-general` * Permiso `price-lists.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `priceListId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `currencyCode`textorequerido * `isGeneral`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/set-general" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/set-general`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "currencyCode": "texto", "isGeneral": false, "status": "active", "statusReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Previsualizar un ajuste porcentual > Revisa, sin grabar, un ajuste porcentual de los precios de una lista desde una fecha: los precios nuevos, los conteos y una huella para confirmarlo. GET`/api/v1/price-lists/preview-adjustment` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `priceListId`uuidrequerido * `percent`númerorequerido mínimo -90, máximo 1000 * `validFrom`textorequerido * `familyId`uuidadmite null * `brandId`uuidadmite null ## Respuesta `200` con este JSON. * `currencyCode`textorequerido * `rows`lista de objetorequerido * `withoutPrice`enterorequerido mínimo 0 * `excluded`enterorequerido mínimo 0 * `previewCount`enterorequerido mínimo 1 * `previewHash`textorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/preview-adjustment?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&percent=100&validFrom=texto" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/preview-adjustment?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&percent=100&validFrom=texto`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "currencyCode": "texto", "rows": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "currentPrice": "texto", "newPrice": "texto" } ], "withoutPrice": 1, "excluded": 1, "previewCount": 1, "previewHash": "texto" } ``` # Quitar un precio especial programado > Quita un precio especial que todavía no rige; vuelve a regir el anterior. POST`/api/v1/price-lists/remove-scheduled-customer-price` * Permiso `price-lists.set-customer-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerPriceId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `itemId`uuidrequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-customer-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/remove-scheduled-customer-price" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerPriceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/remove-scheduled-customer-price`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerPriceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Quitar un precio programado > Quita un precio programado que todavía no rige; vuelve a regir el anterior. POST`/api/v1/price-lists/remove-scheduled-price` * Permiso `price-lists.set-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `listPriceId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `priceListId`uuidrequerido * `itemId`uuidrequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/remove-scheduled-price" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "listPriceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/remove-scheduled-price`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "listPriceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Renombrar una lista de precios > Cambia el nombre de una lista de precios con la versión leída. POST`/api/v1/price-lists/update` * Permiso `price-lists.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `priceListId`uuidrequerido * `version`enterorequerido mínimo 1 * `name`textorequerido de 1 a 80 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `currencyCode`textorequerido * `isGeneral`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "currencyCode": "texto", "isGeneral": false, "status": "active", "statusReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Resolver el precio para un cliente > Resuelve el precio sin IVA de un artículo para un cliente, una fecha, un nivel y una cantidad: el precio especial del cliente, su lista o la general, con la promoción por cantidad y su origen. GET`/api/v1/price-lists/resolve-price` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `itemId`uuidrequerido * `customerId`uuidadmite null * `date`cualquiera * `level`opción Valores: `unit` `primary_box` `secondary_box` `pallet`Por defecto: `unit` * `quantity`número Por defecto: `1`mayor que 0, máximo 100000000000 ## Respuesta `200` con este JSON. * `found`sí o norequerido * `date`fecharequerido * `level`opciónrequerido Valores: `unit` `primary_box` `secondary_box` `pallet` * `quantity`númerorequerido * `price`texto * `listPrice`texto * `discountPercent`número * `currencyCode`texto * `source`opción Valores: `customer-price` `customer-list` `general-list` * `priceListId`uuid * `priceListName`texto * `customerPriceId`uuid * `validFrom`fecha * `totalStockUnits`número * `promotion`objeto ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/resolve-price?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/resolve-price?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "found": false, "date": "2026-10-23", "level": "unit", "quantity": 100, "price": "texto", "listPrice": "texto", "discountPercent": 100, "currencyCode": "texto", "source": "customer-price", "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListName": "texto", "customerPriceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "validFrom": "2026-10-23", "totalStockUnits": 100, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "fromQuantity": 100, "tier": "texto" } } ``` # Terminar un precio especial > Termina un precio especial en una fecha desde hoy, nunca después de su fin actual. POST`/api/v1/price-lists/end-customer-price` * Permiso `price-lists.set-customer-prices` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerPriceId`uuidrequerido * `validTo`textorequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `customerId`uuidrequerido * `itemId`uuidrequerido * `price`textorequerido * `currencyCode`textorequerido * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null * `reason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.set-customer-prices`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/price-lists/end-customer-price" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerPriceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "validTo": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/end-customer-price`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerPriceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "validTo": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "currencyCode": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "reason": null } ``` # Ver el historial de una lista > Lista los cambios de una lista, sus precios y sus promociones, del más nuevo al más viejo, campo por campo. GET`/api/v1/price-lists/get-history` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `priceListId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/get-history?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/get-history?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver el historial de una promoción > Lista los cambios de una promoción, sus artículos y sus escalas, del más nuevo al más viejo, campo por campo. GET`/api/v1/price-lists/get-promotion-history` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `promotionId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/get-promotion-history?promotionId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/get-promotion-history?promotionId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver la historia de precios de un artículo > Lista todos los precios de un artículo en una lista, del más nuevo al más viejo, con quién los cargó y las promociones que lo alcanzan. GET`/api/v1/price-lists/get-price-history` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `priceListId`uuidrequerido * `itemId`uuidrequerido ## Respuesta `200` con este JSON. * `currencyCode`textorequerido * `prices`lista de objetorequerido * `promotions`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/get-price-history?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/get-price-history?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "currencyCode": "texto", "prices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "price": "texto", "validFrom": "2026-10-23", "validTo": "2026-10-23", "scheduled": false, "loadedBy": { "id": "texto", "name": null }, "loadedAt": "2026-10-23T14:30:00.000Z" } ], "promotions": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "tiers": "texto" } ] } ``` # Ver una lista de precios > Devuelve una lista con su moneda, si es la general y cuántos artículos tienen precio hoy. GET`/api/v1/price-lists/get` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `priceListId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `name`textorequerido * `currencyCode`textorequerido * `isGeneral`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `statusReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `itemsWithPrice`enterorequerido mínimo 0 * `assignedCustomers`enterorequerido mínimo 0 * `promotionsInForce`enterorequerido mínimo 0 * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/get?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/get?priceListId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "name": "texto", "currencyCode": "texto", "isGeneral": false, "status": "active", "statusReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "itemsWithPrice": 1, "assignedCustomers": 1, "promotionsInForce": 1, "validFrom": "2026-10-23", "validTo": "2026-10-23" } ``` # Ver una promoción > Devuelve una promoción por cantidad con su alcance (artículos o familia), medida, beneficio, vigencia, estado y escalas. GET`/api/v1/price-lists/get-promotion` * Permiso `price-lists.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `promotionId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `priceListId`uuidrequerido * `priceListName`textorequerido * `name`textorequerido * `scope`opciónrequerido Valores: `item` `items` `family` `list` * `family`objetorequeridoadmite null * `items`lista de objetorequerido * `measure`opciónrequerido Valores: `unit` `package` * `benefit`opciónrequerido Valores: `percent` `price` * `validFrom`fecharequerido * `validTo`fecharequeridoadmite null * `status`opciónrequerido Valores: `draft` `active` `inactive` * `statusReason`cualquierarequerido * `validity`opciónrequerido Valores: `current` `scheduled` `expired` * `version`enterorequerido mínimo 1 * `tiers`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `price-lists.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/price-lists/get-promotion?promotionId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/price-lists/get-promotion?promotionId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "priceListName": "texto", "name": "texto", "scope": "item", "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "path": "texto" }, "items": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitName": "texto", "level": "primary_box", "levelUnits": 100, "counts": false } ], "measure": "unit", "benefit": "percent", "validFrom": "2026-10-23", "validTo": "2026-10-23", "status": "draft", "statusReason": null, "validity": "current", "version": 1, "tiers": [ { "fromQuantity": 100, "discountPercent": null, "freeQuantity": null, "prices": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitPrice": "texto" } ] } ] } ``` # Marcas y familias > Las marcas y el árbol de familias que clasifican los artículos. Las marcas y el árbol de familias que clasifican los artículos. | Operación | Ruta | | ----------------------------------------------------------------------------------------------------------- | ---------------------------------- | | [Listar marcas](/api/referencia/marcas-y-familias/listar-marcas/) | GET `/api/v1/brands/list` | | [Crear una marca](/api/referencia/marcas-y-familias/crear-una-marca/) | POST `/api/v1/brands/create` | | [Renombrar una marca](/api/referencia/marcas-y-familias/renombrar-una-marca/) | POST `/api/v1/brands/update` | | [Desactivar o reactivar una marca](/api/referencia/marcas-y-familias/desactivar-o-reactivar-una-marca/) | POST `/api/v1/brands/set-status` | | [Listar familias](/api/referencia/marcas-y-familias/listar-familias/) | GET `/api/v1/families/list` | | [Crear una familia](/api/referencia/marcas-y-familias/crear-una-familia/) | POST `/api/v1/families/create` | | [Renombrar una familia](/api/referencia/marcas-y-familias/renombrar-una-familia/) | POST `/api/v1/families/update` | | [Desactivar o reactivar una familia](/api/referencia/marcas-y-familias/desactivar-o-reactivar-una-familia/) | POST `/api/v1/families/set-status` | # Crear una familia > Crea una familia con su nombre y, opcional, su familia padre. POST`/api/v1/families/create` * Permiso `classifications.manage` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `name`textorequerido de 1 a 80 caracteres * `parentId`uuidadmite null * `confirmedItems`enteroadmite null mínimo 0 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `parentId`uuidrequeridoadmite null * `name`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `inUse`sí o norequerido * `path`lista de textorequerido * `depth`enterorequerido mínimo 0 * `isLeaf`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.manage`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/families/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/families/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "inUse": false, "path": [ "texto" ], "depth": 1, "isLeaf": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Crear una marca > Crea una marca con su nombre. POST`/api/v1/brands/create` * Permiso `classifications.manage` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `name`textorequerido de 1 a 80 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `name`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.manage`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/brands/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/brands/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar una familia > Desactiva o reactiva una familia; sus subfamilias la siguen. POST`/api/v1/families/set-status` * Permiso `classifications.manage` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `familyId`uuidrequerido * `status`opciónrequerido Valores: `active` `inactive` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `parentId`uuidrequeridoadmite null * `name`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `inUse`sí o norequerido * `path`lista de textorequerido * `depth`enterorequerido mínimo 0 * `isLeaf`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.manage`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/families/set-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/families/set-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "inUse": false, "path": [ "texto" ], "depth": 1, "isLeaf": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar una marca > Desactiva o reactiva una marca. POST`/api/v1/brands/set-status` * Permiso `classifications.manage` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `brandId`uuidrequerido * `status`opciónrequerido Valores: `active` `inactive` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `name`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.manage`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/brands/set-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/brands/set-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Listar familias > Lista el árbol de familias, con búsqueda por nombre, filtro de estado y, opcional, sólo las hojas. GET`/api/v1/families/list` * Permiso `classifications.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `leavesOnly`sí o no ## Respuesta `200` con este JSON. * `families`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/families/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/families/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "families": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "inUse": false, "path": [ "texto" ], "depth": 1, "isLeaf": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "activeItems": 1, "branchItems": 1 } ], "total": 1 } ``` # Listar marcas > Lista las marcas por nombre, con búsqueda por nombre y filtro de estado. GET`/api/v1/brands/list` * Permiso `classifications.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `brands`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/brands/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/brands/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "brands": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "activeItems": 1 } ], "total": 1 } ``` # Renombrar una familia > Renombra una familia con la versión leída; su familia padre no cambia. POST`/api/v1/families/update` * Permiso `classifications.manage` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `familyId`uuidrequerido * `version`enterorequerido mínimo 1 * `name`textorequerido de 1 a 80 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `parentId`uuidrequeridoadmite null * `name`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `inUse`sí o norequerido * `path`lista de textorequerido * `depth`enterorequerido mínimo 0 * `isLeaf`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.manage`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/families/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/families/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "familyId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "inUse": false, "path": [ "texto" ], "depth": 1, "isLeaf": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Renombrar una marca > Renombra una marca con la versión leída. POST`/api/v1/brands/update` * Permiso `classifications.manage` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `brandId`uuidrequerido * `version`enterorequerido mínimo 1 * `name`textorequerido de 1 a 80 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `name`textorequerido * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `classifications.manage`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/brands/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/brands/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "brandId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Movimientos > Movimientos de stock, saldos iniciales y cambios de condición. Movimientos de stock, saldos iniciales y cambios de condición. | Operación | Ruta | | --------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | [Listar movimientos de stock](/api/referencia/movimientos/listar-movimientos-de-stock/) | GET `/api/v1/stock-movements/list` | | [Ver un movimiento](/api/referencia/movimientos/ver-un-movimiento/) | GET `/api/v1/stock-movements/get` | | [Cargar saldos iniciales](/api/referencia/movimientos/cargar-saldos-iniciales/) | POST `/api/v1/stock-movements/load-opening-balance` | | [Cambiar la condición del stock](/api/referencia/movimientos/cambiar-la-condicion-del-stock/) | POST `/api/v1/stock-movements/change-condition` | | [Revertir un movimiento](/api/referencia/movimientos/revertir-un-movimiento/) | POST `/api/v1/stock-movements/revert` | | [Ver el historial de un movimiento](/api/referencia/movimientos/ver-el-historial-de-un-movimiento/) | GET `/api/v1/stock-movements/get-history` | # Cambiar la condición del stock > Pasa stock de un depósito de apto a bloqueado o al revés, con su motivo. El costo y el stock físico no cambian. POST`/api/v1/stock-movements/change-condition` * Permiso `stock-movements.register` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `reason`opciónrequerido Valores: `quality` `damage` `release` `other` * `notes`textoadmite null hasta 300 caracteres * `date`fechaadmite null * `from`opciónrequerido Valores: `apt` `blocked` * `to`opciónrequerido Valores: `apt` `blocked` * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `type`opciónrequerido Valores: `entry` `exit` `opening_balance` `condition_change` `count_adjustment` `reversal` * `reason`cualquierarequerido * `notes`cualquierarequerido * `date`fecharequerido * `status`opciónrequerido Valores: `registered` `reverted` * `warehouse`objetorequerido * `lineCount`enterorequerido mínimo 1 * `source`objetorequeridoadmite null * `itemLine`objeto * `from`opciónrequeridoadmite null Valores: `apt` `blocked` * `to`opciónrequeridoadmite null Valores: `apt` `blocked` * `reverses`objetorequeridoadmite null * `reversedBy`objetorequeridoadmite null * `count`objetorequeridoadmite null * `registeredBy`objetorequerido * `registeredAt`fecha y horarequerido * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.register`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/change-condition" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "quality", "from": "apt", "to": "apt", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/change-condition`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "quality", "from": "apt", "to": "apt", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "type": "entry", "reason": null, "notes": null, "date": "2026-10-23", "status": "registered", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "lineCount": 1, "source": { "kind": "delivery-note", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }, "itemLine": { "quantity": 100, "physicalAfter": 100, "from": "apt", "to": "apt" }, "from": "apt", "to": "apt", "reverses": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversedBy": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "count": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "registeredBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "physicalAfter": 100, "aptAfter": 100, "blockedAfter": 100, "released": null, "unitCost": null, "amount": null } ] } ``` # Cargar saldos iniciales > Carga los saldos iniciales de un depósito: un documento en el que cada línea trae su costo unitario. No tiene pantalla: se carga por la API. POST`/api/v1/stock-movements/load-opening-balance` * Permiso `stock-movements.register` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `notes`textoadmite null hasta 300 caracteres * `date`fechaadmite null * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `type`opciónrequerido Valores: `entry` `exit` `opening_balance` `condition_change` `count_adjustment` `reversal` * `reason`cualquierarequerido * `notes`cualquierarequerido * `date`fecharequerido * `status`opciónrequerido Valores: `registered` `reverted` * `warehouse`objetorequerido * `lineCount`enterorequerido mínimo 1 * `source`objetorequeridoadmite null * `itemLine`objeto * `from`opciónrequeridoadmite null Valores: `apt` `blocked` * `to`opciónrequeridoadmite null Valores: `apt` `blocked` * `reverses`objetorequeridoadmite null * `reversedBy`objetorequeridoadmite null * `count`objetorequeridoadmite null * `registeredBy`objetorequerido * `registeredAt`fecha y horarequerido * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.register`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/load-opening-balance" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100, "unitCost": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/load-opening-balance`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100, "unitCost": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "type": "entry", "reason": null, "notes": null, "date": "2026-10-23", "status": "registered", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "lineCount": 1, "source": { "kind": "delivery-note", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }, "itemLine": { "quantity": 100, "physicalAfter": 100, "from": "apt", "to": "apt" }, "from": "apt", "to": "apt", "reverses": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversedBy": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "count": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "registeredBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "physicalAfter": 100, "aptAfter": 100, "blockedAfter": 100, "released": null, "unitCost": null, "amount": null } ] } ``` # Listar movimientos de stock > Lista los movimientos, del más nuevo al más viejo, con búsqueda por número, artículo o detalle y filtros de tipo, depósito, artículo, estado y fechas. GET`/api/v1/stock-movements/list` * Permiso `stock-movements.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `type`opciónadmite null Valores: `entry` `exit` `opening_balance` `condition_change` `count_adjustment` `reversal` * `warehouseId`uuidadmite null * `itemId`uuidadmite null * `status`opciónadmite null Valores: `registered` `reverted` * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `movements`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock-movements/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "movements": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "type": "entry", "reason": null, "notes": null, "date": "2026-10-23", "status": "registered", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "lineCount": 1, "source": { "kind": "delivery-note", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }, "itemLine": { "quantity": 100, "physicalAfter": 100, "from": "apt", "to": "apt" } } ], "total": 1 } ``` # Revertir un movimiento > Revierte un movimiento manual o un saldo inicial con una reversión vinculada de signo contrario y el mismo costo congelado. POST`/api/v1/stock-movements/revert` * Permiso `stock-movements.revert` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `movementId`uuidrequerido * `reason`textorequerido de 1 a 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `type`opciónrequerido Valores: `entry` `exit` `opening_balance` `condition_change` `count_adjustment` `reversal` * `reason`cualquierarequerido * `notes`cualquierarequerido * `date`fecharequerido * `status`opciónrequerido Valores: `registered` `reverted` * `warehouse`objetorequerido * `lineCount`enterorequerido mínimo 1 * `source`objetorequeridoadmite null * `itemLine`objeto * `from`opciónrequeridoadmite null Valores: `apt` `blocked` * `to`opciónrequeridoadmite null Valores: `apt` `blocked` * `reverses`objetorequeridoadmite null * `reversedBy`objetorequeridoadmite null * `count`objetorequeridoadmite null * `registeredBy`objetorequerido * `registeredAt`fecha y horarequerido * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.revert`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/revert" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "movementId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/revert`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "movementId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "type": "entry", "reason": null, "notes": null, "date": "2026-10-23", "status": "registered", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "lineCount": 1, "source": { "kind": "delivery-note", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }, "itemLine": { "quantity": 100, "physicalAfter": 100, "from": "apt", "to": "apt" }, "from": "apt", "to": "apt", "reverses": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversedBy": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "count": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "registeredBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "physicalAfter": 100, "aptAfter": 100, "blockedAfter": 100, "released": null, "unitCost": null, "amount": null } ] } ``` # Ver el historial de un movimiento > Lista los cambios de un movimiento y sus líneas, del más nuevo al más viejo, campo por campo. GET`/api/v1/stock-movements/get-history` * Permiso `stock-movements.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `movementId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock-movements/get-history?movementId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/get-history?movementId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un movimiento > Devuelve un movimiento con sus líneas, el stock físico que dejó cada una, sus vínculos y quién lo registró. GET`/api/v1/stock-movements/get` * Permiso `stock-movements.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `movementId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `type`opciónrequerido Valores: `entry` `exit` `opening_balance` `condition_change` `count_adjustment` `reversal` * `reason`cualquierarequerido * `notes`cualquierarequerido * `date`fecharequerido * `status`opciónrequerido Valores: `registered` `reverted` * `warehouse`objetorequerido * `lineCount`enterorequerido mínimo 1 * `source`objetorequeridoadmite null * `itemLine`objeto * `from`opciónrequeridoadmite null Valores: `apt` `blocked` * `to`opciónrequeridoadmite null Valores: `apt` `blocked` * `reverses`objetorequeridoadmite null * `reversedBy`objetorequeridoadmite null * `count`objetorequeridoadmite null * `registeredBy`objetorequerido * `registeredAt`fecha y horarequerido * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock-movements/get?movementId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/get?movementId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "type": "entry", "reason": null, "notes": null, "date": "2026-10-23", "status": "registered", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "lineCount": 1, "source": { "kind": "delivery-note", "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "deliveryId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }, "itemLine": { "quantity": 100, "physicalAfter": 100, "from": "apt", "to": "apt" }, "from": "apt", "to": "apt", "reverses": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversedBy": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "count": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "registeredBy": { "id": "texto", "name": null }, "registeredAt": "2026-10-23T14:30:00.000Z", "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "physicalAfter": 100, "aptAfter": 100, "blockedAfter": 100, "released": null, "unitCost": null, "amount": null } ] } ``` # Órdenes de compra > El pedido al proveedor: se arma en borrador, se emite y se modifica mientras tenga pendiente. El pedido al proveedor: se arma en borrador, se emite y se modifica mientras tenga pendiente. | Operación | Ruta | | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | [Listar órdenes de compra](/api/referencia/ordenes-de-compra/listar-ordenes-de-compra/) | GET `/api/v1/purchase-orders/list` | | [Ver una orden de compra](/api/referencia/ordenes-de-compra/ver-una-orden-de-compra/) | GET `/api/v1/purchase-orders/get` | | [Crear una orden de compra](/api/referencia/ordenes-de-compra/crear-una-orden-de-compra/) | POST `/api/v1/purchase-orders/create` | | [Modificar una orden en borrador](/api/referencia/ordenes-de-compra/modificar-una-orden-en-borrador/) | POST `/api/v1/purchase-orders/update` | | [Proponer precios de compra](/api/referencia/ordenes-de-compra/proponer-precios-de-compra/) | GET `/api/v1/purchase-orders/propose-prices` | | [Emitir una orden de compra](/api/referencia/ordenes-de-compra/emitir-una-orden-de-compra/) | POST `/api/v1/purchase-orders/issue` | | [Modificar una orden emitida](/api/referencia/ordenes-de-compra/modificar-una-orden-emitida/) | POST `/api/v1/purchase-orders/modify` | | [Cerrar una orden de compra](/api/referencia/ordenes-de-compra/cerrar-una-orden-de-compra/) | POST `/api/v1/purchase-orders/close` | | [Descartar una orden de compra](/api/referencia/ordenes-de-compra/descartar-una-orden-de-compra/) | POST `/api/v1/purchase-orders/discard` | | [Descargar el PDF de una orden](/api/referencia/ordenes-de-compra/descargar-el-pdf-de-una-orden/) | POST `/api/v1/purchase-orders/print` | | [Ver el historial de una orden](/api/referencia/ordenes-de-compra/ver-el-historial-de-una-orden/) | GET `/api/v1/purchase-orders/get-history` | | [Listar adjuntos de una orden](/api/referencia/ordenes-de-compra/listar-adjuntos-de-una-orden/) | GET `/api/v1/purchase-orders/list-attachments` | | [Adjuntar un archivo a una orden](/api/referencia/ordenes-de-compra/adjuntar-un-archivo-a-una-orden/) | POST `/api/v1/purchase-orders/add-attachment` | | [Descargar un adjunto de una orden](/api/referencia/ordenes-de-compra/descargar-un-adjunto-de-una-orden/) | POST `/api/v1/purchase-orders/get-attachment` | | [Quitar un adjunto de una orden](/api/referencia/ordenes-de-compra/quitar-un-adjunto-de-una-orden/) | POST `/api/v1/purchase-orders/remove-attachment` | # Adjuntar un archivo a una orden > Adjunta un archivo (PDF, JPEG, PNG, WebP, Excel o Word de hasta 10 MB) a una orden no descartada. Hasta 20 por documento y nunca el mismo dos veces. POST`/api/v1/purchase-orders/add-attachment` * Permiso `purchase-orders.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `fileName`textorequerido de 1 a 200 caracteres * `contentBase64`textorequerido de 1 a 15728640 caracteres, formato \`^\[A-Za-z0-9+/]+={0,2}$\` ## Respuesta `200` con este JSON. * `id`textorequerido * `fileName`textorequerido * `mediaType`opciónrequerido Valores: `application/pdf` `image/jpeg` `image/png` `image/webp` `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` `application/vnd.ms-excel` `application/vnd.openxmlformats-officedocument.wordprocessingml.document` `application/msword` * `sizeBytes`enterorequerido * `uploadedAt`fecha y horarequerido * `uploadedBy`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/add-attachment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fileName": "texto", "contentBase64": "ARS" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/add-attachment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fileName": "texto", "contentBase64": "ARS" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "texto", "fileName": "texto", "mediaType": "application/pdf", "sizeBytes": 1, "uploadedAt": "2026-10-23T14:30:00.000Z", "uploadedBy": { "id": "texto", "name": null } } ``` # Cerrar una orden de compra > Cierra una orden emitida con lo pendiente, con un motivo opcional: se cancela lo no recibido. Se rechaza si una recepción en borrador retiene cantidades o si no queda nada pendiente. POST`/api/v1/purchase-orders/close` * Permiso `purchase-orders.close` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `purchaseOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textoadmite null hasta 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `issued` `closed` `discarded` * `orderType`opciónrequerido Valores: `domestic` `import` `services` * `documentDate`fecharequerido * `expectedDate`fecharequeridoadmite null * `supplier`objetorequerido * `currencyCode`textorequerido * `netTotal`textorequerido * `receivingProgress`opciónrequeridoadmite null Valores: `not-received` `partial` `received` * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `withDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `warehouse`objetorequerido * `agreedExchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `receipts`lista de objetorequerido * `invoices`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.close`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/close" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/close`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false, "version": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "agreedExchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "unitPrice": null, "priceSource": "supplier-item", "discountPercent": 100, "netAmount": "texto", "vatRate": null, "receivedQuantity": 100, "inReceiptQuantity": 100, "pendingQuantity": 100, "invoicedQuantity": 100, "customsDeclarations": [ "texto" ] } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "status": "draft", "reversal": "none", "supplierDeliveryNote": null } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Crear una orden de compra > Crea una orden en borrador a un proveedor con fecha, entrega prevista, depósito destino, moneda y cotización pactada, condición, notas y líneas. El precio de cada línea lo propone el último precio del proveedor en esa moneda. POST`/api/v1/purchase-orders/create` * Permiso `purchase-orders.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierId`uuidrequerido * `documentDate`fechaadmite null * `expectedDate`fechaadmite null * `warehouseId`uuidadmite null * `currencyCode`texto formato \`^\[A-Za-z]{3}$\` * `agreedExchangeRate`cualquiera * `paymentTermId`uuidadmite null * `notes`textoadmite null hasta 1000 caracteres * `services`sí o no Por defecto: `false` * `lines`lista de objetorequerido hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `issued` `closed` `discarded` * `orderType`opciónrequerido Valores: `domestic` `import` `services` * `documentDate`fecharequerido * `expectedDate`fecharequeridoadmite null * `supplier`objetorequerido * `currencyCode`textorequerido * `netTotal`textorequerido * `receivingProgress`opciónrequeridoadmite null Valores: `not-received` `partial` `received` * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `withDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `warehouse`objetorequerido * `agreedExchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `receipts`lista de objetorequerido * `invoices`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false, "version": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "agreedExchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "unitPrice": null, "priceSource": "supplier-item", "discountPercent": 100, "netAmount": "texto", "vatRate": null, "receivedQuantity": 100, "inReceiptQuantity": 100, "pendingQuantity": 100, "invoicedQuantity": 100, "customsDeclarations": [ "texto" ] } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "status": "draft", "reversal": "none", "supplierDeliveryNote": null } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Descargar el PDF de una orden > Descarga el PDF de una orden emitida para mandar al proveedor: emisor, proveedor, dónde entregar, condición, líneas con códigos, precio, bonificación e importe, neto, IVA informativo y total. POST`/api/v1/purchase-orders/print` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta un PDF ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `purchaseOrderId`uuidrequerido ## Respuesta `200` con un PDF y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/print" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/print`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Descargar un adjunto de una orden > Devuelve un archivo adjunto a una orden de compra para descargarlo con su nombre. POST`/api/v1/purchase-orders/get-attachment` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta el archivo ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `attachmentId`uuidrequerido ## Respuesta `200` con el archivo y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/get-attachment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/get-attachment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Descartar una orden de compra > Descarta una orden en borrador con un motivo. Conserva su número. POST`/api/v1/purchase-orders/discard` * Permiso `purchase-orders.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `purchaseOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `issued` `closed` `discarded` * `orderType`opciónrequerido Valores: `domestic` `import` `services` * `documentDate`fecharequerido * `expectedDate`fecharequeridoadmite null * `supplier`objetorequerido * `currencyCode`textorequerido * `netTotal`textorequerido * `receivingProgress`opciónrequeridoadmite null Valores: `not-received` `partial` `received` * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `withDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `warehouse`objetorequerido * `agreedExchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `receipts`lista de objetorequerido * `invoices`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/discard" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/discard`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false, "version": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "agreedExchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "unitPrice": null, "priceSource": "supplier-item", "discountPercent": 100, "netAmount": "texto", "vatRate": null, "receivedQuantity": 100, "inReceiptQuantity": 100, "pendingQuantity": 100, "invoicedQuantity": 100, "customsDeclarations": [ "texto" ] } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "status": "draft", "reversal": "none", "supplierDeliveryNote": null } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Emitir una orden de compra > Emite una orden en borrador con la versión leída: congela precios, bonificaciones, códigos del proveedor y cuotas, y actualiza el último precio del proveedor de cada artículo. No mueve stock. POST`/api/v1/purchase-orders/issue` * Permiso `purchase-orders.issue` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `purchaseOrderId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `issued` `closed` `discarded` * `orderType`opciónrequerido Valores: `domestic` `import` `services` * `documentDate`fecharequerido * `expectedDate`fecharequeridoadmite null * `supplier`objetorequerido * `currencyCode`textorequerido * `netTotal`textorequerido * `receivingProgress`opciónrequeridoadmite null Valores: `not-received` `partial` `received` * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `withDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `warehouse`objetorequerido * `agreedExchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `receipts`lista de objetorequerido * `invoices`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.issue`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/issue" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/issue`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false, "version": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "agreedExchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "unitPrice": null, "priceSource": "supplier-item", "discountPercent": 100, "netAmount": "texto", "vatRate": null, "receivedQuantity": 100, "inReceiptQuantity": 100, "pendingQuantity": 100, "invoicedQuantity": 100, "customsDeclarations": [ "texto" ] } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "status": "draft", "reversal": "none", "supplierDeliveryNote": null } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Listar adjuntos de una orden > Lista los archivos adjuntos a una orden de compra, del más nuevo al más viejo. GET`/api/v1/purchase-orders/list-attachments` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `documentId`uuidrequerido ## Respuesta `200` con este JSON. * `attachments`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/list-attachments?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/list-attachments?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "attachments": [ { "id": "texto", "fileName": "texto", "mediaType": "application/pdf", "sizeBytes": 1, "uploadedAt": "2026-10-23T14:30:00.000Z", "uploadedBy": { "id": "texto", "name": null } } ] } ``` # Listar órdenes de compra > Lista las órdenes de compra con búsqueda por número o proveedor y filtros de estado, recepción, facturación, proveedor y fechas. Por defecto trae todas menos las descartadas. GET`/api/v1/purchase-orders/list` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `status`lista de opciónadmite null Valores: `draft` `issued` `closed` `discarded` * `receiving`lista de opciónadmite null Valores: `pending` `not-received` `partial` `received` * `receivable`sí o no * `invoicing`lista de opciónadmite null Valores: `not-invoiced` `partial` `invoiced` * `orderType`lista de opciónadmite null Valores: `domestic` `import` `services` * `supplierId`uuidadmite null * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `sort`opción Valores: `number` `date` `supplier` `expected` `amount`Por defecto: `number` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `purchaseOrders`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "purchaseOrders": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false } ], "total": 1 } ``` # Modificar una orden emitida > Modifica una orden emitida con la versión leída: agrega o quita líneas y cambia cantidades, precios y bonificaciones de lo pendiente, la entrega prevista, el depósito y las notas. Nunca por debajo de lo recibido. POST`/api/v1/purchase-orders/modify` * Permiso `purchase-orders.modify` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `purchaseOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `expectedDate`fechaadmite null * `warehouseId`uuidrequerido * `notes`textoadmite null hasta 1000 caracteres * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `issued` `closed` `discarded` * `orderType`opciónrequerido Valores: `domestic` `import` `services` * `documentDate`fecharequerido * `expectedDate`fecharequeridoadmite null * `supplier`objetorequerido * `currencyCode`textorequerido * `netTotal`textorequerido * `receivingProgress`opciónrequeridoadmite null Valores: `not-received` `partial` `received` * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `withDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `warehouse`objetorequerido * `agreedExchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `receipts`lista de objetorequerido * `invoices`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.modify`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/modify" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/modify`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false, "version": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "agreedExchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "unitPrice": null, "priceSource": "supplier-item", "discountPercent": 100, "netAmount": "texto", "vatRate": null, "receivedQuantity": 100, "inReceiptQuantity": 100, "pendingQuantity": 100, "invoicedQuantity": 100, "customsDeclarations": [ "texto" ] } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "status": "draft", "reversal": "none", "supplierDeliveryNote": null } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Modificar una orden en borrador > Edita una orden en borrador con la versión leída. Cada línea que sigue conserva su id y los precios que no son manuales se vuelven a proponer. POST`/api/v1/purchase-orders/update` * Permiso `purchase-orders.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `purchaseOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `supplierId`uuidrequerido * `documentDate`fechaadmite null * `expectedDate`fechaadmite null * `warehouseId`uuidadmite null * `currencyCode`texto formato \`^\[A-Za-z]{3}$\` * `agreedExchangeRate`cualquiera * `paymentTermId`uuidadmite null * `notes`textoadmite null hasta 1000 caracteres * `lines`lista de objetorequerido hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `issued` `closed` `discarded` * `orderType`opciónrequerido Valores: `domestic` `import` `services` * `documentDate`fecharequerido * `expectedDate`fecharequeridoadmite null * `supplier`objetorequerido * `currencyCode`textorequerido * `netTotal`textorequerido * `receivingProgress`opciónrequeridoadmite null Valores: `not-received` `partial` `received` * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `withDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `warehouse`objetorequerido * `agreedExchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `receipts`lista de objetorequerido * `invoices`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false, "version": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "agreedExchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "unitPrice": null, "priceSource": "supplier-item", "discountPercent": 100, "netAmount": "texto", "vatRate": null, "receivedQuantity": 100, "inReceiptQuantity": 100, "pendingQuantity": 100, "invoicedQuantity": 100, "customsDeclarations": [ "texto" ] } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "status": "draft", "reversal": "none", "supplierDeliveryNote": null } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Proponer precios de compra > Devuelve, sin grabar, el último precio del proveedor para cada artículo en la moneda pedida, con su fecha, el código y la descripción del proveedor y la unidad de compra. GET`/api/v1/purchase-orders/propose-prices` * Permiso `purchase-orders.prepare` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido * `currencyCode`textorequerido formato \`^\[A-Za-z]{3}$\` * `itemIds`lista de uuidrequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `items`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/propose-prices?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90¤cyCode=ARS&itemIds=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/propose-prices?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90¤cyCode=ARS&itemIds=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "items": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitPrice": null, "priceDate": "2026-10-23", "supplierCode": null, "supplierDescription": null, "purchaseLevel": null, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false, "isImported": false, "vatRate": null } ] } ``` # Quitar un adjunto de una orden > Quita un archivo adjunto a una orden no descartada. POST`/api/v1/purchase-orders/remove-attachment` * Permiso `purchase-orders.prepare` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `attachmentId`uuidrequerido ## Respuesta `200` con este JSON. * `id`textorequerido * `removed`constanterequerido Valores: `true` ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.prepare`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/remove-attachment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/remove-attachment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "texto", "removed": true } ``` # Ver el historial de una orden > Lista los cambios de una orden, sus líneas y sus adjuntos, del más nuevo al más viejo, campo por campo. GET`/api/v1/purchase-orders/get-history` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `purchaseOrderId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/get-history?purchaseOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/get-history?purchaseOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver una orden de compra > Devuelve una orden con su proveedor, depósito, moneda, condición, líneas con lo recibido, retenido y pendiente, sus totales con el IVA informativo, sus recepciones y quién la emitió o cerró. GET`/api/v1/purchase-orders/get` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `purchaseOrderId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `issued` `closed` `discarded` * `orderType`opciónrequerido Valores: `domestic` `import` `services` * `documentDate`fecharequerido * `expectedDate`fecharequeridoadmite null * `supplier`objetorequerido * `currencyCode`textorequerido * `netTotal`textorequerido * `receivingProgress`opciónrequeridoadmite null Valores: `not-received` `partial` `received` * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `withDifferences`sí o norequerido * `version`enterorequerido mínimo 1 * `warehouse`objetorequerido * `agreedExchangeRate`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `receipts`lista de objetorequerido * `invoices`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `issuedAt`fecha y horarequeridoadmite null * `issuedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/get?purchaseOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/get?purchaseOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "orderType": "domestic", "documentDate": "2026-10-23", "expectedDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "currencyCode": "texto", "netTotal": "texto", "receivingProgress": "not-received", "invoicingProgress": "not-invoiced", "withDifferences": false, "version": 1, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "agreedExchangeRate": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "unitPrice": null, "priceSource": "supplier-item", "discountPercent": 100, "netAmount": "texto", "vatRate": null, "receivedQuantity": 100, "inReceiptQuantity": 100, "pendingQuantity": 100, "invoicedQuantity": 100, "customsDeclarations": [ "texto" ] } ], "totals": { "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "receiptDate": "2026-10-23", "status": "draft", "reversal": "none", "supplierDeliveryNote": null } ], "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "issuedAt": "2026-10-23T14:30:00.000Z", "issuedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Pagos > Órdenes de pago a proveedores con sus medios de pago, su imputación y lo que queda a favor. Órdenes de pago a proveedores con sus medios de pago, su imputación y lo que queda a favor. | Operación | Ruta | | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | | [Listar órdenes de pago](/api/referencia/pagos/listar-ordenes-de-pago/) | GET `/api/v1/payments/list` | | [Ver una orden de pago](/api/referencia/pagos/ver-una-orden-de-pago/) | GET `/api/v1/payments/get` | | [Listar cuotas abiertas de un proveedor](/api/referencia/pagos/listar-cuotas-abiertas-de-un-proveedor/) | GET `/api/v1/payments/list-open-items` | | [Registrar una orden de pago](/api/referencia/pagos/registrar-una-orden-de-pago/) | POST `/api/v1/payments/register` | | [Proponer la aplicación de saldos a favor](/api/referencia/pagos/proponer-la-aplicacion-de-saldos-a-favor/) | GET `/api/v1/payments/propose-credit-application` | | [Aplicar saldos a favor](/api/referencia/pagos/aplicar-saldos-a-favor/) | POST `/api/v1/payments/apply-credit` | | [Deshacer una aplicación](/api/referencia/pagos/deshacer-una-aplicacion/) | POST `/api/v1/payments/undo-clearing` | | [Recuperar una orden de pago](/api/referencia/pagos/recuperar-una-orden-de-pago/) | POST `/api/v1/payments/recover` | | [Descargar el PDF de una orden de pago](/api/referencia/pagos/descargar-el-pdf-de-una-orden-de-pago/) | POST `/api/v1/payments/download-pdf` | | [Ver el historial de una orden de pago](/api/referencia/pagos/ver-el-historial-de-una-orden-de-pago/) | GET `/api/v1/payments/get-history` | # Aplicar saldos a favor > Aplica lo que la empresa tiene a favor con un proveedor a sus cuotas abiertas de la misma moneda, tal como se confirmó, controlado bajo bloqueo. POST`/api/v1/payments/apply-credit` * Permiso `payments.apply-credit` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierId`uuidrequerido * `applications`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `applications`lista de objetorequerido * `orders`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.apply-credit`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payments/apply-credit" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "debitItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": null } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/apply-credit`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "debitItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": null } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "debitItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": "texto" } ], "orders": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "advanceBalance": "texto" } ] } ``` # Descargar el PDF de una orden de pago > Descarga el PDF de una orden de pago para entregar al proveedor: la empresa, el proveedor, la cotización, cada medio de pago con su cuenta destino, la imputación y el total. POST`/api/v1/payments/download-pdf` * Permiso `payments.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta un PDF ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `paymentOrderId`uuidrequerido ## Respuesta `200` con un PDF y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payments/download-pdf" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "paymentOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/download-pdf`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "paymentOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Deshacer una aplicación > Deshace la cancelación entre un crédito del proveedor y una cuota sin recuperar la orden ni anular la nota: ambos quedan abiertos otra vez por su importe y se revierten sus asientos. POST`/api/v1/payments/undo-clearing` * Permiso `payments.apply-credit` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `allocationId`uuidrequerido * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `allocationId`uuidrequerido * `orders`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.apply-credit`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payments/undo-clearing" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "allocationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/undo-clearing`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "allocationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "allocationId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "orders": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "advanceBalance": "texto" } ] } ``` # Listar cuotas abiertas de un proveedor > Lista las cuotas abiertas de un proveedor que puede imputar una orden de una fecha y moneda, con la imputación propuesta de un importe, lo que se le debe y lo que hay a favor por moneda, y sus cuentas bancarias activas. GET`/api/v1/payments/list-open-items` * Permiso `payments.create` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido * `paymentDate`fechaadmite null * `currencyCode`texto Por defecto: `ARS`formato \`^\[A-Z]{3}$\` * `foreignCurrencyCode`textoadmite null formato \`^\[A-Z]{3}$\` * `exchangeRate`cualquiera * `amount`cualquiera * `documentSourceId`uuidadmite null ## Respuesta `200` con este JSON. * `supplier`objetorequerido * `items`lista de objetorequerido * `owed`lista de objetorequerido * `inFavor`lista de objetorequerido * `bankAccounts`lista de objetorequerido * `warnings`lista de objetorequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payments/list-open-items?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/list-open-items?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "status": "active", "origin": "domestic" }, "items": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "texto", "label": "texto" }, "installment": null, "documentDate": "2026-10-23", "dueDate": "2026-10-23", "currencyCode": "texto", "exchangeRate": null, "amount": "texto", "balance": "texto", "daysOverdue": 1, "allocatable": false, "proposedAmount": "texto", "proposedDebtAmount": "texto" } ], "owed": [ { "currencyCode": "texto", "amount": "texto" } ], "inFavor": [ { "currencyCode": "texto", "amount": "texto" } ], "bankAccounts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "bankName": null, "accountKey": "texto", "isPrimary": false } ], "warnings": [ { "code": "payments.apocryphal", "message": "texto" } ], "today": "2026-10-23" } ``` # Listar órdenes de pago > Lista las órdenes de pago, de la más nueva a la más vieja, con búsqueda por número o proveedor y filtros de estado (vigentes por defecto, recuperadas, con saldo a favor), medio de pago, moneda, proveedor y fechas. GET`/api/v1/payments/list` * Permiso `payments.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `status`opción Valores: `issued` `recovered` `with-advance` `all`Por defecto: `issued` * `kind`opciónadmite null Valores: `transfer` `cash` `own-check` `own-echeq` `endorsed-check` * `currencyCode`textoadmite null formato \`^\[A-Z]{3}$\` * `supplierId`uuidadmite null * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `page`entero Por defecto: `1`mínimo 1, máximo 100000 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `orders`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payments/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "orders": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "paymentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto" }, "currencyCode": "texto", "kinds": [ "transfer" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "recovered": false } ], "total": 1 } ``` # Proponer la aplicación de saldos a favor > Propone cómo aplicar lo que la empresa tiene a favor con un proveedor a sus cuotas abiertas de la misma moneda. No graba nada. GET`/api/v1/payments/propose-credit-application` * Permiso `payments.apply-credit` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido * `documentSourceId`uuidadmite null ## Respuesta `200` con este JSON. * `supplier`objetorequerido * `credits`lista de objetorequerido * `items`lista de objetorequerido * `applications`lista de objetorequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.apply-credit`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payments/propose-credit-application?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/propose-credit-application?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto" }, "credits": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "texto", "label": "texto" }, "paymentOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "documentDate": "2026-10-23", "currencyCode": "texto", "balance": "texto" } ], "items": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "texto", "label": "texto" }, "installment": null, "documentDate": "2026-10-23", "dueDate": "2026-10-23", "currencyCode": "texto", "exchangeRate": null, "amount": "texto", "balance": "texto", "daysOverdue": 1 } ], "applications": [ { "creditItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "debitItemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "amount": "texto" } ], "today": "2026-10-23" } ``` # Recuperar una orden de pago > Registra el recupero total de una orden de pago con su fecha, cómo terminó el dinero, un motivo y la versión leída: revierte lo imputado y lo aplicado, en un solo acto. La orden no se anula. POST`/api/v1/payments/recover` * Permiso `payments.recover` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `paymentOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `recoveryDate`fechaadmite null * `refundKind`opciónrequerido Valores: `returned` `not-paid` * `toAccount`textoadmite null hasta 120 caracteres * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`enterorequerido * `name`textorequerido * `paymentDate`fecharequerido * `supplier`objetorequerido * `currencyCode`textorequerido * `kinds`lista de opciónrequerido Valores: `transfer` `cash` `own-check` `own-echeq` `endorsed-check` * `methodsText`textorequerido * `advanceBalance`textorequerido * `total`textorequerido * `recovered`sí o norequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `foreignCurrencyCode`cualquierarequerido * `allocatedTotal`textorequerido * `advanceTotal`textorequerido * `isAdvance`sí o norequerido * `methodsTotal`textorequerido * `exchangeDifference`textorequerido * `notes`cualquierarequerido * `warningsAccepted`lista de opciónrequerido Valores: `payments.apocryphal` `payments.invoice-not-verified` * `methods`lista de objetorequerido * `allocations`lista de objetorequerido * `recovery`objetorequeridoadmite null * `registeredAt`fecha y horarequerido * `registeredBy`objetorequeridoadmite null * `supplierAccount`lista de objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.recover`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payments/recover" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "paymentOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "refundKind": "returned", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/recover`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "paymentOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "refundKind": "returned", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "paymentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "taxId": "texto", "address": "texto" }, "currencyCode": "texto", "kinds": [ "transfer" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "recovered": false, "version": 1, "exchangeRate": null, "foreignCurrencyCode": null, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "methodsTotal": "texto", "exchangeDifference": "texto", "notes": null, "warningsAccepted": [ "payments.apocryphal" ], "methods": [ { "kind": "transfer", "amount": "texto", "fromAccount": null, "toAccount": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "bankName": null, "accountKey": "texto" }, "reference": null, "bankName": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "dueDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "payment-order", "allocatedOn": "2026-10-23", "paid": "texto", "cancelled": "texto", "currencyCode": "texto", "exchangeDifference": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "texto", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "documentRate": null, "reversed": false, "createdBy": { "id": "texto", "name": null } } ], "recovery": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "recoveryDate": "2026-10-23", "total": "texto", "refundKind": "returned", "toAccount": null, "reason": "texto", "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null } }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "supplierAccount": [ { "currencyCode": "texto", "amount": "texto" } ] } ``` # Registrar una orden de pago > Registra una orden de pago a un proveedor en pesos u otra moneda habilitada, con sus medios de pago (transferencia, efectivo, cheque o echeq propio y cheque endosado) y la imputa a sus cuotas abiertas. Lo que no se imputa queda a favor de la empresa. POST`/api/v1/payments/register` * Permiso `payments.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierId`uuidrequerido * `paymentDate`fechaadmite null * `currencyCode`texto Por defecto: `ARS`formato \`^\[A-Z]{3}$\` * `foreignCurrencyCode`textoadmite null formato \`^\[A-Z]{3}$\` * `exchangeRate`cualquiera * `total`cualquierarequerido * `methods`lista de objetorequerido al menos 1, hasta 50 * `allocations`lista de objeto hasta 200 * `notes`textoadmite null hasta 1000 caracteres * `isAdvance`sí o no Por defecto: `false` * `acceptWarnings`lista de opción Valores: `payments.apocryphal` `payments.invoice-not-verified`Por defecto: `[]`hasta 2 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`enterorequerido * `name`textorequerido * `paymentDate`fecharequerido * `supplier`objetorequerido * `currencyCode`textorequerido * `kinds`lista de opciónrequerido Valores: `transfer` `cash` `own-check` `own-echeq` `endorsed-check` * `methodsText`textorequerido * `advanceBalance`textorequerido * `total`textorequerido * `recovered`sí o norequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `foreignCurrencyCode`cualquierarequerido * `allocatedTotal`textorequerido * `advanceTotal`textorequerido * `isAdvance`sí o norequerido * `methodsTotal`textorequerido * `exchangeDifference`textorequerido * `notes`cualquierarequerido * `warningsAccepted`lista de opciónrequerido Valores: `payments.apocryphal` `payments.invoice-not-verified` * `methods`lista de objetorequerido * `allocations`lista de objetorequerido * `recovery`objetorequeridoadmite null * `registeredAt`fecha y horarequerido * `registeredBy`objetorequeridoadmite null * `supplierAccount`lista de objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/payments/register" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "total": null, "methods": [ { "kind": "transfer", "amount": null } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/register`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "total": null, "methods": [ { "kind": "transfer", "amount": null } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "paymentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "taxId": "texto", "address": "texto" }, "currencyCode": "texto", "kinds": [ "transfer" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "recovered": false, "version": 1, "exchangeRate": null, "foreignCurrencyCode": null, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "methodsTotal": "texto", "exchangeDifference": "texto", "notes": null, "warningsAccepted": [ "payments.apocryphal" ], "methods": [ { "kind": "transfer", "amount": "texto", "fromAccount": null, "toAccount": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "bankName": null, "accountKey": "texto" }, "reference": null, "bankName": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "dueDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "payment-order", "allocatedOn": "2026-10-23", "paid": "texto", "cancelled": "texto", "currencyCode": "texto", "exchangeDifference": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "texto", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "documentRate": null, "reversed": false, "createdBy": { "id": "texto", "name": null } } ], "recovery": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "recoveryDate": "2026-10-23", "total": "texto", "refundKind": "returned", "toAccount": null, "reason": "texto", "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null } }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "supplierAccount": [ { "currencyCode": "texto", "amount": "texto" } ] } ``` # Ver el historial de una orden de pago > Lista los cambios de una orden de pago, sus medios, su recupero y lo imputado o aplicado, del más nuevo al más viejo, campo por campo. GET`/api/v1/payments/get-history` * Permiso `payments.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `paymentOrderId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payments/get-history?paymentOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/get-history?paymentOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver una orden de pago > Devuelve una orden de pago con su proveedor tal como se registró, sus medios de pago, lo imputado con la diferencia de cambio, lo que dejó a favor y sus aplicaciones posteriores, los avisos confirmados y su recupero. GET`/api/v1/payments/get` * Permiso `payments.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `paymentOrderId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`enterorequerido * `name`textorequerido * `paymentDate`fecharequerido * `supplier`objetorequerido * `currencyCode`textorequerido * `kinds`lista de opciónrequerido Valores: `transfer` `cash` `own-check` `own-echeq` `endorsed-check` * `methodsText`textorequerido * `advanceBalance`textorequerido * `total`textorequerido * `recovered`sí o norequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `foreignCurrencyCode`cualquierarequerido * `allocatedTotal`textorequerido * `advanceTotal`textorequerido * `isAdvance`sí o norequerido * `methodsTotal`textorequerido * `exchangeDifference`textorequerido * `notes`cualquierarequerido * `warningsAccepted`lista de opciónrequerido Valores: `payments.apocryphal` `payments.invoice-not-verified` * `methods`lista de objetorequerido * `allocations`lista de objetorequerido * `recovery`objetorequeridoadmite null * `registeredAt`fecha y horarequerido * `registeredBy`objetorequeridoadmite null * `supplierAccount`lista de objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `payments.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/payments/get?paymentOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/payments/get?paymentOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "paymentDate": "2026-10-23", "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "legalName": "texto", "taxId": "texto", "address": "texto" }, "currencyCode": "texto", "kinds": [ "transfer" ], "methodsText": "texto", "advanceBalance": "texto", "total": "texto", "recovered": false, "version": 1, "exchangeRate": null, "foreignCurrencyCode": null, "allocatedTotal": "texto", "advanceTotal": "texto", "isAdvance": false, "methodsTotal": "texto", "exchangeDifference": "texto", "notes": null, "warningsAccepted": [ "payments.apocryphal" ], "methods": [ { "kind": "transfer", "amount": "texto", "fromAccount": null, "toAccount": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "bankName": null, "accountKey": "texto" }, "reference": null, "bankName": null, "checkNumber": null, "drawerName": null, "drawerTaxId": null, "dueDate": "2026-10-23" } ], "allocations": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "origin": "payment-order", "allocatedOn": "2026-10-23", "paid": "texto", "cancelled": "texto", "currencyCode": "texto", "exchangeDifference": "texto", "document": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "kind": "texto", "label": "texto" }, "installment": null, "dueDate": "2026-10-23", "balance": "texto", "documentBalance": "texto", "documentRate": null, "reversed": false, "createdBy": { "id": "texto", "name": null } } ], "recovery": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": 1, "name": "texto", "recoveryDate": "2026-10-23", "total": "texto", "refundKind": "returned", "toAccount": null, "reason": "texto", "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null } }, "registeredAt": "2026-10-23T14:30:00.000Z", "registeredBy": { "id": "texto", "name": null }, "supplierAccount": [ { "currencyCode": "texto", "amount": "texto" } ] } ``` # Pedidos > El compromiso de venta: se arma en borrador, se confirma y fija precios y condiciones. El compromiso de venta: se arma en borrador, se confirma y fija precios y condiciones. | Operación | Ruta | | ------------------------------------------------------------------------------------------------- | --------------------------------------------- | | [Listar pedidos](/api/referencia/pedidos/listar-pedidos/) | GET `/api/v1/sales-orders/list` | | [Ver un pedido](/api/referencia/pedidos/ver-un-pedido/) | GET `/api/v1/sales-orders/get` | | [Crear un pedido](/api/referencia/pedidos/crear-un-pedido/) | POST `/api/v1/sales-orders/create` | | [Modificar un pedido en borrador](/api/referencia/pedidos/modificar-un-pedido-en-borrador/) | POST `/api/v1/sales-orders/update` | | [Poner un precio manual a una línea](/api/referencia/pedidos/poner-un-precio-manual-a-una-linea/) | POST `/api/v1/sales-orders/set-line-price` | | [Proponer precios](/api/referencia/pedidos/proponer-precios/) | GET `/api/v1/sales-orders/propose-prices` | | [Controlar el límite de crédito](/api/referencia/pedidos/controlar-el-limite-de-credito/) | GET `/api/v1/sales-orders/check-credit` | | [Confirmar un pedido](/api/referencia/pedidos/confirmar-un-pedido/) | POST `/api/v1/sales-orders/confirm` | | [Cerrar el saldo de un pedido](/api/referencia/pedidos/cerrar-el-saldo-de-un-pedido/) | POST `/api/v1/sales-orders/close-balance` | | [Descartar un pedido](/api/referencia/pedidos/descartar-un-pedido/) | POST `/api/v1/sales-orders/discard` | | [Ver el historial de un pedido](/api/referencia/pedidos/ver-el-historial-de-un-pedido/) | GET `/api/v1/sales-orders/get-history` | | [Listar adjuntos de un pedido](/api/referencia/pedidos/listar-adjuntos-de-un-pedido/) | GET `/api/v1/sales-orders/list-attachments` | | [Adjuntar un archivo a un pedido](/api/referencia/pedidos/adjuntar-un-archivo-a-un-pedido/) | POST `/api/v1/sales-orders/add-attachment` | | [Descargar un adjunto de un pedido](/api/referencia/pedidos/descargar-un-adjunto-de-un-pedido/) | POST `/api/v1/sales-orders/get-attachment` | | [Quitar un adjunto de un pedido](/api/referencia/pedidos/quitar-un-adjunto-de-un-pedido/) | POST `/api/v1/sales-orders/remove-attachment` | # Adjuntar un archivo a un pedido > Adjunta un archivo (PDF, JPEG, PNG, WebP, Excel o Word de hasta 10 MB) a un pedido no descartado. Hasta 20 por documento y nunca el mismo archivo dos veces. POST`/api/v1/sales-orders/add-attachment` * Permiso `sales-orders.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `fileName`textorequerido de 1 a 200 caracteres * `contentBase64`textorequerido de 1 a 15728640 caracteres, formato \`^\[A-Za-z0-9+/]+={0,2}$\` ## Respuesta `200` con este JSON. * `id`textorequerido * `fileName`textorequerido * `mediaType`opciónrequerido Valores: `application/pdf` `image/jpeg` `image/png` `image/webp` `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet` `application/vnd.ms-excel` `application/vnd.openxmlformats-officedocument.wordprocessingml.document` `application/msword` * `sizeBytes`enterorequerido * `uploadedAt`fecha y horarequerido * `uploadedBy`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/add-attachment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fileName": "texto", "contentBase64": "ARS" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/add-attachment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "fileName": "texto", "contentBase64": "ARS" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "texto", "fileName": "texto", "mediaType": "application/pdf", "sizeBytes": 1, "uploadedAt": "2026-10-23T14:30:00.000Z", "uploadedBy": { "id": "texto", "name": null } } ``` # Cerrar el saldo de un pedido > Cierra un pedido confirmado con un motivo: lo que faltaba facturar y entregar deja de estar pendiente. Se rechaza mientras una factura o un remito sin emitir retenga cantidades del pedido. POST`/api/v1/sales-orders/close-balance` * Permiso `sales-orders.close-balance` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `salesOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `confirmed` `closed` `discarded` * `documentDate`fecharequerido * `customer`objetorequerido * `netTotal`textorequerido * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `tracksDelivery`sí o norequerido * `deliveryProgress`opciónrequeridoadmite null Valores: `not-delivered` `partial` `delivered` * `version`enterorequerido mínimo 1 * `notes`cualquierarequerido * `customerOrderReference`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `headerDiscountPercent`númerorequerido * `headerDiscountAmount`textorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `confirmedAt`fecha y horarequeridoadmite null * `confirmedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.close-balance`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/close-balance" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/close-balance`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered", "version": 1, "notes": null, "customerOrderReference": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "headerDiscountPercent": 100, "headerDiscountAmount": "texto", "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "isSold": false, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "lineKind": "sale", "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "proposedPrice": null, "discountPercent": 100, "netAmount": "texto", "vatRate": null, "invoicedQuantity": 100, "heldQuantity": 100, "pendingQuantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "pendingDeliveryQuantity": 100, "tracksStock": false } ], "totals": { "subtotal": "texto", "headerDiscount": "texto", "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "confirmedAt": "2026-10-23T14:30:00.000Z", "confirmedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Confirmar un pedido > Confirma un pedido en borrador con la versión leída: congela precios, bonificaciones y cuotas de la condición de pago. No reserva stock ni rechaza por crédito; si supera el límite, responde el aviso y lo deja en la actividad del pedido. POST`/api/v1/sales-orders/confirm` * Permiso `sales-orders.confirm` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `salesOrderId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `confirmed` `closed` `discarded` * `documentDate`fecharequerido * `customer`objetorequerido * `netTotal`textorequerido * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `tracksDelivery`sí o norequerido * `deliveryProgress`opciónrequeridoadmite null Valores: `not-delivered` `partial` `delivered` * `version`enterorequerido mínimo 1 * `notes`cualquierarequerido * `customerOrderReference`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `headerDiscountPercent`númerorequerido * `headerDiscountAmount`textorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `confirmedAt`fecha y horarequeridoadmite null * `confirmedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido * `creditWarning`uno derequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.confirm`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/confirm" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/confirm`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered", "version": 1, "notes": null, "customerOrderReference": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "headerDiscountPercent": 100, "headerDiscountAmount": "texto", "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "isSold": false, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "lineKind": "sale", "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "proposedPrice": null, "discountPercent": 100, "netAmount": "texto", "vatRate": null, "invoicedQuantity": 100, "heldQuantity": 100, "pendingQuantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "pendingDeliveryQuantity": 100, "tracksStock": false } ], "totals": { "subtotal": "texto", "headerDiscount": "texto", "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "confirmedAt": "2026-10-23T14:30:00.000Z", "confirmedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null, "creditWarning": { "exceeded": true, "balance": "texto", "otherOrders": "texto", "thisOrder": "texto", "limit": "texto", "excess": "texto" } } ``` # Controlar el límite de crédito > Indica si confirmar un pedido en borrador lleva al cliente por encima de su límite de crédito: su saldo, más lo no facturado de sus otros pedidos, más este pedido, con IVA. Nunca bloquea la confirmación. GET`/api/v1/sales-orders/check-credit` * Permiso `sales-orders.confirm` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `salesOrderId`uuidrequerido ## Respuesta `200` con este JSON. * `creditWarning`uno derequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.confirm`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/sales-orders/check-credit?salesOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/check-credit?salesOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "creditWarning": { "exceeded": true, "balance": "texto", "otherOrders": "texto", "thisOrder": "texto", "limit": "texto", "excess": "texto" } } ``` # Crear un pedido > Crea un pedido en borrador para un cliente, con fecha, condición de pago, notas y líneas. El precio sin IVA de cada línea lo propone la lista del cliente y la bonificación es la general del cliente. POST`/api/v1/sales-orders/create` * Permiso `sales-orders.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `customerId`uuidrequerido * `documentDate`fechaadmite null * `paymentTermId`uuidadmite null * `notes`textoadmite null hasta 1000 caracteres * `customerOrderReference`textoadmite null hasta 40 caracteres * `headerDiscountPercent`número * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `confirmed` `closed` `discarded` * `documentDate`fecharequerido * `customer`objetorequerido * `netTotal`textorequerido * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `tracksDelivery`sí o norequerido * `deliveryProgress`opciónrequeridoadmite null Valores: `not-delivered` `partial` `delivered` * `version`enterorequerido mínimo 1 * `notes`cualquierarequerido * `customerOrderReference`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `headerDiscountPercent`númerorequerido * `headerDiscountAmount`textorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `confirmedAt`fecha y horarequeridoadmite null * `confirmedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered", "version": 1, "notes": null, "customerOrderReference": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "headerDiscountPercent": 100, "headerDiscountAmount": "texto", "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "isSold": false, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "lineKind": "sale", "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "proposedPrice": null, "discountPercent": 100, "netAmount": "texto", "vatRate": null, "invoicedQuantity": 100, "heldQuantity": 100, "pendingQuantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "pendingDeliveryQuantity": 100, "tracksStock": false } ], "totals": { "subtotal": "texto", "headerDiscount": "texto", "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "confirmedAt": "2026-10-23T14:30:00.000Z", "confirmedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Descargar un adjunto de un pedido > Devuelve un archivo adjunto a un pedido para descargarlo con su nombre. POST`/api/v1/sales-orders/get-attachment` * Permiso `sales-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta el archivo ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `attachmentId`uuidrequerido ## Respuesta `200` con el archivo y su nombre en `Content-Disposition`. ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/get-attachment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' \ -o archivo ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/get-attachment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const archivo = await respuesta.blob(); ``` # Descartar un pedido > Descarta un pedido en borrador con un motivo. El pedido conserva su número. POST`/api/v1/sales-orders/discard` * Permiso `sales-orders.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `salesOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `confirmed` `closed` `discarded` * `documentDate`fecharequerido * `customer`objetorequerido * `netTotal`textorequerido * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `tracksDelivery`sí o norequerido * `deliveryProgress`opciónrequeridoadmite null Valores: `not-delivered` `partial` `delivered` * `version`enterorequerido mínimo 1 * `notes`cualquierarequerido * `customerOrderReference`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `headerDiscountPercent`númerorequerido * `headerDiscountAmount`textorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `confirmedAt`fecha y horarequeridoadmite null * `confirmedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/discard" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/discard`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered", "version": 1, "notes": null, "customerOrderReference": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "headerDiscountPercent": 100, "headerDiscountAmount": "texto", "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "isSold": false, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "lineKind": "sale", "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "proposedPrice": null, "discountPercent": 100, "netAmount": "texto", "vatRate": null, "invoicedQuantity": 100, "heldQuantity": 100, "pendingQuantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "pendingDeliveryQuantity": 100, "tracksStock": false } ], "totals": { "subtotal": "texto", "headerDiscount": "texto", "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "confirmedAt": "2026-10-23T14:30:00.000Z", "confirmedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Listar adjuntos de un pedido > Lista los archivos adjuntos a un pedido, del más nuevo al más viejo, con nombre, tipo, tamaño, fecha y quién lo adjuntó. GET`/api/v1/sales-orders/list-attachments` * Permiso `sales-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `documentId`uuidrequerido ## Respuesta `200` con este JSON. * `attachments`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/sales-orders/list-attachments?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/list-attachments?documentId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "attachments": [ { "id": "texto", "fileName": "texto", "mediaType": "application/pdf", "sizeBytes": 1, "uploadedAt": "2026-10-23T14:30:00.000Z", "uploadedBy": { "id": "texto", "name": null } } ] } ``` # Listar pedidos > Lista los pedidos de la empresa activa con búsqueda por número o cliente y filtros de estado, facturación, cliente y fechas. Por defecto trae todos menos los descartados. GET`/api/v1/sales-orders/list` * Permiso `sales-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `status`lista de opciónadmite null Valores: `draft` `confirmed` `closed` `discarded` * `invoicing`lista de opciónadmite null Valores: `pending` `not-invoiced` `partial` `invoiced` * `delivery`lista de opciónadmite null Valores: `not-delivered` `partial` `delivered` * `customerId`uuidadmite null * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `sort`opción Valores: `number` `date` `customer` `amount`Por defecto: `number` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `salesOrders`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/sales-orders/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "salesOrders": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered" } ], "total": 1 } ``` # Modificar un pedido en borrador > Edita un pedido en borrador con la versión leída: cliente, fecha, condición, notas y líneas. Cada línea que sigue conserva su id y los precios que no son manuales se vuelven a resolver. POST`/api/v1/sales-orders/update` * Permiso `sales-orders.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `salesOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `customerId`uuidrequerido * `documentDate`fechaadmite null * `paymentTermId`uuidadmite null * `notes`textoadmite null hasta 1000 caracteres * `customerOrderReference`textoadmite null hasta 40 caracteres * `headerDiscountPercent`número * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `confirmed` `closed` `discarded` * `documentDate`fecharequerido * `customer`objetorequerido * `netTotal`textorequerido * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `tracksDelivery`sí o norequerido * `deliveryProgress`opciónrequeridoadmite null Valores: `not-delivered` `partial` `delivered` * `version`enterorequerido mínimo 1 * `notes`cualquierarequerido * `customerOrderReference`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `headerDiscountPercent`númerorequerido * `headerDiscountAmount`textorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `confirmedAt`fecha y horarequeridoadmite null * `confirmedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "customerId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered", "version": 1, "notes": null, "customerOrderReference": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "headerDiscountPercent": 100, "headerDiscountAmount": "texto", "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "isSold": false, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "lineKind": "sale", "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "proposedPrice": null, "discountPercent": 100, "netAmount": "texto", "vatRate": null, "invoicedQuantity": 100, "heldQuantity": 100, "pendingQuantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "pendingDeliveryQuantity": 100, "tracksStock": false } ], "totals": { "subtotal": "texto", "headerDiscount": "texto", "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "confirmedAt": "2026-10-23T14:30:00.000Z", "confirmedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Poner un precio manual a una línea > Fija a mano el precio sin IVA de una línea de un pedido en borrador, guardando el que propuso la lista. Con null la línea vuelve al precio propuesto. POST`/api/v1/sales-orders/set-line-price` * Permiso `sales-orders.set-manual-price` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `salesOrderId`uuidrequerido * `version`enterorequerido mínimo 1 * `lineId`uuidrequerido * `unitPrice`cualquierarequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `confirmed` `closed` `discarded` * `documentDate`fecharequerido * `customer`objetorequerido * `netTotal`textorequerido * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `tracksDelivery`sí o norequerido * `deliveryProgress`opciónrequeridoadmite null Valores: `not-delivered` `partial` `delivered` * `version`enterorequerido mínimo 1 * `notes`cualquierarequerido * `customerOrderReference`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `headerDiscountPercent`númerorequerido * `headerDiscountAmount`textorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `confirmedAt`fecha y horarequeridoadmite null * `confirmedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.set-manual-price`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/set-line-price" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "lineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitPrice": null }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/set-line-price`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "salesOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "lineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "unitPrice": null }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered", "version": 1, "notes": null, "customerOrderReference": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "headerDiscountPercent": 100, "headerDiscountAmount": "texto", "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "isSold": false, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "lineKind": "sale", "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "proposedPrice": null, "discountPercent": 100, "netAmount": "texto", "vatRate": null, "invoicedQuantity": 100, "heldQuantity": 100, "pendingQuantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "pendingDeliveryQuantity": 100, "tracksStock": false } ], "totals": { "subtotal": "texto", "headerDiscount": "texto", "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "confirmedAt": "2026-10-23T14:30:00.000Z", "confirmedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Proponer precios > Devuelve, sin grabar, el precio sin IVA que proponen las listas para cada artículo y cantidad de un cliente en una fecha. Es la misma resolución que hace el pedido al guardarse. GET`/api/v1/sales-orders/propose-prices` * Permiso `sales-orders.create` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `customerId`uuidrequerido * `documentDate`fechaadmite null * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `lines`lista de objetorequerido * `freeLines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/sales-orders/propose-prices?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&lines=%5Bobject+Object%5D" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/propose-prices?customerId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90&lines=%5Bobject+Object%5D`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100, "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "tier": "texto" }, "rememberedDiscount": { "percent": 100, "date": "2026-10-23", "orderNumber": null }, "proposedDiscount": 100, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false, "vatRate": null } ], "freeLines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100, "unitPrice": "texto", "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" } } ] } ``` # Quitar un adjunto de un pedido > Quita un archivo adjunto a un pedido no descartado. POST`/api/v1/sales-orders/remove-attachment` * Permiso `sales-orders.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `documentId`uuidrequerido * `attachmentId`uuidrequerido ## Respuesta `200` con este JSON. * `id`textorequerido * `removed`constanterequerido Valores: `true` ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/sales-orders/remove-attachment" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/remove-attachment`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "documentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "attachmentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "texto", "removed": true } ``` # Ver el historial de un pedido > Lista los cambios de un pedido, sus líneas y sus adjuntos, del más nuevo al más viejo, campo por campo. GET`/api/v1/sales-orders/get-history` * Permiso `sales-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `salesOrderId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/sales-orders/get-history?salesOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/get-history?salesOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un pedido > Devuelve un pedido con su cliente, condición de pago, líneas con lo facturado, retenido y pendiente, sus totales con IVA y quién lo confirmó o cerró. GET`/api/v1/sales-orders/get` * Permiso `sales-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `salesOrderId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `confirmed` `closed` `discarded` * `documentDate`fecharequerido * `customer`objetorequerido * `netTotal`textorequerido * `invoicingProgress`opciónrequeridoadmite null Valores: `not-invoiced` `partial` `invoiced` * `tracksDelivery`sí o norequerido * `deliveryProgress`opciónrequeridoadmite null Valores: `not-delivered` `partial` `delivered` * `version`enterorequerido mínimo 1 * `notes`cualquierarequerido * `customerOrderReference`cualquierarequerido * `paymentTerm`objetorequeridoadmite null * `paymentPlan`lista de objetorequeridoadmite null * `paymentPlanText`textorequerido * `headerDiscountPercent`númerorequerido * `headerDiscountAmount`textorequerido * `lines`lista de objetorequerido * `totals`objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `confirmedAt`fecha y horarequeridoadmite null * `confirmedBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `closeReason`cualquierarequerido * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `sales-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/sales-orders/get?salesOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/sales-orders/get?salesOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "documentDate": "2026-10-23", "customer": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "documentType": "texto", "taxId": "texto" }, "netTotal": "texto", "invoicingProgress": "not-invoiced", "tracksDelivery": false, "deliveryProgress": "not-delivered", "version": 1, "notes": null, "customerOrderReference": null, "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "paymentPlan": [ { "percent": 100, "dueDays": 1 } ], "paymentPlanText": "texto", "headerDiscountPercent": 100, "headerDiscountAmount": "texto", "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "isSold": false, "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "quantity": 100, "lineKind": "sale", "unitPrice": null, "priceSource": "customer-price", "listPrice": null, "promotion": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "proposedPrice": null, "discountPercent": 100, "netAmount": "texto", "vatRate": null, "invoicedQuantity": 100, "heldQuantity": 100, "pendingQuantity": 100, "deliveredQuantity": 100, "inDeliveryQuantity": 100, "pendingDeliveryQuantity": 100, "tracksStock": false } ], "totals": { "subtotal": "texto", "headerDiscount": "texto", "net": "texto", "vat": [ { "rate": 100, "base": "texto", "amount": "texto" } ], "total": "texto" }, "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "confirmedAt": "2026-10-23T14:30:00.000Z", "confirmedBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "closeReason": null, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Plan de cuentas > Las cuentas contables y qué cuenta usa cada rol del sistema y cada artículo. Las cuentas contables y qué cuenta usa cada rol del sistema y cada artículo. | Operación | Ruta | | --------------------------------------------------------------------------------------------------- | --------------------------------------------- | | [Listar cuentas contables](/api/referencia/plan-de-cuentas/listar-cuentas-contables/) | GET `/api/v1/accounting/list-accounts` | | [Ver una cuenta contable](/api/referencia/plan-de-cuentas/ver-una-cuenta-contable/) | GET `/api/v1/accounting/get-account` | | [Crear una cuenta contable](/api/referencia/plan-de-cuentas/crear-una-cuenta-contable/) | POST `/api/v1/accounting/create-account` | | [Modificar una cuenta contable](/api/referencia/plan-de-cuentas/modificar-una-cuenta-contable/) | POST `/api/v1/accounting/update-account` | | [Activar o desactivar una cuenta](/api/referencia/plan-de-cuentas/activar-o-desactivar-una-cuenta/) | POST `/api/v1/accounting/set-account-status` | | [Listar cuentas por rol](/api/referencia/plan-de-cuentas/listar-cuentas-por-rol/) | GET `/api/v1/accounting/list-role-accounts` | | [Asignar una cuenta a un rol](/api/referencia/plan-de-cuentas/asignar-una-cuenta-a-un-rol/) | POST `/api/v1/accounting/assign-role-account` | | [Listar cuentas de un artículo](/api/referencia/plan-de-cuentas/listar-cuentas-de-un-articulo/) | GET `/api/v1/accounting/list-item-accounts` | | [Fijar la cuenta de un artículo](/api/referencia/plan-de-cuentas/fijar-la-cuenta-de-un-articulo/) | POST `/api/v1/accounting/set-item-account` | # Activar o desactivar una cuenta > Activa o desactiva una cuenta del plan. POST`/api/v1/accounting/set-account-status` * Permiso `accounting.manage-chart` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `accountId`uuidrequerido * `status`opciónrequerido Valores: `active` `inactive` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `type`opciónrequerido Valores: `asset` `liability` `equity` `income` `expense` * `postable`sí o norequerido * `parentId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.manage-chart`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/accounting/set-account-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/set-account-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "type": "asset", "postable": false, "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Asignar una cuenta a un rol > Asigna una cuenta a un rol del sistema, con una clave opcional, o quita la asignación. Completa los asientos pendientes del rol. POST`/api/v1/accounting/assign-role-account` * Permiso `accounting.manage-chart` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `role`opciónrequerido Valores: `accounts-receivable` `sales` `vat-debit` `perceptions-payable` `customer-advances` `collection-differences` `cost-of-sales` `accounts-payable` `vat-credit` `suffered-perceptions` `goods-received-not-invoiced` `supplier-advances` `payment-differences` `withholdings-payable` `expenses` `merchandise` `inventory-differences` `cash` `bank` `checks-to-deposit` `deferred-checks-payable` `suffered-withholdings` `exchange-difference` `rounding` `opening` * `key`textoadmite null hasta 71 caracteres * `accountId`uuidrequeridoadmite null ## Respuesta `200` con este JSON. * `role`textorequerido * `key`cualquierarequerido * `accountId`uuidrequeridoadmite null * `completedLines`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.manage-chart`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/accounting/assign-role-account" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "role": "accounts-receivable", "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/assign-role-account`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "role": "accounts-receivable", "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "role": "texto", "key": null, "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "completedLines": 1 } ``` # Crear una cuenta contable > Crea una cuenta del plan con su código, nombre, tipo y cuenta padre. POST`/api/v1/accounting/create-account` * Permiso `accounting.manage-chart` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `code`textorequerido de 1 a 20 caracteres * `name`textorequerido de 1 a 120 caracteres * `type`opciónrequerido Valores: `asset` `liability` `equity` `income` `expense` * `postable`sí o norequerido * `parentId`uuidadmite null ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `type`opciónrequerido Valores: `asset` `liability` `equity` `income` `expense` * `postable`sí o norequerido * `parentId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.manage-chart`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/accounting/create-account" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "code": "texto", "name": "texto", "type": "asset", "postable": false }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/create-account`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "code": "texto", "name": "texto", "type": "asset", "postable": false }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "type": "asset", "postable": false, "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Fijar la cuenta de un artículo > Registra o retira la excepción de cuenta de un artículo para un uso: ventas, costo de ventas, stock o gasto. POST`/api/v1/accounting/set-item-account` * Permiso `accounting.manage-chart` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `itemId`uuidrequerido * `usage`opciónrequerido Valores: `sales` `cost-of-sales` `inventory` `expense` * `accountId`uuidrequeridoadmite null ## Respuesta `200` con este JSON. * `itemId`uuidrequerido * `usage`opciónrequerido Valores: `sales` `cost-of-sales` `inventory` `expense` * `accountId`uuidrequeridoadmite null * `completedLines`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.manage-chart`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/accounting/set-item-account" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "usage": "sales", "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/set-item-account`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "usage": "sales", "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "usage": "sales", "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "completedLines": 1 } ``` # Listar cuentas contables > Lista el plan de cuentas por código, con el tipo, la cuenta padre y el estado de cada una. GET`/api/v1/accounting/list-accounts` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Respuesta `200` con este JSON. * `accounts`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/list-accounts" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/list-accounts`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "accounts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "type": "asset", "postable": false, "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ] } ``` # Listar cuentas de un artículo > Lista las excepciones de cuenta de un artículo, por uso. GET`/api/v1/accounting/list-item-accounts` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `itemId`uuidrequerido ## Respuesta `200` con este JSON. * `exceptions`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/list-item-accounts?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/list-item-accounts?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "exceptions": [ { "usage": "sales", "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ] } ``` # Listar cuentas por rol > Lista los roles del sistema con las cuentas que la empresa asignó a cada clave y los asientos pendientes de cada rol. GET`/api/v1/accounting/list-role-accounts` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Respuesta `200` con este JSON. * `roles`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/list-role-accounts" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/list-role-accounts`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "roles": [ { "role": "texto", "label": "texto", "group": "texto", "keyKind": "none", "assignments": [ { "key": null, "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ], "pendingEntries": 1 } ] } ``` # Modificar una cuenta contable > Cambia el código, el nombre, el tipo y la cuenta padre de una cuenta, con la versión leída. POST`/api/v1/accounting/update-account` * Permiso `accounting.manage-chart` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `accountId`uuidrequerido * `version`enterorequerido mínimo 1 * `code`textorequerido de 1 a 20 caracteres * `name`textorequerido de 1 a 120 caracteres * `type`opciónrequerido Valores: `asset` `liability` `equity` `income` `expense` * `parentId`uuidadmite null ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`textorequerido * `name`textorequerido * `type`opciónrequerido Valores: `asset` `liability` `equity` `income` `expense` * `postable`sí o norequerido * `parentId`uuidrequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.manage-chart`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/accounting/update-account" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "code": "texto", "name": "texto", "type": "asset" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/update-account`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "accountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "code": "texto", "name": "texto", "type": "asset" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "type": "asset", "postable": false, "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Ver una cuenta contable > Devuelve una cuenta con los roles y las excepciones de artículo que la usan y su cantidad de asientos. GET`/api/v1/accounting/get-account` * Permiso `accounting.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `accountId`uuidrequerido ## Respuesta `200` con este JSON. * `account`objetorequerido * `usage`objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `accounting.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/accounting/get-account?accountId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/accounting/get-account?accountId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "account": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "type": "asset", "postable": false, "parentId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" }, "usage": { "roles": [ { "role": "texto", "key": null } ], "items": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemCode": "texto", "itemName": "texto", "usage": "sales" } ], "entries": 1 } } ``` # Proveedores > La ficha del proveedor local o del exterior, con sus contactos y cuentas bancarias. La ficha del proveedor local o del exterior, con sus contactos y cuentas bancarias. | Operación | Ruta | | --------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | [Listar proveedores](/api/referencia/proveedores/listar-proveedores/) | GET `/api/v1/suppliers/list` | | [Ver un proveedor](/api/referencia/proveedores/ver-un-proveedor/) | GET `/api/v1/suppliers/get` | | [Crear un proveedor](/api/referencia/proveedores/crear-un-proveedor/) | POST `/api/v1/suppliers/create` | | [Modificar un proveedor](/api/referencia/proveedores/modificar-un-proveedor/) | POST `/api/v1/suppliers/update` | | [Desactivar o reactivar un proveedor](/api/referencia/proveedores/desactivar-o-reactivar-un-proveedor/) | POST `/api/v1/suppliers/set-status` | | [Aplicar los datos de ARCA a un proveedor](/api/referencia/proveedores/aplicar-los-datos-de-arca-a-un-proveedor/) | POST `/api/v1/suppliers/apply-taxpayer-data` | | [Agregar un contacto](/api/referencia/proveedores/agregar-un-contacto/) | POST `/api/v1/suppliers/create-contact` | | [Modificar un contacto](/api/referencia/proveedores/modificar-un-contacto/) | POST `/api/v1/suppliers/update-contact` | | [Desactivar o reactivar un contacto](/api/referencia/proveedores/desactivar-o-reactivar-un-contacto/) | POST `/api/v1/suppliers/set-contact-status` | | [Agregar una cuenta bancaria](/api/referencia/proveedores/agregar-una-cuenta-bancaria/) | POST `/api/v1/suppliers/create-bank-account` | | [Modificar una cuenta bancaria](/api/referencia/proveedores/modificar-una-cuenta-bancaria/) | POST `/api/v1/suppliers/update-bank-account` | | [Desactivar o reactivar una cuenta bancaria](/api/referencia/proveedores/desactivar-o-reactivar-una-cuenta-bancaria/) | POST `/api/v1/suppliers/set-bank-account-status` | | [Ver el historial de un proveedor](/api/referencia/proveedores/ver-el-historial-de-un-proveedor/) | GET `/api/v1/suppliers/get-history` | # Agregar un contacto > Agrega un contacto a un proveedor, con un correo o un teléfono. POST`/api/v1/suppliers/create-contact` * Permiso `suppliers.manage-contacts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierId`uuidrequerido * `name`textorequerido de 1 a 120 caracteres * `role`textoadmite null hasta 80 caracteres * `email`textoadmite null hasta 254 caracteres * `phone`textoadmite null hasta 40 caracteres * `isPrimary`sí o no Por defecto: `false` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `name`textorequerido * `role`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.manage-contacts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/create-contact" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/create-contact`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Agregar una cuenta bancaria > Agrega una cuenta bancaria a un proveedor: CBU o CVU en el país, SWIFT con IBAN o número de cuenta en el exterior. POST`/api/v1/suppliers/create-bank-account` * Permiso `suppliers.manage-bank-accounts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierId`uuidrequerido * `currencyCode`textorequerido formato \`^\[A-Z]{3}$\` * `cbu`cualquiera * `swift`cualquiera * `iban`cualquiera * `accountNumber`textoadmite null hasta 34 caracteres * `bankName`textoadmite null hasta 120 caracteres * `holderName`textoadmite null hasta 200 caracteres * `isPrimary`sí o no Por defecto: `false` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `cbu`cualquierarequerido * `swift`cualquierarequerido * `iban`cualquierarequerido * `accountNumber`cualquierarequerido * `bankName`cualquierarequerido * `currencyCode`textorequerido * `holderName`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.manage-bank-accounts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/create-bank-account" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "currencyCode": "ARS" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/create-bank-account`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "currencyCode": "ARS" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cbu": null, "swift": null, "iban": null, "accountNumber": null, "bankName": null, "currencyCode": "texto", "holderName": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Aplicar los datos de ARCA a un proveedor > Aplica a un proveedor local los datos fiscales que ARCA guardó para su CUIT en la fecha revisada. POST`/api/v1/suppliers/apply-taxpayer-data` * Permiso `suppliers.apply-taxpayer-data` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierId`uuidrequerido * `version`enterorequerido mínimo 1 * `taxDataConsultedAt`fecha y horarequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `origin`opciónrequerido Valores: `domestic` `foreign` * `cuit`cualquierarequerido * `cuitFormatted`cualquierarequerido * `countryCode`cualquierarequerido * `countryName`cualquierarequerido * `foreignTaxId`cualquierarequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `supplierType`opciónrequerido Valores: `goods` `services` `goods-and-services` `carrier` * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequeridoadmite null Valores: `registered` `monotributo` `exempt` * `iibbCondition`opciónrequeridoadmite null Valores: `local` `multilateral` `exempt` `unregistered` * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `floorUnit`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `paymentTermId`uuidrequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `currencyCode`cualquierarequerido * `notes`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `isOccasional`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `contacts`lista de objetorequerido * `bankAccounts`lista de objetorequerido * `enabledCurrencies`lista de textorequerido * `apocryphal`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.apply-taxpayer-data`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/apply-taxpayer-data" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "taxDataConsultedAt": "2026-10-23T14:30:00.000Z" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/apply-taxpayer-data`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "taxDataConsultedAt": "2026-10-23T14:30:00.000Z" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "origin": "domestic", "cuit": null, "cuitFormatted": null, "countryCode": null, "countryName": null, "foreignTaxId": null, "legalName": "texto", "tradeName": null, "supplierType": "goods", "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": "local", "iibbNumber": null, "street": null, "streetNumber": null, "floorUnit": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "currencyCode": null, "notes": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "deactivationReason": null, "isOccasional": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "contacts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ], "bankAccounts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cbu": null, "swift": null, "iban": null, "accountNumber": null, "bankName": null, "currencyCode": "texto", "holderName": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ], "enabledCurrencies": [ "texto" ], "apocryphal": { "listedOn": "2026-10-23", "checkedAt": "2026-10-23T14:30:00.000Z" } } ``` # Crear un proveedor > Crea un proveedor local o del exterior con lo que lo identifica y, opcional, el resto de su ficha y, si es local, su primera cuenta bancaria en pesos. POST`/api/v1/suppliers/create` * Permiso `suppliers.create` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `respuesta`uno derequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `origin`opciónrequerido Valores: `domestic` `foreign` * `cuit`cualquierarequerido * `cuitFormatted`cualquierarequerido * `countryCode`cualquierarequerido * `countryName`cualquierarequerido * `foreignTaxId`cualquierarequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `supplierType`opciónrequerido Valores: `goods` `services` `goods-and-services` `carrier` * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequeridoadmite null Valores: `registered` `monotributo` `exempt` * `iibbCondition`opciónrequeridoadmite null Valores: `local` `multilateral` `exempt` `unregistered` * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `floorUnit`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `paymentTermId`uuidrequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `currencyCode`cualquierarequerido * `notes`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `isOccasional`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.create`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/create" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "origin": "domestic", "cuit": "texto", "legalName": "texto", "supplierType": "goods", "vatCondition": "registered" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/create`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "origin": "domestic", "cuit": "texto", "legalName": "texto", "supplierType": "goods", "vatCondition": "registered" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "origin": "domestic", "cuit": null, "cuitFormatted": null, "countryCode": null, "countryName": null, "foreignTaxId": null, "legalName": "texto", "tradeName": null, "supplierType": "goods", "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": "local", "iibbNumber": null, "street": null, "streetNumber": null, "floorUnit": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "currencyCode": null, "notes": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "deactivationReason": null, "isOccasional": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar un contacto > Desactiva o reactiva un contacto de un proveedor. POST`/api/v1/suppliers/set-contact-status` * Permiso `suppliers.manage-contacts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `contactId`uuidrequerido * `version`enterorequerido mínimo 1 * `status`opciónrequerido Valores: `active` `inactive` ## Respuesta `200` con este JSON. * `id`uuidrequerido * `name`textorequerido * `role`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.manage-contacts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/set-contact-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/set-contact-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "status": "active" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar un proveedor > Desactiva con un motivo, o reactiva, un proveedor. POST`/api/v1/suppliers/set-status` * Permiso `suppliers.change-status` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `supplierId`uuidrequerido * `status`opciónrequerido Valores: `active` `inactive` * `reason`textoadmite null hasta 500 caracteres * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `origin`opciónrequerido Valores: `domestic` `foreign` * `cuit`cualquierarequerido * `cuitFormatted`cualquierarequerido * `countryCode`cualquierarequerido * `countryName`cualquierarequerido * `foreignTaxId`cualquierarequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `supplierType`opciónrequerido Valores: `goods` `services` `goods-and-services` `carrier` * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequeridoadmite null Valores: `registered` `monotributo` `exempt` * `iibbCondition`opciónrequeridoadmite null Valores: `local` `multilateral` `exempt` `unregistered` * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `floorUnit`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `paymentTermId`uuidrequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `currencyCode`cualquierarequerido * `notes`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `isOccasional`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.change-status`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/set-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/set-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "origin": "domestic", "cuit": null, "cuitFormatted": null, "countryCode": null, "countryName": null, "foreignTaxId": null, "legalName": "texto", "tradeName": null, "supplierType": "goods", "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": "local", "iibbNumber": null, "street": null, "streetNumber": null, "floorUnit": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "currencyCode": null, "notes": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "deactivationReason": null, "isOccasional": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Desactivar o reactivar una cuenta bancaria > Desactiva con un motivo, o reactiva, una cuenta bancaria de un proveedor. POST`/api/v1/suppliers/set-bank-account-status` * Permiso `suppliers.manage-bank-accounts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `bankAccountId`uuidrequerido * `status`opciónrequerido Valores: `active` `inactive` * `reason`textoadmite null hasta 500 caracteres * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `cbu`cualquierarequerido * `swift`cualquierarequerido * `iban`cualquierarequerido * `accountNumber`cualquierarequerido * `bankName`cualquierarequerido * `currencyCode`textorequerido * `holderName`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.manage-bank-accounts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/set-bank-account-status" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "bankAccountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/set-bank-account-status`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "bankAccountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "status": "active", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cbu": null, "swift": null, "iban": null, "accountNumber": null, "bankName": null, "currencyCode": "texto", "holderName": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Listar proveedores > Lista los proveedores con búsqueda por nombre, CUIT o código y filtros de tipo, condición de IVA y estado. GET`/api/v1/suppliers/list` * Permiso `suppliers.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 80 caracteres * `supplierType`lista de opción Valores: `goods` `services` `goods-and-services` `carrier` * `vatCondition`lista de opción Valores: `registered` `monotributo` `exempt` * `status`opción Valores: `active` `inactive` `all`Por defecto: `active` * `sort`opción Valores: `name` `code`Por defecto: `name` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `suppliers`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/suppliers/list" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/list`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "suppliers": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "tradeName": null, "origin": "domestic", "cuit": null, "cuitFormatted": null, "countryCode": null, "countryName": null, "vatCondition": "registered", "supplierType": "goods", "paymentTermName": null, "status": "active" } ], "total": 1 } ``` # Modificar un contacto > Cambia un contacto de un proveedor con la versión leída. POST`/api/v1/suppliers/update-contact` * Permiso `suppliers.manage-contacts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `contactId`uuidrequerido * `version`enterorequerido mínimo 1 * `name`textorequerido de 1 a 120 caracteres * `role`textoadmite null hasta 80 caracteres * `email`textoadmite null hasta 254 caracteres * `phone`textoadmite null hasta 40 caracteres * `isPrimary`sí o no ## Respuesta `200` con este JSON. * `id`uuidrequerido * `name`textorequerido * `role`cualquierarequerido * `email`cualquierarequerido * `phone`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.manage-contacts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/update-contact" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/update-contact`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "contactId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "name": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Modificar un proveedor > Cambia un bloque de un proveedor (datos generales, situación impositiva, domicilio o condiciones de compra) con la versión leída. POST`/api/v1/suppliers/update` * Permiso `suppliers.update` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `respuesta`uno derequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `origin`opciónrequerido Valores: `domestic` `foreign` * `cuit`cualquierarequerido * `cuitFormatted`cualquierarequerido * `countryCode`cualquierarequerido * `countryName`cualquierarequerido * `foreignTaxId`cualquierarequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `supplierType`opciónrequerido Valores: `goods` `services` `goods-and-services` `carrier` * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequeridoadmite null Valores: `registered` `monotributo` `exempt` * `iibbCondition`opciónrequeridoadmite null Valores: `local` `multilateral` `exempt` `unregistered` * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `floorUnit`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `paymentTermId`uuidrequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `currencyCode`cualquierarequerido * `notes`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `isOccasional`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.update`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/update" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "block": "general", "legalName": "texto", "supplierType": "goods" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/update`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "block": "general", "legalName": "texto", "supplierType": "goods" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "origin": "domestic", "cuit": null, "cuitFormatted": null, "countryCode": null, "countryName": null, "foreignTaxId": null, "legalName": "texto", "tradeName": null, "supplierType": "goods", "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": "local", "iibbNumber": null, "street": null, "streetNumber": null, "floorUnit": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "currencyCode": null, "notes": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "deactivationReason": null, "isOccasional": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Modificar una cuenta bancaria > Cambia una cuenta bancaria de un proveedor con la versión leída. Su moneda nunca cambia. POST`/api/v1/suppliers/update-bank-account` * Permiso `suppliers.manage-bank-accounts` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `bankAccountId`uuidrequerido * `version`enterorequerido mínimo 1 * `cbu`cualquiera * `swift`cualquiera * `iban`cualquiera * `accountNumber`textoadmite null hasta 34 caracteres * `bankName`textoadmite null hasta 120 caracteres * `holderName`textoadmite null hasta 200 caracteres * `isPrimary`sí o no ## Respuesta `200` con este JSON. * `id`uuidrequerido * `cbu`cualquierarequerido * `swift`cualquierarequerido * `iban`cualquierarequerido * `accountNumber`cualquierarequerido * `bankName`cualquierarequerido * `currencyCode`textorequerido * `holderName`cualquierarequerido * `isPrimary`sí o norequerido * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.manage-bank-accounts`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/suppliers/update-bank-account" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "bankAccountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/update-bank-account`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "bankAccountId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cbu": null, "swift": null, "iban": null, "accountNumber": null, "bankName": null, "currencyCode": "texto", "holderName": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ``` # Ver el historial de un proveedor > Lista los cambios de un proveedor, sus contactos y sus cuentas bancarias, del más nuevo al más viejo, campo por campo. GET`/api/v1/suppliers/get-history` * Permiso `suppliers.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/suppliers/get-history?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/get-history?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver un proveedor > Devuelve un proveedor con sus contactos y sus cuentas bancarias. GET`/api/v1/suppliers/get` * Permiso `suppliers.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `supplierId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `code`enterorequerido mínimo 1 * `origin`opciónrequerido Valores: `domestic` `foreign` * `cuit`cualquierarequerido * `cuitFormatted`cualquierarequerido * `countryCode`cualquierarequerido * `countryName`cualquierarequerido * `foreignTaxId`cualquierarequerido * `legalName`textorequerido * `tradeName`cualquierarequerido * `supplierType`opciónrequerido Valores: `goods` `services` `goods-and-services` `carrier` * `email`cualquierarequerido * `phone`cualquierarequerido * `vatCondition`opciónrequeridoadmite null Valores: `registered` `monotributo` `exempt` * `iibbCondition`opciónrequeridoadmite null Valores: `local` `multilateral` `exempt` `unregistered` * `iibbNumber`cualquierarequerido * `street`cualquierarequerido * `streetNumber`cualquierarequerido * `floorUnit`cualquierarequerido * `city`cualquierarequerido * `provinceId`uuidrequeridoadmite null * `postalCode`cualquierarequerido * `paymentTermId`uuidrequeridoadmite null * `paymentTerm`objetorequeridoadmite null * `currencyCode`cualquierarequerido * `notes`cualquierarequerido * `taxDataSource`cualquierarequerido * `taxDataCheckedAt`fecha y horarequeridoadmite null * `status`opciónrequerido Valores: `active` `inactive` * `deactivationReason`cualquierarequerido * `isOccasional`sí o norequerido * `version`enterorequerido mínimo 1 * `createdAt`fecha y horarequerido * `contacts`lista de objetorequerido * `bankAccounts`lista de objetorequerido * `enabledCurrencies`lista de textorequerido * `apocryphal`objetorequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `suppliers.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/suppliers/get?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/suppliers/get?supplierId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "origin": "domestic", "cuit": null, "cuitFormatted": null, "countryCode": null, "countryName": null, "foreignTaxId": null, "legalName": "texto", "tradeName": null, "supplierType": "goods", "email": null, "phone": null, "vatCondition": "registered", "iibbCondition": "local", "iibbNumber": null, "street": null, "streetNumber": null, "floorUnit": null, "city": null, "provinceId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "postalCode": null, "paymentTermId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "paymentTerm": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "status": "active" }, "currencyCode": null, "notes": null, "taxDataSource": null, "taxDataCheckedAt": "2026-10-23T14:30:00.000Z", "status": "active", "deactivationReason": null, "isOccasional": false, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z", "contacts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "role": null, "email": null, "phone": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ], "bankAccounts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "cbu": null, "swift": null, "iban": null, "accountNumber": null, "bankName": null, "currencyCode": "texto", "holderName": null, "isPrimary": false, "status": "active", "deactivationReason": null, "version": 1, "createdAt": "2026-10-23T14:30:00.000Z" } ], "enabledCurrencies": [ "texto" ], "apocryphal": { "listedOn": "2026-10-23", "checkedAt": "2026-10-23T14:30:00.000Z" } } ``` # Recepciones > La mercadería que llega contra una orden de compra y entra al depósito al costo de la orden. La mercadería que llega contra una orden de compra y entra al depósito al costo de la orden. | Operación | Ruta | | ------------------------------------------------------------------------------------------------------- | --------------------------------------------------- | | [Listar recepciones](/api/referencia/recepciones/listar-recepciones/) | GET `/api/v1/purchase-orders/list-receipts` | | [Ver una recepción](/api/referencia/recepciones/ver-una-recepcion/) | GET `/api/v1/purchase-orders/get-receipt` | | [Listar líneas para recibir](/api/referencia/recepciones/listar-lineas-para-recibir/) | GET `/api/v1/purchase-orders/list-receivable-lines` | | [Preparar una recepción](/api/referencia/recepciones/preparar-una-recepcion/) | POST `/api/v1/purchase-orders/prepare-receipt` | | [Modificar una recepción en borrador](/api/referencia/recepciones/modificar-una-recepcion-en-borrador/) | POST `/api/v1/purchase-orders/update-receipt` | | [Cerrar una recepción](/api/referencia/recepciones/cerrar-una-recepcion/) | POST `/api/v1/purchase-orders/close-receipt` | | [Descartar una recepción](/api/referencia/recepciones/descartar-una-recepcion/) | POST `/api/v1/purchase-orders/discard-receipt` | | [Revertir una recepción](/api/referencia/recepciones/revertir-una-recepcion/) | POST `/api/v1/purchase-orders/revert-receipt` | | [Ver el historial de una recepción](/api/referencia/recepciones/ver-el-historial-de-una-recepcion/) | GET `/api/v1/purchase-orders/get-receipt-history` | # Cerrar una recepción > Cierra una recepción en borrador con la versión leída: el stock entra al depósito al costo de la orden en pesos, se actualizan el costo promedio y el último costo, y lo retenido pasa a recibido. POST`/api/v1/purchase-orders/close-receipt` * Permiso `purchase-orders.receive` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `goodsReceiptId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `closed` `discarded` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `receiptDate`fecharequerido * `purchaseOrder`objetorequerido * `supplier`objetorequerido * `supplierDeliveryNote`cualquierarequerido * `warehouse`objetorequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `reversals`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.receive`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/close-receipt" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/close-receipt`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "reversal": "none", "receiptDate": "2026-10-23", "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "currencyCode": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "supplierDeliveryNote": null, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "version": 1, "exchangeRate": null, "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "customsDeclaration": null, "unitCost": null, "revertedQuantity": 100, "revertibleQuantity": 100, "reversalAtReceiptCost": null, "reversalCostReason": "later-entry", "invoicedQuantity": 100, "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ] } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Descartar una recepción > Descarta una recepción en borrador con un motivo: lo retenido vuelve a quedar pendiente de recibir. POST`/api/v1/purchase-orders/discard-receipt` * Permiso `purchase-orders.receive` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `goodsReceiptId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 500 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `closed` `discarded` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `receiptDate`fecharequerido * `purchaseOrder`objetorequerido * `supplier`objetorequerido * `supplierDeliveryNote`cualquierarequerido * `warehouse`objetorequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `reversals`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.receive`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/discard-receipt" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/discard-receipt`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "reversal": "none", "receiptDate": "2026-10-23", "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "currencyCode": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "supplierDeliveryNote": null, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "version": 1, "exchangeRate": null, "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "customsDeclaration": null, "unitCost": null, "revertedQuantity": 100, "revertibleQuantity": 100, "reversalAtReceiptCost": null, "reversalCostReason": "later-entry", "invoicedQuantity": 100, "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ] } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Listar líneas para recibir > Lista las líneas de una orden con algo pendiente de recibir, con lo pedido, recibido, retenido por recepciones en borrador y pendiente. GET`/api/v1/purchase-orders/list-receivable-lines` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `purchaseOrderId`uuidrequerido * `goodsReceiptId`uuidadmite null ## Respuesta `200` con este JSON. * `purchaseOrder`objetorequerido * `lines`lista de objetorequerido * `warehouses`lista de objetorequerido * `today`fecharequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/list-receivable-lines?purchaseOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/list-receivable-lines?purchaseOrderId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "texto", "supplierId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "currencyCode": "texto", "agreedExchangeRate": null, "documentDate": "2026-10-23" }, "lines": [ { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false, "isImported": false }, "quantity": 100, "receivedQuantity": 100, "inReceiptQuantity": 100, "heldByReceipt": 100, "pendingQuantity": 100 } ], "warehouses": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "isGeneral": false } ], "today": "2026-10-23" } ``` # Listar recepciones > Lista las recepciones con búsqueda por número, orden, remito del proveedor o proveedor y filtros de estado, reversión, depósito, proveedor y fechas. Por defecto trae todas menos las descartadas. GET`/api/v1/purchase-orders/list-receipts` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `status`lista de opciónadmite null Valores: `draft` `closed` `discarded` * `reversal`lista de opciónadmite null Valores: `none` `partial` `total` * `warehouseId`uuidadmite null * `supplierId`uuidadmite null * `dateFrom`fechaadmite null * `dateTo`fechaadmite null * `sort`opción Valores: `number` `date` `supplier`Por defecto: `number` * `direction`opción Valores: `asc` `desc`Por defecto: `desc` * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `receipts`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/list-receipts" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/list-receipts`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "receipts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "reversal": "none", "receiptDate": "2026-10-23", "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "supplierDeliveryNote": null, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" } } ], "total": 1 } ``` # Modificar una recepción en borrador > Edita una recepción en borrador con la versión leída. Se reemplaza lo que retiene de la orden. POST`/api/v1/purchase-orders/update-receipt` * Permiso `purchase-orders.receive` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `goodsReceiptId`uuidrequerido * `version`enterorequerido mínimo 1 * `warehouseId`uuid * `receiptDate`fechaadmite null * `supplierDeliveryNote`textoadmite null hasta 30 caracteres * `exchangeRate`cualquiera * `notes`textoadmite null hasta 500 caracteres * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `closed` `discarded` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `receiptDate`fecharequerido * `purchaseOrder`objetorequerido * `supplier`objetorequerido * `supplierDeliveryNote`cualquierarequerido * `warehouse`objetorequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `reversals`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.receive`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/update-receipt" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "lines": [ { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/update-receipt`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "lines": [ { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "reversal": "none", "receiptDate": "2026-10-23", "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "currencyCode": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "supplierDeliveryNote": null, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "version": 1, "exchangeRate": null, "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "customsDeclaration": null, "unitCost": null, "revertedQuantity": 100, "revertibleQuantity": 100, "reversalAtReceiptCost": null, "reversalCostReason": "later-entry", "invoicedQuantity": 100, "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ] } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Preparar una recepción > Prepara una recepción en borrador de una orden emitida: depósito, fecha, remito del proveedor, cotización, notas y, por línea, lo que llegó y su despacho. Retiene esas cantidades y no mueve stock. POST`/api/v1/purchase-orders/prepare-receipt` * Permiso `purchase-orders.receive` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `purchaseOrderId`uuidrequerido * `warehouseId`uuid * `receiptDate`fechaadmite null * `supplierDeliveryNote`textoadmite null hasta 30 caracteres * `exchangeRate`cualquiera * `notes`textoadmite null hasta 500 caracteres * `lines`lista de objetorequerido al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `closed` `discarded` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `receiptDate`fecharequerido * `purchaseOrder`objetorequerido * `supplier`objetorequerido * `supplierDeliveryNote`cualquierarequerido * `warehouse`objetorequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `reversals`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.receive`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/prepare-receipt" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/prepare-receipt`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "purchaseOrderId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lines": [ { "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "reversal": "none", "receiptDate": "2026-10-23", "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "currencyCode": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "supplierDeliveryNote": null, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "version": 1, "exchangeRate": null, "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "customsDeclaration": null, "unitCost": null, "revertedQuantity": 100, "revertibleQuantity": 100, "reversalAtReceiptCost": null, "reversalCostReason": "later-entry", "invoicedQuantity": 100, "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ] } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Revertir una recepción > Revierte una recepción cerrada, total o por líneas, con un motivo: el stock sale al costo de la recepción y lo revertido queda pendiente de recibir mientras la orden siga emitida. POST`/api/v1/purchase-orders/revert-receipt` * Permiso `purchase-orders.revert-receipt` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `goodsReceiptId`uuidrequerido * `reason`textorequerido de 1 a 300 caracteres * `lines`lista de objetoadmite null al menos 1, hasta 200 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `closed` `discarded` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `receiptDate`fecharequerido * `purchaseOrder`objetorequerido * `supplier`objetorequerido * `supplierDeliveryNote`cualquierarequerido * `warehouse`objetorequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `reversals`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.revert-receipt`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/purchase-orders/revert-receipt" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/revert-receipt`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "goodsReceiptId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "reversal": "none", "receiptDate": "2026-10-23", "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "currencyCode": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "supplierDeliveryNote": null, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "version": 1, "exchangeRate": null, "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "customsDeclaration": null, "unitCost": null, "revertedQuantity": 100, "revertibleQuantity": 100, "reversalAtReceiptCost": null, "reversalCostReason": "later-entry", "invoicedQuantity": 100, "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ] } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Ver el historial de una recepción > Lista los cambios de una recepción, sus líneas y sus reversiones, del más nuevo al más viejo, campo por campo. GET`/api/v1/purchase-orders/get-receipt-history` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `goodsReceiptId`uuidrequerido * `cursor`uuid * `limit`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `events`lista de objetorequerido * `nextCursor`uuidrequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/get-receipt-history?goodsReceiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/get-receipt-history?goodsReceiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "events": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "recordedAt": "2026-10-23T14:30:00.000Z", "userId": "texto", "userName": null, "channel": "ui", "operation": "texto", "useCase": "texto", "kind": "change", "outcome": "success", "code": null, "reason": null, "detail": {}, "changes": [ { "entity": "texto", "recordId": "texto", "action": "insert", "field": "texto", "before": null, "after": null } ] } ], "nextCursor": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" } ``` # Ver una recepción > Devuelve una recepción con su orden, proveedor, depósito, remito del proveedor, cotización, líneas con su despacho y lo revertido, y sus reversiones. GET`/api/v1/purchase-orders/get-receipt` * Permiso `purchase-orders.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `goodsReceiptId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `draft` `closed` `discarded` * `reversal`opciónrequerido Valores: `none` `partial` `total` * `receiptDate`fecharequerido * `purchaseOrder`objetorequerido * `supplier`objetorequerido * `supplierDeliveryNote`cualquierarequerido * `warehouse`objetorequerido * `version`enterorequerido mínimo 1 * `exchangeRate`cualquierarequerido * `notes`cualquierarequerido * `lines`lista de objetorequerido * `stockMovement`objetorequeridoadmite null * `reversals`lista de objetorequerido * `createdAt`fecha y horarequerido * `createdBy`objetorequeridoadmite null * `closedAt`fecha y horarequeridoadmite null * `closedBy`objetorequeridoadmite null * `discardedAt`fecha y horarequeridoadmite null * `discardedBy`objetorequeridoadmite null * `discardReason`cualquierarequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `purchase-orders.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/purchase-orders/get-receipt?goodsReceiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/purchase-orders/get-receipt?goodsReceiptId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "reversal": "none", "receiptDate": "2026-10-23", "purchaseOrder": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "draft", "currencyCode": "texto" }, "supplier": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": 1, "legalName": "texto", "cuit": null }, "supplierDeliveryNote": null, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "version": 1, "exchangeRate": null, "notes": null, "lines": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "purchaseOrderLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "isImported": false, "supplierCode": null, "quantity": 100, "customsDeclaration": null, "unitCost": null, "revertedQuantity": 100, "revertibleQuantity": 100, "reversalAtReceiptCost": null, "reversalCostReason": "later-entry", "invoicedQuantity": 100, "invoices": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "label": "texto", "total": null, "currencyCode": "texto" } ] } ], "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "reversals": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "reason": "texto", "reversalDate": "2026-10-23", "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "stockMovement": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "goodsReceiptLineId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "quantity": 100 } ] } ], "createdAt": "2026-10-23T14:30:00.000Z", "createdBy": { "id": "texto", "name": null }, "closedAt": "2026-10-23T14:30:00.000Z", "closedBy": { "id": "texto", "name": null }, "discardedAt": "2026-10-23T14:30:00.000Z", "discardedBy": { "id": "texto", "name": null }, "discardReason": null } ``` # Recuentos > Recuentos de un depósito, a ciegas o no, con el ajuste de sus diferencias. Recuentos de un depósito, a ciegas o no, con el ajuste de sus diferencias. | Operación | Ruta | | ------------------------------------------------------------------------- | -------------------------------------------- | | [Listar recuentos](/api/referencia/recuentos/listar-recuentos/) | GET `/api/v1/stock-movements/list-counts` | | [Ver un recuento](/api/referencia/recuentos/ver-un-recuento/) | GET `/api/v1/stock-movements/get-count` | | [Crear un recuento](/api/referencia/recuentos/crear-un-recuento/) | POST `/api/v1/stock-movements/create-count` | | [Registrar lo contado](/api/referencia/recuentos/registrar-lo-contado/) | POST `/api/v1/stock-movements/record-count` | | [Terminar de contar](/api/referencia/recuentos/terminar-de-contar/) | POST `/api/v1/stock-movements/finish-count` | | [Confirmar un recuento](/api/referencia/recuentos/confirmar-un-recuento/) | POST `/api/v1/stock-movements/confirm-count` | | [Cancelar un recuento](/api/referencia/recuentos/cancelar-un-recuento/) | POST `/api/v1/stock-movements/cancel-count` | # Cancelar un recuento > Cancela un recuento abierto con un motivo, sin ningún ajuste. POST`/api/v1/stock-movements/cancel-count` * Permiso `stock-movements.confirm-count` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `countId`uuidrequerido * `version`enterorequerido mínimo 1 * `reason`textorequerido de 1 a 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `in_progress` `review` `confirmed` `cancelled` * `warehouse`objetorequerido * `location`objetorequeridoadmite null * `family`objetorequeridoadmite null * `blind`sí o norequerido * `notes`cualquierarequerido * `countedLines`enterorequerido mínimo 0 * `lineCount`enterorequerido mínimo 0 * `createdBy`objetorequerido * `createdAt`fecha y horarequerido * `version`enterorequerido mínimo 1 * `uncounted`opciónrequeridoadmite null Valores: `keep` `zero` * `closingNotes`cualquierarequerido * `closedAt`fecha y horarequeridoadmite null * `adjustment`objetorequeridoadmite null * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.confirm-count`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/cancel-count" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/cancel-count`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "reason": "texto" }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "in_progress", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "location": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "blind": false, "notes": null, "countedLines": 1, "lineCount": 1, "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "version": 1, "uncounted": "keep", "closingNotes": null, "closedAt": "2026-10-23T14:30:00.000Z", "adjustment": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "counted": null, "snapshot": 100, "moved": null, "movedAfterPhoto": null, "system": null, "difference": null, "unitCost": null, "cause": "shrinkage" } ] } ``` # Confirmar un recuento > Confirma un recuento en revisión y aplica sus diferencias en un solo ajuste, cada faltante con su causa (merma, rotura o robo) y cada sobrante como sobrante. POST`/api/v1/stock-movements/confirm-count` * Permiso `stock-movements.confirm-count` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `countId`uuidrequerido * `version`enterorequerido mínimo 1 * `uncounted`opciónrequerido Valores: `keep` `zero` * `causes`lista de objeto hasta 10000 * `reviewed`lista de objetorequerido hasta 10000 * `notes`textoadmite null hasta 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `in_progress` `review` `confirmed` `cancelled` * `warehouse`objetorequerido * `location`objetorequeridoadmite null * `family`objetorequeridoadmite null * `blind`sí o norequerido * `notes`cualquierarequerido * `countedLines`enterorequerido mínimo 0 * `lineCount`enterorequerido mínimo 0 * `createdBy`objetorequerido * `createdAt`fecha y horarequerido * `version`enterorequerido mínimo 1 * `uncounted`opciónrequeridoadmite null Valores: `keep` `zero` * `closingNotes`cualquierarequerido * `closedAt`fecha y horarequeridoadmite null * `adjustment`objetorequeridoadmite null * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.confirm-count`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/confirm-count" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "uncounted": "keep", "reviewed": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "difference": 100 } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/confirm-count`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "uncounted": "keep", "reviewed": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "difference": 100 } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "in_progress", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "location": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "blind": false, "notes": null, "countedLines": 1, "lineCount": 1, "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "version": 1, "uncounted": "keep", "closingNotes": null, "closedAt": "2026-10-23T14:30:00.000Z", "adjustment": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "counted": null, "snapshot": 100, "moved": null, "movedAfterPhoto": null, "system": null, "difference": null, "unitCost": null, "cause": "shrinkage" } ] } ``` # Crear un recuento > Crea un recuento de un depósito, opcionalmente de una ubicación y de una rama de familias, y a ciegas, con la foto del stock físico de cada artículo que cuenta. POST`/api/v1/stock-movements/create-count` * Permiso `stock-movements.count` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `warehouseId`uuidrequerido * `locationId`uuidadmite null * `familyId`uuidadmite null * `blind`sí o norequerido * `notes`textoadmite null hasta 300 caracteres ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `in_progress` `review` `confirmed` `cancelled` * `warehouse`objetorequerido * `location`objetorequeridoadmite null * `family`objetorequeridoadmite null * `blind`sí o norequerido * `notes`cualquierarequerido * `countedLines`enterorequerido mínimo 0 * `lineCount`enterorequerido mínimo 0 * `createdBy`objetorequerido * `createdAt`fecha y horarequerido * `version`enterorequerido mínimo 1 * `uncounted`opciónrequeridoadmite null Valores: `keep` `zero` * `closingNotes`cualquierarequerido * `closedAt`fecha y horarequeridoadmite null * `adjustment`objetorequeridoadmite null * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.count`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/create-count" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "blind": false }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/create-count`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "blind": false }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "in_progress", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "location": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "blind": false, "notes": null, "countedLines": 1, "lineCount": 1, "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "version": 1, "uncounted": "keep", "closingNotes": null, "closedAt": "2026-10-23T14:30:00.000Z", "adjustment": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "counted": null, "snapshot": 100, "moved": null, "movedAfterPhoto": null, "system": null, "difference": null, "unitCost": null, "cause": "shrinkage" } ] } ``` # Listar recuentos > Lista los recuentos, del más nuevo al más viejo, con filtros de estado y depósito y cuántos artículos se contaron. GET`/api/v1/stock-movements/list-counts` * Permiso `stock-movements.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `status`opciónadmite null Valores: `in_progress` `review` `confirmed` `cancelled` * `warehouseId`uuidadmite null * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `counts`lista de objetorequerido * `total`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock-movements/list-counts" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/list-counts`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "counts": [ { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "in_progress", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "location": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "blind": false, "notes": null, "countedLines": 1, "lineCount": 1, "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "version": 1 } ], "total": 1 } ``` # Registrar lo contado > Registra lo contado de algunos artículos de un recuento en curso sin tocar el stock. Un artículo que no estaba en el recuento se agrega con su foto. POST`/api/v1/stock-movements/record-count` * Permiso `stock-movements.count` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `countId`uuidrequerido * `version`enterorequerido mínimo 1 * `lines`lista de objetorequerido al menos 1, hasta 1000 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `in_progress` `review` `confirmed` `cancelled` * `warehouse`objetorequerido * `location`objetorequeridoadmite null * `family`objetorequeridoadmite null * `blind`sí o norequerido * `notes`cualquierarequerido * `countedLines`enterorequerido mínimo 0 * `lineCount`enterorequerido mínimo 0 * `createdBy`objetorequerido * `createdAt`fecha y horarequerido * `version`enterorequerido mínimo 1 * `uncounted`opciónrequeridoadmite null Valores: `keep` `zero` * `closingNotes`cualquierarequerido * `closedAt`fecha y horarequeridoadmite null * `adjustment`objetorequeridoadmite null * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.count`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/record-count" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "countedQuantity": null } ] }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/record-count`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1, "lines": [ { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "countedQuantity": null } ] }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "in_progress", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "location": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "blind": false, "notes": null, "countedLines": 1, "lineCount": 1, "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "version": 1, "uncounted": "keep", "closingNotes": null, "closedAt": "2026-10-23T14:30:00.000Z", "adjustment": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "counted": null, "snapshot": 100, "moved": null, "movedAfterPhoto": null, "system": null, "difference": null, "unitCost": null, "cause": "shrinkage" } ] } ``` # Terminar de contar > Termina el conteo de un recuento en curso: no se registra nada más y sus diferencias quedan para revisar, sin tocar el stock. POST`/api/v1/stock-movements/finish-count` * Permiso `stock-movements.count` * Empresa Opera sobre la empresa activa * Tipo Escritura: pide Idempotency-Key * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). * `Idempotency-Key`textorequerido Una clave única por intento, de hasta 255 caracteres. Reintentar con la misma clave y los mismos datos devuelve el mismo resultado sin repetir la operación. Ver [Idempotencia](/api/idempotencia/). ## Cuerpo JSON con `Content-Type: application/json`. * `countId`uuidrequerido * `version`enterorequerido mínimo 1 ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `in_progress` `review` `confirmed` `cancelled` * `warehouse`objetorequerido * `location`objetorequeridoadmite null * `family`objetorequeridoadmite null * `blind`sí o norequerido * `notes`cualquierarequerido * `countedLines`enterorequerido mínimo 0 * `lineCount`enterorequerido mínimo 0 * `createdBy`objetorequerido * `createdAt`fecha y horarequerido * `version`enterorequerido mínimo 1 * `uncounted`opciónrequeridoadmite null Valores: `keep` `zero` * `closingNotes`cualquierarequerido * `closedAt`fecha y horarequeridoadmite null * `adjustment`objetorequeridoadmite null * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.count`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `409` | Otra persona cambió el registro desde que lo leíste (`record.stale`). | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl -X POST "$ERP_URL/api/v1/stock-movements/finish-count" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }' ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/finish-count`, { method: "POST", headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, "Idempotency-Key": crypto.randomUUID(), "Content-Type": "application/json", }, body: JSON.stringify({ "countId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "version": 1 }), }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "in_progress", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "location": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "blind": false, "notes": null, "countedLines": 1, "lineCount": 1, "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "version": 1, "uncounted": "keep", "closingNotes": null, "closedAt": "2026-10-23T14:30:00.000Z", "adjustment": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "counted": null, "snapshot": 100, "moved": null, "movedAfterPhoto": null, "system": null, "difference": null, "unitCost": null, "cause": "shrinkage" } ] } ``` # Ver un recuento > Devuelve un recuento con lo contado de cada artículo y la causa de cada diferencia confirmada. En un recuento a ciegas en curso nunca muestra la foto ni las diferencias. GET`/api/v1/stock-movements/get-count` * Permiso `stock-movements.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `countId`uuidrequerido ## Respuesta `200` con este JSON. * `id`uuidrequerido * `number`textorequerido * `status`opciónrequerido Valores: `in_progress` `review` `confirmed` `cancelled` * `warehouse`objetorequerido * `location`objetorequeridoadmite null * `family`objetorequeridoadmite null * `blind`sí o norequerido * `notes`cualquierarequerido * `countedLines`enterorequerido mínimo 0 * `lineCount`enterorequerido mínimo 0 * `createdBy`objetorequerido * `createdAt`fecha y horarequerido * `version`enterorequerido mínimo 1 * `uncounted`opciónrequeridoadmite null Valores: `keep` `zero` * `closingNotes`cualquierarequerido * `closedAt`fecha y horarequeridoadmite null * `adjustment`objetorequeridoadmite null * `lines`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock-movements.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock-movements/get-count?countId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock-movements/get-count?countId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto", "status": "in_progress", "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "location": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto" }, "family": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto" }, "blind": false, "notes": null, "countedLines": 1, "lineCount": 1, "createdBy": { "id": "texto", "name": null }, "createdAt": "2026-10-23T14:30:00.000Z", "version": 1, "uncounted": "keep", "closingNotes": null, "closedAt": "2026-10-23T14:30:00.000Z", "adjustment": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "number": "texto" }, "lines": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "counted": null, "snapshot": 100, "moved": null, "movedAfterPhoto": null, "system": null, "difference": null, "unitCost": null, "cause": "shrinkage" } ] } ``` # Stock > Saldos por artículo y depósito, su valuación y el último costo de compra. Saldos por artículo y depósito, su valuación y el último costo de compra. | Operación | Ruta | | ------------------------------------------------------------------------------------- | -------------------------------------- | | [Listar saldos de stock](/api/referencia/stock/listar-saldos-de-stock/) | GET `/api/v1/stock/list-balances` | | [Valuar el stock](/api/referencia/stock/valuar-el-stock/) | GET `/api/v1/stock/get-valuation` | | [Contar artículos por depósito](/api/referencia/stock/contar-articulos-por-deposito/) | GET `/api/v1/stock/count-by-warehouse` | | [Ver el último costo de compra](/api/referencia/stock/ver-el-ultimo-costo-de-compra/) | GET `/api/v1/stock/get-purchase-cost` | # Contar artículos por depósito > Cuenta, para cada depósito pedido, los artículos con stock físico. GET`/api/v1/stock/count-by-warehouse` * Permiso `stock.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `warehouseIds`uno derequerido ## Respuesta `200` con este JSON. * `warehouses`lista de objetorequerido ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock/count-by-warehouse?warehouseIds=texto" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock/count-by-warehouse?warehouseIds=texto`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "warehouses": [ { "warehouseId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "itemsWithStock": 1 } ] } ``` # Listar saldos de stock > Lista los saldos por artículo y depósito (físico, no disponible y disponible), con búsqueda y filtros de depósito, familia, marca y saldo. GET`/api/v1/stock/list-balances` * Permiso `stock.view` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `warehouseId`uuidadmite null * `familyId`uuidadmite null * `brandId`uuidadmite null * `balance`opción Valores: `with-stock` `without-stock` `all`Por defecto: `with-stock` * `sort`opción Valores: `code` `item` `warehouse` `physical` `available` `cost` `value` `relevance`Por defecto: `code` * `direction`opción Valores: `asc` `desc`Por defecto: `asc` * `countTotal`sí o no * `groupBy`opción Valores: `warehouse` `item`Por defecto: `warehouse` * `itemIds`uno deadmite null * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `balances`lista de objetorequerido * `total`entero mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock.view`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock/list-balances" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock/list-balances`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "balances": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "physical": 100, "unavailable": 100, "reserved": 100, "available": 100, "averageCost": null, "bookValue": null } ], "total": 1 } ``` # Valuar el stock > Valúa el stock a costo promedio o a los precios sin IVA de una lista, por fila y en total, con los mismos filtros de los saldos. GET`/api/v1/stock/get-valuation` * Permiso `stock.view-valuation` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `search`textoadmite null hasta 100 caracteres * `warehouseId`uuidadmite null * `familyId`uuidadmite null * `brandId`uuidadmite null * `balance`opción Valores: `with-stock` `without-stock` `all`Por defecto: `with-stock` * `sort`opción Valores: `code` `item` `warehouse` `physical` `available` `cost` `value`Por defecto: `code` * `direction`opción Valores: `asc` `desc`Por defecto: `asc` * `base`opción Valores: `book` `commercial`Por defecto: `book` * `priceListId`uuidadmite null * `groupBy`opción Valores: `warehouse` `item`Por defecto: `warehouse` * `itemIds`uno deadmite null * `page`entero Por defecto: `1`mínimo 1 * `pageSize`entero Por defecto: `50`mínimo 1, máximo 100 ## Respuesta `200` con este JSON. * `base`opciónrequerido Valores: `book` `commercial` * `label`textorequerido * `priceList`objetorequeridoadmite null * `currencyCode`textorequerido * `priceDate`cualquierarequerido * `rows`lista de objetorequerido * `total`enterorequerido mínimo 0 * `totalValue`textorequerido * `rowsWithoutValue`enterorequerido mínimo 0 * `itemsWithoutValue`enterorequerido mínimo 0 ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock.view-valuation`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock/get-valuation" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock/get-valuation`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "base": "book", "label": "texto", "priceList": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "name": "texto", "currencyCode": "texto" }, "currencyCode": "texto", "priceDate": null, "rows": [ { "item": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active", "unitCode": "texto", "unitName": "texto", "allowsDecimals": false }, "warehouse": { "id": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "code": "texto", "name": "texto", "status": "active" }, "physical": 100, "unavailable": 100, "reserved": 100, "available": 100, "averageCost": null, "bookValue": null, "value": null } ], "total": 1, "totalValue": "texto", "rowsWithoutValue": 1, "itemsWithoutValue": 1 } ``` # Ver el último costo de compra > Devuelve el último costo de compra en pesos de un artículo y la fecha de la recepción que lo dejó. GET`/api/v1/stock/get-purchase-cost` * Permiso `stock.view-valuation` * Empresa Opera sobre la empresa activa * Tipo Lectura: no cambia nada * Respuesta JSON ## Encabezados * `Cookie`textorequerido La cookie de sesión del usuario de la integración (`__Secure-erp.session_token`). Cuando esté la clave API, va en `Authorization: Bearer`. Ver [Autenticación](/api/autenticacion/). * `X-Expected-Company`uuidrequerido La empresa sobre la que operás. Si no coincide con la de la credencial, responde 409. Ver [Empresa activa](/api/empresa-activa/). ## Parámetros de la consulta * `itemId`uuidrequerido ## Respuesta `200` con este JSON. * `itemId`uuidrequerido * `lastPurchaseCost`cualquierarequerido * `lastPurchaseDate`fecharequeridoadmite null ## Errores Un rechazo responde `application/problem+json` con un `code` estable. Los más comunes en esta operación: | | | | ----- | ---------------------------------------------------------------------- | | `401` | Falta la credencial o venció. | | `403` | La credencial no tiene el permiso `stock.view-valuation`. | | `409` | La empresa activa no es la de `X-Expected-Company`. | | `422` | Datos inválidos o una regla de negocio rota, con el detalle por campo. | | `503` | Sistema ocupado: reintentá después de `Retry-After` segundos. | La lista completa está en [Errores](/api/errores/). * curl ```bash curl "$ERP_URL/api/v1/stock/get-purchase-cost?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90" \ -b sesion.txt \ -H "X-Expected-Company: $ERP_EMPRESA" ``` * TypeScript ```ts const respuesta = await fetch(`${process.env.ERP_URL}/api/v1/stock/get-purchase-cost?itemId=3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90`, { headers: { Cookie: process.env.ERP_SESION!, "X-Expected-Company": process.env.ERP_EMPRESA!, }, }); if (!respuesta.ok) throw new Error((await respuesta.json()).title); const datos = await respuesta.json(); ``` Respuesta 200 ```json { "itemId": "3f2a9c1e-5b7d-4e8a-9c21-7d4e5f6a8b90", "lastPurchaseCost": null, "lastPurchaseDate": "2026-10-23" } ``` # Versiones > Qué cambios pueden pasar sin aviso y cuáles cambian la versión. La API está en la versión 1: todas las rutas empiezan con `/api/v1`. ## Cambios que no cambian la versión [Sección titulada «Cambios que no cambian la versión»](#cambios-que-no-cambian-la-versión) Una integración tiene que tolerar estos cambios, que llegan con cada actualización del ERP: * Operaciones nuevas. * Campos nuevos en una respuesta. * Parámetros o campos nuevos opcionales en un pedido. * Valores nuevos en un campo de opciones (por ejemplo un estado nuevo). * Códigos de error nuevos. ## Cambios que sí [Sección titulada «Cambios que sí»](#cambios-que-sí) Quitar o renombrar un campo, una operación o un valor, o volver obligatorio algo que era opcional, sale en una versión nueva (`/api/v2`) y la anterior sigue funcionando un tiempo anunciado. ## Dónde ver la versión actual [Sección titulada «Dónde ver la versión actual»](#dónde-ver-la-versión-actual) La [referencia](/api/referencia/) se genera del código de cada versión del ERP, así que siempre describe exactamente lo que está publicado. # Ayuda > Cómo usar el ERP en el día a día. Esta ayuda es para quien opera el ERP: vendedores, administración, depósito, compras y contabilidad. Explica cómo se hace cada tarea en la pantalla, en el orden en que se hace. [Primeros pasos](/ayuda/primeros-pasos/)Entrar, elegir la empresa, buscar y moverte por el menú. [Cómo está organizado](/ayuda/como-esta-organizado/)Empresas, áreas del menú, permisos y documentos. [Cómo se recorre una venta](/ayuda/ventas/circuito-de-venta/)Pedido, entrega, factura, cuenta corriente y cobranza. Las guías de cada área (Compras, Inventario, Finanzas, Impuestos y Contabilidad) se van sumando acá, con capturas de la versión actual del ERP. # Cómo está organizado > Empresas, áreas, permisos y documentos del ERP. ## Una instalación, varias empresas [Sección titulada «Una instalación, varias empresas»](#una-instalación-varias-empresas) Tu ERP es una instalación propia, con su dirección, su base de datos y sus usuarios. Adentro puede haber varias empresas legales: cada una con su CUIT, sus clientes, proveedores, artículos, comprobantes y saldos. Los datos de una empresa nunca aparecen en otra. Lo que sí es común a todas son los datos oficiales: alícuotas de IVA, unidades, jurisdicciones, feriados y los padrones de ARCA y ARBA. ## Áreas [Sección titulada «Áreas»](#áreas) | Área | Qué tiene | | -------------- | -------------------------------------------------------------------------------------------- | | Ventas | Pedidos, entregas, facturación, cuentas corrientes, clientes y listas de precios. | | Finanzas | Cobranzas, pagos y condiciones de pago. | | Compras | Órdenes de compra, recepciones, facturas de proveedor, cuentas de proveedores y proveedores. | | Inventario | Recuentos, stock, movimientos, artículos, depósitos y marcas y familias. | | Impuestos | Percepciones practicadas y sufridas, y la posición de IVA. | | Contabilidad | Diario, conciliación, operaciones X y plan de cuentas. | | Administración | Empresas, usuarios, roles, configuración, auditoría y datos de referencia. | ## Permisos [Sección titulada «Permisos»](#permisos) Cada persona tiene uno o varios roles en cada empresa. Los roles se arman desde cero, sumando permisos; no hay roles que vengan hechos. Lo que tu rol no permite no aparece en la pantalla, y tampoco se puede hacer por la API ni con un asistente de IA. ## Documentos [Sección titulada «Documentos»](#documentos) Los documentos (pedidos, remitos, facturas, recibos, órdenes de compra y de pago) siguen el mismo ciclo: se arman en **borrador**, se revisan y se **confirman o emiten**. Un borrador se puede editar o descartar; un documento emitido ya no se edita: se corrige con otro documento, como una nota de crédito o una reversión. Nada se borra: cada cambio queda en la actividad del documento, con quién lo hizo y cuándo. # Primeros pasos > Entrar al ERP, elegir la empresa y moverte por el menú. ## Entrar [Sección titulada «Entrar»](#entrar) 1. El administrador te invita con tu correo. Te llega un enlace para crear tu contraseña; vale una sola vez. 2. Entrá a la dirección del ERP de tu empresa con tu correo y tu contraseña. 3. Si tenés acceso a más de una empresa, elegí con cuál vas a trabajar. Si olvidaste la contraseña, pedile al administrador un enlace para recuperarla. ## Elegir la empresa [Sección titulada «Elegir la empresa»](#elegir-la-empresa) Arriba del menú está la empresa con la que estás trabajando. Tocala para cambiar a otra. Con `⌘` `1`, `⌘` `2` (o `Ctrl` en Windows) cambiás directo a la primera, la segunda, y así. Precaución Cambiar de empresa cambia todo lo que ves: clientes, artículos, comprobantes y saldos son de cada empresa y nunca se mezclan. ## El menú [Sección titulada «El menú»](#el-menú) El menú de la izquierda está ordenado por uso diario: **Inicio**, **Flujo de documentos**, **Ventas**, **Finanzas**, **Compras**, **Inventario**, **Impuestos**, **Contabilidad**, **Calendario** y, al final, **Administración**. Dentro de cada área, lo que se opera todos los días va primero y los datos maestros después. Sólo ves lo que tu rol te permite. Si te falta una pantalla, pedile el permiso al administrador. ## Buscar [Sección titulada «Buscar»](#buscar) `⌘` `K` abre el buscador desde cualquier pantalla. Para encontrar un documento por su número, usá **Flujo de documentos**: acepta el número con prefijo (por ejemplo `PED-4` o `FAC-12`), el número legal, un CAE o un número de cheque, y te muestra todo lo vinculado a ese documento. ## Tu cuenta [Sección titulada «Tu cuenta»](#tu-cuenta) En el menú de tu avatar, arriba a la derecha, está **Mi cuenta**: tus datos, tu contraseña, las sesiones abiertas y los asistentes de IA que conectaste. # Cómo se recorre una venta > Del pedido a la cobranza, con lo que deja cada paso. Una venta pasa por cinco pantallas de **Ventas** y **Finanzas**. Cada paso toma lo pendiente del anterior, así que nunca se carga dos veces el mismo dato. 1. **Pedido** (Ventas › Pedidos). Cargás el cliente y los artículos; el precio lo propone la lista del cliente y la bonificación es la suya. Al **confirmarlo** quedan fijos los precios, las bonificaciones y las cuotas de la condición de pago. Si el cliente pasa su límite de crédito, el ERP te avisa pero no te frena. 2. **Entrega** (Ventas › Entregas). Preparás el remito con lo pendiente de los pedidos del cliente, desde un depósito; el borrador reserva el stock. Al **emitirlo** toma el número legal y saca la mercadería del depósito. Si la empresa usa COT y el viaje pasa por Buenos Aires, lo pide a ARBA en el momento. Para entregar muchos pedidos de una vez, **Backorders** arma un remito por cliente con lo que el stock alcanza a cubrir. 3. **Factura** (Ventas › Facturación). Facturás lo entregado o lo pedido. El **pool de facturación** junta todo lo pendiente y genera una factura por cliente de una vez. Al **emitir**, el ERP pide el CAE a ARCA y te dice el resultado: autorizada, rechazada (vuelve a borrador para corregirla) o pendiente, que se reintenta. 4. **Cuenta corriente** (Ventas › Cuentas corrientes). La factura autorizada queda como deuda del cliente, en cuotas según su condición de pago, con la antigüedad de cada una. 5. **Cobranza** (Finanzas › Cobranzas). Registrás el recibo con sus medios (efectivo, transferencia, cheque, echeq, retenciones) y lo imputás a las cuotas abiertas. Lo que sobra queda a cuenta, para aplicarlo después. ## Seguir una venta [Sección titulada «Seguir una venta»](#seguir-una-venta) Desde cualquier documento, **Flujo de documentos** muestra la cadena completa: el pedido, sus remitos, sus facturas y notas de crédito y los recibos que las cobraron, con lo que queda pendiente en cada paso. ## Corregir [Sección titulada «Corregir»](#corregir) | Qué pasó | Cómo se corrige | | ------------------------------------- | --------------------------------------------------------------------- | | El pedido no se va a completar | **Cerrar saldo** del pedido: lo pendiente deja de estarlo. | | Se entregó de más o volvió mercadería | **Revertir** el remito, total o por líneas: el stock vuelve a entrar. | | La factura tiene un error | Una **nota de crédito** de la factura, por líneas y cantidades. | | Se cargó mal un recibo | **Anular** el recibo: se revierte lo que imputó. | # IA > Conectar un asistente de IA al ERP con tus permisos. El ERP habla [MCP](https://modelcontextprotocol.io), el protocolo con el que Claude, ChatGPT y otros asistentes usan herramientas externas. Conectado, un asistente puede consultar y operar el ERP por vos: buscar un cliente, ver su cuenta, armar un pedido. El asistente nunca puede más que la persona que lo conecta. Vos elegís en qué empresa trabaja, qué permisos tuyos le das y hasta cuándo; lo podés revocar cuando quieras, y todo lo que hace queda en la auditoría como «vos, vía el asistente». [Conectar un asistente](/ia/conectar-un-asistente/)Paso a paso, con Claude o con cualquier cliente MCP. [Guía para agentes](/ia/guia-para-agentes/)Cómo trabaja un agente con el ERP y qué herramientas tiene. [llms.txt](/ia/llms-txt/)Esta documentación en un formato que lee un modelo. # Conectar un asistente > Cómo conectar Claude u otro cliente MCP al ERP. El ERP publica un servidor MCP en la misma dirección de tu instalación, en `/mcp`. Se conecta con OAuth: no hay que copiar claves. 1. En tu asistente, agregá un conector MCP con la dirección: ```text https://erp.tuempresa.com.ar/mcp ``` En Claude es **Configuración › Conectores › Agregar conector personalizado**. 2. El asistente te lleva a la pantalla de ingreso del ERP. Entrá con tu usuario. 3. En la pantalla de consentimiento elegí la **empresa**, si el asistente puede **Sólo consultar** o **Consultar y operar** (con **Elegir permisos** le das sólo algunos de los tuyos) y el **vencimiento**, dentro del máximo de la empresa (90 días por defecto). 4. Tocá **Permitir**. El asistente ya puede usar las herramientas del ERP en esa empresa. ## Revocar [Sección titulada «Revocar»](#revocar) En **Mi cuenta › Asistentes conectados** ves cada asistente que conectaste, en qué empresa, con qué permisos y su estado. Revocalo y su próxima llamada se rechaza, aunque su token no haya vencido. Un administrador puede ver y revocar los asistentes de cualquier usuario desde su ficha. ## Lectura y escritura [Sección titulada «Lectura y escritura»](#lectura-y-escritura) El asistente pide dos alcances: `erp:read` para consultar y `erp:write` para operar. Si sólo le diste lectura, una herramienta que escribe se rechaza y el rechazo queda en la auditoría. # llms.txt > Esta documentación en texto plano para modelos de lenguaje. El portal publica su contenido en el formato [llms.txt](https://llmstxt.org), para que un modelo lo lea entero o por partes: | Archivo | Qué tiene | | ------------------------------------ | ------------------------------------------------------ | | [`/llms.txt`](/llms.txt) | El índice: qué es el ERP y los enlaces a cada sección. | | [`/llms-full.txt`](/llms-full.txt) | Toda la documentación en un solo archivo. | | [`/llms-small.txt`](/llms-small.txt) | La misma, compacta, sin notas ni detalles plegados. | Para que un asistente responda sobre la API, pasale `/llms-full.txt` como contexto. # Documentación del ERP > Guías para usar el ERP, la API para integrarlo y cómo conectarle un asistente de IA. Documentación # ¿Qué querés hacer con el ERP? Guías para usarlo, la API para integrarlo y cómo conectarle un asistente de IA. Buscá una guía, una pantalla o una operación`Ctrl K` Lo más buscado:PedidosFacturaciónStockCobranzasARCAMCP ## Por dónde empezar [AyudaPara quien usa el ERP todos los días: cómo está organizado, cómo se recorre una venta y qué hacer cuando algo no sale.Ir a la ayuda →](/ayuda/)[APIPara integrar el ERP con otro sistema: 260 operaciones documentadas campo por campo, con ejemplos listos para copiar.Ver la API →](/api/)[IAPara conectar Claude, ChatGPT u otro asistente por MCP, con los mismos permisos que la persona que lo conecta.Conectar un asistente →](/ia/) ## La API por área Agrupada como el menú del ERP: encontrás cada operación donde está la pantalla. [Empresa y referencias11Empresa, Datos de referencia, Flujo de documentos](/api/referencia/empresa/)[Ventas91Pedidos, Entregas, Facturación, Cuentas corrientes, Clientes, Listas de precios](/api/referencia/pedidos/)[Finanzas30Cobranzas, Pagos, Condiciones de pago](/api/referencia/cobranzas/)[Compras55Órdenes de compra, Recepciones, Facturas de proveedor, Cuentas de proveedores, Proveedores](/api/referencia/ordenes-de-compra/)[Inventario50Stock, Movimientos, Recuentos, Artículos, Depósitos, Marcas y familias](/api/referencia/stock/)[Impuestos8Impuestos](/api/referencia/impuestos/)[Contabilidad15Plan de cuentas, Diario](/api/referencia/plan-de-cuentas/) ## Lo más consultado [Primeros pasosEntrar, elegir la empresa y moverte por el menú.](/ayuda/primeros-pasos/)[Cómo se recorre una ventaDel pedido a la cobranza, con lo que deja cada paso.](/ayuda/ventas/circuito-de-venta/)[Autenticación de la APICómo entra una integración y qué manda en cada llamada.](/api/autenticacion/)[Conectar un asistenteClaude o ChatGPT trabajando en tu empresa, con tu permiso.](/ia/conectar-un-asistente/)