Como consultar uma DC-e pela API
GET /v1/subscriptions/{subscriptionId}/taxpayers/{taxpayerId}/contentdeclarations/{id}
Devolve o estado atual de uma DC-e e o que foi declarado nela:
- situação (
status,flowStatus), chave de acesso, protocolo, série e número; - emitente e destinatário — nome e CNPJ ou CPF — e o valor total;
- os itens declarados, em
items, com os mesmos nomes de campo do corpo da emissão e na mesma ordem; - quais arquivos já podem ser baixados, em
artifacts(veja DACE e XML); - o código e o motivo da SEFAZ quando ela rejeitou (
rejectionCStat,rejectionReason) ou respondeu ao cancelamento (cancellationCStat,cancellationReason); - o lote (
batchId), a versão do leiaute registrada na criação (specVersion) e o ambiente (environment:1produção,2homologação).
Endereços, transporte e informações adicionais não estão no detalhe. Se precisar deles, guarde o corpo que você enviou na emissão ou baixe o XML autorizado.
O campo status
| Valor | Significado |
|---|---|
Created | Criado, ainda não transmitido |
Processing | Em processamento |
Authorized | Autorizado pela SEFAZ — tem accessKey e protocol |
Rejected | Rejeitado pela SEFAZ — veja rejectionCStat e rejectionReason |
Cancelled | Cancelado |
Refused | Parou por veredito nosso — veja refusedStep e refusedReasons |
Unknown | Situação que esta versão do contrato não conhece |
Rejected e Refused não são a mesma coisaRejected é a SEFAZ dizendo não, depois de receber o documento — motivo fiscal, com cStat. Refused é a NFE.io parando a emissão antes de transmitir — cadastro incompleto, certificado com problema, ou validação local. Um documento Refused nunca chegou à SEFAZ.
status e flowStatus podem ganhar valores novos sem aviso, e durante uma atualização do serviço duas versões podem conviver por alguns minutos. Trate um valor desconhecido (Unknown ou outro) como "estado que ainda não conheço" e não falhe.
{
"id": "0f6b1f5c-9a5e-4a0e-9c1b-2f4e6d8a1b23",
"status": "Authorized",
"flowStatus": "Finished",
"accessKey": "33260811222333000181990010000000211208201894",
"serie": 1,
"number": 21,
"protocol": "133260000123456",
"createdAt": "2026-08-19T13:04:11.512Z",
"artifacts": { "hasFull": true, "hasSummary": true, "hasXml": true },
"issuerName": "EMPRESA EXEMPLO LTDA - MATRIZ",
"issuerFederalTaxNumber": "11222333000181",
"recipientName": "EMPRESA EXEMPLO LTDA - FILIAL",
"recipientFederalTaxNumber": "99887766000105",
"totalValue": 3000,
"items": [
{
"itemNumber": 1,
"description": "EQUIPAMENTO DE EXEMPLO",
"ncm": "84713012",
"quantity": 2,
"unitValue": 1500.00,
"totalValue": 3000.00
}
],
"specVersion": "1.00",
"environment": 2
}
{
"id": "5d1e9a77-3c2b-4f0e-8a6d-7b9c0e1f2a34",
"status": "Rejected",
"flowStatus": "Finished",
"accessKey": "33260811222333000181990010000000221208201890",
"serie": 1,
"number": 22,
"createdAt": "2026-08-19T14:10:02.118Z",
"artifacts": { "hasFull": false, "hasSummary": false, "hasXml": false },
"rejectionCStat": 812,
"rejectionReason": "Usuário emitente bloqueado para emissão de DCe",
"issuerName": "EMPRESA EXEMPLO LTDA - MATRIZ",
"issuerFederalTaxNumber": "11222333000181",
"recipientName": "EMPRESA EXEMPLO LTDA - FILIAL",
"recipientFederalTaxNumber": "99887766000105",
"totalValue": 3000,
"items": [ … ],
"environment": 2
}
{
"id": "0f6b1f5c-9a5e-4a0e-9c1b-2f4e6d8a1b23",
"status": "Refused",
"flowStatus": "Finished",
"serie": 0,
"number": 0,
"refusedStep": "DefineNumber",
"refusedReasons": ["Empresa sem certificado digital válido em custódia"],
"createdAt": "2026-08-19T13:04:11.512Z",
"artifacts": { "hasFull": false, "hasSummary": false, "hasXml": false },
"issuerName": "EMPRESA EXEMPLO LTDA - MATRIZ",
"issuerFederalTaxNumber": "11222333000181",
"recipientName": "EMPRESA EXEMPLO LTDA - FILIAL",
"recipientFederalTaxNumber": "99887766000105",
"totalValue": 3000,
"items": [ … ],
"environment": 2
}
Campos opcionais sem valor são omitidos do JSON — nunca devolvidos como null. É por isso que o exemplo Refused não tem accessKey nem protocol: nenhum dos dois chegou a existir. Alguns campos têm outra regra:
serieenumbervêm0enquanto a numeração não foi definida;artifactseitemsvêm sempre — sem artefato, os trêshas*sãofalse; sem item,itemsé[];issuerNameerecipientNamevêm sempre, e podem vir como texto vazio ("");rejectionCStat,cancellationCState os motivos correspondentes só aparecem quando a SEFAZ respondeu algo a eles;specVersionsó aparece quando foi registrada na criação.
Os textos da SEFAZ (rejectionReason, cancellationReason) vêm em português, como ela respondeu.
O cabeçalho ETag
A resposta 200 traz o cabeçalho ETag com a versão atual do documento, no formato de ETag fraca:
ETag: W/"4"
É esse valor que vai no If-Match do cancelamento: se o documento mudar entre a sua leitura e o pedido de cancelamento, a resposta é 412 e nada é enviado.
O histórico de eventos
GET /v1/subscriptions/{subscriptionId}/taxpayers/{taxpayerId}/contentdeclarations/{id}/events
Devolve o histórico do documento, em ordem de versão — é a resposta para "por que este documento está neste estado?", inclusive quando o estado é Rejected ou Refused.
eventType | O que traz em data |
|---|---|
ContentDeclarationCreated | emitterType, emissionType, serie, number |
NumberDefined | number, serie, accessKey |
SentToSefaz | Nada além de tipo, versão e data |
Authorized | protocol, authorizedAt |
Rejected | cStat, reason |
ContingencyAccepted | accessKey |
DaceGenerated | hasFull, hasSummary, hasXml |
CancelRequested | reason, cancellationProtocol, cStat |
Cancelled | protocol, cancelledAt, cStat |
CancelRejected | cStat, reason |
Notified | eventType (o evento notificado) |
Refused | step (o passo em que a NFE.io parou a emissão), reasons |
FlowFailed | step, reasons — uma falha no processamento daquele passo |
FlowExhausted | step, reasons, attempts (quantas tentativas foram feitas), cStat — as tentativas daquele passo se esgotaram |
AuthorizationNotFound | step, reasons, attempts, notFoundAnswers (quantas vezes a SEFAZ respondeu que não encontrou a autorização), cStat |
ReprocessExecuted | step — o documento voltou a ser processado a partir desse passo |
Os eventos de falha guardam o motivo no histórico de forma permanente. Se o documento voltar a ser processado depois de uma falha, refusedStep e refusedReasons são limpos no detalhe, mas o histórico continua mostrando o que aconteceu.
XML assinado e dados pessoais completos não aparecem aqui de propósito. Tipos de evento novos podem surgir — um tipo que você não conhece vem apenas com tipo, versão e data, sem data.
[
{
"eventType": "ContentDeclarationCreated",
"version": 1,
"occurredAt": "2026-08-19T13:04:11.512Z",
"data": {
"emitterType": "SelfIssuer",
"emissionType": "Normal",
"serie": 1,
"number": 0
}
},
{
"eventType": "NumberDefined",
"version": 2,
"occurredAt": "2026-08-19T13:04:12.004Z",
"data": {
"number": 21,
"serie": 1,
"accessKey": "33260811222333000181990010000000211208201894"
}
},
{
"eventType": "Authorized",
"version": 4,
"occurredAt": "2026-08-19T13:04:19.881Z",
"data": {
"protocol": "133260000123456",
"authorizedAt": "2026-08-19T13:04:19Z"
}
}
]
Consultar várias de uma vez
Quando o que você precisa é uma grade — o que foi emitido hoje, o que está preso em Processing, o que a SEFAZ rejeitou — a consulta em lista responde em uma chamada:
GET /v1/subscriptions/{subscriptionId}/taxpayers/{taxpayerId}/contentdeclarations
Ela aceita $filter, $orderby, $top, $skip, $count e $select, e devolve as colunas promovidas de cada documento — chave de acesso, situação, série e número, emitente, destinatário, valor total e ambiente. Itens, transporte e endereços não estão na lista: para os itens, use o GET {id} acima.
Quatro coisas que costumam pegar quem começa:
- A resposta não é um array nu. As linhas vêm em
value, no envelope OData. $toptem teto de 200, que também é o padrão. Acima disso a resposta é400; pagine com$skip.- O total vem em
@odata.count, e só quando você manda$count=true. Ele conta sob o mesmo filtro, não o tamanho da página. - Opção que a listagem não sabe resolver é
400, comtypeterminado emunsupported-query, títuloThe query could not be resolved.e, emdetail, a mensagem do interpretador da consulta dizendo o que não foi entendido.
No filtro por lote ($filter=batchId eq '…'), um GUID casa com ou sem hífens.
Os parâmetros, o conjunto fechado de campos filtráveis e o que responde 400 estão na referência da operação.
Erros
| Código | O que significa |
|---|---|
400 | Na listagem: opção de consulta que não pode ser resolvida (unsupported-query) ou $top acima de 200 |
401 | Token ausente, inválido ou expirado — peça um novo token (veja Autenticação) |
403 | A assinatura da URL não é a do token nem uma que o usuário acessa (type termina em subscription-scope-undetermined) |
404 | Empresa da URL inexistente ou fora da assinatura (type termina em company-not-in-subscription), ou documento inexistente nessa empresa |