> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.api.corpx.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.api.corpx.com/_mcp/server.

# Guia de PIX em lote

O **PIX em lote** resolve o caso em que você tem uma planilha — folha de
pagamento, repasse a fornecedores, comissões, reembolsos — e quer pagar tudo de
uma vez sem escrever um loop de `POST /pix/out`. Você sobe as linhas, a API
confere chaves, duplicidades, saldo e limites **antes de qualquer débito**, e
só depois do seu aceite explícito cada linha vira um PIX out comum, com os
mesmos limites, políticas, webhooks e lançamentos no extrato de
[PIX Out](/baas/guias/pagar/pix-out).

> **Quando usar lote e quando usar PIX avulso**
>
> Use o lote quando as linhas já existem juntas (um arquivo, um fechamento) e
> você quer um resumo para aprovar e um relatório único no fim. Use
> `POST /pix/out` quando o pagamento nasce de um evento isolado e precisa de
> resposta síncrona. Os dois caminhos geram o mesmo PIX e os mesmos webhooks
> `pix.out.*`.

## Como funciona

```mermaid
flowchart LR
  T["GET template"] --> C["POST batches<br />DRAFT"]
  C --> I["POST items/csv<br />PUT items"]
  I --> R["POST review<br />REVIEWING → REVIEWED"]
  R -->|"itens INVALID"| X["GET items/export?status=invalid<br />corrigir e reenviar"]
  X --> I
  R -->|"acknowledged: true"| D["POST dispatch<br />QUEUED → PROCESSING"]
  D --> P["1 PixOut por item<br />pix.out.completed / failed"]
  P --> F["COMPLETED | PARTIAL_FAILED | FAILED<br />pix.batch.completed"]
  F --> Z["POST receipts (ZIP)<br />GET items/export?status=failed"]
```

Três decisões de desenho que valem para toda a superfície:

* **Somente API (M2M).** As rotas exigem credencial com escopo
  `pix_out.create` (ou `api2/write` legado). Token de usuário humano não
  cria nem dispara lote; o Portal e o Internet Banking não expõem essa
  superfície. Uma credencial só-leitura (`read`) consegue **acompanhar**
  lotes (`GET`), baixar o modelo e comprovantes, mas não cria, edita nem
  dispara.
* **Habilitação em dois níveis.** A CorpX liga a feature `pix_batch` no
  tenant **e** a seção `pixBatch.enabled = true` na policy da conta. Sem a
  primeira a API responde `403 feature_disabled`; sem a segunda,
  `403 pix_batch_account_disabled`. Peça a ativação ao seu gerente de conta
  informando as contas que vão operar em lote.
* **Nada sai sem conferência e aceite.** O dispatch exige lote `REVIEWED`,
  zero itens inválidos, saldo suficiente e `acknowledged: true` no corpo. O
  resumo da conferência existe para ser mostrado a quem aprova.

### Pré-requisitos

| Item                                                                                                                | Onde ver                                                          |
| ------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------- |
| Credencial M2M com escopo `pix_out.create` restrita às contas que vão pagar                                         | [Autenticação](/baas/guias/autenticacao/oauth2)                   |
| Feature `pix_batch` no tenant e `pixBatch.enabled` na policy da conta (ativação CorpX)                              | [Políticas](/baas/guias/autenticacao/politicas)                   |
| Assinatura de webhook para `pix.batch.completed` e, se quiser granularidade, `pix.out.completed` / `pix.out.failed` | [Webhooks](/baas/guias/conta/webhooks)                            |
| Se a conta usa travas ou PIN transacional, os cabeçalhos de cash out no dispatch                                    | [Segurança da conta](/baas/guias/autenticacao/seguranca-da-conta) |

## Início rápido

Cinco chamadas levam um arquivo do zero ao pagamento. Nos exemplos,
`$BASE` é `https://tenant.api.corpx.com/v1/accounts/{accountId}` e os
cabeçalhos `Authorization: Bearer $TOKEN` e `X-Tenant-Id` estão implícitos.

#### Baixe o modelo

```bash
curl "$BASE/pix/batches/template" -o pix-lote-modelo.csv
```

#### Crie o lote

```bash
curl -X POST "$BASE/pix/batches" \
  -H "Idempotency-Key: folha-2026-09" \
  -H "Content-Type: application/json" \
  -d '{"name": "Folha de setembro"}'
# 201 → {"batchId": "pxb_…", "status": "DRAFT", …}
```

#### Suba as linhas

```bash
curl -X POST "$BASE/pix/batches/$BATCH/items/csv" \
  -H "Content-Type: text/csv" \
  --data-binary @folha-setembro.csv
# 200 com o lote e os itens; 400 com errors[] se alguma linha estiver errada (nada é salvo)
```

#### Confira

```bash
curl -X POST "$BASE/pix/batches/$BATCH/review"      # 202, status REVIEWING
curl "$BASE/pix/batches/$BATCH"                      # repita até status REVIEWED; leia "review"
```

#### Aprove e dispare

```bash
curl -X POST "$BASE/pix/batches/$BATCH/dispatch" \
  -H "Content-Type: application/json" \
  -d '{"acknowledged": true}'
# 202, status QUEUED. Aguarde o webhook pix.batch.completed.
```

## Rotas

Todas sob `/v1/accounts/{accountId}/pix/batches`. A coluna **Escopo** indica
o que a credencial precisa ter; `read` acompanha, `pix_out.create` opera.

| Método e rota                           | Escopo                               | O que faz                                                                                      |
| --------------------------------------- | ------------------------------------ | ---------------------------------------------------------------------------------------------- |
| `GET /template`                         | `read`                               | Baixa `pix-lote-modelo.csv` com as colunas e duas linhas de exemplo.                           |
| `POST /`                                | `pix_out.create`                     | Cria um lote `DRAFT`. `Idempotency-Key` obrigatório.                                           |
| `GET /`                                 | `read`                               | Lista lotes da conta (`status`, `page`, `pageSize`).                                           |
| `GET /{batchId}`                        | `read`                               | Lote, `review`, `statistics` e itens paginados (`status`, `reviewStatus`, `page`, `pageSize`). |
| `PUT /{batchId}/items`                  | `pix_out.create`                     | Adiciona de 1 a 50 itens em JSON.                                                              |
| `POST /{batchId}/items/csv`             | `pix_out.create`                     | Adiciona itens a partir de um CSV (corpo cru, até 5 MiB).                                      |
| `DELETE /{batchId}/items/{itemId}`      | `pix_out.create`                     | Remove um item.                                                                                |
| `POST /{batchId}/review`                | `pix_out.create`                     | Inicia a conferência assíncrona.                                                               |
| `POST /{batchId}/dispatch`              | `pix_out.create`                     | Dispara os pagamentos. Exige `acknowledged: true`.                                             |
| `GET /{batchId}/items/export`           | `read`                               | CSV de correção (`status=failed` padrão, `invalid`, `completed`, `all`; `separator=comma`).    |
| `GET /{batchId}/items/{itemId}/receipt` | `read`                               | PDF do comprovante de um item `COMPLETED`.                                                     |
| `POST /{batchId}/receipts`              | `pix_out.create` ou `exports.create` | Job que gera o ZIP com todos os comprovantes.                                                  |

A referência campo a campo está em
[Referência da API → PIX em lote](/baas/referencia).

## 1. O arquivo

`GET .../pix/batches/template` devolve `pix-lote-modelo.csv`: UTF-8 com BOM e
separador `;`, que o Excel em português abre direto. O conteúdo é exatamente
este:

```csv
identifier;amount;description;pixKeyType;pixKey;receiverName;receiverDocument;bankIspb;bankCode;branch;accountNumber;accountType
folha-set-001;1436.85;Pagamento setembro;CPF;12345678909;;;;;;;
folha-set-002;2500.00;Fornecedor;;;EMPRESA EXEMPLO LTDA;12345678000195;60701190;341;0001;123456;CHECKING
```

Cada linha é **um** PIX e preenche **um** dos dois blocos de destinatário:

| Coluna                                                                                               | Regra                                                                                                                                                                                                        |
| ---------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `identifier`                                                                                         | Obrigatório. Sua chave de negócio, até 38 caracteres, única no lote **e** entre os pagamentos vivos da conta (mesma regra do `identifier` do PIX out). Vira o `identifier` do pagamento e do extrato.        |
| `amount`                                                                                             | Obrigatório e positivo. Aceita `1234.56`, `1.234,56` ou `R$ 1.234,56`.                                                                                                                                       |
| `description`                                                                                        | Opcional, até 140 caracteres. Vai no PIX como descrição.                                                                                                                                                     |
| `pixKeyType`, `pixKey`                                                                               | **Modo chave.** `pixKey` liga o modo; `pixKeyType` (`CPF`, `CNPJ`, `EMAIL`, `PHONE`, `EVP`) é opcional e detectado pelo formato. Nome, documento e banco do recebedor são resolvidos no DICT na conferência. |
| `receiverName`, `receiverDocument`, `bankIspb`, `bankCode`, `branch`, `accountNumber`, `accountType` | **Modo dados bancários.** Nome, CPF/CNPJ, ISPB **ou** código COMPE, agência, conta com dígito e tipo (`CHECKING`, `SAVINGS`, `PAYMENT`, `SALARY`; vazio = `CHECKING`).                                       |

> **Regras do parser que evitam retrabalho**
>
> * O cabeçalho é casado por **nome**, sem importar ordem ou caixa; colunas que
>   você não usa podem ficar vazias ou ser omitidas.
> * `;` e `,` são detectados automaticamente; aspas seguem o padrão CSV.
> * As colunas `errorCode` e `errorMessage` do arquivo de correção são
>   ignoradas na entrada: o arquivo exportado sobe de volta como está.
> * Linha com `pixKey` **e** dados bancários ao mesmo tempo é rejeitada —
>   escolha um modo por linha.

## 2. Criar o lote

```bash
curl -X POST "https://tenant.api.corpx.com/v1/accounts/{accountId}/pix/batches" \
  -H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa" \
  -H "Idempotency-Key: folha-2026-09" \
  -H "Content-Type: application/json" \
  -d '{"name": "Folha de setembro"}'
```

* `Idempotency-Key` (até 128 caracteres) é **obrigatório**; repetir a mesma
  chave na mesma conta devolve o lote existente com `200` em vez de criar
  outro. Use algo que identifique o fechamento (`folha-2026-09`), não um
  UUID aleatório — assim um retry do seu lado nunca abre lote duplicado.
* `name` é opcional (até 120 caracteres) e aparece nas listagens e no
  `resumo.csv` dos comprovantes.

Resposta `201`:

```json
{
  "batchId": "pxb_3f9c2a1b7d4e5f60718293a4b5c6d7e8",
  "name": "Folha de setembro",
  "status": "DRAFT",
  "totalItems": 0,
  "totalAmount": "0.00",
  "completedItems": 0,
  "failedItems": 0,
  "limits": { "maxItems": 50, "source": "default" },
  "statistics": {
    "total": 0, "pending": 0, "processing": 0, "completed": 0, "failed": 0,
    "reviewedOk": 0, "invalid": 0,
    "totalAmount": "0.00", "validAmount": "0.00", "completedAmount": "0.00", "failedAmount": "0.00",
    "progressPercentage": 0
  },
  "items": [],
  "page": 1, "pageSize": 50, "totalPages": 0, "hasNext": false,
  "createdAt": "2026-09-30T13:00:00Z",
  "updatedAt": "2026-09-30T13:00:00Z"
}
```

`limits.maxItems` é o tamanho máximo deste lote **nesta conta** e
`limits.source` diz de onde veio (`default` = 50, `tenant` ou `account`,
até 5.000). Valores monetários são sempre **strings decimais** com duas
casas (`"1436.85"`), nunca números de ponto flutuante.

## 3. Enviar os itens

Você pode misturar os dois métodos no mesmo lote, em quantas chamadas
precisar, enquanto o lote estiver `DRAFT` ou `REVIEWED`.

#### CSV

```bash
curl -X POST ".../pix/batches/{batchId}/items/csv" \
  -H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa" \
  -H "Content-Type: text/csv" \
  --data-binary @folha-setembro.csv
```

O corpo é o arquivo cru (até 5 MiB; acima disso `413`). O upload é
**atômico**: se uma linha estiver inválida a resposta é
`400 pix_batch_csv_invalid` com a lista de problemas e **nada é salvo**.

```json
{
  "errorCode": "pix_batch_csv_invalid",
  "message": "one or more rows are invalid; nothing was saved",
  "errors": [
    { "line": 3, "field": "amount", "message": "must be a positive amount" },
    { "line": 7, "field": "pixKey", "message": "use either pixKey or the bank account columns, not both" },
    { "line": 9, "field": "identifier", "message": "duplicated identifier (first seen on line 4)" }
  ],
  "docs": "https://docs.api.corpx.com/baas/guias/referencia/erros#pix_batch_csv_invalid"
}
```

`line` conta a partir do cabeçalho = linha 1, então `3` é a segunda linha de
dados — igual ao que o Excel mostra. Um arquivo com mais linhas que
`limits.maxItems` é `400 pix_batch_too_large`.

#### JSON

```bash
curl -X PUT ".../pix/batches/{batchId}/items" \
  -H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "identifier": "folha-set-001", "amount": "1436.85", "description": "Pagamento setembro",
        "key": "12345678909", "keyType": "CPF" },
      { "identifier": "folha-set-002", "amount": 2500.00, "description": "Fornecedor",
        "name": "EMPRESA EXEMPLO LTDA", "documentNumber": "12345678000195",
        "bankIspb": "60701190", "accountBranch": "0001", "accountNumber": "123456",
        "accountType": "CHECKING" }
    ]
  }'
```

De **1 a 50 itens por chamada**, no mesmo vocabulário do `POST /pix/out`:
`identifier`, `amount` (string ou número), `description`, e `key`/`keyType`
**ou** `name`, `documentNumber`, `bankIspb` ou `bankCode`, `accountBranch`,
`accountNumber`, `accountType`. Para lotes grandes, envie chunks de 50 em
sequência — cada chamada devolve o lote atualizado.

Chunk vazio, com mais de 50 itens ou com qualquer item inválido é
`400 pix_batch_chunk_invalid` com o mesmo envelope `errors[]` do CSV
(`line` é a posição no array, começando em 1) e nada é salvo. Um
`identifier` repetido dentro do próprio chunk também é apontado.

### Regras comuns aos dois métodos

* **Idempotência por linha.** Repetir um `identifier` com o **mesmo**
  conteúdo é ignorado (não duplica, não dá erro). Repetir com conteúdo
  **diferente** é `409 pix_batch_item_conflict` e a chamada inteira é
  recusada — corrija o arquivo em vez de contar com sobrescrita.
* **Remover.** `DELETE .../items/{itemId}` tira um item; o `itemId`
  (`pxi_…`) vem em `items[]` do lote.
* **Estados editáveis.** Só `DRAFT` e `REVIEWED` aceitam itens ou remoção.
  Qualquer alteração num lote `REVIEWED` o devolve a `DRAFT` e zera a
  conferência: você precisa revisar de novo antes de disparar. Em
  `REVIEWING` ou depois do dispatch, `409 pix_batch_not_editable`.
* **Tamanho.** O total de itens do lote nunca passa de `limits.maxItems`;
  a chamada que estouraria o teto é recusada inteira com
  `400 pix_batch_too_large`.

## 4. Conferir (review)

```
POST /v1/accounts/{accountId}/pix/batches/{batchId}/review   → 202, status REVIEWING
```

A conferência é assíncrona e roda **antes de qualquer débito**. Repetir o
`POST` enquanto está `REVIEWING` só devolve o estado atual. Por item, nesta
ordem:

| Verificação                                                                    | `reviewError.errorCode`                            |
| ------------------------------------------------------------------------------ | -------------------------------------------------- |
| Valor positivo                                                                 | `invalid_amount`                                   |
| `identifier` já usado por um pagamento vivo na conta (inclusive de outro lote) | `identifier_conflict`                              |
| Valor acima do limite por operação da conta                                    | `limit_exceeded_transaction`                       |
| Chave PIX inexistente, inativa ou malformada (consulta DICT)                   | `key_not_found`, `key_inactive`, `invalid_pix_key` |
| DICT indisponível após 3 tentativas                                            | `dict_lookup_failed`                               |

No modo chave o DICT resolve **nome, documento e banco** do recebedor, que
passam a aparecer em `items[].receiver` — é o que você mostra para quem
aprova. As consultas usam o cache de 24 h da conta e **contam na janela de
consultas DICT** como `GET /pix/key/{pixKey}`; leia
[Consultas de chave PIX](/baas/guias/pagar/consulta-dict) antes de conferir
milhares de chaves novas. Itens em dados bancários são aceitos como enviados;
a validação da conta destino acontece no liquidante, na execução.

Acompanhe com `GET .../pix/batches/{batchId}`. Quando `status` vira
`REVIEWED`, `review` traz o resumo:

```json
{
  "reviewedAt": "2026-09-30T13:09:30Z",
  "totalItems": 120, "validItems": 118, "invalidItems": 2,
  "totalAmount": "143685.00", "validAmount": "141200.00",
  "balance": { "available": "150000.00", "sufficient": true, "checked": true },
  "limits": [
    { "window": "daily_out", "enforced": true, "limit": "500000.00", "used": "12000.00", "available": "488000.00", "sufficient": true },
    { "window": "monthly", "enforced": false, "limit": "0.00", "used": "0.00", "available": "0.00", "sufficient": true }
  ],
  "warnings": []
}
```

* `balance` e `limits` são um **retrato do momento**. O saldo é checado de
  novo no dispatch e cada PIX passa pelos limites por janela na execução.
  `limits[].window` é `daily_out` (6h–20h) ou `nightly_out` (20h–6h) conforme
  a hora da conferência, mais `monthly`; `enforced: false` significa que a
  conta não tem teto configurado naquela janela.
* `balance.checked: false` quer dizer que o liquidante não respondeu; o
  aviso vai para `warnings[]` e não bloqueia.
* `warnings[]` **não bloqueia** o aceite (ex.: saldo insuficiente agora —
  pode entrar dinheiro até o dispatch). Itens `INVALID` **bloqueiam**.
* Se a conferência não conseguir rodar, o lote volta a `DRAFT` e `review`
  traz um campo `error`; basta chamar `review` de novo.

Um item reprovado fica assim em `items[]`:

```json
{
  "itemId": "pxi_9b1c…", "line": 17, "identifier": "folha-set-017",
  "mode": "KEY", "amount": "980.00", "description": "Pagamento setembro",
  "status": "PENDING", "reviewStatus": "INVALID",
  "receiver": { "name": "", "documentNumber": "", "keyType": "EMAIL", "key": "ex-funcionario@empresa.com", "bankCode": "", "bankIspb": "" },
  "reviewError": { "errorCode": "key_not_found", "message": "chave PIX não encontrada no DICT" },
  "createdAt": "2026-09-30T13:02:11Z", "updatedAt": "2026-09-30T13:09:28Z"
}
```

Para corrigir, baixe só as linhas reprovadas, ajuste e suba de novo (o
`identifier` igual com conteúdo novo é recusado — remova o item antes com
`DELETE`, ou use um `identifier` novo), depois confira outra vez:

```
GET /v1/accounts/{accountId}/pix/batches/{batchId}/items/export?status=invalid
GET /v1/accounts/{accountId}/pix/batches/{batchId}?reviewStatus=invalid
```

## 5. Disparar (dispatch)

```bash
curl -X POST ".../pix/batches/{batchId}/dispatch" \
  -H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa" \
  -H "X-Acting-Document: 12345678909" \
  -H "X-Transaction-Pin: 123456" \
  -H "Content-Type: application/json" \
  -d '{"acknowledged": true}'
```

`acknowledged: true` é a declaração de que o resumo da conferência foi lido e
aprovado — grave do seu lado quem aprovou e quando. Sem ele a API responde
`409 pix_batch_acknowledgement_required`. O dispatch ainda exige, nesta
ordem:

1. Lote `REVIEWED` (`409 pix_batch_not_reviewed`).
2. Ao menos um item (`409 pix_batch_empty`) e total dentro de `limits.maxItems`
   (`400 pix_batch_too_large`).
3. Nenhum item `INVALID` e todos conferidos
   (`409 pix_batch_has_invalid_items` / `409 pix_batch_not_reviewed`).
4. Saldo disponível **maior ou igual ao total do lote** no momento do
   dispatch (`422 pix_batch_insufficient_balance` — nada é iniciado).

> **Dispatch movimenta dinheiro**
>
> O dispatch é uma rota de cash out: valem as travas de saída da conta, o PIN
> transacional e os cabeçalhos `X-Acting-Document` / `X-Transaction-Pin` /
> `X-Acting-Ip` exatamente como em `POST /pix/out` (ver
> [Segurança da conta](/baas/guias/autenticacao/seguranca-da-conta)). Os
> cabeçalhos só são necessários se a conta tiver PIN ou travas configurados.
> Depois do `202` **não há cancelamento**: os itens já em voo seguem até
> liquidar ou falhar.

Resposta `202` com `status: QUEUED` e `dispatchedAt`. Repetir o dispatch de
um lote já disparado é idempotente (`200` com o estado atual), então um
retry por timeout de rede é seguro.

## 6. Acompanhar

Cada item vira um `PixOut.Workflow` próprio — o mesmo que atende
`POST /pix/out` — com `identifier` igual ao da linha e idempotência
`{batchId}_{itemId}`. Ele passa pelas mesmas políticas, limites por janela e
registro no extrato de um PIX avulso, e emite os mesmos
`pix.out.completed`, `pix.out.failed` ou `pix.out.timeout`. O lote paga até
5 itens em paralelo (configuração CorpX) e só avança quando o liquidante
responde; um item lento não trava os demais.

### Estados do lote

| `status`         | Significado                                                          | Editável? |
| ---------------- | -------------------------------------------------------------------- | --------- |
| `DRAFT`          | Recebendo itens.                                                     | Sim       |
| `REVIEWING`      | Conferência em andamento.                                            | Não       |
| `REVIEWED`       | Conferido; pronto para o aceite. Qualquer edição volta para `DRAFT`. | Sim       |
| `QUEUED`         | Dispatch aceito; aguardando o processador.                           | Não       |
| `PROCESSING`     | Itens sendo pagos. `statistics` avança.                              | Não       |
| `COMPLETED`      | Todos os itens liquidaram.                                           | Não       |
| `PARTIAL_FAILED` | Alguns liquidaram, outros falharam. Baixe o export de falhas.        | Não       |
| `FAILED`         | Nenhum item liquidou.                                                | Não       |

### Estados do item

| `status`     | `reviewStatus`   | Quando                                                                                                                                                  |
| ------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PENDING`    | `PENDING`        | Recém-adicionado, ainda não conferido.                                                                                                                  |
| `PENDING`    | `OK` / `INVALID` | Conferido; `INVALID` traz `reviewError`.                                                                                                                |
| `PROCESSING` | `OK`             | PixOut em voo.                                                                                                                                          |
| `COMPLETED`  | `OK`             | Liquidado: `paymentId`, `endToEndId`, `transactionId`, `completedAt`.                                                                                   |
| `FAILED`     | `OK`             | Recusado ou expirado: `error.errorCode` e `error.message` com o vocabulário do PIX avulso (`insufficient_funds`, `limit_exceeded_daily`, `timeout`, …). |

`GET .../pix/batches/{batchId}` traz `statistics` e os itens paginados
(`page`, `pageSize` até 200), filtráveis por `status`
(`pending`, `processing`, `completed`, `failed`) e `reviewStatus`
(`pending`, `ok`, `invalid`):

```json
{
  "batchId": "pxb_3f9c2a1b7d4e5f60718293a4b5c6d7e8",
  "status": "PROCESSING",
  "totalItems": 120, "totalAmount": "141200.00",
  "completedItems": 87, "failedItems": 2,
  "statistics": {
    "total": 120, "pending": 0, "processing": 31, "completed": 87, "failed": 2,
    "reviewedOk": 120, "invalid": 0,
    "totalAmount": "141200.00", "validAmount": "141200.00",
    "completedAmount": "102340.00", "failedAmount": "1960.00",
    "progressPercentage": 74.17
  },
  "items": [
    {
      "itemId": "pxi_1a2b…", "line": 1, "identifier": "folha-set-001",
      "mode": "KEY", "amount": "1436.85", "description": "Pagamento setembro",
      "status": "COMPLETED", "reviewStatus": "OK",
      "receiver": { "name": "JOAO ANTONIO DA CONCEICAO", "documentNumber": "12345678909", "keyType": "CPF", "key": "12345678909", "bankCode": "341", "bankIspb": "60701190" },
      "paymentId": "pay_1f2e3d4c", "endToEndId": "E5087192120260930131200abcdef0123",
      "transactionId": "9f8e7d6c-5b4a-4321-8765-43210fedcba9",
      "completedAt": "2026-09-30T13:12:01Z",
      "createdAt": "2026-09-30T13:02:11Z", "updatedAt": "2026-09-30T13:12:01Z"
    }
  ],
  "page": 1, "pageSize": 50, "totalPages": 3, "hasNext": true,
  "reviewedAt": "2026-09-30T13:09:30Z",
  "acknowledgedAt": "2026-09-30T13:10:02Z",
  "dispatchedAt": "2026-09-30T13:10:02Z",
  "createdAt": "2026-09-30T13:00:00Z", "updatedAt": "2026-09-30T13:12:01Z"
}
```

### Webhook de fechamento

Ao final a API envia **`pix.batch.completed`**. Ele é o fechamento do lote e
**não substitui** os eventos por item: para reconciliar linha a linha use
`pix.out.completed` / `pix.out.failed` (o `identifier` do evento é o da sua
linha) ou a lista de itens.

```json
{
  "id": "pix-batch-pxb_3f9c2a1b7d4e5f60718293a4b5c6d7e8-completed",
  "type": "pix.batch.completed",
  "occurredAt": "2026-09-30T13:12:40.000Z",
  "schemaVersion": "1.0",
  "environment": "production",
  "tenantId": "tenant-suaempresa",
  "accountId": "acc_123456",
  "data": {
    "batchId": "pxb_3f9c2a1b7d4e5f60718293a4b5c6d7e8",
    "accountId": "acc_123456",
    "status": "PARTIAL_FAILED",
    "statistics": {
      "total": 120, "completed": 118, "failed": 2,
      "totalAmount": "141200.00", "completedAmount": "139240.00", "failedAmount": "1960.00"
    }
  }
}
```

Assine com `authType: HMAC`, valide `X-Signature` sobre os bytes brutos e
deduplique pelo `id` — detalhes em [Webhooks](/baas/guias/conta/webhooks).

> **Webhook primeiro, polling como reserva**
>
> Prefira reagir a `pix.batch.completed`. Se precisar de polling (uma barra de
> progresso, por exemplo), consulte `GET .../pix/batches/{batchId}` a cada
> 10–30 s e leia só `status` e `statistics`; não liste os itens a cada ciclo.

## 7. Corrigir e reenviar

```
GET /v1/accounts/{accountId}/pix/batches/{batchId}/items/export?status=failed
```

Devolve, no **mesmo formato do modelo**, só as linhas que falharam na
execução ou foram marcadas inválidas na conferência, com duas colunas a mais
no fim: `errorCode` e `errorMessage`. O cabeçalho `X-Total-Rows` diz quantas
linhas vieram.

```csv
identifier;amount;description;pixKeyType;pixKey;receiverName;receiverDocument;bankIspb;bankCode;branch;accountNumber;accountType;errorCode;errorMessage
folha-set-017;980.00;Pagamento setembro;EMAIL;ex-funcionario@empresa.com;;;;;;;;key_not_found;chave PIX não encontrada no DICT
folha-set-044;1200.00;Pagamento setembro;;;MARIA DA SILVA;98765432100;;001;1234;56789-0;CHECKING;limit_exceeded_daily;limite diário de saída excedido
```

Corrija e suba o arquivo **como está** em um **novo** lote — o parser ignora
as colunas de erro. Um `identifier` que falhou pode ser reutilizado; um que
liquidou não (a conferência o apontaria como `identifier_conflict`), o que
protege contra pagar duas vezes a mesma linha.

| `status=`         | Linhas incluídas                                                       |
| ----------------- | ---------------------------------------------------------------------- |
| `failed` (padrão) | Falharam na execução **ou** reprovadas na conferência.                 |
| `invalid`         | Só as reprovadas na conferência (use enquanto o lote está `REVIEWED`). |
| `completed`       | Só as liquidadas — útil para conciliar com o `endToEndId`.             |
| `all`             | Todas, com `errorCode`/`errorMessage` vazios onde não houve erro.      |

`separator=comma` troca `;` por `,` para ferramentas em inglês.

## 8. Comprovantes

Os comprovantes são PDFs no padrão CorpX (logo do tenant quando configurada,
pagador, recebedor com documento mascarado, valor, descrição, `identifier`,
`endToEndId`, data de liquidação em horário de Brasília).

**Um item** — resposta direta em `application/pdf`, só para itens
`COMPLETED` (`409 pix_batch_receipt_unavailable`):

```
GET /v1/accounts/{accountId}/pix/batches/{batchId}/items/{itemId}/receipt
```

**Lote inteiro** — para lotes encerrados (`COMPLETED`, `PARTIAL_FAILED` ou
`FAILED` com ao menos um item liquidado; senão `409 pix_batch_no_receipts`):

```bash
curl -X POST ".../pix/batches/{batchId}/receipts" \
  -H "Authorization: Bearer $TOKEN" -H "X-Tenant-Id: tenant-suaempresa"
```

```json
{
  "exportId": "exp_7c1d2e3f-…",
  "accountId": "acc_123456",
  "batchId": "pxb_3f9c2a1b7d4e5f60718293a4b5c6d7e8",
  "type": "pix_batch_receipts",
  "format": "zip",
  "status": "PENDING",
  "receipts": 118,
  "download": "/v1/accounts/acc_123456/exports/exp_7c1d2e3f-…/download",
  "createdAt": "2026-09-30T13:15:00Z"
}
```

O ZIP é gerado em segundo plano. Chame a rota em `download`: enquanto o job
roda ela responde `409 not_ready`; quando termina, devolve `downloadUrl`
pré-assinada (válida por `expiresIn` segundos) e `checksumMd5`. O arquivo
traz um PDF por item liquidado e um `resumo.csv` com as colunas `linha`,
`identificador`, `destinatario`, `valor`, `endToEnd`, `data`, `arquivo` e
`erro` (preenchida só se algum PDF não pôde ser gerado).

Os PDFs seguem o padrão
`{AAAA-MM-DD}_{HHMM}_PIX_{valor}_{destinatario}_{identifier}_{endToEnd}.pdf`
— por exemplo
`2026-09-30_1312_PIX_1436-85_JOAO-ANTONIO-DA-CONCEICAO_folha-set-001_E5087192120260930131200abcdef0123.pdf`
— sem acentos e com sufixo `-2`, `-3`… em caso de colisão.

## Boas práticas

* **Uma `Idempotency-Key` por fechamento.** `folha-2026-09`, `fornecedores-2026-09-30`… Assim um retry da criação nunca abre um segundo lote, e você consegue reencontrar o lote pelo seu próprio calendário.
* **`identifier` determinístico e único por linha.** Monte-o a partir dos seus dados (`{folha}-{matricula}`), nunca de um contador em memória. É ele que liga o PIX ao seu sistema no extrato, nos webhooks e no arquivo de correção — e é ele que impede pagar a mesma linha duas vezes.
* **Confira sempre antes de pedir aprovação.** Mostre `review` (totais, saldo, limites, inválidos) a quem aprova e só então envie `acknowledged: true`. Guarde quem aprovou, quando e o `reviewedAt` que estava na tela.
* **Separe quem monta de quem dispara.** Uma credencial `read` pode acompanhar; só a credencial com `pix_out.create` dispara. Se a conta usa PIN transacional, o dispatch exige o PIN do operador que aprova.
* **Trate `PARTIAL_FAILED` como rotina, não exceção.** Chaves excluídas e contas encerradas acontecem em qualquer folha grande. Baixe `items/export?status=failed`, corrija e suba um novo lote; não refaça o lote inteiro.
* **Reconcilie por `identifier` e `endToEndId`.** O `pix.out.completed` de cada item e a linha em `items[]` trazem os dois; o `endToEndId` é o comprovante perante o Banco Central.
* **Respeite as janelas de limite.** O `review` mostra `daily_out`/`nightly_out` e `monthly`. Um lote maior que o limite disponível do dia não é bloqueado no dispatch — os itens excedentes falham na execução com `limit_exceeded_*`. Se for o caso, divida em lotes por dia ou peça ajuste de limite.
* **Lotes grandes.** Para milhares de linhas, suba por CSV (uma chamada) em vez de dezenas de chunks JSON, e peça à CorpX o `maxItems` adequado antes do fechamento.

## Perguntas frequentes

#### Posso cancelar um lote depois do dispatch?

Não. Depois do `202` os itens já estão em execução no liquidante. O que você
controla é o momento do aceite: até o `dispatch` o lote é apenas um rascunho e
pode ser editado ou simplesmente abandonado em `DRAFT`/`REVIEWED`.

#### O que acontece se eu editar um lote REVIEWED?

Ele volta para `DRAFT` e todos os itens voltam a `reviewStatus: PENDING`.
Você precisa chamar `review` de novo. Isso vale para adicionar, remover ou
reenviar um item — a conferência sempre reflete o conteúdo atual.

#### O saldo era suficiente na conferência mas o dispatch deu 422. Por quê?

`review.balance` é um retrato do momento; outro pagamento pode ter saído
entre a conferência e o aceite. O dispatch checa o saldo de novo e recusa
**sem iniciar nada** se ele for menor que o total do lote. Reabasteça a
conta ou remova linhas e confira novamente.

#### Por que um item passou na conferência e falhou na execução?

A conferência valida o que dá para validar sem mover dinheiro: chave,
duplicidade, valor, limite por operação, saldo e janelas no agregado. Na
execução entram as regras do liquidante e do banco de destino (conta
encerrada, limite diário consumido por outros pagamentos, política da conta).
O código de erro é o mesmo do PIX avulso e vem em `error.errorCode`.

#### Posso reaproveitar um identifier?

Um `identifier` de item que **falhou** pode ser usado em um novo lote. Um
que **liquidou** não: a conferência marca `identifier_conflict`, porque na
conta existe um pagamento vivo com esse identificador. Essa é a proteção
contra pagamento duplicado — não a contorne gerando sufixos aleatórios.

#### Os itens do lote aparecem no extrato?

Sim, como PIX out individuais, com o `identifier` de cada linha. Não existe
um lançamento agregado do lote; `GET .../pix/batches/{batchId}` e o
`resumo.csv` dos comprovantes são a visão consolidada.

#### A conferência consome cota de DICT?

Sim, uma consulta por chave distinta não presente no cache de 24 h da conta,
contada na mesma janela de `GET /pix/key/{pixKey}`. Chaves repetidas no
lote e chaves consultadas recentemente não geram nova consulta. Em dados
bancários não há consulta ao DICT.

#### Como testo antes de produção?

Crie um lote pequeno, suba duas ou três linhas de valor simbólico para
contas suas, confira e dispare — o fluxo e os webhooks são idênticos aos de
um lote de milhares de linhas. Para validar apenas o arquivo sem pagar
nada, pare depois do `review`: o parser e a conferência já apontam todo
problema de formato, chave e duplicidade.

## Erros

| Código                                                    | HTTP | Quando                                                                                |
| --------------------------------------------------------- | ---- | ------------------------------------------------------------------------------------- |
| `feature_disabled`                                        | 403  | Tenant sem a feature `pix_batch`.                                                     |
| `pix_batch_account_disabled`                              | 403  | Conta sem `pixBatch.enabled = true` na policy.                                        |
| `missing_idempotency_key`                                 | 400  | `POST /pix/batches` sem `Idempotency-Key`.                                            |
| `pix_batch_not_found` / `pix_batch_item_not_found`        | 404  | Lote ou item não existe nesta conta.                                                  |
| `pix_batch_chunk_invalid` / `pix_batch_csv_invalid`       | 400  | Upload rejeitado; `errors[]` aponta linha e campo. `413` quando o CSV passa de 5 MiB. |
| `pix_batch_too_large`                                     | 400  | Acima de `limits.maxItems`.                                                           |
| `pix_batch_item_conflict`                                 | 409  | `identifier` repetido com conteúdo diferente.                                         |
| `pix_batch_not_editable`                                  | 409  | Lote em `REVIEWING` ou já disparado.                                                  |
| `pix_batch_empty`                                         | 409  | Lote sem itens.                                                                       |
| `pix_batch_not_reviewed`                                  | 409  | Dispatch sem conferência válida.                                                      |
| `pix_batch_has_invalid_items`                             | 409  | Conferência marcou itens inválidos.                                                   |
| `pix_batch_acknowledgement_required`                      | 409  | Dispatch sem `acknowledged: true`.                                                    |
| `pix_batch_insufficient_balance`                          | 422  | Saldo disponível menor que o total no dispatch.                                       |
| `pix_batch_no_receipts` / `pix_batch_receipt_unavailable` | 409  | Lote não encerrado ou item não liquidado.                                             |
| `receipt_render_failed`                                   | 500  | Falha ao gerar o PDF; repita a chamada.                                               |
| `workflow_unavailable`                                    | 503  | Orquestração indisponível; repita a chamada.                                          |

A lista completa, com âncoras, está em
[Tratamento de erros](/baas/guias/referencia/erros).

## Veja também

* [PIX Out](/baas/guias/pagar/pix-out) — o pagamento avulso que cada linha do lote executa.
* [Consultas de chave PIX](/baas/guias/pagar/consulta-dict) — cota e cache do DICT usados na conferência.
* [Segurança da conta](/baas/guias/autenticacao/seguranca-da-conta) — travas, PIN transacional e cabeçalhos de cash out.
* [Idempotência](/baas/guias/comece-aqui/idempotencia) — como a `Idempotency-Key` se comporta em toda a API.
* [Webhooks](/baas/guias/conta/webhooks) — `pix.batch.completed` e os eventos `pix.out.*` por item.