# Enviar lotes de serviços

> Como criar e atualizar lotes de serviços a partir do seu sistema, e como tratar os erros.

URL canônica: https://apis.cortecloud.com.br/docs/guias/integracao-erp/lotes/

Um **lote** agrupa [serviços](https://apis.cortecloud.com.br/docs/comecando/conceitos.md#servico) da central para a produção. A sua integração monta o lote no seu sistema e o envia ao Cortecloud, que guarda o agrupamento e o mostra à produção e ao PCP. Um serviço pode estar em vários lotes, e o lote não altera o serviço.

Duas rotas, ambas exigem autenticação por central ([HMAC](https://apis.cortecloud.com.br/docs/comecando/autenticacao.md)):

| Rota | Uso |
|---|---|
| [`POST /batches`](https://apis.cortecloud.com.br/docs/swagger#/Batches/createBatch) | Cria o lote e devolve o `id`. |
| [`PUT /batches/{id}`](https://apis.cortecloud.com.br/docs/swagger#/Batches/updateBatch) | Atualiza o lote pelo `id`. |

## Criar um lote {#criar-um-lote}

```json
{
  "internal_code": "LOTE-0042",
  "description": "Turno da manhã",
  "services": [
    { "id": 1234 },
    { "internal_code": "PED-000123" }
  ]
}
```

- `internal_code` é o código do lote no seu sistema e é obrigatório. Não pode se repetir na central.
- `description` é opcional.
- `services` é obrigatório na criação, com 1 a 100 serviços por requisição.
- Cada serviço é identificado por `id` ou por `internal_code`; enviar os dois no mesmo serviço é recusado com `400`.

A resposta `201` traz o `id` do lote. **Guarde-o**: a atualização exige esse `id`.

## Atualizar um lote {#atualizar-um-lote}

Só os campos enviados mudam, e é preciso enviar ao menos um:

| Campo | Efeito |
|---|---|
| `internal_code` | Troca o código do lote. Ausente preserva. |
| `description` | Troca a descrição. Ausente preserva; `null` apaga. |
| `services` | Substitui a lista inteira: os serviços ausentes saem do lote, e `[]` o esvazia. Ausente preserva os serviços. |

```json
{ "services": [{ "id": 1234 }, { "id": 1235 }] }
```

A atualização sobrescreve as edições feitas no Cortecloud. Repetir a mesma chamada não muda o resultado.

## Quais serviços entram {#quais-servicos-entram}

O serviço precisa ser produzido na central da requisição e estar liberado para produção (status `7`, `13`, `21` ou `22`). Serviço concluído (`9`) ou ainda não liberado é recusado.

O `internal_code` de serviço que casa com mais de um serviço da central é ambíguo, e o lote inteiro é recusado. Nesse caso, envie o `id`. A busca olha serviços em todos os status, então um serviço antigo com o mesmo código também causa ambiguidade.

## Erros {#erros}

| Status | Quando |
|---|---|
| `400` | Corpo fora do formato: sem `internal_code` ou sem `services` na criação, corpo vazio na atualização, serviço sem `id` nem `internal_code` ou com os dois, mais de 100 serviços. |
| `404` | Na atualização, lote inexistente ou de outra central. |
| `409` | Já existe lote com esse `internal_code` na central. |
| `422` | Algum serviço não pode compor o lote. |

Em `422`, o campo `problems` lista cada serviço recusado e o motivo:

```json
{
  "status": 422,
  "problems": [
    { "ref": { "id": 1234 }, "reason": "finished" },
    { "ref": { "internalCode": "PED-000123" }, "reason": "ambiguous" }
  ]
}
```

| `reason` | Significado |
|---|---|
| `not_found` | Serviço inexistente ou de outra central. |
| `ambiguous` | `internal_code` com mais de um serviço; envie o `id`. |
| `finished` | Serviço concluído. |
| `not_released` | Serviço ainda não liberado para produção. |
| `duplicated` | Serviço repetido na lista. |

Um lote com serviço recusado não é criado nem alterado.

:::caution Resposta perdida na criação
Se a resposta do `POST` se perder, uma nova tentativa recebe `409` sem o `id` do lote. Nesse caso, procure o suporte para recuperá-lo.
:::
