> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.api.corpx.com/baas/guias/pagar/pix-em-lote/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
DRAFT"]
C --> I["POST items/csv
PUT items"]
I --> R["POST review
REVIEWING → REVIEWED"]
R -->|"itens INVALID"| X["GET items/export?status=invalid
corrigir e reenviar"]
X --> I
R -->|"acknowledged: true"| D["POST dispatch
QUEUED → PROCESSING"]
D --> P["1 PixOut por item
pix.out.completed / failed"]
P --> F["COMPLETED | PARTIAL_FAILED | FAILED
pix.batch.completed"]
F --> Z["POST receipts (ZIP)
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.
> Pague dezenas ou milhares de PIX a partir de um CSV ou de JSON, com conferência prévia e aceite explícito antes do dinheiro sair.