Valida un XML de CFE SIN emitirlo
POST /v1/cfe/validar-cfe-xml
La contraparte de POST /v1/cfe/emitir-xml: valida el XML pre-armado (parseo, tipo soportado, campos prohibidos y validación XSD del sobre que se construiría) y devuelve los problemas sin consumir CAE y sin enviar a DGI. Para validar el sobre completo lo firma en memoria con el certificado de la empresa, así que exige certificado vigente: sin él responde 409 CERTIFICADO_NO_VIGENTE.
Es la herramienta con la que un proveedor que mantiene su propio armador verifica un cambio de formato de DGI contra los XSD vigentes antes de mandar nada a producción.
Mismo cuerpo que POST /v1/cfe/emitir-xml. Igual que la validación JSON: siempre 200, con data.valido y data.errores[].
Alcance requerido:
cfe:emitirocfe:leer. Si la credencial no lo tiene, la respuesta es403 API_ALCANCE_INSUFICIENTEcon la lista enerror.requerido. Las credenciales creadas antes del modelo de alcances (alcances: null) conservan acceso total.
Autorizaciones
Sección titulada «Autorizaciones »Parámetros
Sección titulada « Parámetros »Parámetros de header
Sección titulada «Parámetros de header »Ejemplo
0199d1b0-0000-7000-8000-000000000000Sólo para credenciales de cuenta proveedora (revendedor). UUID de la subcuenta de la cartera sobre la que se quiere operar: la cuenta efectiva del request pasa a ser esa.
Una credencial que no es de proveedor, o una subcuenta que no está en su cartera, recibe 403 API_CUENTA_FUERA_DE_CARTERA. Sin la cabecera, la cuenta es siempre la de la credencial.
Sucursal contra la que operar, cuando la credencial es global. Si la credencial está fijada a una sucursal y esta cabecera indica otra, la respuesta es 403 API_ACCESS_BRANCH_MISMATCH. Sin la cabecera se asume la casa central.
Punto de emisión dentro de la sucursal resuelta. Obligatorio cuando la sucursal tiene 2 o más puntos activos (400 PUNTO_EMISION_REQUERIDO si falta); con uno solo se selecciona automáticamente.
Cuerpo de la solicitud required
Sección titulada «Cuerpo de la solicitud required »El mismo cuerpo que POST /v1/cfe/emitir-xml
object
Ejemplos
XML de e-Ticket (tipo 101)
CFE armado por el cliente al formato DGI nativo. El nodo eTck corresponde al tipo 101. NO incluye CAEData, Signature, IdDoc.Serie ni IdDoc.Nro — los inyecta Host Factura.
{ "xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CFE xmlns=\"http://cfe.dgi.gub.uy\" version=\"1.0\">\n <eTck>\n <Encabezado>\n <IdDoc>\n <TipoCFE>101</TipoCFE>\n <FchEmis>2026-05-17</FchEmis>\n <FmaPago>1</FmaPago>\n </IdDoc>\n <Emisor>\n <RUCEmisor>210000000000</RUCEmisor>\n <RznSoc>MI EMPRESA S.A.</RznSoc>\n <NomComercial>Mi Empresa</NomComercial>\n <CdgDGISucur>1</CdgDGISucur>\n <DomFiscal>18 de Julio 1234</DomFiscal>\n <Ciudad>Montevideo</Ciudad>\n <Departamento>Montevideo</Departamento>\n </Emisor>\n <Totales>\n <TpoMoneda>UYU</TpoMoneda>\n <MntNetoIVATasaBasica>200</MntNetoIVATasaBasica>\n <IVATasaBasica>22</IVATasaBasica>\n <MntTotal>244</MntTotal>\n <CantLinDet>1</CantLinDet>\n <MntPagar>244</MntPagar>\n </Totales>\n </Encabezado>\n <Detalle>\n <Item>\n <NroLinDet>1</NroLinDet>\n <IndFact>3</IndFact>\n <NomItem>Café americano</NomItem>\n <Cantidad>2.000</Cantidad>\n <UniMed>UN</UniMed>\n <PrecioUnitario>100.00</PrecioUnitario>\n <MontoItem>200.00</MontoItem>\n </Item>\n </Detalle>\n </eTck>\n</CFE>"}XML de e-Factura (tipo 111)
E-Factura completa con receptor identificado por RUT. El nodo eFact corresponde al tipo 111. Notar que Encabezado.Receptor es obligatorio en este tipo.
{ "xml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<CFE xmlns=\"http://cfe.dgi.gub.uy\" version=\"1.0\">\n <eFact>\n <Encabezado>\n <IdDoc>\n <TipoCFE>111</TipoCFE>\n <FchEmis>2026-05-17</FchEmis>\n <FmaPago>2</FmaPago>\n </IdDoc>\n <Emisor>\n <RUCEmisor>210000000000</RUCEmisor>\n <RznSoc>MI EMPRESA S.A.</RznSoc>\n <CdgDGISucur>1</CdgDGISucur>\n <DomFiscal>18 de Julio 1234</DomFiscal>\n <Ciudad>Montevideo</Ciudad>\n <Departamento>Montevideo</Departamento>\n </Emisor>\n <Receptor>\n <TipoDocRecep>2</TipoDocRecep>\n <CodPaisRecep>UY</CodPaisRecep>\n <DocRecep>219999830019</DocRecep>\n <RznSocRecep>EMPRESA EJEMPLO S.A.</RznSocRecep>\n <DirRecep>18 DE JULIO 1234</DirRecep>\n <CiudadRecep>MONTEVIDEO</CiudadRecep>\n <DeptoRecep>MONTEVIDEO</DeptoRecep>\n </Receptor>\n <Totales>\n <TpoMoneda>UYU</TpoMoneda>\n <MntNetoIVATasaBasica>12500</MntNetoIVATasaBasica>\n <IVATasaBasica>2750</IVATasaBasica>\n <MntTotal>15250</MntTotal>\n <CantLinDet>1</CantLinDet>\n <MntPagar>15250</MntPagar>\n </Totales>\n </Encabezado>\n <Detalle>\n <Item>\n <NroLinDet>1</NroLinDet>\n <IndFact>3</IndFact>\n <NomItem>Servicio de consultoría — Septiembre</NomItem>\n <Cantidad>1.000</Cantidad>\n <UniMed>UN</UniMed>\n <PrecioUnitario>12500.00</PrecioUnitario>\n <MontoItem>12500.00</MontoItem>\n </Item>\n </Detalle>\n </eFact>\n</CFE>"}Respuestas
Sección titulada « Respuestas »Resultado de la validación del XML
object
Ejemplos
{ "data": { "valido": true, "errores": [] }}XSD rechazado
{ "data": { "valido": false, "errores": [ "Element 'MntNoGrv': This element is not expected (línea 42)" ] }}El cuerpo no trae un xml utilizable
object
object
Identificador estable del error en SCREAMING_SNAKE_CASE
Mensaje legible en español. No parsearlo: puede cambiar
object
object
Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación
UUID de correlación; mismo valor que el header X-Request-ID
Ejemplos
XML mal formado o sin IdDoc
{ "error": { "code": "XML_EXTERNO_INVALIDO", "message": "El CFE debe contener un nodo IdDoc" }, "requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"}No autenticado. La API_KEY no fue enviada, no es válida o la credencial está desactivada.
Códigos posibles: API_AUTH_HEADER_MISSING, API_AUTH_HEADER_INVALID, API_ACCESS_INVALID.
object
object
Identificador estable del error en SCREAMING_SNAKE_CASE
Mensaje legible en español. No parsearlo: puede cambiar
object
object
Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación
UUID de correlación; mismo valor que el header X-Request-ID
Ejemplos
Falta header Authorization
{ "error": { "code": "API_AUTH_HEADER_MISSING", "message": "Se esperaba la cabecera Authorization con esquema Bearer" }, "requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"}Secret key inválida o revocada
{ "error": { "code": "API_ACCESS_INVALID", "message": "Acceso no autorizado" }, "requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"}Acceso prohibido. La credencial es válida pero algo del contexto lo impide. Las cinco causas se corrigen de forma distinta y ninguna se arregla reintentando:
| Code | Qué pasó | Cómo se corrige |
|---|---|---|
API_FEATURE_DISABLED | La cuenta no tiene la API habilitada en su plan | Pedir la habilitación a soporte o al proveedor |
API_ALCANCE_INSUFICIENTE | La credencial no tiene el alcance de la operación (va en error.requerido) | Editar la credencial en Integraciones → API |
API_ALCANCE_NO_DISPONIBLE | La credencial tiene el alcance pero la cuenta no lo admite: sin cobros habilitados (pagos:*), sin facturación (cfe:*) o no es cuenta proveedora (webhooks:gestionar). Va en error.details | Pedir la habilitación a soporte o al proveedor |
API_ACCESS_BRANCH_MISMATCH | x-branch-id distinto de la sucursal fijada en la credencial | Quitar la cabecera o usar otra credencial |
API_CUENTA_FUERA_DE_CARTERA | x-cuenta-id apunta a una cuenta que no es de la cartera | Revisar el UUID de la subcuenta |
object
object
Identificador estable del error en SCREAMING_SNAKE_CASE
Mensaje legible en español. No parsearlo: puede cambiar
object
object
Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación
UUID de correlación; mismo valor que el header X-Request-ID
Ejemplos
Falta el alcance
{ "error": { "code": "API_ALCANCE_INSUFICIENTE", "message": "La credencial de API no tiene ninguno de los alcances necesarios para esta operación (pagos:cobrar)", "requerido": [ "pagos:cobrar" ] }, "requestId": "3f6b1c2e-9a4d-4f80-bc11-7e2d5a8f0c31"}La cuenta no admite el alcance
{ "error": { "code": "API_ALCANCE_NO_DISPONIBLE", "message": "Disponible sólo para cuentas proveedoras. La credencial tiene el permiso, pero la cuenta no puede usarlo.", "details": { "alcances": [ "webhooks:gestionar" ], "motivo": "SOLO_REVENDEDOR" } }, "requestId": "3f6b1c2e-9a4d-4f80-bc11-7e2d5a8f0c31"}La cuenta no tiene la API habilitada
{ "error": { "code": "API_FEATURE_DISABLED", "message": "El plan de esta cuenta no tiene habilitado el acceso a la API" }, "requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"}Header x-branch-id distinto al fijo del ApiAccess
{ "error": { "code": "API_ACCESS_BRANCH_MISMATCH", "message": "El ApiAccess está fijado a otra sucursal y no coincide con x-branch-id" }, "requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"}x-cuenta-id fuera de la cartera
{ "error": { "code": "API_CUENTA_FUERA_DE_CARTERA", "message": "La cuenta indicada en 'x-cuenta-id' no pertenece a la cartera de esta credencial" }, "requestId": "3f6b1c2e-9a4d-4f80-bc11-7e2d5a8f0c31"}La empresa no tiene un certificado de facturación electrónica vigente.
object
object
Identificador estable del error en SCREAMING_SNAKE_CASE
Mensaje legible en español. No parsearlo: puede cambiar
object
object
Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación
UUID de correlación; mismo valor que el header X-Request-ID
Ejemplos
La empresa no tiene certificado de facturación electrónica vigente
{ "error": { "code": "CERTIFICADO_NO_VIGENTE", "message": "No es posible emitir el comprobante: la empresa no tiene un certificado de facturación electrónica vigente." }, "requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"}Rate limit excedido. Esperá los segundos del header Retry-After. La cuota va por credencial: 60 req/min en cuentas estándar, 600 en cuentas proveedor.
object
object
Identificador estable del error en SCREAMING_SNAKE_CASE
Mensaje legible en español. No parsearlo: puede cambiar
object
object
Sólo en 403 API_ALCANCE_INSUFICIENTE: alcances que habilitan la operación
UUID de correlación; mismo valor que el header X-Request-ID
Ejemplos
Excediste el rate limit
{ "error": { "code": "API_RATE_LIMITED", "message": "Se superó el límite de requests para esta API key" }, "requestId": "5b2c7c8a-1f6e-4d29-9a0b-7c3a8d1e2f4c"}Headers
Sección titulada «Headers »Ejemplo
42Segundos hasta que se libera la ventana de rate limit