Documentation › NFS-e issuance
NFS-e issuance
Issue, validate, query, cancel and replace NFS-e, with automatic adjustments per municipality.
Issue NFS-e through the same engine as the spreadsheet and the dashboard: same validation, same queue, same recovery from technical failures. An invoice issued by the API appears in the dashboard, with the origin "API".
You always send the same JSON, whatever the municipality. What
changes per municipality or per tax scenario (fill in, omit,
require a field) is decided on our side, and the response tells what was
done in ajustes:
{
"campo": "/prestador/inscricao_municipal",
"acao": "omitido",
"motivo": "O município não aceita a inscrição municipal do prestador nesta DPS (E0120). A nota foi reenviada sem ela.",
"regra": "correcao.E0120"
}
acao is preenchido, omitido, derivado or exigido; regra is the
stable identifier of the rule in our catalog (for example
dps.pAliq.exigido.simples_retido, param.aliquota_iss,
correcao.E0120). regras_versao carries the version of the two catalogs that
decided the invoice, automatic correction and field rules, in that order
(2026-09-30.1+2026-10-02.1).
When the ISS tax rate is required and you send none (and the
company has no default), we use the OFFICIAL tax rate that the municipality
registered in the Sistema Nacional NFS-e for the service, if it is the only one in
the accrual period (competência). It appears as a preenchido adjustment with the rule
param.aliquota_iss.
Status
The full cycle, with what to do in each status and the matching webhook, is in NFS-e statuses.
| Status | What it means |
|---|---|
transmitindo |
We are handling it: in the queue, sending, or recovering from a technical failure of the Sistema Nacional NFS-e. Do not resend. |
autorizada |
NFS-e issued. numero and chave_acesso filled in. |
rejeitada |
The Sistema Nacional NFS-e refused it. Reason in rejeicao. Fix it and issue a new invoice. |
cancelada |
Cancelled after authorization. Protocol in cancelamento. If it was a replacement, substituida_por tells which invoice replaced it. |
falha_transmissao |
Final. The transmission could not be completed or confirmed, and nothing else will be tried automatically. See falha: with dps_enviada: "desconhecido", check in the Emissor Nacional before issuing again. |
descartada |
The invoice came back without success and was discarded in the dashboard. |
aguardando_confirmacao |
The invoice's accrual period ended before an automatic retry. Nothing is transmitted until you confirm in POST /v1/nfse/{id}/confirmacao (you can change the accrual period). |
If the invoice stays 30 minutes in transmitindo, the response gets
aviso: {"codigo": "processamento_prolongado"} and the webhook
NFSE_PROCESSAMENTO_PROLONGADO is sent, once. It is only a warning: the invoice is still
being handled and the status does not change.
Replace an NFS-e
To correct an authorized invoice without cancelling it and issuing another, issue the
correct invoice in POST /v1/nfse with the substituicao block:
{
"empresa_id": "…",
"tomador": { "documento": "11222333000181" },
"valor": "1500.00",
"servico": { "descricao": "Consultoria de setembro, valor corrigido" },
"substituicao": { "nfse_id": "id-da-nota-original", "codigo_motivo": "99", "motivo": "Valor do serviço informado errado na nota original." }
}
The new invoice follows the usual path. When it is authorized, the
Sistema Nacional NFS-e cancels the original by itself (cancellation by
replacement): the original becomes cancelada, with substituida_por, and
its NFSE_CANCELADA webhook is sent. If the new one is rejected, the original
stays authorized and nothing changes in it.
Before transmitting, we refuse with 422 what is already known not to pass:
invoice cancelled or already replaced (E0046), invoice from another environment
(E0065), another replacement of the same invoice in progress, and codigo_motivo
99 without motivo (E0078). The municipality's replacement deadline (E0050) and the
service recipient's (tomador) manifestation (E0070) are known only to the Sistema Nacional NFS-e; they come back as a
rejection, with rejeicao.explicacao.
For an NFS-e issued outside Sudrel, use chave_acesso instead of
nfse_id. Replacement does not exist in batches.
Civil construction: construction site data
For the civil construction codes (07.02.01, 07.02.02, 07.04.01, 07.05.01,
07.05.02, 07.06.01, 07.06.02, 07.07.01, 07.08.01, 07.17.01, 07.19.01,
14.14.03 and 14.14.04) the Sistema Nacional NFS-e requires the construction site data, and for the
others it refuses it. Send servico.obra with the CNO, the CIB, or the CEP and street number
of the site, and the municipality, when it does not come from the CEP:
{ "servico": { "codigo_nacional": "070201", "obra": { "cno": "90.012.34567/89", "municipio": "Lauro de Freitas - BA" } } }
The site's municipality becomes the invoice's place of service. For the codes where the ISS is due where the site is, that municipality's agreement decides whether the ISS tax rate is required. In the spreadsheet, these are the columns "CNO da obra", "CEP da obra" etc., in the Completo layout.
Testing the integration (sandbox)
Use a sdr_test_ key on the SAME routes and with the SAME JSON. The invoice is
really transmitted to the test environment of the Sistema Nacional NFS-e
("restricted production", the national system's test environment), with the company's real certificate, and comes back
authorized or rejected by the same rules. It has no fiscal value,
does not count against the allowance, does not depend on a plan and does not appear in the dashboard.
ambiente comes as sandbox in the response and in the webhooks.
The two environments never mix: the test key sees only test
invoices, the production key only production ones, and the same referencia or
Idempotency-Key can be used in both. A company that issues through
the municipality's own system has no test environment: readiness returns the
item sandbox_municipio_proprio in bloqueio, and issuance is refused with 412
empresa_nao_pronta.
A technical failure of the Sistema Nacional NFS-e is not a response for you: the invoice
stays transmitindo while the automatic recovery works
(it queries the DPS before any resend, so the invoice is never
issued twice).
Minimal issuance
curl https://api.sudrel.com.br/api/v1/nfse \
-H "Authorization: Bearer sdr_live_..." \
-H "Idempotency-Key: 7f1c0d9a-4a51-4e0e-9b1f-2b6f0d3c5a10" \
-H "Prefer: wait=15" \
-H "Content-Type: application/json" \
-d '{"empresa_id":"0b7e6a52-3c1d-4f8e-9a20-5d4c3b2a1f00","referencia":"PED-1001","tomador":{"documento":"11222333000181"},"valor":"1500.00","servico":{"descricao":"Consultoria em sistemas"}}'
Money values and tax rates go as TEXT with a decimal point
("1500.00"). A JSON number is refused, so that no invoice value
depends on floating-point rounding.
Endpoints in this section, with in-page testing
- GET/v1/servicos/{codigo}/nbs · NBS codes accepted for a service code
- GET/v1/municipios/{ibge}/parametros · Agreement and official parameters of a municipality
- GET/v1/nfse · List issued NFS-e
- POST/v1/nfse · Issue an NFS-e
- POST/v1/nfse/validacoes · Validate an NFS-e without issuing
- GET/v1/nfse/{id} · Get an NFS-e
- GET/v1/nfse/{id}/xml · NFS-e XML
- GET/v1/nfse/{id}/pdf · NFS-e PDF (DANFSe)
- POST/v1/nfse/{id}/confirmacao · Confirm transmission of an invoice that awaits confirmation
- POST/v1/nfse/{id}/cancelamento · Cancel an authorized NFS-e