Como exportar NFS-e em massa (XML, PDF, CSV)
Em vez de baixar XML/PDF nota a nota, gere um único arquivo consolidado com todas as NFS-es de um período. Casos típicos: fechamento contábil mensal, conciliação com contas a pagar, geração de relatórios para Power BI, auditoria SEFAZ. A geração roda no shared-usage-api (pipeline separado do dfetech-distribution-api), de forma assíncrona, e entrega o resultado via URL temporária por e-mail.
Sumário
Pré-requisitos
- Empresa com NFS-e Inbound ativo e documentos capturados — veja Integração REST.
- API Key com papel
Nota Fiscal (api.nfe.io)ouNFSeDist (dfe.nfe.io)— a mesma usada na API principal. accountIdesubscriptionIdda sua conta — visíveis no painel NFE.io.- Cliente HTTP capaz de polling (cURL + jq, Python, Node, etc.).
Fluxo
Solução
A exportação é assíncrona: você cria um ExportJob via POST (resposta 202 Accepted), recebe um jobId, e acompanha por polling em GET .../exports({jobId}) até status: "Completed". O resultado fica em uma URL pré-assinada (HMAC) válida por 7 dias — baixe ou encaminhe rápido.
Três formatos de saída via resource:
resource | Saída | Tempo típico (1.000 notas) |
|---|---|---|
company-nfse-inbound-xml | ZIP de XMLs assinados | 3-8 minutos |
company-nfse-inbound-pdf | ZIP de DANFSes em PDF | 3-8 minutos |
company-nfse-inbound-analytical-csv | CSV analítico com 24 colunas (1 linha por nota) | 30-60 segundos |
Etapa 1: Criar o job de exportação
export NFEIO_API_KEY="<sua-chave>"
export ACCOUNT_ID="<account-id>"
export SUB_ID="<subscription-id>"
export USAGE_BASE="https://shared-usage-api.azurewebsites.net"
curl -X POST "$USAGE_BASE/accounts($ACCOUNT_ID)/subscriptions($SUB_ID)/exports" \
-H "Authorization: $NFEIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"companyId": "65a1b2c3d4e5f6789abcdef0",
"resource": "company-nfse-inbound-analytical-csv",
"beginOn": "2026-04-01",
"endOn": "2026-04-30",
"emails": ["[email protected]"],
"createdBy": "[email protected]",
"userEmail": "[email protected]",
"apiKey": "'$NFEIO_API_KEY'",
"splitDays": false,
"language": "pt-BR"
}'
Resposta 202 Accepted traz id (= jobId) e status: "Pending". O header Location aponta para o endpoint de acompanhamento.
Etapa 2: Acompanhar até concluir
JOB_ID="<id-retornado>"
while true; do
RESP=$(curl -s "$USAGE_BASE/accounts($ACCOUNT_ID)/subscriptions($SUB_ID)/exports($JOB_ID)" \
-H "Authorization: $NFEIO_API_KEY")
STATUS=$(echo "$RESP" | jq -r .status)
echo "Status: $STATUS"
[ "$STATUS" = "Completed" ] && break
[ "$STATUS" = "Failed" ] && echo "ERRO: $(echo $RESP | jq -r .errorMessage)" && exit 1
sleep 30
done
DOWNLOAD_URL=$(echo "$RESP" | jq -r .downloadUrl)
curl -o nfse-inbound-202604.csv "$DOWNLOAD_URL"
Estados terminais: Completed (sucesso, downloadUrl válida por 7 dias), Failed (errorMessage preenchido). Os contadores totalLines (notas no arquivo final) e failed (notas que erraram individualmente sem parar o job) ajudam a validar — se failed > 0, abra os detalhes para investigar.
Etapa 3: Interpretar o CSV analítico
Cada linha = 1 NFS-e. As 24 colunas combinam identificação (Invoice_Id, NSU, Access_Key), datas (Generated_On, Issued_Date, Accrual_On, Created_At), partes (Provider_Federal_Tax_Number, Borrower_Federal_Tax_Number e nomes), valores (Services_Amount), classificação (Issue_City_Code, Service_Code), status (Invoice_Status, Webhook_Status, Has_Pdf, Environment, Description) e — para notas com eventos relacionados — o evento primário achatado: Event_Type, Event_Code, Event_Access_Key, Event_Generated_On, Substitute_Access_Key.
A regra de prioridade do evento primário (NFS-e): Substituição (310611) > Cancelamento (310610) > mais recente por GeneratedOn. Quando a nota não tem evento, as 5 colunas finais ficam vazias mas a linha continua sendo emitida.
Encoding: ISO-8859-1, delimitador ;, CRLF, decimais com ponto. Abre direto no Excel BR sem conversão.
⚠️ Os códigos
310610/310611que aparecem na colunaEvent_Codedeste CSV são do catálogo NFE.io, não os códigos XSDtpEventodo SEFIN. Veja Códigos de evento para o mapeamento.
Variações
splitDays=true: gera 1 arquivo por dia em vez de um único. Recomendado para períodos longos (>1 mês) — facilita download paralelo e tolerância a falha por dia.language: "en-US": colunas do CSV em inglês. Útil para sistemas internacionais ou times multilíngues.- NF-e Recebidas em massa: o mesmo endpoint aceita os
resourceparaleloscompany-nfe-inbound-{xml,pdf,analytical-csv}. CT-e Recebidas não tem bulk export ainda (no roadmap). - Sem e-mail (polling-only): envie
emails: []. Útil para integrações automatizadas. - Reexecução de período: simplesmente crie um novo job com o mesmo
beginOn/endOn. Não há endpoint de "atualizar job".
Armadilhas comuns
apiKeyno body é obrigatório: o worker doshared-usage-apié assíncrono e não tem acesso ao headerAuthorizationoriginal — precisa do valor duplicado no body. Sem ele,400 MISSING_API_KEY.createdBy/userEmailaparecem em logs de auditoria: use um identificador rastreável (e-mail real do solicitante), não valores genéricos comosystemoubot.downloadUrlexpira em 7 dias: por política de privacidade, o arquivo é deletado após esse prazo. Baixe e armazene localmente se precisar reter — não guarde só o link.- Polling agressivo não acelera: intervalo de 30 segundos é suficiente. Polling mais frequente desperdiça quota e não muda o tempo de processamento (que depende do volume de notas e da fila do
AzExport). - Job "Em processamento" por mais de 1 hora: pode estar travado. Verifique status persistente; se continuar, contate o suporte mencionando o
jobId. - CSV abre tudo em 1 coluna no Excel: o Excel está usando delimitador errado. Importe via Dados → Obter Dados → Do Arquivo → CSV/Texto, escolha delimitador
;e encoding ISO-8859-1. - Excede limite de período: máximo prático é 6 meses. Para fechamento anual, use
splitDays=trueou rode 12 jobs mensais.
Veja também
- Integração REST — consumo individual de documentos via API principal
- Catálogo de eventos do webhook — captura em tempo real (alternativa a bulk para fluxo contínuo)
- Códigos de evento — mapeamento entre
Event_Codedo CSV etpEventodo XSD - Arquitetura — como
shared-usage-apise relaciona com a API principal - Troubleshooting — diagnóstico de jobs
Failed