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

# Emision Masiva

> Acumula facturas en un lote y enviálas juntas al SIAT en paquetes comprimidos.

La emision masiva es la tercera modalidad de emision del SIAT. Abris un lote sobre un punto de venta, emitis normalmente, y al cerrar el lote todas las facturas viajan juntas al SIAT comprimidas en uno o mas paquetes.

Sirve cuando emitis mucho volumen y no necesitas la confirmacion del SIAT factura por factura: en vez de una llamada por documento, se hace una por paquete.

<Note>
  **No confundir con `/invoices/batch`.** Ese endpoint manda hasta 20 facturas en un request, pero cada una se envia al SIAT por separado y en linea. La emision masiva es otra modalidad ante el SIAT, con su propio codigo de emision y su propio ciclo.
</Note>

## Las tres modalidades

| Modalidad      | Codigo  | Cuando                                | Evento significativo |
| -------------- | ------- | ------------------------------------- | -------------------- |
| En linea       | `1`     | Emision normal, una por una           | No                   |
| Fuera de linea | `2`     | Contingencia — el SIAT no responde    | Si, y admite CAFC    |
| **Masiva**     | **`3`** | **Volumen alto, con SIAT disponible** | **No**               |

La masiva **se emite en linea**: necesita el SIAT operativo. Si el punto de venta entra en contingencia, las facturas nuevas salen como contingencia aunque haya un lote abierto; las que ya entraron al lote quedan intactas y se envian cuando lo cierres. Para contingencia, ver [Contingencia](/api/events).

## Ciclo de un lote

<Steps>
  <Step title="Abrir el lote">
    `POST /api/v1/massive` sobre el punto de venta.
  </Step>

  <Step title="Emitir normalmente">
    Las facturas se crean con `POST /api/v1/invoices` como siempre. Mientras el lote este abierto quedan en estado `MASSIVE_PENDING` — con su CUF definitivo, listas para imprimir y entregar — pero todavia no viajaron al SIAT.
  </Step>

  <Step title="Cerrar el lote">
    `POST /api/v1/massive/end`. Se arman los paquetes, se envian y se validan. Cada factura queda `ACCEPTED` o `REJECTED` con su motivo.
  </Step>

  <Step title="Rectificar, si hubo rechazos">
    `POST /api/v1/massive/rectify` regenera las rechazadas y las devuelve a la cola. Despues volves a cerrar.
  </Step>
</Steps>

## Abrir un lote

`POST /api/v1/massive`

| Parametro     | Ubicacion | Tipo    | Req | Descripcion                                                    |
| ------------- | --------- | ------- | --- | -------------------------------------------------------------- |
| `X-API-Key`   | Header    | string  | Si  | Tu API Key                                                     |
| `posId`       | Body      | string  | Si  | UUID del punto de venta                                        |
| `sector`      | Body      | integer | No  | Sector documental del lote. Por defecto, el del punto de venta |
| `invoiceType` | Body      | integer | No  | Tipo de documento SIAT. Por defecto `1` (factura)              |

Es idempotente: si el punto de venta ya tiene un lote abierto, la llamada devuelve ese lote en vez de crear otro. Un punto de venta no puede tener dos lotes abiertos a la vez.

<CodeGroup>
  ```bash cURL theme={"system"}
  curl -X POST https://sandbox.cucu.bo/api/v1/massive \
    -H "Content-Type: application/json" \
    -H "X-API-Key: YOUR_API_KEY" \
    -d '{
      "posId": "660e8400-e29b-41d4-a716-446655440004"
    }'
  ```

  ```javascript JavaScript theme={"system"}
  const response = await fetch('https://sandbox.cucu.bo/api/v1/massive', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': 'YOUR_API_KEY'
    },
    body: JSON.stringify({
      posId: '660e8400-e29b-41d4-a716-446655440004'
    })
  });
  ```
</CodeGroup>

```json Respuesta 201 theme={"system"}
{
  "success": true,
  "message": "Lote masivo abierto: las facturas que emitas ahora entran al lote hasta que lo cierres",
  "data": {
    "batchId": "8f14e45f-ceea-467a-9575-4c4d0a8f4c23",
    "batchCode": "K3M9PQZ7XR2WNB4TV",
    "posId": "660e8400-e29b-41d4-a716-446655440004",
    "sector": 1,
    "invoiceType": 1,
    "status": "OPEN",
    "closedAt": null
  }
}
```

Si el sector no esta soportado o la empresa no lo tiene autorizado ante el SIN, la respuesta es `422` con `SECTOR_NOT_SUPPORTED` o `SECTOR_NOT_AUTHORIZED`. La validacion se hace al abrir a proposito: descubrirlo al cerrar significaria tener el lote entero ya emitido.

## Cerrar el lote

`POST /api/v1/massive/end`

| Parametro   | Ubicacion | Tipo   | Req | Descripcion             |
| ----------- | --------- | ------ | --- | ----------------------- |
| `X-API-Key` | Header    | string | Si  | Tu API Key              |
| `posId`     | Body      | string | Si  | UUID del punto de venta |

<Warning>
  En lotes grandes esta llamada puede tardar varios minutos: envia y valida cada paquete contra el SIAT. Configura el timeout de tu cliente HTTP en consecuencia.
</Warning>

Es reentrante. Si un cierre se corta a mitad, volver a llamarlo retoma donde quedo: los paquetes ya validados no se reenvian.

```json Respuesta 200 theme={"system"}
{
  "success": true,
  "message": "Lote cerrado: 1250 factura(s) aceptadas por SIAT en 3 paquete(s)",
  "data": {
    "batchId": "8f14e45f-ceea-467a-9575-4c4d0a8f4c23",
    "batchCode": "K3M9PQZ7XR2WNB4TV",
    "facturasEnLote": 1250,
    "packsEnviados": 3,
    "packsValidados": 3,
    "packsRechazados": 0,
    "facturasAceptadas": 1250,
    "facturasRechazadas": 0
  }
}
```

El `message` distingue tres desenlaces que no hay que confundir:

* **Sin facturas** — el lote se cerro vacio, no habia nada que enviar.
* **Todo aceptado** — `facturasRechazadas` y `packsRechazados` en `0`.
* **Con rechazos** — parte del lote quedo `REJECTED`; hay que rectificar.

## Ver el lote

`GET /api/v1/massive/{posId}`

Devuelve el lote abierto del punto de venta con el detalle de cada paquete: cuantas facturas lleva, el `receptionCode` que devolvio el SIAT y su estado.

```json Respuesta 200 theme={"system"}
{
  "success": true,
  "data": {
    "batchId": "8f14e45f-ceea-467a-9575-4c4d0a8f4c23",
    "batchCode": "K3M9PQZ7XR2WNB4TV",
    "status": "CLOSED",
    "packs": [
      {
        "packageId": "c1a2b3d4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "sequence": 1,
        "invoiceCount": 500,
        "receptionCode": "1899274638201",
        "status": "VALIDATED",
        "errorDetail": null
      },
      {
        "packageId": "d2b3c4e5-6f7a-4b8c-9d0e-1f2a3b4c5d6e",
        "sequence": 2,
        "invoiceCount": 250,
        "receptionCode": "1899274638455",
        "status": "REJECTED",
        "errorDetail": "[1009] LA FECHA DE EMISION ENVIADA EN EL XML NO ES VALIDA"
      }
    ]
  }
}
```

Estados de un paquete:

| Estado      | Significa                                               |
| ----------- | ------------------------------------------------------- |
| `PENDING`   | Armado, todavia no enviado                              |
| `SENT`      | El SIAT lo recibio y dio `receptionCode`; falta validar |
| `VALIDATED` | El SIAT lo dio por bueno                                |
| `REJECTED`  | El SIAT rechazo facturas del paquete                    |
| `ERROR`     | Fallo el armado o el envio                              |

## Rectificar rechazos

`POST /api/v1/massive/rectify`

| Parametro   | Ubicacion | Tipo   | Req | Descripcion             |
| ----------- | --------- | ------ | --- | ----------------------- |
| `X-API-Key` | Header    | string | Si  | Tu API Key              |
| `posId`     | Body      | string | Si  | UUID del punto de venta |

A las facturas que el SIAT rechazo se les regenera el CUF, el XML, la firma y el QR contra el CUFD vigente, y vuelven a la cola del lote. Despues hay que cerrar de nuevo con `/massive/end` para reenviarlas.

Las facturas ya aceptadas no se tocan: su CUF esta validado por el SIAT y regenerarlo cambiaria un documento fiscal firme.

```json Respuesta 200 theme={"system"}
{
  "success": true,
  "message": "12 factura(s) regeneradas y devueltas al lote: cerrar de nuevo con /massive/end para reenviarlas",
  "data": {
    "batchId": "8f14e45f-ceea-467a-9575-4c4d0a8f4c23",
    "batchCode": "K3M9PQZ7XR2WNB4TV",
    "facturasRectificadas": 12
  }
}
```

## Estados de la factura en masiva

| Estado            | Cuando                                                    |
| ----------------- | --------------------------------------------------------- |
| `MASSIVE_PENDING` | Emitida dentro del lote abierto; todavia no viajo al SIAT |
| `ACCEPTED`        | El paquete se valido y esta factura no tuvo observaciones |
| `REJECTED`        | El SIAT la observo; el motivo queda en la factura         |

Una factura en `MASSIVE_PENDING` ya tiene su CUF definitivo y su QR: podes entregarla e imprimirla. El SIAT validara ese mismo documento cuando cierres el lote.

## Limites

| Limite                            | Valor      |
| --------------------------------- | ---------- |
| Facturas por paquete              | 500        |
| Paquetes por lote                 | Sin limite |
| Lotes abiertos por punto de venta | 1          |

Si el lote tiene mas facturas que el limite por paquete, se parte solo en tantos paquetes como haga falta.
