> ## Documentation Index
> Fetch the complete documentation index at: https://www.emissa.com.ar/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Reconciliar un comprobante sin resolver

> Le pregunta a ARCA qué pasó con un comprobante que quedó en `PENDING` o `UNKNOWN` —típicamente por un corte durante la autorización— y actualiza el estado con la respuesta.

**Es el camino de salida.** Sin esto un comprobante en ese estado traba la serie: no se puede reintentar (podría duplicar) ni saltear (ARCA exige numeración correlativa).

**Scope de API key:** `invoice:write`. Una key sin ese scope recibe `403 API_KEY_INSUFFICIENT_SCOPE`, aunque el rol de quien la creó lo permita: el permiso efectivo es la **intersección** de los dos.



## OpenAPI

````yaml https://api.emissa.com.ar/openapi.json post /v1/invoices/{id}/reconcile
openapi: 3.0.0
info:
  title: Emissa API
  description: >-
    API de facturación electrónica ante ARCA (ex-AFIP) para la República
    Argentina.


    ## Autenticación


    Dos credenciales, **dos headers distintos**:


    | Quién | Header |

    |---|---|

    | Integración de un sistema de terceros | `X-API-Key: emi_test_… /
    emi_live_…` |

    | Panel de Emissa | `Authorization: Bearer <JWT>` |


    Una API key en `Authorization` devuelve **401 `API_KEY_WRONG_HEADER`** con
    la

    indicación exacta, no un "token inválido" genérico.


    La key se crea desde el panel y **pertenece a la organización**, con una

    restricción **opcional** a un subconjunto de contribuyentes: sin restricción

    alcanza a todos los de la organización, incluidos los que se den de alta

    después. Lleva scopes, y no se puede crear una API key con otra API key:
    sería

    una escalada de privilegio.


    ## Identificá tu producto: `X-Emissa-Producto`


    Cabecera **opcional**, sólo con API key: el producto que origina el pedido

    (`inmos`, por ejemplo). Formato `^[a-z0-9-]{1,32}$`; cualquier otro valor

    devuelve `400 INVALID_INPUT`. Ausente o vacía, no pasa nada: queda `null`.


    Queda en el comprobante (`producto`, que no cambia después: un reintento

    idempotente con otra etiqueta devuelve el original), en el consumo

    (`GET /v1/consumo` trae `porProducto` y acepta `?producto=`), en el registro

    de pedidos y en el payload de `invoice.resolved`. `GET /v1/invoices/search`

    acepta `?producto=`. **Es atribución, no autorización**: no cambia lo que la
    key

    puede hacer.


    ## Sandbox: keys `test` y `live`


    **El modo está en el texto de la key**, así que se ve sin ejecutar nada:


    | Prefijo | Opera contra | Qué emite |

    |---|---|---|

    | `emi_test_` | contribuyentes de `HOMOLOGACION` | CAE real de ARCA, **sin
    validez fiscal** |

    | `emi_live_` | contribuyentes de `PRODUCCION` | comprobantes fiscales |


    El modo **no se elige**: se deriva del ambiente del contribuyente al crear
    la

    key, y se verifica en **cada** llamada. Una key `test` contra un
    contribuyente

    de producción devuelve `403 API_KEY_WRONG_MODE` — nunca emite.


    **Toda respuesta autenticada con API key lleva `X-Emissa-Mode: test|live`**,

    y el comprobante trae `environment`. Si tu suite de integración chequea una

    sola cosa, que sea ésta.


    > **En `PRODUCCION` lo que emitís es un comprobante fiscal real.** Entra en
    los

    > registros del contribuyente ante ARCA, pesa en su declaración y no se
    borra: se

    > revierte con una nota de crédito. Para probar está `HOMOLOGACION`, que
    también

    > da CAE real del organismo y no tiene consecuencia fiscal.


    ## Emitir un comprobante


    ```bash

    curl -X POST https://api.ejemplo/v1/invoices/authorize \
      -H 'X-API-Key: emi_...' \
      -H 'Idempotency-Key: pedido-8421' \
      -H 'Content-Type: application/json' \
      -d '{
        "taxpayerId": "...",
        "cbteTipo": 1, "concepto": 1,
        "receiverDocTipo": 80, "receiverDocNro": "30500010912",
        "receiverName": "Cliente SA", "receiverVatConditionId": 1,
        "issueDate": "2026-07-26",
        "items": [{ "description": "Consultoría", "unit": "UNIDADES",
                    "quantity": 1, "unitPrice": 1000,
                    "tratamiento": "GRAVADO", "vatRateId": 5 }]
      }'
    ```


    **`Idempotency-Key` es obligatorio.** Un duplicado fiscal no se deshace, así

    que el default tiene que ser el seguro: reintentar con la misma clave
    devuelve el

    comprobante original y la respuesta lleva `Idempotent-Replay: true`.


    ## Cuota y consumo


    **La unidad es el comprobante autorizado por ARCA.** No la creación, no el

    request. Un rechazo **no consume cuota**; el padrón, la constatación de CAE
    y los

    PDF se miden pero no se cobran.


    Cada emisión responde con:


    | Cabecera | Qué dice |

    |---|---|

    | `X-Cuota-Limite` | incluidos en el período, o `ilimitado` |

    | `X-Cuota-Usada` | comprobantes autorizados en el período, éste incluido |

    | `X-Cuota-Restante` | nunca negativo |

    | `X-Cuota-Reinicio` | ISO 8601 del primer instante del período siguiente |

    | `X-Cuota-Excedente-Unitario` | **sólo si te excediste**: a qué precio se
    factura cada uno |


    > **La cuota es blanda: llegar a cero NO bloquea nada.** Se sigue emitiendo
    y el

    > excedente se factura al unitario publicado. No la confundas con

    > `X-RateLimit-*`, que sí es duro y sí devuelve 429.


    `GET /v1/consumo?periodo=YYYY-MM` da el total de la organización y el
    desglose

    por CUIT. Un **CUIT activo** es el que emitió al menos un comprobante en el

    período: se deriva de los eventos, así que un contribuyente dado de alta que
    no

    facturó no cuenta.


    ## Reintentos


    | Código | Qué hacer |

    |---|---|

    | `503 SERIES_BUSY` | **Reintentá.** Las emisiones de una serie se
    serializan para que los números lleguen a ARCA en orden; el 503 es esa
    espera hecha explícita. |

    | `429 RATE_LIMIT_EXCEEDED` | Reintentá con backoff. |

    | `409 IDEMPOTENCY_IN_PROGRESS` | El pedido original sigue corriendo. Esperá
    su resultado; **no** cambies la clave. |

    | cortes de red sin respuesta | Reintentá **con la misma
    `Idempotency-Key`**. Es exactamente para lo que está. |


    Si un comprobante quedó en `PENDING` o `UNKNOWN`, `POST
    /v1/invoices/{id}/reconcile`

    le pregunta a ARCA qué pasó. Es el camino de salida: sin él la serie queda
    trabada.


    ## Errores


    Todos tienen la misma forma. Lo estable para ramificar es `errorCode`; el

    `message` es texto para mostrar y puede cambiar. `details` **no viaja en

    producción** cuando es material de diagnóstico.


    ## Webhooks


    Para lo que **no podés saber por la respuesta HTTP**. Se configuran desde el

    panel —una vez por organización, no por cliente— y hay cinco eventos:


    | Evento | Cuándo |

    |---|---|

    | `invoice.resolved` | un comprobante que quedó `PENDING` o `UNKNOWN` llegó
    a un estado final |

    | `connection.established` | un contribuyente pasó a `CONECTADO`: ya puede
    facturar |

    | `credential.expiring` | al certificado de ARCA le quedan 30 días o menos |

    | `api_key.expiring` | a una API key le quedan 30 días o menos |

    | `quota.exceeded` | se pasó la cuota del plan: **no bloquea**, se sigue
    emitiendo y el excedente se factura al unitario. Sale una vez por período |


    `connection.established` se emite **sólo en la transición**, no en cada

    verificación: quien está esperando la conexión verifica varias veces
    seguidas, y

    un aviso por cada una sería ruido. Es lo que le permite a una plataforma
    avisarle

    a su cliente sin encuestar `/conexion/verificar`.


    **No hay `invoice.authorized`**: `POST /v1/invoices/authorize` ya devuelve
    el

    comprobante con su CAE. Un evento por eso te obligaría a procesar dos veces
    lo

    mismo y a resolver cuál llegó primero.


    ### Verificar la firma


    ```

    POST /tu-receptor

    X-Emissa-Signature: t=1769472000,v1=5257a869e7...

    X-Emissa-Event-Id: inv_cmft8x2k30001_authorized

    X-Emissa-Event-Type: invoice.resolved

    X-Emissa-Delivery-Attempt: 1

    ```


    `v1` es `HMAC-SHA256(secreto, "${t}.${cuerpo crudo}")` en hexadecimal.

    Compará **con el cuerpo sin parsear**: reserializar cambia los bytes y la
    firma

    deja de dar. Rechazá lo que llegue con más de 5 minutos de diferencia — el
    `t`

    está dentro del HMAC justamente para que una captura no se pueda repetir
    mañana.


    ```js

    const [t, v1] = cabecera.split(',').map((p) => p.split('=')[1]);

    const esperado = crypto.createHmac('sha256', secreto)
      .update(`${t}.${cuerpoCrudo}`).digest('hex');
    const ok = crypto.timingSafeEqual(Buffer.from(v1,'hex'),
    Buffer.from(esperado,'hex'))
      && Math.abs(Date.now()/1000 - Number(t)) <= 300;
    ```


    ### Deduplicá por `id`


    **La entrega es "al menos una vez".** *Exactamente una vez* no existe sobre

    HTTP: si procesás el evento y te morís antes de contestar 200, desde acá es

    indistinguible de que nunca te llegó, así que se reintenta.


    El `id` del evento es estable entre reintentos. Guardalo y descartá lo
    repetido.


    ### Contestá rápido


    Un 2xx cuenta como entregado. Cualquier otra cosa se reintenta a los 30 s, 2
    min,

    10 min, 1 h, 6 h y 24 h; después queda en la cola de dead-letter para
    reenviarla

    a mano desde el panel. El timeout es de **10 segundos**: encolá y contestá,
    no

    proceses adentro del handler.


    ## Trazabilidad


    **Toda** respuesta lleva `X-Request-Id`. Si lo mandás vos y respeta

    `[A-Za-z0-9._:-]{1,128}`, se te devuelve el mismo, para que tu traza y la

    nuestra sean una sola. Es el dato que hay que citar en un ticket.


    ## Ambientes


    `HOMOLOGACION` es el ambiente de pruebas de ARCA: emite comprobantes con CAE

    real pero **sin validez fiscal**. Es donde se integra y se prueba.


    `PRODUCCION` emite **comprobantes fiscales reales**. Requiere certificado

    productivo, punto de venta de tipo "Factura Electrónica – Web Service" y el

    servicio autorizado en ARCA; si falta alguno, contesta ARCA con el motivo.


    Los dos son conjuntos **disjuntos** de claves: una key `test` contra un

    contribuyente de `PRODUCCION` se rechaza con 403, así que no podés emitir un

    comprobante real con la clave con la que estabas probando.


    ## Compatibilidad


    Mientras `/v1` esté vigente se pueden **agregar** campos, parámetros

    opcionales y endpoints. No se quita ni se renombra un campo, no se le cambia
    el

    tipo ni la semántica, no se vuelve obligatorio algo opcional y no se cambia
    un

    código de estado. **Tu cliente tiene que tolerar campos que no conoce.**
  version: 1.0.0
  contact: {}
servers:
  - url: https://api.emissa.com.ar
    description: Producción
  - url: http://localhost:3001
    description: Local
security: []
tags:
  - name: Comprobantes
    description: Emitir, consultar, anular y exportar
  - name: Contribuyentes
    description: Los CUIT desde los que se factura
  - name: Clientes
    description: Receptores y validación contra el padrón de ARCA
  - name: Credenciales ARCA
    description: Certificado y clave privada del emisor
  - name: Consumo
    description: Cuánto se emitió en el período, y con qué cuota
  - name: Panel
    description: 'Operaciones internas del panel: sesión, 2FA, keys'
  - name: Salud
    description: Sondas de vida y de disponibilidad
paths:
  /v1/invoices/{id}/reconcile:
    post:
      tags:
        - Comprobantes
      summary: Reconciliar un comprobante sin resolver
      description: >-
        Le pregunta a ARCA qué pasó con un comprobante que quedó en `PENDING` o
        `UNKNOWN` —típicamente por un corte durante la autorización— y actualiza
        el estado con la respuesta.


        **Es el camino de salida.** Sin esto un comprobante en ese estado traba
        la serie: no se puede reintentar (podría duplicar) ni saltear (ARCA
        exige numeración correlativa).


        **Scope de API key:** `invoice:write`. Una key sin ese scope recibe `403
        API_KEY_INSUFFICIENT_SCOPE`, aunque el rol de quien la creó lo permita:
        el permiso efectivo es la **intersección** de los dos.
      operationId: InvoicesController_reconcile
      parameters:
        - name: id
          required: true
          in: path
          description: Id del comprobante sin resolver.
          schema:
            type: string
        - name: X-Emissa-Producto
          in: header
          description: >-
            El producto que origina el pedido (`inmos`, por ejemplo). Opcional,
            sólo con API key. Formato `^[a-z0-9-]{1,32}$`; otro valor da `400
            INVALID_INPUT`. Queda en el comprobante, en el consumo y en el
            registro de pedidos.


            Con una key **sin** producto es sólo atribución: no autoriza ni
            restringe nada. Con una key **atada a un producto** el pedido se
            etiqueta con el de la key aunque no mandes la cabecera, y si mandás
            otro valor la respuesta es `403 API_KEY_PRODUCTO_DISTINTO`.
          required: false
          schema:
            type: string
            pattern: ^[a-z0-9-]{1,32}$
            example: inmos
      responses:
        '200':
          description: El comprobante con su estado ya resuelto.
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ComprobanteDto'
              example:
                id: cmt42xc1t001ouri4evkjusrs
                taxpayerId: cmt42x6jb000curi4sz1gyeij
                environment: HOMOLOGACION
                origin: API
                externalReference: null
                cbteTipo: 1
                cbteTipoNombre: FACTURA_A
                letra: A
                concepto: 1
                conceptoNombre: PRODUCTOS
                salePoint: 1
                number: 2
                comprobante: 0001-00000002
                issueDate: '2026-08-22'
                emitter:
                  cuit: '20000000001'
                  name: Estudio Contable SRL
                  vatStatus: Responsable Inscripto
                  address: Av. Corrientes 1234, CABA
                  grossIncomeTax: 901-123456-01
                  activityStartDate: '2020-03-01'
                receiver:
                  docTipo: 80
                  docTipoNombre: CUIT
                  docNro: '30000000007'
                  name: Cliente Mayorista SA
                  vatConditionId: 1
                  vatConditionNombre: IVA_RESPONSABLE_INSCRIPTO
                  address: null
                currency: PES
                exchangeRate: '1'
                totals:
                  netAmount: '1000.00'
                  nonTaxedAmount: '0.00'
                  exemptAmount: '0.00'
                  vatAmount: '210.00'
                  otherTaxesAmount: '0.00'
                  totalAmount: '1210.00'
                vatBreakdown:
                  - vatRateId: 5
                    vatRatePercent: 21
                    baseAmount: '1000.00'
                    vatAmount: '210.00'
                taxes: []
                saleCondition: null
                saleConditionNombre: null
                servicePeriod: null
                status: REJECTED
                cae: null
                caeExpiresAt: null
                cancelledByInvoiceId: null
                associations: []
                optionals: []
                observations: []
                rechazoArca: null
                items:
                  - position: 1
                    description: Servicio de consultoría
                    unit: UNIDADES
                    quantity: '1'
                    unitPrice: '1000'
                    tratamiento: GRAVADO
                    vatRateId: 5
                    vatRatePercent: 21
                    netAmount: '1000.00'
                    vatAmount: '210.00'
                customer:
                  id: cmt42x8pf000ruri4bt2gjtai
                  documentType: CUIT
                  documentNumber: '30000000007'
                  name: Cliente Mayorista SA
                  vatCondition: IVA_RESPONSABLE_INSCRIPTO
                arcaMetadata:
                  service: wsfev1
                  resultado: no existe en ARCA
                  authorized: false
                  reconciliado: true
                createdAt: '2026-08-22T07:51:17.058Z'
        '400':
          description: |-
            Pedido mal formado o inválido.

            `errorCode`: `INVALID_INPUT`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - INVALID_INPUT
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
        '401':
          description: >-
            Falta la credencial o no es válida.


            `errorCode`: `UNAUTHORIZED`, `INVALID_API_KEY`,
            `API_KEY_WRONG_HEADER`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - UNAUTHORIZED
                          - INVALID_API_KEY
                          - API_KEY_WRONG_HEADER
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
        '403':
          description: >-
            La credencial es válida pero no alcanza. Con API key, también: el
            **modo de la key no coincide con el ambiente del contribuyente**.
            Una `emi_test_` contra un contribuyente de `PRODUCCION` nunca emite.


            `errorCode`: `FORBIDDEN`, `API_KEY_INSUFFICIENT_PERMISSIONS`,
            `API_KEY_INSUFFICIENT_SCOPE`, `API_KEY_WRONG_MODE`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - FORBIDDEN
                          - API_KEY_INSUFFICIENT_PERMISSIONS
                          - API_KEY_INSUFFICIENT_SCOPE
                          - API_KEY_WRONG_MODE
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
        '404':
          description: |-
            No existe ese comprobante.

            `errorCode`: `INVOICE_NOT_FOUND`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - INVOICE_NOT_FOUND
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
        '409':
          description: >-
            El comprobante **no está irresuelto**: ya tiene estado final, así
            que no hay nada que reconciliar.


            `errorCode`: `INVOICE_NOTHING_TO_RECONCILE`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - INVOICE_NOTHING_TO_RECONCILE
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
        '429':
          description: |-
            Se excedió el límite de peticiones. **Reintentá con backoff.**

            `errorCode`: `RATE_LIMIT_EXCEEDED`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - RATE_LIMIT_EXCEEDED
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
        '500':
          description: |-
            Error interno. Citá el `requestId` al reportarlo.

            `errorCode`: `INTERNAL_ERROR`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - INTERNAL_ERROR
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
        '502':
          description: |-
            ARCA no está disponible para consultarle. Reintentá.

            `errorCode`: `ARCA_WSFEV1_UNAVAILABLE`, `ARCA_INVALID_RESPONSE`
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/ErrorDto'
                  - type: object
                    properties:
                      errorCode:
                        type: string
                        enum:
                          - ARCA_WSFEV1_UNAVAILABLE
                          - ARCA_INVALID_RESPONSE
          headers:
            X-Request-Id:
              description: >-
                Identificador del pedido. Va en TODA respuesta. Si lo mandás en
                el pedido y respeta `[A-Za-z0-9._:-]{1,128}`, se te devuelve el
                mismo; si no, se genera uno. Es lo que hay que citar en un
                ticket.
              schema:
                type: string
            X-Emissa-Mode:
              description: >-
                `test` o `live`. **Va en toda respuesta autenticada con API
                key**, y es la forma más barata de verificar que no estás
                emitiendo contra el ambiente equivocado. No aparece cuando se
                entra con sesión de panel: ahí el ambiente lo decide cada
                contribuyente, no la credencial.
              schema:
                type: string
                enum:
                  - test
                  - live
      security:
        - api-key: []
        - panel-jwt: []
components:
  schemas:
    ComprobanteDto:
      type: object
      properties:
        id:
          type: string
          example: cmft8x2k30001
          description: >-
            Id interno de Emissa. **No es el número del comprobante**: es lo que
            se usa en `GET /v1/invoices/{id}` y en la anulación.
        taxpayerId:
          type: string
          example: cmfa1b2c30000
          description: Bajo qué contribuyente se emitió.
        externalReference:
          type: string
          nullable: true
          example: COBRO-8842
          description: >-
            La referencia de **tu** sistema, tal como la mandaste al emitir.
            (5.7) `null` si no mandaste ninguna, que es el caso de todo lo
            emitido desde el panel y de todo lo anterior a la 5.7.


            Es **única por contribuyente y ambiente**: reusarla al emitir
            devuelve 409 `EXTERNAL_REFERENCE_ALREADY_USED`, con el id del
            comprobante que ya existe en `details`. Se busca con `GET
            /v1/invoices/search?externalReference=`.
        environment:
          type: string
          enum:
            - HOMOLOGACION
            - PRODUCCION
          example: HOMOLOGACION
          description: >-
            Contra qué ambiente de ARCA se emitió. Un comprobante de
            `HOMOLOGACION` **no tiene validez fiscal**, aunque traiga CAE.
        origin:
          type: string
          nullable: true
          enum:
            - API
            - PANEL
          example: API
          description: >-
            Por dónde entró el comprobante: `API` lo emitió una integración con
            API key, `PANEL` se cargó a mano desde el panel. Se estampa al
            emitir y no cambia.


            `null` en los comprobantes emitidos antes de que se registrara el
            origen. **No quiere decir `PANEL`**: quiere decir que no se sabe, y
            ponerles un valor sería inventar el dato.
        producto:
          type: string
          nullable: true
          example: inmos
          description: >-
            El producto que originó el pedido, de la cabecera
            `X-Emissa-Producto` que mandó quien emitió. Se estampa al emitir y
            **no cambia**: un reintento idempotente con otra etiqueta no lo
            reescribe.


            `null` si no se mandó la cabecera, si se emitió desde el panel o si
            el comprobante es anterior a la etiqueta.
        cbteTipo:
          type: number
          example: 1
          description: >-
            El tipo de comprobante según ARCA: `1` factura A, `6` factura B, `3`
            nota de crédito A, `8` nota de crédito B. **Es el campo
            autoritativo**; `cbteTipoNombre` y `letra` se derivan de él.
        cbteTipoNombre:
          type: string
          nullable: true
          example: FACTURA_A
          description: >-
            La etiqueta de `cbteTipo`. `null` si el código no está en el
            catálogo local — el número igual es correcto.
        letra:
          type: string
          nullable: true
          example: A
          description: >-
            La letra, que sale de `cbteTipo`. Depende de la condición frente al
            IVA de emisor y receptor: entre responsables inscriptos es A, a
            consumidor final es B.
        concepto:
          type: number
          example: 1
          description: >-
            Qué se factura: `1` productos, `2` servicios, `3` ambos. **Con 2 o 3
            ARCA exige `servicePeriod`**, y con 1 lo rechaza.
        conceptoNombre:
          type: string
          nullable: true
          example: PRODUCTOS
          description: La etiqueta de `concepto`.
        salePoint:
          type: number
          example: 1
          description: >-
            El punto de venta con el que se emitió. Cada punto de venta lleva su
            propia numeración correlativa.
        number:
          type: number
          example: 7
          description: >-
            El número correlativo dentro del punto de venta. Lo asigna Emissa
            pidiéndole a ARCA el último autorizado: **no lo elige el cliente**.
        comprobante:
          type: string
          example: 0001-00000007
          description: Punto de venta y número, como se lee un comprobante argentino
        issueDate:
          type: string
          nullable: true
          example: '2026-07-26'
          description: >-
            Fecha del comprobante, `YYYY-MM-DD`. **ARCA no acepta cualquier
            fecha**: tiene una ventana alrededor del día de hoy y exige que la
            numeración sea cronológica dentro del punto de venta.
        emitter:
          description: Quién emite, congelado al momento de emitir.
          allOf:
            - $ref: '#/components/schemas/EmisorDto'
        receiver:
          description: A quién se le factura, congelado al momento de emitir.
          allOf:
            - $ref: '#/components/schemas/ReceptorDto'
        currency:
          type: string
          nullable: true
          example: PES
          description: >-
            Moneda según ARCA: `PES` pesos, `DOL` dólares. Con una moneda
            distinta de `PES` hace falta `exchangeRate`.
        exchangeRate:
          type: string
          example: '1'
          description: >-
            Cotización de la moneda contra el peso. **`1` cuando es `PES`**; con
            otra moneda es la que ARCA va a usar para convertir.
        totals:
          description: Los totales. `totalAmount` tiene que cerrar exacto.
          allOf:
            - $ref: '#/components/schemas/ImportesDto'
        vatBreakdown:
          description: >-
            El IVA por alícuota. Vacío en los comprobantes sin IVA discriminado
            (letra B o C).
          type: array
          items:
            $ref: '#/components/schemas/DesgloseIvaDto'
        taxes:
          description: Los tributos que no son IVA. Vacío si no hay ninguno.
          type: array
          items:
            $ref: '#/components/schemas/TributoDto'
        servicePeriod:
          nullable: true
          description: '`null` en los comprobantes de productos (`concepto` 1).'
          type: object
          allOf:
            - $ref: '#/components/schemas/PeriodoDeServicioDto'
        saleCondition:
          type: string
          nullable: true
          example: CUENTA_CORRIENTE
          description: >-
            La condición de venta tal como se mandó al emitir. `null` en los
            comprobantes emitidos sin informarla — **no se supone `CONTADO`**.
        saleConditionNombre:
          type: string
          nullable: true
          example: Cuenta corriente
          description: >-
            La etiqueta de `saleCondition`, que es la que va impresa en el
            comprobante. `null` cuando no se informó, y también cuando el valor
            guardado no está en el catálogo.
        status:
          type: string
          enum:
            - AUTHORIZED
            - REJECTED
            - PENDING
            - UNKNOWN
            - CANCELLED
          example: AUTHORIZED
          description: >-
            En qué quedó. **`AUTHORIZED` es el único con validez fiscal.**
            `REJECTED`: ARCA lo rechazó y no hay CAE. `PENDING` y `UNKNOWN`: no
            se sabe si ARCA lo autorizó —se cortó la comunicación— y hay que
            reconciliar con `POST /v1/invoices/{id}/reconcile` antes de
            reintentar, o se emite dos veces. `CANCELLED`: se anuló con una nota
            de crédito.
        cae:
          type: string
          nullable: true
          example: '75123456789012'
          description: El CAE. `null` mientras el comprobante no esté autorizado.
        caeExpiresAt:
          type: string
          nullable: true
          example: '2026-08-05'
          description: >-
            Hasta cuándo vale el CAE, `YYYY-MM-DD`. **Es la fecha límite para
            entregar el comprobante al receptor**, no para emitirlo: pasada esa
            fecha el comprobante sigue siendo válido pero se entregó tarde.
        cancelledByInvoiceId:
          type: string
          nullable: true
          description: Id de la nota de crédito que anuló este comprobante.
        associations:
          description: >-
            A qué comprobantes hace referencia. **Una nota de crédito sin esto
            no anula nada.** Vacío en una factura.
          type: array
          items:
            $ref: '#/components/schemas/AsociacionDto'
        optionals:
          description: >-
            Campos opcionales de ARCA, que dependen del régimen. Vacío en el
            caso corriente.
          type: array
          items:
            $ref: '#/components/schemas/OpcionalDto'
        observations:
          description: >-
            Lo que ARCA observó **junto con el CAE**. No son errores: el
            comprobante se autorizó igual. Tratarlas como fallo hace creer que
            la emisión no salió.
          type: array
          items:
            $ref: '#/components/schemas/ObservacionDto'
        rechazoArca:
          nullable: true
          description: >-
            **Por qué ARCA rechazó el comprobante.** Sólo si `status` es
            `REJECTED`; `null` en cualquier otro estado. Es un **rechazo
            fiscal**, no un error de Emissa: ARCA contestó y dijo que no. Los
            textos son los de ARCA, literales, y sirven para que quien emite
            corrija el dato y reintente.


            Con la misma forma que `details.arca` del error
            `ARCA_WSFEV1_REJECTED` y que `data.rechazoArca` de
            `invoice.resolved`. Un `REJECTED` con las dos listas vacías es un
            comprobante que el reconciliar no encontró en ARCA.
          type: object
          allOf:
            - $ref: '#/components/schemas/MotivoDelRechazoDto'
        items:
          description: >-
            El detalle. **No viaja a ARCA**: se guarda para imprimir y para que
            el integrador recupere lo que mandó.
          type: array
          items:
            $ref: '#/components/schemas/ItemDeRespuestaDto'
        customer:
          description: >-
            La ficha del cliente guardada, con su estado **actual**. Difiere de
            `receiver` si el cliente cambió después de emitir.
          allOf:
            - $ref: '#/components/schemas/ClienteDto'
        arcaMetadata:
          type: object
          additionalProperties: true
          description: Crudo de la respuesta de ARCA. Diagnóstico, no contractual.
        createdAt:
          type: string
          example: '2026-07-26T18:30:00.000Z'
          description: >-
            Cuándo se creó el registro en Emissa, en UTC. **No es `issueDate`**:
            la fecha del comprobante es un dato fiscal y ésta es de auditoría.
      required:
        - id
        - taxpayerId
        - externalReference
        - environment
        - origin
        - producto
        - cbteTipo
        - cbteTipoNombre
        - letra
        - concepto
        - conceptoNombre
        - salePoint
        - number
        - comprobante
        - issueDate
        - emitter
        - receiver
        - currency
        - exchangeRate
        - totals
        - vatBreakdown
        - taxes
        - servicePeriod
        - saleCondition
        - saleConditionNombre
        - status
        - cae
        - caeExpiresAt
        - cancelledByInvoiceId
        - associations
        - optionals
        - observations
        - rechazoArca
        - items
        - createdAt
    ErrorDto:
      type: object
      properties:
        statusCode:
          type: number
          example: 401
          description: >-
            El mismo código HTTP de la respuesta. Va repetido en el cuerpo para
            que un cliente que sólo loguea el JSON no pierda el dato.
        errorCode:
          type: string
          example: UNAUTHORIZED
          description: >-
            Siempre una entrada del catálogo de errores. Es el campo por el que
            se ramifica.
        message:
          type: string
          example: No autorizado
          description: '**Siempre un string**, nunca un arreglo.'
        details:
          description: >-
            Detalle adicional. Lo contractual viaja siempre; lo de diagnóstico
            **no viaja en producción**. No ramifiques por este campo.
          oneOf:
            - type: string
            - type: object
              additionalProperties: true
        retryable:
          type: boolean
          example: false
          description: >-
            **¿Tiene sentido reintentar?** Si viene, le gana a cualquier
            heurística basada en el status.


            Existe porque el status no alcanza: `ARCA_TICKET_ALREADY_ISSUED` es
            un 409 que **se resuelve esperando**, y
            `ARCA_COMPUTER_NOT_AUTHORIZED` es un 502 que **no se arregla nunca
            esperando** — hay que autorizar el certificado en ARCA. Un cliente
            que ramifique sólo por 4xx/5xx acierta al revés en los dos.


            **Ausente significa "no lo sabemos"**, y es distinto de `false`: ahí
            corresponde la heurística de siempre. Sólo se declara donde la
            respuesta es certera.
        retryAfterSeconds:
          type: number
          example: 43200
          description: >-
            Cuántos segundos esperar antes de reintentar. **Sólo cuando el
            número es real** —el vencimiento de un ticket, la ventana de un
            límite—, nunca una estimación.


            El 429 y el bloqueo del segundo factor ya lo mandaban como
            `details.reintentarEnSegundos`, en castellano y anidado. Sigue ahí
            para no romper a nadie, y ahora **también arriba**, con el nombre
            del resto del sobre.
        requestId:
          type: string
          example: 0f2c1a5e-1d9b-4c7a-9a55-7f1a2b3c4d5e
          description: >-
            El mismo valor de la cabecera `X-Request-Id`. Es lo que hay que
            pegar en un ticket.
        timestamp:
          type: string
          example: '2026-07-26T18:30:00.000Z'
          description: Cuándo falló, en UTC. Sirve para ubicarlo en los logs.
        path:
          type: string
          example: /v1/invoices/authorize
          description: La ruta que se pidió, sin el host ni la query.
      required:
        - statusCode
        - errorCode
        - message
        - timestamp
        - path
    EmisorDto:
      type: object
      properties:
        cuit:
          type: string
          example: '20437136697'
          description: El CUIT que emite, sin guiones.
        name:
          type: string
          example: Estudio Contable SRL
          description: Razón social, como va impresa.
        vatStatus:
          type: string
          example: RESPONSABLE_INSCRIPTO
          description: >-
            Condición frente al IVA del emisor. Junto con la del receptor decide
            qué letra de comprobante corresponde.
        address:
          type: string
          nullable: true
          example: Av. Corrientes 1234, CABA
          description: >-
            Domicilio comercial. `null` si el contribuyente no lo tenía cargado
            al emitir: el comprobante sale igual pero **incompleto para la RG
            1415**.
        grossIncomeTax:
          type: string
          nullable: true
          example: 901-123456-01
          description: Ingresos Brutos. Obligatorio en el papel (RG 1415).
        activityStartDate:
          type: string
          nullable: true
          example: '2020-03-01'
          description: Inicio de actividades. Obligatorio en el papel (RG 1415).
      required:
        - cuit
        - name
        - vatStatus
        - address
        - grossIncomeTax
        - activityStartDate
    ReceptorDto:
      type: object
      properties:
        docTipo:
          type: number
          example: 80
          description: 80 CUIT, 86 CUIL, 96 DNI, 99 CF
        docTipoNombre:
          type: string
          nullable: true
          example: CUIT
          description: La etiqueta de `docTipo`, para no mantener la tabla afuera.
        docNro:
          type: string
          example: '30500010912'
          description: >-
            El número del documento, sin guiones. Con `docTipo` 99 (consumidor
            final) va `0`.
        name:
          type: string
          example: Cliente SA
          description: Nombre o razón social del receptor, como va impreso.
        vatConditionId:
          type: number
          example: 1
          description: >-
            La condición frente al IVA **del receptor**, según el catálogo de
            ARCA. Es lo que decide si corresponde factura A o B: a un
            responsable inscripto se le emite A, a un consumidor final o
            monotributista, B.
        vatConditionNombre:
          type: string
          nullable: true
          example: IVA Responsable Inscripto
          description: La etiqueta de `vatConditionId`.
        address:
          type: string
          nullable: true
          example: Av. Rivadavia 500, CABA
          description: Domicilio del receptor. Opcional.
      required:
        - docTipo
        - docTipoNombre
        - docNro
        - name
        - vatConditionId
        - vatConditionNombre
        - address
    ImportesDto:
      type: object
      properties:
        netAmount:
          type: string
          example: '1000.00'
          description: >-
            Lo que paga IVA, **antes** del IVA. Es la base sobre la que se
            calcula el desglose.
        nonTaxedAmount:
          type: string
          example: '0.00'
          description: >-
            Conceptos que **no** están alcanzados por el IVA, como una
            percepción que se traslada. No confundir con exento.
        exemptAmount:
          type: string
          example: '0.00'
          description: >-
            Lo alcanzado por el IVA pero con **exención**: libros, leche,
            ciertos servicios de salud. Está gravado a tasa cero, que no es lo
            mismo que no gravado.
        vatAmount:
          type: string
          example: '210.00'
          description: El IVA total. Igual a la suma de `vatBreakdown[].vatAmount`.
        otherTaxesAmount:
          type: string
          example: '0.00'
          description: >-
            Todo lo que no es IVA: Ingresos Brutos, internos, tasas. Igual a la
            suma de `taxes[].amount`.
        totalAmount:
          type: string
          example: '1210.00'
          description: >-
            Lo que el receptor paga. **Suma exacta de los cinco anteriores**, y
            ARCA lo verifica.
      required:
        - netAmount
        - nonTaxedAmount
        - exemptAmount
        - vatAmount
        - otherTaxesAmount
        - totalAmount
    DesgloseIvaDto:
      type: object
      properties:
        vatRateId:
          type: number
          example: 5
          description: >-
            El **id** de alícuota de ARCA, no el porcentaje: `5` es 21 %, `4` es
            10,5 %, `3` es 0 %. Mandar `21` acá es el error más común, y ARCA lo
            rechaza porque `21` no existe como id.
        vatRatePercent:
          type: number
          nullable: true
          example: 21
          description: >-
            El porcentaje que corresponde a ese id, para no tener que mantener
            la tabla del lado del cliente. `null` si el id no está en el
            catálogo local — el id igual es válido.
        baseAmount:
          type: string
          example: '1000.00'
          description: Sobre cuánto se calculó el IVA de esta alícuota.
        vatAmount:
          type: string
          example: '210.00'
          description: El IVA de esta alícuota. La suma de todas da `totals.vatAmount`.
      required:
        - vatRateId
        - vatRatePercent
        - baseAmount
        - vatAmount
    TributoDto:
      type: object
      properties:
        taxId:
          type: number
          example: 2
          description: >-
            El código de tributo de ARCA. `1` nacional, `2` provincial, `3`
            municipal, `4` interno, `99` otro.
        description:
          type: string
          nullable: true
          example: Ingresos Brutos CABA
          description: Texto libre para identificarlo en el comprobante impreso.
        baseAmount:
          type: string
          example: '1000.00'
          description: Sobre cuánto se calculó.
        rate:
          type: string
          nullable: true
          example: '3.0000'
          description: >-
            La alícuota aplicada, en porcentaje y con hasta 4 decimales. `null`
            cuando el tributo es un monto fijo y no sale de un porcentaje.
        amount:
          type: string
          example: '30.00'
          description: El importe del tributo. Suma a `totals.otherTaxesAmount`.
      required:
        - taxId
        - description
        - baseAmount
        - rate
        - amount
    PeriodoDeServicioDto:
      type: object
      properties:
        from:
          type: string
          nullable: true
          example: '2026-07-01'
          description: Desde cuándo se prestó el servicio, `YYYY-MM-DD`.
        to:
          type: string
          nullable: true
          example: '2026-07-31'
          description: Hasta cuándo, `YYYY-MM-DD`. No puede ser anterior a `from`.
        paymentDueDate:
          type: string
          nullable: true
          example: '2026-08-10'
          description: >-
            Vencimiento del pago, `YYYY-MM-DD`. Es un dato del comprobante, no
            una condición que el sistema controle: nadie se entera si se paga
            después.
      required:
        - from
        - to
        - paymentDueDate
    AsociacionDto:
      type: object
      properties:
        cbteTipo:
          type: number
          example: 1
          description: El `CbteTipo` del comprobante asociado (`1` factura A, etc.).
        salePoint:
          type: number
          example: 1
          description: El punto de venta del comprobante asociado.
        number:
          type: number
          example: 7
          description: Su número correlativo, sin el punto de venta adelante.
        cuit:
          type: string
          nullable: true
          example: '20437136697'
          description: >-
            El CUIT del emisor del comprobante asociado. Sólo hace falta cuando
            no es el mismo que emite este.
        issueDate:
          type: string
          nullable: true
          example: '2026-07-20'
          description: Fecha del comprobante asociado, `YYYY-MM-DD`.
      required:
        - cbteTipo
        - salePoint
        - number
        - cuit
        - issueDate
    OpcionalDto:
      type: object
      properties:
        optionalId:
          type: string
          example: '2'
          description: 'El Id es texto: lo define el WSDL'
        value:
          type: string
          example: '20437136697'
          description: >-
            El valor, **siempre como texto**, aunque represente un número o una
            fecha. Lo define el WSDL de ARCA para cada `optionalId`.
      required:
        - optionalId
        - value
    ObservacionDto:
      type: object
      properties:
        code:
          type: number
          example: 10048
          description: >-
            El código de observación de ARCA. Es lo estable para ramificar; el
            texto cambia sin aviso.
        message:
          type: string
          example: El campo Condicion Frente al IVA...
          description: >-
            Qué observó ARCA, en sus palabras. **No es un error**: el
            comprobante ya tiene CAE.
      required:
        - code
        - message
    MotivoDelRechazoDto:
      type: object
      properties:
        errores:
          description: >-
            Los `Errors` de WSFEv1: **por qué ARCA no autorizó**. Hasta 20.
            Puede venir vacío: cuando ARCA no manda `Errors`, el motivo está en
            `observaciones`.
          type: array
          items:
            $ref: '#/components/schemas/CodigoYTextoDeArcaDto'
        observaciones:
          description: >-
            Las `Observaciones` de ARCA sobre este comprobante. Hasta 20. **No
            son lo mismo que `errores`**: en un comprobante autorizado son
            avisos, y en uno rechazado a veces son el único motivo.
          type: array
          items:
            $ref: '#/components/schemas/CodigoYTextoDeArcaDto'
      required:
        - errores
        - observaciones
    ItemDeRespuestaDto:
      type: object
      properties:
        position:
          type: number
          example: 1
          description: El orden en que va impreso. Arranca en 1.
        description:
          type: string
          example: Servicio de consultoría
          description: Qué se vendió, como va impreso.
        unit:
          type: string
          example: UNIDADES
          description: 'Unidad de medida: `UNIDADES`, `HORAS`, `KILOGRAMOS`, etc.'
        quantity:
          type: string
          example: '1'
          description: >-
            Cantidad, como **string** para no perder precisión al parsear.
            Admite hasta 6 decimales.
        unitPrice:
          type: string
          example: '1000'
          description: Precio unitario **sin IVA**, como string.
        tratamiento:
          type: string
          example: GRAVADO
          description: >-
            Cómo trata el IVA esta línea: `GRAVADO`, `NO_GRAVADO` o `EXENTO`. Es
            lo que decide a qué total de `totals` suma.
        vatRateId:
          type: number
          nullable: true
          example: 5
          description: >-
            El id de alícuota de ARCA. `null` en las líneas no gravadas o
            exentas, donde no hay alícuota que aplicar.
        vatRatePercent:
          type: number
          nullable: true
          example: 21
          description: El porcentaje de `vatRateId`, para no mantener la tabla afuera.
        netAmount:
          type: string
          example: '1000.00'
          description: 'Neto de la línea: `quantity × unitPrice`, sin IVA.'
        vatAmount:
          type: string
          example: '210.00'
          description: El IVA de esta línea. `0.00` si no está gravada.
      required:
        - position
        - description
        - unit
        - quantity
        - unitPrice
        - tratamiento
        - vatRateId
        - vatRatePercent
        - netAmount
        - vatAmount
    ClienteDto:
      type: object
      properties:
        id:
          type: string
          example: cms5182zy00hkurgsa6512cha
          description: Id del cliente guardado, para reusarlo en otra emisión.
        documentType:
          type: string
          example: '80'
          description: 'Tipo de documento: `80` CUIT, `86` CUIL, `96` DNI, `99` CF.'
        documentNumber:
          type: string
          example: '30500010912'
          description: El número, sin guiones.
        name:
          type: string
          example: Cliente SA
          description: Nombre o razón social, con el último valor conocido.
        vatCondition:
          type: string
          nullable: true
          example: IVA Responsable Inscripto
          description: >-
            Su condición frente al IVA. `null` si nunca se validó contra el
            padrón ni se declaró.
      required:
        - id
        - documentType
        - documentNumber
        - name
        - vatCondition
    CodigoYTextoDeArcaDto:
      type: object
      properties:
        codigo:
          type: number
          example: 10016
          description: >-
            El código de ARCA. Es lo estable para ramificar; el texto cambia sin
            aviso.
        mensaje:
          type: string
          example: >-
            El campo DocNro es incorrecto. Debe ser mayor o igual a 0 y menor o
            igual a 99999999999.
          description: >-
            **El texto de ARCA, literal.** Emissa no lo traduce ni lo reescribe;
            sólo lo recorta a 500 caracteres.
      required:
        - codigo
        - mensaje
  securitySchemes:
    api-key:
      type: apiKey
      in: header
      name: X-API-Key
      description: >-
        API key de integración. **El modo va en el prefijo**: `emi_test_` opera
        contra homologación, `emi_live_` contra producción. Después, 64
        hexadecimales.
    panel-jwt:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: Sesión del panel. **No** es donde va la API key.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.