{"info":{"name":"API pública de facturación electrónica","description":"API pública de la plataforma de facturación electrónica (CFE) para Uruguay.\nPermite a integradores (ERPs, e-commerce, sistemas de gestión) consultar comprobantes, crear y emitir CFE contra DGI, descargar el PDF y el XML firmado, y administrar contactos, productos e inventario — sobre la misma capa de aplicación que la app (mismas validaciones DGI, misma idempotencia, mismo pipeline).\n\n**Autenticación**: header `Authorization: Bearer afk_live_<secreto>`. Cada API key pertenece a exactamente una empresa y se administra en `/app/configuracion/api-keys`; la key resuelve el tenant, que nunca viaja en la URL ni en el body.\n\n**Scopes**: cada key puede restringirse por scopes (`documents:read`, `documents:write`, `documents:issue`, `contacts:read`, `contacts:write`, `products:read`, `products:write`, `inventory:read`, `inventory:write`, `payments:read`, `payments:write`). Cada operación declara su scope requerido en la extensión `x-required-scope`. Una key **sin scopes** no puede operar ninguna operación que requiera scope (deny por defecto). Operar sin el scope requerido devuelve `403 FORBIDDEN`.\n\n**Rate limiting**: 240 req/min por IP (pre-autenticación) y 120 req/min por API key; toda respuesta incluye `X-RateLimit-Limit`, `X-RateLimit-Remaining` y `X-RateLimit-Reset`, y los 429 agregan `Retry-After`.\n\n**Convenciones**: montos y cantidades son SIEMPRE strings decimales (nunca floats). Las respuestas usan coma decimal es-UY sin separador de miles (`\"12200,50\"`; los enteros van sin separador: `\"12200\"`). En la entrada se acepta coma o punto decimal (`\"10,80\"` ≡ `\"10.80\"`; con coma, los puntos previos solo valen como miles en grupos de 3: `\"1.234,56\"`). Instantes ISO-8601; fechas calendario `YYYY-MM-DD`. Errores con envelope estable `{ \"error\": { \"code\", \"message\", \"details?\" } }`.","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json"},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{apiKey}}","type":"string"}]},"variable":[{"key":"baseUrl","value":"https://facturar.uy","type":"string","description":"Origen de la plataforma (sin barra final)."},{"key":"apiKey","value":"afk_live_…","type":"string","description":"API key de la empresa (Bearer). Se crea en /app/configuracion/api-keys."}],"item":[{"name":"Identidad","description":"Verificación de la API key y su empresa.","item":[{"name":"Identidad de la API key","request":{"method":"GET","description":"Devuelve la empresa (id, nombre, razón social, RUC) y los metadatos de la key (nombre, prefijo). Úsalo como health check de la integración antes de operar. No requiere ningún scope: cualquier key válida puede llamarlo.\n\nNo requiere scope (solo autenticación).","header":[],"url":{"raw":"{{baseUrl}}/api/v1/me","host":["{{baseUrl}}"],"path":["api","v1","me"]}}}]},{"name":"Documentos","description":"Comprobantes fiscales electrónicos (CFE): listado, creación, emisión a DGI, NC/ND y artefactos (PDF / XML firmado).","item":[{"name":"Listar comprobantes","request":{"method":"GET","description":"Listado de comprobantes de la empresa (emitidos y recibidos), más reciente primero. Nunca incluye plantillas de facturas recurrentes. Scope requerido: `documents:read`.\n\nScope requerido: documents:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/documents","host":["{{baseUrl}}"],"path":["api","v1","documents"],"query":[{"key":"status","value":"ACCEPTED","description":"Filtra por estado del documento.","disabled":true},{"key":"direction","value":"","description":"Emitidos o recibidos.","disabled":true},{"key":"type","value":"111","description":"Código DGI del tipo de comprobante (p.ej. 101 e-Ticket, 111 e-Factura).","disabled":true},{"key":"search","value":"","description":"Búsqueda por receptor, tipo o número (mínimo 3 caracteres). Un valor solo numérico busca por número de comprobante, RUT/CI y número interno; «A-112» por serie y número.","disabled":true},{"key":"limit","value":"50","description":"Cantidad máxima de resultados (1-100).","disabled":true},{"key":"offset","value":"0","description":"Desplazamiento para paginar (0-10000). Para recorrer más allá usá paginación por `cursor` donde esté disponible.","disabled":true},{"key":"cursor","value":"","description":"Cursor opaco devuelto en `pagination.nextCursor` de la página anterior (paginación keyset, costo constante a cualquier profundidad). Excluyente con `offset` > 0.","disabled":true},{"key":"createdAfter","value":"2026-07-01T00:00:00Z","description":"Solo comprobantes creados DESPUÉS de este instante ISO-8601 (sincronización incremental).","disabled":true},{"key":"updatedAfter","value":"2026-07-05T12:00:00Z","description":"Solo comprobantes modificados DESPUÉS de este instante ISO-8601 — la forma eficiente de sondear cambios de estado (DGI, entrega) sin recorrer todo el listado.","disabled":true},{"key":"includeTotal","value":"","description":"`false` omite `pagination.total` y ahorra el conteo del lado del servidor (recomendado al paginar por `cursor`). Default `true`.","disabled":true}]}}},{"name":"Crear un comprobante","request":{"method":"POST","description":"Crea un comprobante en una llamada, con el mismo flujo que el sistema: la API compone los pasos del wizard (borrador → datos generales → líneas → datos adicionales) sobre la misma capa de aplicación que la UI. Nunca va directo a DGI: el resultado es un `DRAFT` normal, visible y editable en la app. Con `autoIssue: true` corre además el gate de validación DGI y encola el pipeline de emisión; si el borrador está incompleto responde `422` con el requisito exacto y `details.documentId` (el draft persiste y puede terminarse en la app). Idempotente vía header `Idempotency-Key` (o `idempotencyKey` en el body; el header gana): un retry devuelve el documento ya creado (`200`, `reused: true`). `series`/`number` se ignoran (la numeración la gestiona la reserva de CAE). Scope requerido: `documents:write` (más `documents:issue` cuando `autoIssue: true`).\n\nScope requerido: documents:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-fact-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa). Un retry con la misma clave devuelve el documento ya creado sin duplicarlo.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/documents","host":["{{baseUrl}}"],"path":["api","v1","documents"]},"body":{"mode":"raw","raw":"{\n  \"documentTypeCode\": 111,\n  \"branchCode\": \"1\",\n  \"receiverCode\": \"CLI-001\",\n  \"currency\": \"UYU\",\n  \"issueDate\": \"2026-07-05\",\n  \"operationType\": \"SERVICE\",\n  \"paymentType\": \"CREDIT\",\n  \"dueDate\": \"2026-08-04\",\n  \"lines\": [\n    {\n      \"description\": \"Servicio mensual\",\n      \"quantity\": \"1\",\n      \"unit\": \"N/A\",\n      \"unitPrice\": \"10000\",\n      \"billingIndicator\": 3,\n      \"productCode\": \"SRV-CONSULT\",\n      \"responsibleIndicator\": \"R\",\n      \"retentionPerceptions\": [\n        {\n          \"retentionCode\": \"2183114\",\n          \"rate\": \"5.000\",\n          \"subjectAmount\": \"10000.00\",\n          \"retentionValue\": \"540.00\"\n        }\n      ]\n    }\n  ],\n  \"adjustments\": [\n    {\n      \"lineNumber\": 1,\n      \"movementType\": \"DISCOUNT\",\n      \"adjustmentType\": 2,\n      \"percent\": \"10.00\",\n      \"description\": \"Descuento por pronto pago\",\n      \"billingIndicator\": 3\n    }\n  ],\n  \"autoIssue\": false\n}","options":{"raw":{"language":"json"}}}}},{"name":"Detalle de un comprobante","request":{"method":"GET","description":"Detalle completo: identidad fiscal (tipo, serie, número), totales (strings decimales, nunca floats), líneas, CAE (número, serie, rango, vencimiento), tracking DGI (`trackingId`, `submittedAt`, `ackSobreCode`), receptor y sucursal. Tras emitir, sondear este endpoint hasta `ACCEPTED` / `REJECTED` / `OBSERVED`. Scope requerido: `documents:read`.\n\nScope requerido: documents:read.","header":[{"key":"If-None-Match","value":"","description":"ETag recibido en una respuesta anterior; si el comprobante no cambió la respuesta es `304 Not Modified` sin body.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/documents/:id","host":["{{baseUrl}}"],"path":["api","v1","documents",":id"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del comprobante."}]}}},{"name":"Emitir a DGI","request":{"method":"POST","description":"Dispara la emisión a DGI. `READY_TO_ISSUE` → encola el pipeline (`202`, `enqueued: true`). `DRAFT` → corre primero la misma validación de completitud que la UI (campos DGI, snapshots fiscales, reserva de numeración CAE, tipo de cambio); si el borrador está incompleto responde `422` con el requisito exacto. Si la empresa tiene activado el ajuste por redondeo automático, al validar un `DRAFT` se agrega/recalcula la línea «Ajuste por redondeo» (indicador de facturación 6/7) que lleva el Monto a pagar al múltiplo configurado. Ya emitido o en curso → idempotente: `200` con `enqueued: false` y el estado actual (el jobId de BullMQ deriva del documento, sin doble-encolado). `FAILED` → reintento: resetea a `READY_TO_ISSUE` (mismo use case que el botón «Reintentar» de la app, auditado) y re-encola (`202`). `CANCELLED` → `409`. El resultado es asíncrono: sondear `GET /documents/{id}`. Scope requerido: `documents:issue`.\n\nScope requerido: documents:issue.","header":[{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/documents/:id/issue","host":["{{baseUrl}}"],"path":["api","v1","documents",":id","issue"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del comprobante a emitir."}]}}},{"name":"Crear NC/ND (nota de corrección)","request":{"method":"POST","description":"Crea una nota de crédito o débito a partir de un comprobante `ACCEPTED`/`OBSERVED`, pre-llenada desde el origen (cabecera, líneas, pagos, retenciones) y con la referencia Zona F al documento fuente puesta automáticamente (monto acotado al total a pagar del origen). La NC resta o anula el comprobante original (devoluciones, descuentos, corrección de errores — es la forma fiscalmente correcta de anular un CFE en Uruguay: no existe el \"delete\"); la ND suma o aumenta su valor (gastos extra, diferencias de precio, intereses). `correctionTypeCode` debe ser la NC o ND que corresponde al tipo del documento fuente (p.ej. 112 NC de e-Factura). Scope requerido: `documents:write` (más `documents:issue` cuando `autoIssue: true`).\n\nScope requerido: documents:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/documents/:id/correction-note","host":["{{baseUrl}}"],"path":["api","v1","documents",":id","correction-note"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del comprobante origen (ACCEPTED u OBSERVED)."}]},"body":{"mode":"raw","raw":"{\n  \"correctionTypeCode\": 112,\n  \"autoIssue\": false\n}","options":{"raw":{"language":"json"}}}}},{"name":"Crear recibo electrónico","request":{"method":"POST","description":"Crea un recibo de cobranza a partir de una e-Factura (111) o e-Ticket (101) en estado ACCEPTED u OBSERVED, según la FAQ 4.10 de DGI (Res. Nº 303/2019): un CFE del mismo tipo con indicador de cobranza propia (A-C20 = 1), una línea «COBRANZA DE …» por cada ítem del original como monto no facturable (B-C4 = 6, IVA incluido en el importe) y la referencia en Zona F al comprobante cobrado. El borrador puede ajustarse (p.ej. cobranza parcial) antes de emitir, o emitirse directo con `autoIssue`. Scope requerido: `documents:write` (+ `documents:issue` si `autoIssue`).\n\nScope requerido: documents:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/documents/:id/collection-receipt","host":["{{baseUrl}}"],"path":["api","v1","documents",":id","collection-receipt"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del comprobante origen (e-Factura/e-Ticket ACCEPTED u OBSERVED)."}]},"body":{"mode":"raw","raw":"{\n  \"autoIssue\": false\n}","options":{"raw":{"language":"json"}}}}},{"name":"Descargar PDF","request":{"method":"GET","description":"Representación imprimible del comprobante, renderizada on-demand (nunca se persiste; el artefacto fiscal autoritativo es el XML firmado). Scope requerido: `documents:read`.\n\nScope requerido: documents:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/documents/:id/pdf","host":["{{baseUrl}}"],"path":["api","v1","documents",":id","pdf"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del comprobante."}]}}},{"name":"Descargar XML firmado","request":{"method":"GET","description":"El XML firmado del comprobante — el artefacto fiscal autoritativo. Devuelve `409 CONFLICT` mientras el documento exista pero aún no haya sido firmado por el pipeline. Scope requerido: `documents:read`.\n\nScope requerido: documents:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/documents/:id/xml","host":["{{baseUrl}}"],"path":["api","v1","documents",":id","xml"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del comprobante."}]}}}]},{"name":"Contactos","description":"Clientes y proveedores (receptores de comprobantes).","item":[{"name":"Listar contactos","request":{"method":"GET","description":"Listado de contactos (clientes y proveedores) de la empresa. Scope requerido: `contacts:read`.\n\nScope requerido: contacts:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/contacts","host":["{{baseUrl}}"],"path":["api","v1","contacts"],"query":[{"key":"type","value":"","description":"Filtra por tipo de contacto.","disabled":true},{"key":"search","value":"","description":"Búsqueda por nombre, documento o código.","disabled":true},{"key":"includeInactive","value":"","description":"Incluye contactos desactivados.","disabled":true},{"key":"limit","value":"50","description":"Cantidad máxima de resultados (1-100).","disabled":true},{"key":"offset","value":"0","description":"Desplazamiento para paginar (0-10000). Para recorrer más allá usá paginación por `cursor` donde esté disponible.","disabled":true}]}}},{"name":"Crear un contacto","request":{"method":"POST","description":"Crea un contacto con el mismo schema y validaciones que el formulario de la app: dígito verificador de RUC (módulo 11), unicidad por empresa de documento y código interno, reglas de receptor. `code` y `legalName` son requeridos. Scope requerido: `contacts:write`.\n\nScope requerido: contacts:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/contacts","host":["{{baseUrl}}"],"path":["api","v1","contacts"]},"body":{"mode":"raw","raw":"{\n  \"type\": \"CUSTOMER\",\n  \"code\": \"CLI-001\",\n  \"legalName\": \"Estudio Méndez SRL\",\n  \"documentType\": \"RUC\",\n  \"countryCode\": \"UY\",\n  \"documentNumber\": \"211234567890\",\n  \"email\": \"administracion@mendez.uy\",\n  \"city\": \"Montevideo\",\n  \"department\": \"Montevideo\"\n}","options":{"raw":{"language":"json"}}}}},{"name":"Detalle de un contacto","request":{"method":"GET","description":"Detalle completo del contacto, incluyendo dirección, datos de receptor y metadatos. Scope requerido: `contacts:read`.\n\nScope requerido: contacts:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/contacts/:id","host":["{{baseUrl}}"],"path":["api","v1","contacts",":id"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del contacto."}]}}},{"name":"Actualizar un contacto","request":{"method":"PATCH","description":"Actualización COMPLETA (semántica PUT sobre el verbo PATCH): el body debe incluir el objeto entero — `type`, `code` y `legalName` son obligatorios y un campo omitido se limpia. Recomendado: GET del contacto, modificar los campos deseados y reenviar todo. Acepta además `isActive` para activar/desactivar. Scope requerido: `contacts:write`.\n\nScope requerido: contacts:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/contacts/:id","host":["{{baseUrl}}"],"path":["api","v1","contacts",":id"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del contacto."}]},"body":{"mode":"raw","raw":"{\n  \"type\": \"COMPANY\",\n  \"code\": \"CLI-0042\",\n  \"legalName\": \"Méndez y Asociados S.A.\",\n  \"email\": \"facturacion@mendez.uy\",\n  \"phone\": \"+598 99 654 321\"\n}","options":{"raw":{"language":"json"}}}}}]},{"name":"Productos","description":"Catálogo de productos y servicios.","item":[{"name":"Listar productos","request":{"method":"GET","description":"Listado de productos y servicios del catálogo de la empresa. Scope requerido: `products:read`.\n\nScope requerido: products:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/products","host":["{{baseUrl}}"],"path":["api","v1","products"],"query":[{"key":"type","value":"","description":"Filtra por tipo.","disabled":true},{"key":"search","value":"","description":"Búsqueda por nombre o SKU.","disabled":true},{"key":"includeInactive","value":"","description":"Incluye productos desactivados.","disabled":true},{"key":"limit","value":"50","description":"Cantidad máxima de resultados (1-100).","disabled":true},{"key":"offset","value":"0","description":"Desplazamiento para paginar (0-10000). Para recorrer más allá usá paginación por `cursor` donde esté disponible.","disabled":true}]}}},{"name":"Crear un producto","request":{"method":"POST","description":"Crea un producto o servicio. `sku`, `name` y `price` son requeridos; los flags de stock solo aplican a `type: \"PRODUCT\"`. Mismas validaciones que la app (SKU único por empresa). Scope requerido: `products:write`.\n\nScope requerido: products:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/products","host":["{{baseUrl}}"],"path":["api","v1","products"]},"body":{"mode":"raw","raw":"{\n  \"type\": \"SERVICE\",\n  \"sku\": \"SRV-CONSULT\",\n  \"name\": \"Servicio de consultoría\",\n  \"unit\": \"N/A\",\n  \"currency\": \"UYU\",\n  \"price\": \"10000\"\n}","options":{"raw":{"language":"json"}}}}},{"name":"Detalle de un producto","request":{"method":"GET","description":"Detalle completo del producto, incluyendo defaults DGI y configuración de stock. Scope requerido: `products:read`.\n\nScope requerido: products:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/products/:id","host":["{{baseUrl}}"],"path":["api","v1","products",":id"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del producto."}]}}},{"name":"Actualizar un producto","request":{"method":"PATCH","description":"Actualización COMPLETA (semántica PUT sobre el verbo PATCH): el body debe incluir el objeto entero — `type`, `sku`, `name` y `price` son obligatorios y un campo omitido se limpia. Recomendado: GET del producto, modificar y reenviar todo. Acepta además `isActive`. Scope requerido: `products:write`.\n\nScope requerido: products:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/products/:id","host":["{{baseUrl}}"],"path":["api","v1","products",":id"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del producto."}]},"body":{"mode":"raw","raw":"{\n  \"type\": \"PRODUCT\",\n  \"sku\": \"SKU-001\",\n  \"name\": \"Consultoría mensual\",\n  \"price\": \"11500\"\n}","options":{"raw":{"language":"json"}}}}}]},{"name":"Sucursales","description":"Sucursales (casa central y locales) de la empresa — datos de referencia para emitir documentos.","item":[{"name":"Listar sucursales","request":{"method":"GET","description":"Listado de sucursales (casa central y locales) de la empresa, la de por defecto primero. Es la forma de descubrir los `branchCode` que se usan al crear documentos. Scope requerido: `documents:read`.\n\nScope requerido: documents:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/branches","host":["{{baseUrl}}"],"path":["api","v1","branches"],"query":[{"key":"search","value":"","description":"Búsqueda por código o nombre de sucursal.","disabled":true},{"key":"includeInactive","value":"","description":"Incluye sucursales desactivadas.","disabled":true},{"key":"limit","value":"50","description":"Cantidad máxima de resultados (1-100).","disabled":true},{"key":"offset","value":"0","description":"Desplazamiento para paginar (0-10000). Para recorrer más allá usá paginación por `cursor` donde esté disponible.","disabled":true}]}}}]},{"name":"Inventario","description":"Stock por sucursal, kardex y movimientos manuales. Requiere el módulo `inventory` en el plan.","item":[{"name":"Stock por producto y sucursal","request":{"method":"GET","description":"Stock actual por producto y sucursal con estado derivado (`normal`, `low`, `out`, `negative`). Requiere el módulo `inventory` en el plan de la empresa (si no, `403`). Scope requerido: `inventory:read`.\n\nScope requerido: inventory:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/inventory","host":["{{baseUrl}}"],"path":["api","v1","inventory"],"query":[{"key":"search","value":"","description":"Búsqueda por producto o SKU.","disabled":true},{"key":"branchId","value":"","description":"Filtra por sucursal.","disabled":true},{"key":"status","value":"","description":"Filtra por estado de stock.","disabled":true},{"key":"limit","value":"50","description":"Cantidad máxima de resultados (1-100).","disabled":true},{"key":"offset","value":"0","description":"Desplazamiento para paginar (0-10000). Para recorrer más allá usá paginación por `cursor` donde esté disponible.","disabled":true}]}}},{"name":"Kardex (movimientos de inventario)","request":{"method":"GET","description":"Historial de movimientos de stock (kardex): manuales, ajustes y automáticos por venta/NC. Requiere el módulo `inventory` en el plan. Scope requerido: `inventory:read`.\n\nScope requerido: inventory:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/inventory/movements","host":["{{baseUrl}}"],"path":["api","v1","inventory","movements"],"query":[{"key":"productId","value":"","description":"Filtra por producto.","disabled":true},{"key":"branchId","value":"","description":"Filtra por sucursal.","disabled":true},{"key":"type","value":"","description":"Filtra por tipo de movimiento.","disabled":true},{"key":"limit","value":"50","description":"Cantidad máxima de resultados (1-100).","disabled":true},{"key":"offset","value":"0","description":"Desplazamiento para paginar (0-10000). Para recorrer más allá usá paginación por `cursor` donde esté disponible.","disabled":true}]}}},{"name":"Movimiento manual de stock","request":{"method":"POST","description":"Crea un movimiento manual auditado. `MANUAL_IN`/`MANUAL_OUT` llevan la cantidad movida (`quantity`); `ADJUSTMENT` es un recuento físico: lleva `countedQuantity` (el delta se calcula server-side) y `reason` obligatorio. Mismas garantías que la app: `SELECT FOR UPDATE` sobre el balance, sin stock negativo salvo que el producto lo permita. Requiere el módulo `inventory` en el plan. Scope requerido: `inventory:write`.\n\nScope requerido: inventory:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/inventory/adjustments","host":["{{baseUrl}}"],"path":["api","v1","inventory","adjustments"]},"body":{"mode":"raw","raw":"{\n  \"type\": \"MANUAL_IN\",\n  \"productId\": \"cmc3pro5d0003uy01d4p6v2r9\",\n  \"branchId\": \"cmc1suc7f0001uy01c2n8w5t3\",\n  \"quantity\": \"5\",\n  \"reason\": \"Reposición de proveedor\"\n}","options":{"raw":{"language":"json"}}}}}]},{"name":"Cobros","description":"Cobros de clientes, cuentas por cobrar con aging y estado de cobro de comprobantes. Metadata comercial que nunca modifica el registro fiscal. Requiere el módulo «payments» habilitado en el plan de la empresa — sin él, todos estos endpoints responden 403. Scopes: `payments:read` / `payments:write`.","item":[{"name":"Registrar un cobro","request":{"method":"POST","description":"Registra un cobro de cliente (total, parcial o a cuenta), opcionalmente imputado a comprobantes. `contactId: null` = consumidor final (exige al menos una imputación). Reglas: los documentos imputados deben ser emitidos ACCEPTED/OBSERVED, del mismo receptor y moneda, y ninguna imputación puede superar el saldo pendiente. Idempotente vía `Idempotency-Key` (header) o `idempotencyKey` (body): un reintento con la misma clave devuelve el cobro ya creado. El registro NUNCA modifica el comprobante fiscal. Scope requerido: `payments:write`.\n\nScope requerido: payments:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/payments","host":["{{baseUrl}}"],"path":["api","v1","payments"]},"body":{"mode":"raw","raw":"{\n  \"contactId\": \"cmc2rec9k0002uy01b7m1x4q8\",\n  \"paidOn\": \"2026-06-15\",\n  \"amount\": \"5000.00\",\n  \"currency\": \"UYU\",\n  \"method\": \"TRANSFER\",\n  \"reference\": \"TRX-9931\",\n  \"allocations\": [\n    {\n      \"fiscalDocumentId\": \"cmc4x8p2h0001uy01a9k3f7d2\",\n      \"amount\": \"5000.00\"\n    }\n  ]\n}","options":{"raw":{"language":"json"}}}}},{"name":"Aplicar crédito de un cobro a cuenta","request":{"method":"POST","description":"Imputa el crédito disponible de un cobro a cuenta existente (monto − imputaciones activas) a comprobantes del mismo receptor y moneda. No crea un cobro nuevo ni modifica el registro fiscal. Scope requerido: `payments:write`.\n\nScope requerido: payments:write.","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/payments/:id/allocations","host":["{{baseUrl}}"],"path":["api","v1","payments",":id","allocations"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del cobro a cuenta."}]},"body":{"mode":"raw","raw":"{\n  \"allocations\": [\n    {\n      \"fiscalDocumentId\": \"cmc4x8p2h0001uy01a9k3f7d2\",\n      \"amount\": \"2500.00\"\n    }\n  ]\n}","options":{"raw":{"language":"json"}}}}},{"name":"Anular un cobro","request":{"method":"DELETE","description":"Anulación lógica: el cobro se conserva con AuditLog y deja de contar en todos los saldos. Un cobro inexistente o ya anulado devuelve `404`. Scope requerido: `payments:write`.\n\nScope requerido: payments:write.","header":[{"key":"Idempotency-Key","value":"erp-op-2026-000123","description":"Clave de idempotencia (8-128 caracteres, única por empresa y operación). Un reintento con la misma clave y el mismo body devuelve la respuesta original (header `Idempotency-Replayed: true`) durante 24 h; la misma clave con otro body responde `409 IDEMPOTENCY_CONFLICT`; si el primer intento sigue en curso, `409` con `Retry-After`.","disabled":true}],"url":{"raw":"{{baseUrl}}/api/v1/payments/:id","host":["{{baseUrl}}"],"path":["api","v1","payments",":id"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del cobro a anular."}]}}},{"name":"Cuentas por cobrar","request":{"method":"GET","description":"Saldos pendientes de cobro de comprobantes emitidos ACCEPTED/OBSERVED, agrupados por moneda y con antigüedad (aging): a vencer / vencido 1–30 / 31–60 / +60 días / sin vencimiento. Las notas de crédito quedan excluidas. Scope requerido: `payments:read`.\n\nScope requerido: payments:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/payments/receivables","host":["{{baseUrl}}"],"path":["api","v1","payments","receivables"]}}},{"name":"Estado de cobro de un comprobante","request":{"method":"GET","description":"Estado de cobro derivado de un comprobante: `PENDING`/`PARTIAL`/`PAID`, total, imputado, saldo y los cobros aplicados. Scope requerido: `payments:read`.\n\nScope requerido: payments:read.","header":[],"url":{"raw":"{{baseUrl}}/api/v1/documents/:id/collection","host":["{{baseUrl}}"],"path":["api","v1","documents",":id","collection"],"variable":[{"key":"id","value":"cmc4x8p2h0001uy01a9k3f7d2","description":"Identificador del comprobante."}]}}}]}]}