---
title: "Cria um lote de emissão"
method: POST
path: "/v1/lotes"
tags: ["Emissão em lote"]
---

# Cria um lote de emissão

`POST /v1/lotes`

## Request

- Base URL: `https://api.sudrel.com.br/api`
- URL: `https://api.sudrel.com.br/api/v1/lotes`
- Auth: HTTP bearer

Até **5.000 notas** num lote (com a chave de sandbox, **100**), por JSON
ou pela planilha do painel. O lote passa pela mesma validação, pela mesma
normalização e pela mesma fila da planilha do painel. Sempre **202**: o
lote é assíncrono. Acompanhe por `GET /v1/lotes/{id}` ou pelo webhook
`LOTE_EMISSAO_CONCLUIDO`.

**Duas formas de entrada, mesma rota:**

- `application/json`: `{ "empresa_id", "modelo"?, "ao_validar"?, "itens": [...] }`.
  Cada item é exatamente o corpo de `POST /v1/nfse` (mesmos campos, mesma
  validação), com `referencia` opcional por item.
- `multipart/form-data`: campo `planilha` (.xlsx ou .csv separado por
  vírgula, no template oficial, qualquer dos três layouts) e os campos
  `empresa_id`, `modelo` e `ao_validar` no formulário.

**`ao_validar`:**

- `emitir_validas` (padrão): as linhas válidas entram na fila assim que
  o lote é validado; as inválidas ficam com erro no resultado, e você
  corrige com `POST /v1/lotes/{id}/reprocessamento`.
- `aguardar`: o lote para depois da validação. Confira o resultado e
  chame `POST /v1/lotes/{id}/emissao`. Serve para quem quer tudo ou nada.

**Reenvio seguro com `referencia`.** Mande sempre uma `referencia` por
item (o seu número de pedido, por exemplo). Se o mesmo lote for enviado
de novo (um timeout, um retry automático), a linha cuja referência já
virou nota **não vira outra nota**: aparece como `ja_existente`, com o
`nfse_id` da nota que já existe. Se o conteúdo da linha mudou,
`divergente: true` avisa, e mesmo assim nenhuma nota nova é criada.
Referência repetida **dentro do mesmo lote** é erro nas linhas
envolvidas (`referencia_duplicada_no_lote`), e nenhuma delas vira nota.

> ⚠️ **Linha sem `referencia` não tem essa proteção.** Reenviar um lote
> sem referências emite as notas de novo. Em lote, mande sempre
> `referencia`.

Use também `Idempotency-Key`: a mesma chave com o mesmo corpo devolve o
mesmo lote; com corpo diferente, 409 `idempotencia_conflito`. Na
planilha, o "corpo" é o arquivo (hash) mais os campos do formulário.

A prontidão da empresa é avaliada uma vez, antes de criar o lote:
`bloqueio` devolve **412** `empresa_nao_pronta`, como no
`POST /v1/nfse`, e nada é criado.

**Limite de requisições:** um `POST /v1/lotes` conta como **uma**
chamada, qualquer que seja o número de itens.

Itens de lote entram na fila de emissão atrás das notas avulsas
(`POST /v1/nfse`): um lote grande não atrasa a nota de outro cliente.

## Headers

- `Idempotency-Key` string

## Request body

- object
  - `tipo` 'nfse' | 'nfe': `nfe`: cada item é o corpo de `POST /v1/nfe` (veja NF-e pela planilha e em lote). Sem `tipo`, o lote é de NFS-e.
  - `empresa_id` string
  - `modelo` string: Nome ou id de um modelo de emissão; vale pra todos os itens que não pedirem outro. Só no lote de NFS-e.
  - `ao_validar` 'emitir_validas' | 'aguardar'
  - `itens` NfseEntrada[], required
    - `empresa_id` string: Empresa emissora. Dispensado quando a chave de API é restrita a uma empresa.
    - `referencia` string: Seu identificador para esta nota (pedido, contrato). Único por empresa; repetido é 409 com o id da nota existente.
    - `modelo` string: Nome ou id de um modelo de emissão salvo no painel. Preenche descrição, código de serviço e competência quando não enviados.
    - `substituicao` object: Esta nota SUBSTITUI uma NFS-e autorizada (grupo `subst` da DPS). Informe `nfse_id` (nota emitida pela Sudrel) ou `chave_acesso` (NFS-e emitida em outro sistema, do mesmo prestador). Veja "Substituir uma NFS-e" acima. Só em `POST /v1/nfse`: o lote recusa (`substituicao_fora_do_lote`).
      - `nfse_id` string: Id da nota a substituir (de `GET /v1/nfse`).
      - `chave_acesso` string: Ou a chave de acesso da NFS-e a substituir, 50 dígitos.
      - `codigo_motivo` '01' | '02' | '03' | '04' | '05' | '99', required: 01 desenquadramento do Simples Nacional; 02 enquadramento no Simples Nacional; 03 inclusão retroativa de imunidade ou isenção; 04 exclusão retroativa de imunidade ou isenção; 05 rejeição da NFS-e pelo tomador ou intermediário; 99 outros.
      - `motivo` string: Descrição do motivo. Obrigatória com `codigo_motivo` 99 (E0078).
    - `tomador` object, required
      - `documento` string, required: CPF (11 dígitos) ou CNPJ (14 posições, numérico ou alfanumérico), com ou sem pontuação.
      - `razao_social` string: Obrigatório para CPF. Para CNPJ, consultamos automaticamente.
      - `email` string: Obrigatório só quando o sistema do município da empresa precisa dele para cancelar a nota (hoje, o WebISS). Nos outros casos, opcional; quando vier, o PDF da nota vai para ele.
      - `endereco` object: Para CPF, opcional: CPF e nome bastam, menos quando o serviço tributa no domicílio do tomador (o `cIndOp` aponta para o endereço dele, ou mão de obra, 17.05.01), e aí a validação devolve `tomador_endereco_obrigatorio`. Quando vier, CEP e número vão juntos e o resto sai do CEP. Para CNPJ, não precisa.
        - `cep` string
        - `numero` string
        - `complemento` string
        - `municipio` string: Só para sobrescrever o município resolvido. Nome com UF ou código IBGE.
    - `valor` string, required: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
    - `servico` object
      - `descricao` string
      - `codigo_nacional` string: Código de tributação nacional (cTribNac), 6 dígitos.
      - `competencia` string: AAAA-MM. Padrão, o mês atual.
      - `nbs` string: Código NBS do serviço (9 dígitos, com ou sem pontos), declarado junto do IBS e da CBS. Tem de ser um dos admitidos para o código de serviço (veja `GET /v1/servicos/{codigo}/nbs`); cada NBS leva a sua classificação tributária. Padrão: o NBS padrão da empresa, e na falta dele o padrão da tabela oficial.
      - `obra` ObraEntrada: Dados da obra (grupo `serv/obra` da DPS). Obrigatório nos códigos de construção civil (E0370) e proibido nos demais, menos o 99.01.01 (E0372). Identifique a obra por UM destes: `cno`, `cib` ou `endereco` (CEP e número); com mais de um, vai o CNO, depois o CIB. O município da obra é o local da prestação: vem do CEP, quando há CEP, ou de `municipio`.
        - `cno` string: Número da obra no Cadastro Nacional de Obras (ou CEI), com ou sem máscara.
        - `cib` string: Código do Cadastro Imobiliário Brasileiro do imóvel, 8 caracteres.
        - `inscricao_imobiliaria` string: Inscrição imobiliária fiscal (a do IPTU), opcional.
        - `endereco` object: Rua e bairro vêm do CEP.
          - `cep` string
          - `numero` string
          - `complemento` string
        - `municipio` string: Nome com UF (`Salvador - BA`) ou código IBGE. Dispensado quando o CEP foi informado; com os dois, têm de concordar (E0380).
    - `retencoes` object: O que o TOMADOR retém.
      - `iss` boolean: ISS retido pelo tomador.
      - `pis` Tributo: Informe o valor OU a alíquota. Com a alíquota, calculamos o valor sobre o valor do serviço.
        - `valor` string: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
        - `aliquota` string: Percentual como texto, com ponto e sem "%".
      - `cofins` Tributo: Informe o valor OU a alíquota. Com a alíquota, calculamos o valor sobre o valor do serviço.
        - `valor` string: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
        - `aliquota` string: Percentual como texto, com ponto e sem "%".
      - `csll` Tributo: Informe o valor OU a alíquota. Com a alíquota, calculamos o valor sobre o valor do serviço.
        - `valor` string: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
        - `aliquota` string: Percentual como texto, com ponto e sem "%".
      - `irrf` Tributo: Informe o valor OU a alíquota. Com a alíquota, calculamos o valor sobre o valor do serviço.
        - `valor` string: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
        - `aliquota` string: Percentual como texto, com ponto e sem "%".
      - `inss` Tributo: Informe o valor OU a alíquota. Com a alíquota, calculamos o valor sobre o valor do serviço.
        - `valor` string: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
        - `aliquota` string: Percentual como texto, com ponto e sem "%".
    - `apuracao_propria` object: PIS/COFINS da apuração da SUA empresa (não é retenção).
      - `pis` Tributo: Informe o valor OU a alíquota. Com a alíquota, calculamos o valor sobre o valor do serviço.
        - `valor` string: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
        - `aliquota` string: Percentual como texto, com ponto e sem "%".
      - `cofins` Tributo: Informe o valor OU a alíquota. Com a alíquota, calculamos o valor sobre o valor do serviço.
        - `valor` string: Texto decimal com ponto, sem separador de milhar. Número JSON é recusado (422 `tipo_invalido`).
        - `aliquota` string: Percentual como texto, com ponto e sem "%".
    - `iss` object
      - `aliquota` string: Percentual como texto, com ponto e sem "%".

## Response `202`

Lote criado. Validação e emissão seguem em segundo plano.

- Lote
  - `id` string
  - `tipo` 'nfse' | 'nfe': O que o lote emite. No de NF-e, `contagens` conta notas e traz `linhas` (os itens das notas).
  - `status` 'validando' | 'aguardando_emissao' | 'processando' | 'concluido' | 'erro': `validando` → (`aguardando_emissao`, só com `ao_validar: "aguardar"`) → `processando` → `concluido`. `concluido` quer dizer que nenhuma nota do lote está mais transmitindo; pode haver rejeitadas e linhas com erro.
  - `empresa_id` string
  - `ambiente` 'producao' | 'sandbox'
  - `origem` 'api' | 'painel'
  - `formato` 'json' | 'planilha'
  - `ao_validar` 'emitir_validas' | 'aguardar', nullable
  - `contagens` object: Linhas por status. `total` é o número de linhas recebidas.
    - `total` integer
    - `transmitindo` integer
    - `autorizada` integer
    - `rejeitada` integer
    - `falha_transmissao` integer
    - `aguardando_confirmacao` integer
    - `cancelada` integer
    - `descartada` integer
    - `com_erro_validacao` integer
    - `aguardando_emissao` integer
    - `ja_existente` integer
  - `criado_em` string, date-time
  - `validado_em` string, date-time, nullable
  - `emissao_disparada_em` string, date-time, nullable
  - `concluido_em` string, date-time, nullable
  - `links` object
    - `self` string
    - `itens` string
    - `relatorio` string

## Other responses

- `401`: `nao_autenticado`: chave de API ausente, inválida ou revogada.
- `403`: `acesso_negado`: a chave é restrita a outra empresa.
- `404`: `empresa_nao_encontrada`.
- `409`: `idempotencia_conflito` (mesma `Idempotency-Key` com outro corpo) ou `conflito` (a mesma chave ainda está em processamento).
- `412`: `empresa_nao_pronta`, com a prontidão em `itens`. Nada foi criado.
- `422`: `validacao`: o LOTE tem erro (sem itens, acima do teto, `ao_validar` inválido, modelo inexistente, planilha ilegível). Nada foi criado. Erros de um ITEM não chegam aqui: aparecem no resultado da linha. Também `planilha_obrigatoria` (multipart sem o arquivo) e `simulacao_so_no_sandbox` / `simulacao_invalida` (campo `simular`). Planilha acima de 20 MB é recusada com 413.
- `429`: `limite_de_requisicoes` (`retentavel: true`): 120 requisições por minuto por chave, janela fixa de 60 s. Sem `Retry-After`: espere a virada do minuto e repita a MESMA requisição (com a mesma `Idempotency-Key`).

---

[API](https://skmtc.dev/sudrel/apis/api-publica-sudrel-nfs-e-nf-e-e-ct-e.md) · [All operations](https://skmtc.dev/sudrel/apis/api-publica-sudrel-nfs-e-nf-e-e-ct-e/llms.txt) · [OpenAPI document](https://skmtc.dev/sudrel/apis/api-publica-sudrel-nfs-e-nf-e-e-ct-e/revisions/efd7baba9e37?raw)
