{"openapi":"3.1.0","info":{"title":"NextData API CFE","version":"2026-09-24.1","description":"La API key determina empresa y ambiente. Pago, verificación fiscal y activación son estados separados."},"servers":[{"url":"https://api.nextdata.uy"}],"externalDocs":{"url":"https://www.nextdata.uy/desarrolladores"},"paths":{"/v1/dev/onboarding":{"get":{"operationId":"nextdata_onboarding","summary":"Requisitos y siguiente acción","description":"Separa pruebas, verificación fiscal, activación, pausa, emisión y aceptación final. La clave determina environment. Una clave live no acredita habilitación productiva.\nDespués del pago y durante toda la preparación productiva.\n401 = clave inactiva. 403 = scope cfe:read ausente.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"checks, blockers y nextAction; volver a consultar antes de activar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."},"401":{"description":"Clave inválida o inactiva"},"403":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."},"404":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."},"409":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."},"422":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."},"429":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."},"502":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."},"503":{"description":"401 = clave inactiva. 403 = scope cfe:read ausente."}}}},"/v1/dev/production/activate":{"post":{"operationId":"nextdata_production_activate","summary":"Activar producción","description":"Clave live y cfe:issue. Comprueba perfil, certificado, CAE, prueba AE, vigencia e inicio fiscal confirmados y verificación de NextData. No sustituye trámites DGI ni levanta suspensiones del operador.\nTras completar los requisitos de onboarding y la verificación fiscal de NextData.\n400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotencyKey":{"type":"string","maxLength":160,"minLength":8},"reason":{"type":"string","maxLength":500,"minLength":8}},"required":["idempotencyKey","reason"],"additionalProperties":false},"example":{"idempotencyKey":"mi-activate-20260924","reason":"Operación solicitada por responsable de la integración"}}}},"responses":{"200":{"description":"idempotencyKey estable y resultado. Repetir la misma operación y motivo con la misma clave devuelve el resultado original.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"401":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"403":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"404":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"409":{"description":"API_PRODUCTION_NOT_READY"},"422":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"429":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"502":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"503":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."}}}},"/v1/dev/production/pause":{"post":{"operationId":"nextdata_production_pause","summary":"Pausar nuevas emisiones","description":"Pausa nuevas emisiones productivas por API/MCP. Los reportes exigibles siguen activos.\nPara cambiar la disponibilidad de nuevas emisiones; repetir onboarding al reanudar.\n400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotencyKey":{"type":"string","maxLength":160,"minLength":8},"reason":{"type":"string","maxLength":500,"minLength":8}},"required":["idempotencyKey","reason"],"additionalProperties":false},"example":{"idempotencyKey":"mi-pause-20260924","reason":"Operación solicitada por responsable de la integración"}}}},"responses":{"200":{"description":"idempotencyKey estable y resultado. Repetir la misma operación y motivo con la misma clave devuelve el resultado original.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"401":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"403":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"404":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"409":{"description":"API_PRODUCTION_NOT_READY"},"422":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"429":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"502":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"503":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."}}}},"/v1/dev/production/resume":{"post":{"operationId":"nextdata_production_resume","summary":"Reanudar producción","description":"Clave live y cfe:issue. Comprueba perfil, certificado, CAE, prueba AE, vigencia e inicio fiscal confirmados y verificación de NextData. No sustituye trámites DGI ni levanta suspensiones del operador.\nPara cambiar la disponibilidad de nuevas emisiones; repetir onboarding al reanudar.\n400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"idempotencyKey":{"type":"string","maxLength":160,"minLength":8},"reason":{"type":"string","maxLength":500,"minLength":8}},"required":["idempotencyKey","reason"],"additionalProperties":false},"example":{"idempotencyKey":"mi-resume-20260924","reason":"Operación solicitada por responsable de la integración"}}}},"responses":{"200":{"description":"idempotencyKey estable y resultado. Repetir la misma operación y motivo con la misma clave devuelve el resultado original.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"401":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"403":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"404":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"409":{"description":"API_PRODUCTION_NOT_READY"},"422":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"429":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"502":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."},"503":{"description":"400 = body inválido. 401 = clave. 403 = testing o scope. 409 = requisitos pendientes, pausa o conflicto de idempotencia."}}}},"/v1/dev/billing-clients/consumidor-final":{"get":{"operationId":"nextdata_consumer_final","summary":"Preparar consumidor final legado","description":"Puede crear un registro billing_client si falta. Aunque use GET, tiene efecto de escritura y requiere cfe:issue.\nSolo para integraciones existentes que ya usan esta superficie. Para nuevas emisiones usar receptor en el issue desde los clientes CRM.\n401 = clave. 403 = permiso. 400 = parámetros inválidos.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"responses":{"200":{"description":"No enviar estos UUID como destinatario del issue con API key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"401":{"description":"Clave inválida o inactiva"},"403":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"404":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"409":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"422":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"429":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"502":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"503":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."}}}},"/v1/dev/billing-clients":{"get":{"operationId":"nextdata_billing_clients_list","summary":"Consultar clientes de facturación legados","description":"Consulta acotada por q, limit (hasta 500), offset e includeInactive. No mezclar sus IDs con clientes CRM.\nSolo para integraciones existentes que ya usan esta superficie. Para nuevas emisiones usar receptor en el issue desde los clientes CRM.\n401 = clave. 403 = permiso. 400 = parámetros inválidos.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[{"in":"query","name":"q","required":false,"schema":{"type":"string","maxLength":80}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":500}},{"in":"query","name":"offset","required":false,"schema":{"type":"integer","minimum":0,"maximum":10000}},{"in":"query","name":"includeInactive","required":false,"schema":{"enum":["0","1"]}},{"in":"query","name":"includeIssuedCfe","required":false,"schema":{"enum":["0","1"]}}],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"No enviar estos UUID como destinatario del issue con API key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"401":{"description":"Clave inválida o inactiva"},"403":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"404":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"409":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"422":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"429":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"502":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"503":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."}}},"post":{"operationId":"nextdata_billing_clients_save","summary":"Guardar cliente de facturación legado","description":"Crea o actualiza por documento y circuito. Superficie de compatibilidad; no es necesaria para emitir por API.\nSolo para integraciones existentes que ya usan esta superficie. Para nuevas emisiones usar receptor en el issue desde los clientes CRM.\n401 = clave. 403 = permiso. 400 = parámetros inválidos.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"rut":{"type":"string","maxLength":32},"name":{"type":"string","maxLength":320},"tradeName":{"type":"string","maxLength":320},"address":{"type":"string","maxLength":400},"city":{"type":"string","maxLength":120},"email":{"type":"string","maxLength":240},"phone":{"type":"string","maxLength":40},"monthlyAmountUyu":{"type":"number","minimum":0,"maximum":99999999.99},"receiverCircuit":{"enum":["e_factura","e_ticket"]},"receptorCountry":{"type":"string","minLength":2,"maxLength":2},"receptorDocType":{"type":"integer","minimum":1,"maximum":7},"receptorState":{"type":"string","maxLength":30},"receptorCountryName":{"type":"string","maxLength":30}},"required":["rut","name"],"additionalProperties":false},"example":{"rut":"219999830019","name":"Ejemplo de integración legado","receiverCircuit":"e_factura","receptorCountry":"UY"}}}},"responses":{"200":{"description":"No enviar estos UUID como destinatario del issue con API key.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"401":{"description":"Clave inválida o inactiva"},"403":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"404":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"409":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"422":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"429":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"502":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."},"503":{"description":"401 = clave. 403 = permiso. 400 = parámetros inválidos."}}}},"/v1/dev/certificate":{"post":{"operationId":"nextdata_certificate_upload","summary":"Subir PFX / P12","description":"Carga el certificado DGI de la empresa (un PFX activo por RUT). En testing el PFX de Abitab sirve: no se exige otro certificado. Lo que cambia es el ambiente (nd_test_) y el CAE de ePrueba. El anterior queda inactivo en historial.\nPaso 4. Key activa (sin 401). Antes de company, CAE e issue. No lo llames si GET /ready ya dice certificate.present true salvo que debas reemplazar el PFX.\n401 = key. 400 = archivo ilegible, no PFX, filename inseguro o RUT inválido. 422 = passphrase incorrecta o PFX sin contraseña. No es 503. No pidas un PFX de DGI Testing.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filename":{"type":"string","maxLength":240},"p12Base64":{"type":"string","maxLength":546136},"passphrase":{"type":"string","maxLength":500}},"required":["filename","p12Base64"],"additionalProperties":false},"example":{"filename":"empresa.p12","p12Base64":"<base64 del archivo P12/PFX>","passphrase":"<contraseña del certificado>"}}}},"responses":{"200":{"description":"Nada secreto. No guardes p12Base64 ni passphrase. Confirmá con GET /v1/dev/certificate o GET /v1/dev/ready.certificate.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"No es PFX/P12, ruta en filename, Base64 inválido o RUT ausente"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"401 = key. 400 = archivo ilegible, no PFX, filename inseguro o RUT inválido. 422 = passphrase incorrecta o PFX sin contraseña. No es 503. No pidas un PFX de DGI Testing."},"404":{"description":"401 = key. 400 = archivo ilegible, no PFX, filename inseguro o RUT inválido. 422 = passphrase incorrecta o PFX sin contraseña. No es 503. No pidas un PFX de DGI Testing."},"409":{"description":"401 = key. 400 = archivo ilegible, no PFX, filename inseguro o RUT inválido. 422 = passphrase incorrecta o PFX sin contraseña. No es 503. No pidas un PFX de DGI Testing."},"422":{"description":"Passphrase incorrecta o PFX sin contraseña"},"429":{"description":"401 = key. 400 = archivo ilegible, no PFX, filename inseguro o RUT inválido. 422 = passphrase incorrecta o PFX sin contraseña. No es 503. No pidas un PFX de DGI Testing."},"502":{"description":"401 = key. 400 = archivo ilegible, no PFX, filename inseguro o RUT inválido. 422 = passphrase incorrecta o PFX sin contraseña. No es 503. No pidas un PFX de DGI Testing."},"503":{"description":"401 = key. 400 = archivo ilegible, no PFX, filename inseguro o RUT inválido. 422 = passphrase incorrecta o PFX sin contraseña. No es 503. No pidas un PFX de DGI Testing."}}},"get":{"operationId":"nextdata_certificate_status","summary":"Estado del PFX","description":"Metadatos del certificado activo (RUT, vigencia, huella). Nunca devuelve el PFX ni la clave.\nDespués de subir el PFX, o al abrir la pestaña Certificado. Usalo para pintar vigencia; el checklist oficial es GET /v1/dev/ready.\n401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"rut y valid_to para la UI. Nunca el archivo ni la passphrase.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate."},"401":{"description":"Key inválida o inactiva"},"403":{"description":"Add-on API no activo"},"404":{"description":"401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate."},"409":{"description":"401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate."},"422":{"description":"401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate."},"429":{"description":"401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate."},"502":{"description":"401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate."},"503":{"description":"401 = key. 403 = add-on. item null o vacío = no hay PFX: llamá POST /v1/dev/certificate."}}}},"/v1/dev/cae":{"post":{"operationId":"nextdata_cae_import","summary":"Cargar CAE","description":"Importa la constancia XML que entrega DGI. El ambiente lo define la key (nd_test_ = testing); no mandes environment. En testing usá las plantillas de /desarrolladores#cae-testing o GET /api/public/cae-testing (90aa000tipo0 envuelto en DA). Eso es un parche: la API aún no acepta solo el número.\nPaso 6. Después del PFX y del perfil de empresa. Un CAE por tipo (101, 111, …). En testing el parche 2026 es 101 = 90260001010 y 111 = 90260001110: descargá el XML, reemplazá RucE por el RUT del PFX y POST { xml, filename }.\n401 = key. 400 = XML ilegible, DOCTYPE/XXE, environment en body o incompleto. 403 = CAE 90aa con nd_live_ o CAE prod con nd_test_. No uses POST /v1/config/cae (eso es JWT del panel).","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"xml":{"type":"string","maxLength":200000,"minLength":20},"filename":{"type":"string","maxLength":240}},"required":["xml"],"additionalProperties":false},"example":{"xml":"<constancia CAE en XML>","filename":"constancia-cae.xml"}}}},"responses":{"200":{"description":"row.id (o el id de GET /v1/dev/cae) como tenantCaeId del issue. También tipoCfe y series.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"XML no es constancia DGI, DOCTYPE/ENTITY o campo environment"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"CAE de ePrueba (90aa) con nd_live_ o CAE de producción con nd_test_"},"404":{"description":"401 = key. 400 = XML ilegible, DOCTYPE/XXE, environment en body o incompleto. 403 = CAE 90aa con nd_live_ o CAE prod con nd_test_. No uses POST /v1/config/cae (eso es JWT del panel)."},"409":{"description":"401 = key. 400 = XML ilegible, DOCTYPE/XXE, environment en body o incompleto. 403 = CAE 90aa con nd_live_ o CAE prod con nd_test_. No uses POST /v1/config/cae (eso es JWT del panel)."},"422":{"description":"401 = key. 400 = XML ilegible, DOCTYPE/XXE, environment en body o incompleto. 403 = CAE 90aa con nd_live_ o CAE prod con nd_test_. No uses POST /v1/config/cae (eso es JWT del panel)."},"429":{"description":"401 = key. 400 = XML ilegible, DOCTYPE/XXE, environment en body o incompleto. 403 = CAE 90aa con nd_live_ o CAE prod con nd_test_. No uses POST /v1/config/cae (eso es JWT del panel)."},"502":{"description":"401 = key. 400 = XML ilegible, DOCTYPE/XXE, environment en body o incompleto. 403 = CAE 90aa con nd_live_ o CAE prod con nd_test_. No uses POST /v1/config/cae (eso es JWT del panel)."},"503":{"description":"401 = key. 400 = XML ilegible, DOCTYPE/XXE, environment en body o incompleto. 403 = CAE 90aa con nd_live_ o CAE prod con nd_test_. No uses POST /v1/config/cae (eso es JWT del panel)."}}},"get":{"operationId":"nextdata_cae_list","summary":"Listar CAE","description":"Talonarios activos del ambiente de la API key (tipo, serie, rango, vencimiento).\nPara armar el selector de tenantCaeId. Elegí el CAE cuyo tipoCfe coincida con el CFE a emitir (101 ≠ 111).\n401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"items[].id → tenantCaeId. No inventes el UUID.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."},"401":{"description":"Key inválida o inactiva"},"403":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."},"404":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."},"409":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."},"422":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."},"429":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."},"502":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."},"503":{"description":"401 = key. Lista vacía = no hay CAE: POST /v1/dev/cae. canIssue sigue false."}}}},"/v1/dev/config/company":{"get":{"operationId":"nextdata_company_get","summary":"Leer perfil de empresa","description":"Ficha fiscal del emisor (razón social, domicilio, ciudad, departamento y Nº de local DGI). DGI la exige en el XML. El RUT lo aporta el PFX; no se pisa desde acá. item.hasLogo indica si hay logo del emisor para el PDF (el base64 no se devuelve); item.sitioWeb es el pie del comprobante.\nPaso 5 y al abrir la pestaña Empresa. Si completo es false, no emitas: el issue responde 422. Si falta dgiBranchCode, el issue responde 409. Si el message habla del domicilio de la sucursal, también es 409 aunque completo sea true: reenviá POST /v1/dev/config/company. Leé message; no es el 409 de retryAt.\n401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel).","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"completo, item.dgiBranchCode y item.hasLogo. Si completo es false, mirá company.missing. El RUT de item.rut es informativo; no lo edites.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."},"401":{"description":"Key inválida o inactiva"},"403":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."},"404":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."},"409":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."},"422":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."},"429":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."},"502":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."},"503":{"description":"401 = key. No hay endpoint para activar tenant. No uses /v1/config/company (JWT del panel)."}}},"post":{"operationId":"nextdata_company_save","summary":"Guardar perfil de empresa","description":"Completa razón social, domicilio fiscal, ciudad, departamento y dgiBranchCode (Nº de local 1–9999; casa central suele ser 1). Sin esos datos canIssue es false. Perfil incompleto en el issue = 422. Sin Nº de local = 409. Si el message dice que la sucursal no tiene domicilio, también es 409 aunque completo y canIssue sean true: este POST copia calle, ciudad y departamento a la sucursal titular solo si están vacíos y no pisa un domicilio que ya emite. No mandes x-branch-id ni inventes /v1/dev/branches. Ese 409 no consume numeración. No mandes rut, tenant_id ni environment. El RUT lo pone el PFX. No hace falta PDF de constancia RUT: el número basta. Opcionales: logoDataUrl (data:image/png|jpeg;base64,… hasta 420 KB decodificados; si es PNG con transparencia o entrelazado, hasta 4096 px por lado y 1.048.576 muestras (ancho × alto × canales: un RGBA entra hasta 512×512; una paleta de menos de 8 bits cuenta cuatro veces, ocho si es entrelazada)) para que el PDF oficial lleve el logo del emisor, y sitioWeb (pie del comprobante). Vacíos u omitidos conservan lo ya guardado.\nPaso 5. Después del PFX (el PFX rellena RUT/razón; no trae domicilio ni Nº de local). Antes de emitir. Obligatorio aunque ready.certificate.present sea true. Volvé a mandarlo con logoDataUrl cuando la empresa cambie el logo.\n400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"razonSocial":{"type":"string","maxLength":320},"nombreEmpresa":{"type":"string","maxLength":320},"domicilioFiscal":{"type":"string","maxLength":70},"ciudad":{"type":"string","maxLength":30},"departamento":{"type":"string","maxLength":30},"email":{"type":"string","maxLength":240},"giroActividad":{"type":"string","maxLength":80},"regimenTributario":{"enum":["general","literal_e","monotributo","monotributo_mides","exonerado"]},"logoDataUrl":{"type":"string","maxLength":600000},"sitioWeb":{"type":"string","maxLength":120},"dgiBranchCode":{"type":"integer","minimum":1,"maximum":9999}},"required":["razonSocial","domicilioFiscal","ciudad","departamento","dgiBranchCode"],"additionalProperties":false},"example":{"razonSocial":"Nexus Global SAS","nombreEmpresa":"Zarpar","domicilioFiscal":"18 de Julio 1234","ciudad":"Montevideo","departamento":"Montevideo","dgiBranchCode":1,"sitioWeb":"www.sistemazarpar.com","logoDataUrl":"data:image/png;base64,iVBORw0KGgo..."}}}},"responses":{"200":{"description":"completo, dgiBranchCode y hasLogo. Volvé a GET /v1/dev/ready: company.missing debe ser [] y canIssue puede pasar a true.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"Campo prohibido (rut, tenantId, environment), email/domicilio inválido o logoDataUrl no válido"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503."},"404":{"description":"400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503."},"409":{"description":"400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503."},"422":{"description":"400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503."},"429":{"description":"400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503."},"502":{"description":"400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503."},"503":{"description":"400 = JSON inválido, falta dgiBranchCode, email/domicilio inválidos, logoDataUrl que no es PNG/JPEG base64, pesa más de 420 KB o es un PNG con transparencia o entrelazado de más de 4096 px por lado o 1.048.576 muestras, o enviaste rut / tenant_id / environment / dgi_environment. 401 = key. 413 = body mayor a 1 MB (achicá el logo). 422 en el issue (no acá) = perfil incompleto. 409 en el issue = falta dgiBranchCode o la sucursal titular no tiene domicilio (leé message; no es retryAt). No es 503."}}}},"/v1/dev/ready":{"get":{"operationId":"nextdata_ready","summary":"Checklist para emitir","description":"Indica PFX, CAE, perfil de empresa (company.completo / missing) y canIssue. canIssue = PFX + CAE + company.completo. environment es el de la key (nd_test_ = testing). El issue con API key usa ese mismo ambiente SOAP: nd_test_ → ePrueba, nd_live_ → ws_efactura.\nPaso 3 (diagnóstico) y paso 8 (gate). Si canIssue es false, leé certificate.present, cae.count y company.missing. No emitas. Si hay 401, no subas PFX.\n401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"environment, canIssue, company.completo, company.missing[] (incluye dgiBranchCode), cae.items[].id (tenantCaeId), certificate.rut.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba."},"401":{"description":"Key inválida o inactiva"},"403":{"description":"Add-on API no activo"},"404":{"description":"401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba."},"409":{"description":"401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba."},"422":{"description":"401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba."},"429":{"description":"401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba."},"502":{"description":"401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba."},"503":{"description":"401 = key, no falta de PFX/CAE/perfil. 403 = add-on. canIssue false no es un HTTP error: es el checklist (missing[]). Si live y falta CAE prod, hint: usá nd_test_ para ePrueba."}}}},"/v1/dev/cfe/types":{"get":{"operationId":"nextdata_cfe_types","summary":"Catálogo de tipos CFE","description":"Lista los 21 tipos emittibles: comunes (101–113, pantalla /pos/emitir) y especiales (121–182, /pos/emitir-especiales). Cada ítem trae codigo, label, scope, extras[] y receptor. No incluye 201–282 (CFC de papel).\nPara armar el selector de tipoCfe. Comunes en /pos/emitir; especiales en /pos/emitir-especiales. Un solo POST /v1/dev/invoices/issue: solo cambia tipoCfe y los extras.\n401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"comunes[].codigo y especiales[].codigo. extras y receptor para mostrar u ocultar bloques del formulario.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."},"401":{"description":"Key inválida o inactiva"},"403":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."},"404":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."},"409":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."},"422":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."},"429":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."},"502":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."},"503":{"description":"401 = key. 403 = add-on. No inventes códigos 201–282. No hay POST de tipos."}}}},"/v1/dev/invoices/issue":{"post":{"operationId":"nextdata_issue","summary":"Emitir CFE","description":"Emite e-Ticket, e-Factura, NC/ND y tipos soportados. El 200 trae pdfBase64: el PDF ya firmado, con serie, número y CAE. Mostralo en esa respuesta; no esperes otro request ni el ACK de DGI. dgiSend queued deja el sobre para después. El servidor arma el XML; no envíes XML de CFE ni environment. Exige tenantCaeId y receptor (clientes del CRM). El SOAP lo define la key (nd_test_ → ePrueba).\nPaso 9. Solo si GET /v1/dev/ready.canIssue es true. Si company.completo es false, no llames: vas a recibir 422.\n401 = key. 402 API_PAYMENT_REQUIRED = saldo API vencido: pagá la factura; la key sigue activa. 400 = JSON, totales o environment. 422 = perfil incompleto. 409 = leé message: falta dgiBranchCode o la sucursal titular no tiene domicilio (no es ventana DGI ni consume numeración). 403 = CAE del ambiente de la key. Un 200 con pdfBase64 es el comprobante firmado; no pidas refresh-status. Un fallo SOAP posterior no cambia ese 200.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"JSON de emisión del catálogo: idempotencyKey estable, tipoCfe, tenantCaeId, receptor e items. Reglas fiscales completas en Fastify.","additionalProperties":true},"example":{"mode":"manual","tenantCaeId":"<uuid del CAE>","tipoCfe":"101","receptor":{"documento":"","nombre":"Consumidor final","receiverCircuit":"e_ticket"},"receptorDocumento":"","amount":1220,"currency":"UYU","idempotencyKey":"demo-20260815-0001","lines":[{"descripcion":"Servicio","cantidad":1,"precioUnitario":1000,"ivaAliquota":22}]}}}},"responses":{"200":{"description":"outboxId, serie, numero, publicConsultUrl, codigoSeguridad, dgiSend y pdfBase64 (PDF firmado con CAE). publicConsultUrl es Consulta Next Data, no el listado DGI. status pending con dgiSend queued no es un fallo: el sobre sale después.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"JSON, totales que no cierran o environment en el body"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"No hay CAE activo para el ambiente de la key"},"404":{"description":"401 = key. 402 API_PAYMENT_REQUIRED = saldo API vencido: pagá la factura; la key sigue activa. 400 = JSON, totales o environment. 422 = perfil incompleto. 409 = leé message: falta dgiBranchCode o la sucursal titular no tiene domicilio (no es ventana DGI ni consume numeración). 403 = CAE del ambiente de la key. Un 200 con pdfBase64 es el comprobante firmado; no pidas refresh-status. Un fallo SOAP posterior no cambia ese 200."},"409":{"description":"Falta dgiBranchCode, o la sucursal titular no tiene calle, ciudad y departamento (message). company.completo puede ser true"},"422":{"description":"Perfil incompleto u otro dato fiscal"},"429":{"description":"401 = key. 402 API_PAYMENT_REQUIRED = saldo API vencido: pagá la factura; la key sigue activa. 400 = JSON, totales o environment. 422 = perfil incompleto. 409 = leé message: falta dgiBranchCode o la sucursal titular no tiene domicilio (no es ventana DGI ni consume numeración). 403 = CAE del ambiente de la key. Un 200 con pdfBase64 es el comprobante firmado; no pidas refresh-status. Un fallo SOAP posterior no cambia ese 200."},"502":{"description":"401 = key. 402 API_PAYMENT_REQUIRED = saldo API vencido: pagá la factura; la key sigue activa. 400 = JSON, totales o environment. 422 = perfil incompleto. 409 = leé message: falta dgiBranchCode o la sucursal titular no tiene domicilio (no es ventana DGI ni consume numeración). 403 = CAE del ambiente de la key. Un 200 con pdfBase64 es el comprobante firmado; no pidas refresh-status. Un fallo SOAP posterior no cambia ese 200."},"503":{"description":"401 = key. 402 API_PAYMENT_REQUIRED = saldo API vencido: pagá la factura; la key sigue activa. 400 = JSON, totales o environment. 422 = perfil incompleto. 409 = leé message: falta dgiBranchCode o la sucursal titular no tiene domicilio (no es ventana DGI ni consume numeración). 403 = CAE del ambiente de la key. Un 200 con pdfBase64 es el comprobante firmado; no pidas refresh-status. Un fallo SOAP posterior no cambia ese 200."}}}},"/v1/dev/cfe/outbox":{"get":{"operationId":"nextdata_outbox","summary":"Consultar outbox","description":"Lista comprobantes y estados DGI (AS/AE/BE) del ambiente de la key.\nPaso 10 y tag Comprobantes. Query from/to (YYYY-MM-DD), tipoCfe (uno de GET /v1/dev/cfe/types) y limit (1–100, default 20). Solo ves los CFE de tu key/actor.\n401 = key. 400 = query inválida. Lista vacía ≠ error de DGI.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[{"in":"query","name":"from","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"in":"query","name":"to","required":false,"schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"in":"query","name":"tipoCfe","required":false,"schema":{"type":"string","maxLength":3}},{"in":"query","name":"limit","required":false,"schema":{"type":"integer","minimum":1,"maximum":100}}],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"items[].id para refresh-status, pdf y print-model. status, dgi_ack_state, dgi_final_state.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"from/to/tipoCfe/limit inválidos"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"401 = key. 400 = query inválida. Lista vacía ≠ error de DGI."},"404":{"description":"401 = key. 400 = query inválida. Lista vacía ≠ error de DGI."},"409":{"description":"401 = key. 400 = query inválida. Lista vacía ≠ error de DGI."},"422":{"description":"401 = key. 400 = query inválida. Lista vacía ≠ error de DGI."},"429":{"description":"401 = key. 400 = query inválida. Lista vacía ≠ error de DGI."},"502":{"description":"401 = key. 400 = query inválida. Lista vacía ≠ error de DGI."},"503":{"description":"401 = key. 400 = query inválida. Lista vacía ≠ error de DGI."}}}},"/v1/dev/cfe/outbox/{id}/refresh-status":{"post":{"operationId":"nextdata_refresh","summary":"Actualizar estado DGI","description":"Consulta el estado final del CFE ante DGI cuando DGI ya abrió EFACCONSULTARESTADOENVIO (ParamConsulta/Fechahora). No lo llames en el mismo request que el issue: el 200 con pdfBase64 ya es el comprobante firmado y con CAE. status pending no es un fallo. El 409 con retryAt no es CFE fallido, ni key mala, ni BE.\nDespués de emitir, solo cuando quieras AE/BE. Si 409 con code DGI_STATUS_WINDOW_NOT_REACHED y retryAt, esperá esa hora America/Montevideo. forceFinal: true exige confirm: true.\n401 = key. 403 = no es tu CFE. 404 = no existe. 409 + retryAt = ventana DGI (el CFE ya fue enviado). 503 = ambiente/certificado no listo para consultar (no es perfil incompleto). SOAP Fault ≠ BE.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"x-required-scope":"cfe:issue","x-read-only":false,"requestBody":{"required":false,"content":{"application/json":{"schema":{"oneOf":[{"type":"object","properties":{"forceFinal":{"const":false}},"required":[],"additionalProperties":false},{"type":"object","properties":{"forceFinal":{"const":true},"confirm":{"const":true}},"required":["forceFinal","confirm"],"additionalProperties":false}]},"example":{}}}},"responses":{"200":{"description":"finalState (AE/BE) y message. AS = sobre aceptado, todavía no es estado final.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"id o body inválido"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"El CFE no es de esta key/actor"},"404":{"description":"No existe en este tenant"},"409":{"description":"Ventana DGI no alcanzada (DGI_STATUS_WINDOW_NOT_REACHED)"},"422":{"description":"401 = key. 403 = no es tu CFE. 404 = no existe. 409 + retryAt = ventana DGI (el CFE ya fue enviado). 503 = ambiente/certificado no listo para consultar (no es perfil incompleto). SOAP Fault ≠ BE."},"429":{"description":"401 = key. 403 = no es tu CFE. 404 = no existe. 409 + retryAt = ventana DGI (el CFE ya fue enviado). 503 = ambiente/certificado no listo para consultar (no es perfil incompleto). SOAP Fault ≠ BE."},"502":{"description":"401 = key. 403 = no es tu CFE. 404 = no existe. 409 + retryAt = ventana DGI (el CFE ya fue enviado). 503 = ambiente/certificado no listo para consultar (no es perfil incompleto). SOAP Fault ≠ BE."},"503":{"description":"401 = key. 403 = no es tu CFE. 404 = no existe. 409 + retryAt = ventana DGI (el CFE ya fue enviado). 503 = ambiente/certificado no listo para consultar (no es perfil incompleto). SOAP Fault ≠ BE."}}}},"/v1/dev/cfe/outbox/{id}/print-model":{"get":{"operationId":"nextdata_print_model","summary":"Representación impresa (modelo)","description":"JSON del CFE firmado para que el ERP dibuje el ticket. Es el camino para impresora térmica 80 mm: emisor, receptor, ítems, totales, QR / URL de consulta, CAE y código de seguridad. NextData no entrega un PDF ni una imagen de 80 mm. El PDF oficial (solo A4) es GET .../pdf.\nPaso 10, solo si vas a dibujar el comprobante (ticket 80 mm, HTML o PDF de respaldo). Reemplazá :id por el outboxId. Si no hay XML firmado, 409. No hay ?format=thermal ni PDF ticket. El PDF listo es GET /v1/dev/cfe/outbox/:id/pdf (A4).\n401 = key. 404 = no es tu CFE. 409 = todavía no firmado.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"item para armar tu representación. publication.url / publicConsultUrl = Consulta Next Data. Ver en DGI es el portal ePrueba.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true}}}},"400":{"description":"id inválido"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado."},"404":{"description":"No es de este tenant/key"},"409":{"description":"Todavía no hay XML firmado"},"422":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado."},"429":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado."},"502":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado."},"503":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado."}}}},"/v1/dev/cfe/outbox/{id}/pdf":{"get":{"operationId":"nextdata_pdf","summary":"PDF oficial del comprobante","description":"Devuelve el mismo PDF A4 que el panel NextData y la consulta pública: diseño estándar DGI, QR, CAE, código de seguridad y logo del emisor (el que cargaste en POST /v1/dev/config/company). Sin marca NextData. Solo A4: no hay query, header ni format=thermal / 80 mm. La respuesta es binaria (application/pdf, Content-Disposition attachment); no es JSON. Ticket 80 mm = GET .../print-model + dibujo en el ERP.\nRespaldo. El PDF de pantalla ya viene en pdfBase64 del 200 de POST /v1/dev/invoices/issue: mostralo ahí. Este GET es solo si ese campo no vino. Reemplazá :id por el outboxId. Pedilo con Accept: application/pdf y guardá el cuerpo tal cual; el nombre viene en Content-Disposition (CFE_<tipo>_<serie>_<numero>.pdf). Si la impresora es térmica 80 mm, no uses este PDF: usá print-model.\n401 = key. 404 = no es tu CFE. 409 = todavía no firmado (no hay representación impresa). Si preferís dibujarlo vos, usá print-model y seguí la guía Diseño del comprobante.","security":[{"apiKeyBearer":[]},{"apiKeyHeader":[]}],"parameters":[{"in":"path","name":"id","required":true,"schema":{"type":"string","format":"uuid"}}],"x-required-scope":"cfe:read","x-read-only":true,"responses":{"200":{"description":"Nada: el PDF se regenera del XML firmado cada vez. Si querés cachearlo, hacelo por outboxId y descartalo si cambia el status.","content":{"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"id inválido"},"401":{"description":"Key inválida o inactiva"},"403":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado (no hay representación impresa). Si preferís dibujarlo vos, usá print-model y seguí la guía Diseño del comprobante."},"404":{"description":"No es de este tenant/key"},"409":{"description":"Todavía no hay XML firmado"},"422":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado (no hay representación impresa). Si preferís dibujarlo vos, usá print-model y seguí la guía Diseño del comprobante."},"429":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado (no hay representación impresa). Si preferís dibujarlo vos, usá print-model y seguí la guía Diseño del comprobante."},"502":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado (no hay representación impresa). Si preferís dibujarlo vos, usá print-model y seguí la guía Diseño del comprobante."},"503":{"description":"401 = key. 404 = no es tu CFE. 409 = todavía no firmado (no hay representación impresa). Si preferís dibujarlo vos, usá print-model y seguí la guía Diseño del comprobante."}}}}},"components":{"securitySchemes":{"apiKeyBearer":{"type":"http","scheme":"bearer","bearerFormat":"nd_test_ / nd_live_"},"apiKeyHeader":{"type":"apiKey","in":"header","name":"X-Api-Key"}}}}