# Emitir CFEs

`POST /v1/companies/{companyRut}/sendCfes/{branchOffice}`

**Emite cualquier CFE (el tipo va en el body). Es asíncrono: devuelve un id y NO confirma la aceptación, después hay que consultar el estado. Requiere certificado y CAE del tipo de documento.**

**Acceso:** restringida. Requiere sesión, y sólo opera sobre el RUT de tu propia empresa: pedir otro RUT responde `403 FORBIDDEN`.

## OpenAPI

```json
{
  "openapi": "3.0.3",
  "info": {
    "title": "pymo Gateway API",
    "version": "1.0.0",
    "description": "API del gateway de facturación electrónica (CFE) de pymo. Los métodos y las rutas salen del código del servicio, así que la referencia refleja lo que la API hace hoy."
  },
  "servers": [
    {
      "url": "https://gatewaytest.pymo.uy",
      "description": "Homologación: emite contra la ePrueba de DGI. Es donde se integra."
    },
    {
      "url": "https://gateway.pymo.uy",
      "description": "Producción: los comprobantes son fiscales y no se pueden borrar."
    }
  ],
  "security": [
    {
      "sessionCookie": []
    }
  ],
  "paths": {
    "/v1/companies/{companyRut}/sendCfes/{branchOffice}": {
      "post": {
        "operationId": "post_v1_companies_companyRut_sendCfes_branchOffice",
        "summary": "Emitir CFEs",
        "description": "**Emite cualquier CFE (el tipo va en el body). Es asíncrono: devuelve un id y NO confirma la aceptación, después hay que consultar el estado. Requiere certificado y CAE del tipo de documento.**\n\n**Acceso:** restringida. Requiere sesión, y sólo opera sobre el RUT de tu propia empresa: pedir otro RUT responde `403 FORBIDDEN`.",
        "tags": [
          "3 Emisión"
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/CompanyRut"
          },
          {
            "$ref": "#/components/parameters/BranchOffice"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SolicitudEmision"
              },
              "example": {
                "111": [
                  {
                    "clientEmissionId": "pedido-2026-000123",
                    "IdDoc": {
                      "MntBruto": "1",
                      "FmaPago": "1"
                    },
                    "Receptor": {
                      "TipoDocRecep": "2",
                      "CodPaisRecep": "UY",
                      "DocRecep": "211234567005",
                      "RznSocRecep": "EMPRESA DE EJEMPLO SA",
                      "DirRecep": "Calle Falsa 1234",
                      "CiudadRecep": "Montevideo",
                      "DeptoRecep": "Montevideo"
                    },
                    "Totales": {
                      "TpoMoneda": "UYU"
                    },
                    "Items": [
                      {
                        "NroLinDet": "1",
                        "IndFact": "1",
                        "NomItem": "Servicio de ejemplo",
                        "Cantidad": 1,
                        "UniMed": "N/A",
                        "PrecioUnitario": 1000,
                        "MontoItem": 1000
                      }
                    ],
                    "adenda": "Texto libre opcional"
                  }
                ],
                "emailsToNotify": []
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Éxito",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaEmision"
                },
                "examples": {
                  "Exito": {
                    "value": {
                      "payload": {
                        "cfesIds": [
                          {
                            "id": "6a7121a37698d7c0ab3f1b51",
                            "clientEmissionId": "pedido-2026-000123",
                            "serie": "A",
                            "nro": 3503,
                            "type": "111",
                            "caeNumber": 90120000538,
                            "caeSerie": "A",
                            "caeRange": {
                              "first": 1,
                              "last": 999999
                            },
                            "caeExpirationDate": "2030-01-01T00:00:00.000Z",
                            "total": "3050.00",
                            "emitionDate": "2026-08-03T20:17:46.000-03:00",
                            "sentXmlHash": "mghK5nJZkGskjJUkRv8EnG+U8xa1vs1tROJsIqDXBMk=",
                            "securityCode": "mghK5n",
                            "qrUrl": "https://gatewaytest.pymo.uy/consultaQR/cfe?...",
                            "CAEEspecial": null,
                            "CausalCAEEsp": null
                          }
                        ]
                      },
                      "message": {
                        "code": "DGI_CFES_RECEIVE_SUCCESS",
                        "value": "Cfes recibidos correctamente."
                      },
                      "status": "SUCCESS"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Sesión no iniciada o vencida (`UNAUTHORIZED`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaError"
                },
                "examples": {
                  "No_autorizado": {
                    "value": {
                      "payload": {},
                      "message": {
                        "code": "UNAUTHORIZED",
                        "value": "Debe iniciar sesión."
                      },
                      "status": "FAIL"
                    }
                  }
                }
              }
            }
          },
          "403": {
            "description": "La sesión existe pero no alcanza este recurso (`FORBIDDEN`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RespuestaError"
                },
                "examples": {
                  "Prohibido": {
                    "value": {
                      "payload": {},
                      "message": {
                        "code": "FORBIDDEN",
                        "value": "No tiene permisos para realizar esta acción."
                      },
                      "status": "FAIL"
                    }
                  }
                }
              }
            }
          }
        },
        "x-acceso": "restringida-por-rut"
      }
    }
  },
  "components": {
    "schemas": {
      "SolicitudEmision": {
        "type": "object",
        "description": "Cuerpo de la emisión. **No hay una clave `cfes`**: cada clave del objeto es el código de tipo de CFE, y su valor es la lista de comprobantes de ese tipo. Un mismo request puede llevar varios tipos. Las únicas claves que no son un código son `emailsToNotify` y `phonesToNotify`.\n\n**Las claves están enumeradas, no son libres.** El gateway ignora en silencio cualquier clave que no sea un código válido, así que un tipo mal escrito no da error: se emite nada y la respuesta dice `SUCCESS`. Acá el esquema las lista todas para que esa clase de error se detecte antes de mandar el request.",
        "properties": {
          "101": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eTicket. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "102": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eTicket. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "103": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eTicket. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "111": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eFactura. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "112": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eFactura. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "113": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eFactura. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "121": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eFactura Expo. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "122": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eFactura Expo. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "123": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eFactura Expo. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "124": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eRemito Expo. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "131": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eTicket Cuenta A.. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "132": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eTicket Cuenta A.. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "133": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eTicket Cuenta A.. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "141": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eFactura Cuenta A.. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "142": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eFactura Cuenta A.. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "143": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eFactura Cuenta A.. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "151": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eBoleta. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "152": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eBoleta. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "153": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eBoleta. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "181": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eRemito. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "182": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eResguardo. Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "201": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eTicket Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "202": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eTicket Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "203": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eTicket Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "211": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eFactura Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "212": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eFactura Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "213": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eFactura Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "221": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eFactura Expo Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "222": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eFactura Expo Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "223": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eFactura Expo Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "224": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eRemito Expo Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "231": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eTicket Cuenta A. Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "232": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eTicket Cuenta A. Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "233": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eTicket Cuenta A. Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "241": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eFactura Cuenta A. Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "242": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eFactura Cuenta A. Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "243": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eFactura Cuenta A. Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "251": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eBoleta Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "252": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "NC eBoleta Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "253": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "ND eBoleta Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "281": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eRemito Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "282": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Cfe"
            },
            "description": "eResguardo Cont. (contingencia). Los tipos de contingencia llevan serie y número propios en `IdDoc`."
          },
          "emailsToNotify": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "email"
            },
            "description": "Direcciones a las que notificar el resultado. Opcional; `[]` es válido."
          },
          "phonesToNotify": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Teléfonos a los que notificar. Opcional."
          }
        },
        "additionalProperties": false
      },
      "Cfe": {
        "type": "object",
        "required": [
          "clientEmissionId",
          "IdDoc",
          "Receptor",
          "Totales",
          "Items"
        ],
        "description": "Un comprobante. Los nombres de campo son los de DGI, no los del gateway, y las reglas de cada campo son las del documento **Formato CFE** de DGI, versión vigente ([v23-1](https://www.efactura.dgi.gub.uy/principal/ampliacion_de_contenido/documento-de-formato-cfe-version-23-1)). Acá se describe la estructura y lo que el gateway hace con ella.\n\n**`additionalProperties` queda abierto a propósito.** El formato de DGI tiene muchos más campos de los que están descritos acá, y cerrarlo haría que el esquema rechace comprobantes válidos. Lo que sí está cerrado es el nivel de arriba: los códigos de tipo.",
        "properties": {
          "clientEmissionId": {
            "type": "string",
            "description": "**Obligatorio.** La clave de idempotencia, elegida por el integrador. Única por empresa + sucursal + tipo de CFE, garantizado por un índice único de la base. Reenviar el mismo id no emite un segundo comprobante: devuelve el original en `firstCfeResponse`.",
            "example": "pedido-2026-000123"
          },
          "IdDoc": {
            "$ref": "#/components/schemas/CfeIdDoc"
          },
          "Receptor": {
            "$ref": "#/components/schemas/CfeReceptor"
          },
          "Totales": {
            "$ref": "#/components/schemas/CfeTotales"
          },
          "Items": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/CfeItem"
            },
            "description": "Líneas del comprobante."
          },
          "DscRcgGlobal": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Descuentos y recargos globales (`NroLinDR`, `TpoMovDR` D o R, `TpoDR`, `CodDR`, `GlosaDR`, `ValorDR`, `IndFactDR`). Opcional."
          },
          "adenda": {
            "type": "string",
            "description": "Texto libre que viaja con el comprobante. Admite saltos de línea."
          }
        }
      },
      "CfeIdDoc": {
        "type": "object",
        "description": "Identificación del documento.",
        "properties": {
          "MntBruto": {
            "type": "string",
            "description": "`1` si los importes de las líneas ya incluyen impuestos."
          },
          "FmaPago": {
            "type": "string",
            "description": "Forma de pago DGI: `1` contado, `2` crédito.",
            "enum": [
              "1",
              "2"
            ]
          },
          "FchEmis": {
            "type": "string",
            "format": "date-time",
            "description": "Fecha de emisión. Si falta, el gateway usa la del momento."
          },
          "Serie": {
            "type": "string",
            "description": "Sólo para los tipos que admiten serie y número propios, que son los de contingencia. En el resto los asigna el gateway desde el CAE."
          },
          "Nro": {
            "type": "integer",
            "description": "Igual que `Serie`: sólo para los tipos que lo admiten."
          },
          "numAuth": {
            "type": "integer",
            "description": "Número de autorización CAE a usar, cuando la empresa tiene más de uno vigente para el tipo."
          }
        },
        "minProperties": 1
      },
      "CfeReceptor": {
        "type": "object",
        "description": "Datos del receptor. Qué campos son obligatorios depende del tipo de CFE y del monto: el gateway responde `RECEPTOR_REQUIRED`, `RECEPTOR_DOC_REQUIRED` o `RECEPTOR_DOC_EXT_REQUIRED` cuando falta lo que ese tipo exige.",
        "properties": {
          "TipoDocRecep": {
            "type": "string",
            "description": "Tipo de documento DGI: `2` RUT, `3` CI, `4` otros, `5` pasaporte, `6` DNI, `7` NIFE. Cuál se exige depende del tipo de CFE: el gateway responde `RECEPTOR_DOC_REQUIRED` o `RECEPTOR_DOC_EXT_REQUIRED` según corresponda.",
            "enum": [
              "1",
              "2",
              "3",
              "4",
              "5",
              "6",
              "7"
            ]
          },
          "DocRecep": {
            "type": "string",
            "description": "Número de documento. DGI valida el dígito verificador del RUT: un RUT mal formado no falla en la emisión, hace que DGI **rechace** el sobre después."
          },
          "CodPaisRecep": {
            "type": "string",
            "description": "Código de país ISO, `UY` para Uruguay."
          },
          "RznSocRecep": {
            "type": "string",
            "description": "Razón social o nombre."
          },
          "DirRecep": {
            "type": "string"
          },
          "CiudadRecep": {
            "type": "string"
          },
          "DeptoRecep": {
            "type": "string"
          }
        },
        "minProperties": 1
      },
      "CfeTotales": {
        "type": "object",
        "description": "Totales del comprobante.",
        "properties": {
          "TpoMoneda": {
            "type": "string",
            "description": "Moneda ISO: `UYU`, `USD`, `UI`, `UR`.",
            "example": "UYU",
            "enum": [
              "UYU",
              "USD",
              "UI",
              "UR"
            ]
          },
          "TpoCambio": {
            "type": "number",
            "description": "Tipo de cambio a moneda nacional. Obligatorio cuando `TpoMoneda` no es `UYU`."
          },
          "CantLinDet": {
            "type": "string",
            "description": "Cantidad de líneas de detalle."
          },
          "MntTotRetenido": {
            "type": "string",
            "description": "Total retenido, para eResguardo."
          },
          "RetencPercep": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Retenciones y percepciones a nivel comprobante (`CodRet`, `ValRetPerc`)."
          }
        },
        "minProperties": 1,
        "required": [
          "TpoMoneda"
        ]
      },
      "CfeItem": {
        "type": "object",
        "description": "Una línea del comprobante.",
        "properties": {
          "NroLinDet": {
            "type": "string",
            "description": "Número de línea, empezando en 1."
          },
          "IndFact": {
            "type": "string",
            "enum": [
              "1",
              "2",
              "3",
              "4",
              "5",
              "6",
              "7",
              "8",
              "10",
              "11",
              "12",
              "13",
              "14",
              "15",
              "16"
            ],
            "description": "Indicador de facturación DGI, define el tratamiento de IVA de la línea. `1` exento, `2` tasa mínima (10%), `3` tasa básica (22%), `4` otra tasa, `5` entrega gratuita, `6`/`7` no facturable, `8`/`10` exportación y asimiladas, `11` impuesto percibido, `12` IVA en suspenso, `13` vendido por no contribuyente, `14` IVA mínimo / Monotributo, `15` IMEBA, `16` obligación IVA mínimo. Para una venta gravada común es `3`. La misma tabla que devuelve `GET /v1/taxes`, así que se puede consultar en vivo.",
            "example": "3"
          },
          "NomItem": {
            "type": "string",
            "description": "Descripción del ítem."
          },
          "Cantidad": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ]
          },
          "UniMed": {
            "type": "string",
            "description": "Unidad de medida. `N/A` cuando no aplica."
          },
          "PrecioUnitario": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Redondeá a 2 decimales antes de enviar: el gateway no re-redondea las líneas, sólo formatea los totales en UYU a 2 decimales al enviarlos a DGI."
          },
          "MontoItem": {
            "oneOf": [
              {
                "type": "number"
              },
              {
                "type": "string"
              }
            ],
            "description": "Monto de la línea. Si falta, DGI lo deriva de cantidad y precio. Redondeá a 2 decimales antes de enviar: el gateway no re-redondea las líneas, sólo formatea los totales en UYU a 2 decimales al enviarlos a DGI."
          },
          "SubDescuento": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "SubRecargo": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "RetencPercep": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Retenciones de la línea (`Tasa`, `CodRet`, `MntSujetoaRet`, `ValRetPerc`)."
          }
        },
        "minProperties": 1,
        "required": [
          "NroLinDet",
          "IndFact",
          "NomItem"
        ]
      },
      "CfeEmitido": {
        "type": "object",
        "description": "Un comprobante emitido, tal como vuelve en `payload.cfesIds`. Todos estos campos hay que persistirlos: `serie` y `nro` identifican fiscalmente el comprobante, los cuatro de CAE son la autorización de DGI para la representación impresa, y `qrUrl` la arma el gateway.",
        "required": [
          "id",
          "clientEmissionId",
          "serie",
          "nro",
          "type",
          "caeNumber",
          "total",
          "emitionDate",
          "sentXmlHash",
          "qrUrl"
        ],
        "properties": {
          "id": {
            "type": "string",
            "description": "Identificador interno del comprobante. Es el que se usa para consultar estado y PDF."
          },
          "clientEmissionId": {
            "type": "string",
            "description": "El id que mandaste. Sirve para hacer corresponder esta entrada con tu comprobante: **el orden del array no es garantía**."
          },
          "serie": {
            "type": "string"
          },
          "nro": {
            "type": "integer"
          },
          "type": {
            "type": "string",
            "description": "Código de tipo de CFE."
          },
          "caeNumber": {
            "type": "integer",
            "description": "Número de autorización DGI."
          },
          "caeSerie": {
            "type": "string"
          },
          "caeRange": {
            "type": "object",
            "description": "Rango autorizado, con su primer y último número."
          },
          "caeExpirationDate": {
            "type": "string",
            "format": "date-time"
          },
          "total": {
            "type": "string",
            "description": "Monto a pagar, como string."
          },
          "emitionDate": {
            "type": "string",
            "format": "date-time"
          },
          "sentXmlHash": {
            "type": "string",
            "description": "Hash del XML firmado."
          },
          "securityCode": {
            "type": "string",
            "description": "Los primeros 6 caracteres de `sentXmlHash`. Va en la representación impresa."
          },
          "qrUrl": {
            "type": "string",
            "description": "URL que se codifica en el QR impreso. La arma el gateway; no se construye del lado del integrador."
          },
          "CAEEspecial": {
            "type": "string",
            "nullable": true
          },
          "CausalCAEEsp": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "CfeConError": {
        "type": "object",
        "description": "Un comprobante del lote que **no** se emitió. Viaja en el mismo array que los emitidos, sin nada que los separe: distinguilos por `status`.",
        "required": [
          "status",
          "message"
        ],
        "properties": {
          "code": {
            "type": "integer",
            "description": "Código HTTP que le habría correspondido a este comprobante si hubiera ido solo."
          },
          "status": {
            "type": "string",
            "enum": [
              "FAIL"
            ]
          },
          "message": {
            "$ref": "#/components/schemas/Mensaje"
          },
          "receivedDataWithError": {
            "type": "object",
            "description": "El comprobante como lo interpretó el gateway, con los totales ya calculados. Trae `clientEmissionId` en el nivel superior.",
            "properties": {
              "clientEmissionId": {
                "type": "string"
              },
              "cfe": {
                "type": "object"
              }
            }
          },
          "firstCfeResponse": {
            "allOf": [
              {
                "$ref": "#/components/schemas/CfeEmitido"
              }
            ],
            "description": "**Sólo en `DUPLICATED_KEY`.** El comprobante original, el que ya se había emitido con ese `clientEmissionId`. Se persiste igual que un éxito."
          }
        }
      },
      "RespuestaEmision": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Respuesta"
          }
        ],
        "description": "**`status` es siempre `SUCCESS`, aunque no se haya emitido ningún comprobante.** No hay conteo ni bandera de éxito parcial: hay que recorrer `payload.cfesIds` y mirar cada entrada.",
        "properties": {
          "payload": {
            "type": "object",
            "required": [
              "cfesIds"
            ],
            "properties": {
              "cfesIds": {
                "type": "array",
                "description": "Una entrada por comprobante del request, emitido o fallado, mezclados.",
                "items": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/CfeEmitido"
                    },
                    {
                      "$ref": "#/components/schemas/CfeConError"
                    }
                  ]
                }
              }
            }
          }
        }
      },
      "Respuesta": {
        "type": "object",
        "required": [
          "payload",
          "status"
        ],
        "description": "Envoltorio común a todas las respuestas. **`status` no se deduce del código HTTP**: hay al menos nueve lugares en el gateway que responden `HTTP 200` con `status: \"FAIL\"` (por ejemplo `CFE_NOT_FOUND` y `DGI_COMPANY_NOT_READY_YET`). Un cliente tiene que leer `status`, no el código.",
        "properties": {
          "payload": {
            "description": "Los datos de la respuesta. `{}` cuando el endpoint no devuelve nada.",
            "oneOf": [
              {
                "type": "object"
              },
              {
                "type": "array",
                "items": {}
              }
            ]
          },
          "message": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Mensaje"
              }
            ],
            "description": "Presente cuando la operación tiene algo que decir. Las lecturas simples responden sólo `payload` y `status`."
          },
          "status": {
            "$ref": "#/components/schemas/Estado"
          }
        }
      },
      "RespuestaError": {
        "allOf": [
          {
            "$ref": "#/components/schemas/Respuesta"
          }
        ],
        "description": "El mismo envoltorio, con `status: \"FAIL\"` y `payload` normalmente vacío."
      },
      "Mensaje": {
        "type": "object",
        "required": [
          "code",
          "value"
        ],
        "description": "Código estable y su texto en español. **El código es el contrato, el texto no**: `value` sale de una tabla de traducciones y puede reescribirse sin aviso, así que un cliente ramifica por `code`.",
        "properties": {
          "code": {
            "type": "string",
            "example": "DGI_CFES_RECEIVE_SUCCESS"
          },
          "value": {
            "type": "string",
            "example": "Cfes recibidos correctamente."
          }
        }
      },
      "Estado": {
        "type": "string",
        "enum": [
          "SUCCESS",
          "FAIL"
        ],
        "description": "De las 82 claves de mensaje del gateway, 29 son `SUCCESS` y 53 `FAIL`. Es lo que hay que mirar para saber si la llamada funcionó."
      }
    },
    "securitySchemes": {
      "sessionCookie": {
        "type": "apiKey",
        "in": "cookie",
        "name": "connect.sid",
        "description": "Sesión por cookie de `POST /v1/login`, válida 1 hora. Ver [Autenticación](/autenticacion)."
      }
    },
    "parameters": {
      "BranchOffice": {
        "name": "branchOffice",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "example": "1",
          "default": "1"
        },
        "example": "1"
      },
      "CompanyRut": {
        "name": "companyRut",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "example": "219999990008",
          "default": "219999990008"
        },
        "example": "219999990008"
      }
    }
  }
}
```
