NFS-e
Emita notas fiscais de serviço (NFS-e) em nome de um emitente registrado: fluxo de integração, diferenças entre canais municipais, manifestação de notas recebidas, cargas dos webhooks, modelo de erros, máquina de estados e checklist de integração.
Visão geral e fluxo de integração
| Passo | Endpoint | Observações |
|---|---|---|
| 1 Registrar emitente | POST /openapi/v2/empresas | Igual à NF-e, com a nova seção opcional emissaoNFSe; o bloco de NF-e pode ser omitido se você só emite NFS-e, e a IE não é exigida nesse caso |
| 2 Vincular certificado | POST /openapi/v1/empresas/{empresaId}/certificadoDigital | Igual à NF-e |
| 3 Registrar callback | POST /openapi/v1/webhooks | Igual à NF-e; os resultados de NFS-e reutilizam a mesma URL de callback |
| 4 Emitir | POST /openapi/v2/empresas/{empresaId}/nfse | Retorna HTTP 200 sem corpo na aceitação; o envio é assíncrono |
| 5 Consultar | GET /openapi/v2/empresas/{empresaId}/nfse/{nfseId} | Status, eventos, links de download do XML / DANFSe, eco da requisição |
| 5-A Conciliar | GET …/nfse/emitidas · GET …/nfse/emitidas/{chaveAcesso} | Lista de emitidas (paginação por janela de tempo) e consulta por chave de acesso |
| 6 Cancelar | POST /openapi/v2/empresas/{empresaId}/nfse/{nfseId}/cancelar | Assíncrono: 200 com recibo de aceitação, resultado via webhook |
| 7 Consultar notas recebidas | GET …/nfse/recebidas · GET …/nfse/recebidas/{chaveAcesso} | Lista das notas recebidas (paginada por período) e consulta de uma pela chave; é daqui que sai a chaveAcesso usada na manifestação |
| 8 Manifestar sobre nota recebida | POST …/recebidas/{chaveAcesso}/manifestar | Registra confirmação / rejeição de uma NFS-e recebida; o corpo traz tipo |
A autenticação é idêntica à da NF-e: cabeçalhos token / timestamp / sign, veja Autenticação.
Três diferenças estruturais em relação à NF-e
1. A chave de acesso tem 50 dígitos e é gerada pelo emissor oficial. A chave de 44 dígitos da NF-e é calculada pelo contribuinte; a chave da NFS-e só existe depois que a autoridade aceita o documento. Um documento que falhou, portanto, não tem chaveAcesso e só pode ser localizado por identificacaoDps, o identificador de DPS de 45 caracteres que geramos.
2. A nota de serviço é regida pelo município. A plataforma roteia pelo município do emitente; o canal resultante aparece como padraoMunicipal na resposta da consulta. Hoje há suporte ao padrão nacional (Nacional) e ao sistema municipal de São Paulo (Paulistana); um município não suportado é rejeitado na aceitação (10018010) em vez de aceito e falhado de forma assíncrona.
3. O cancelamento tem janela, e fora dela a resposta não é "não dá para cancelar" e sim "vai para análise municipal". Veja Cancelar NFS-e.
Pré-requisitos
- O emitente precisa estar aprovado e com certificado utilizável, caso contrário a aceitação é rejeitada (
10018004). - O emitente precisa ter perfil de NFS-e, criado pela seção
emissaoNFSede Registrar empresa ou mantido pela operação no console. Enquadramento no Simples, apuração no Simples, regime especial e série do DPS vêm sempre do perfil; a requisição de emissão não os envia nem os substitui. Sem perfil, a aceitação recusa (10018005). Código de serviço, CNAE, NBS e os demais campos do serviço não ficam no perfil: vão em cada nota. - O
ambienteEmissaoprecisa coincidir com o ambiente atual do emitente. Após o registro o emitente fica no ambiente de testes (Homologacao); a virada para produção é ação da operação e não é exposta pela API. - Os valores de tributação seguem a requisição: o que ela traz prevalece, e só o que falta a plataforma busca nos dados de referência fiscal, como a lista da LC 116, a classificação e as alíquotas de retenção federal e a carga aproximada do IBPT. Se os dados que a retenção federal, as alíquotas próprias de PIS/COFINS ou o local de incidência do ISS precisam consultar ainda não foram importados, a aceitação recusa com
10018065, listando os campos da requisição que podem substituí-los. - Quando o tomador é pessoa jurídica (CNPJ) há retenção federal: envie os valores em
servico.retencoes, em que zero declara que não há retenção, ou omita-os junto compisCofins.tipoRetencaoe a plataforma os determina pela classificação oficial de retenção do serviço e porcliente.orgaoPublicoecliente.optanteSimplesNacional; enviarpisCofins.tipoRetencaosem os valores é recusado (10018001). Informação faltante é rejeitada explicitamente (10018023) com tudo o que falta listado de uma vez, em vez de tratada como zero.
Restrições adicionais do canal Paulistana
Um emitente de São Paulo (padraoMunicipal = Paulistana) precisa do CCM (inscricaoMunicipal): se estiver no perfil, é usado como está; se faltar, a plataforma consulta o sistema municipal por CNPJ na aceitação e grava o resultado no perfil; a aceitação só é rejeitada (10018005) quando nada é encontrado.
O canal não suporta campos de desconto: incorpore o desconto ao valor do serviço ou à dedução. Também não suporta emissão substitutiva (o layout municipal de RPS não tem esse grupo): cancele a original e emita uma nova; enviar o grupo é rejeitado na aceitação (10018001).
Ele também ganha duas capacidades automáticas que não exigem nenhum endpoint novo: as notas paulistanas recebidas são puxadas direto do sistema municipal para a lista de recebidas (origem=PrefeituraSP, mescladas automaticamente quando a transcrição da ADN chega); uma nota emitida e cancelada no portal municipal é sincronizada para Cancelada e o nfse.canceled é enviado normalmente.
Máquina de estados
┌──────────────► Negada (terminal)│Pendente ────────┼──────────────► Autorizada ──┬──► Cancelada (terminal)│ │└──────────────► Falha ├──► EmProcessoDeCancelamento ──┬──► Cancelada(falhou antes da numeração, │ └──► Autorizada (análise indeferida)nenhum documento existe) └──► Substituida (substituída)
| Status | Significado | Terminal |
|---|---|---|
Pendente | Aceito, sem desfecho ainda | não |
Autorizada | Emitida com sucesso | não (pode ser cancelada ou substituída) |
Negada | Rejeitada pela autoridade | sim |
Falha | Falha do lado da plataforma (parâmetros inválidos / emitente inapto); nenhum documento foi criado | sim |
Cancelada | Cancelada | sim |
EmProcessoDeCancelamento | Análise de cancelamento aceita, aguardando o município | não |
Substituida | Substituída por outro documento | sim |
Status de manifestação de uma nota recebida
O status de uma nota recebida usa Autorizada / Cancelada / Substituida da tabela acima; a manifestação deste emitente fica separada no bloco manifestacao, e cada parte manifesta no máximo uma vez por nota.
(sem manifestação, filtro da lista Pendente) ──┬──► Confirmada (confirmada por este emitente, terminal)├──► Rejeitada (rejeitada por este emitente) ──► RejeicaoAnulada (rejeição anulada pelo município, terminal)└──► ConfirmacaoTacita (confirmação tácita do município, terminal)
| Status | Significado | Ainda pode manifestar |
|---|---|---|
null (valor de filtro Pendente) | Sem manifestação | sim (enquanto a nota estiver Autorizada) |
Confirmada | Confirmada por este emitente | não |
Rejeitada | Rejeitada por este emitente | não |
ConfirmacaoTacita | Confirmada tacitamente pelo município após o prazo | não |
RejeicaoAnulada | O município anulou a rejeição deste emitente | não |
Callbacks de webhook
Entregues na URL que você registra como carga JSON pura.
| Código do evento | Disparo | nfseStatus |
|---|---|---|
nfse.authorized | Emitida com sucesso | Autorizada |
nfse.rejected | Rejeitada pela autoridade ou falha do nosso lado | Negada |
nfse.canceled | Cancelamento concluído (inclusive análise deferida) | Cancelada |
nfse.cancel_requested | Análise de cancelamento aceita | EmProcessoDeCancelamento |
nfse.cancel_denied | O cancelamento não ocorreu e o documento segue autorizado: recusa síncrona da autoridade, envio esgotado, ou pedido de análise indeferido pelo município | Autorizada |
nfse.substituted | Este documento foi substituído; a carga traz um nfseChaveSubstituta adicional | Substituida |
nfse.inbound.received | NFS-e recebida (este emitente é tomador / intermediário, exige assinatura explícita) | — |
nfse.inbound.canceled | NFS-e recebida foi cancelada (exige assinatura explícita) | — |
nfse.inbound.substituted | NFS-e recebida foi substituída (exige assinatura explícita) | — |
Nota: Semântica das assinaturas. Um aplicativo que nunca registrou nenhuma linha de assinatura recebe todos os seis eventos de saída. Assim que existir qualquer linha de assinatura para o aplicativo (por exemplo um evento de entrada), ele passa ao modo lista de permissão e só os eventos explicitamente habilitados são entregues. Ao assinar eventos de entrada, habilite também os eventos de saída necessários, senão as notificações de saída ficam paradas aguardando destinatário.
{"tipo": "NFS-e","empresaId": "1001","nfseId": "PED-20260918-001","nfseStatus": "Autorizada","nfseMotivoStatus": null,"nfseLinkDanfse": "https://api.v2.tffiscal.com/openapi/files/danfse/…","nfseLinkXml": "https://api.v2.tffiscal.com/openapi/files/xml/9001?token=…","nfseNumero": "1287","nfseSerie": "1","nfseChaveAcesso": "3550308…","nfseIdentificacaoDps": "DPS3550308…","nfseDataEmissao": "2026-09-18T13:00:00Z","nfseDataAutorizacao": "2026-09-18T13:00:03Z","nfseNumeroProtocolo": null,"nfseAtualizadoEm": "2026-09-18T13:00:03Z"}
nfseAtualizadoEm é o momento desta mudança de estado. A ordem de entrega não é garantida: retentativas e múltiplas instâncias podem fazer um evento antigo chegar depois de um novo. Compare com o horário que você já tem e descarte o mais antigo em vez de sobrescrever o estado pela ordem de chegada.
Num callback de falha o nfseChaveAcesso pode vir vazio (a autoridade nunca gerou a chave); concilie por nfseIdentificacaoDps nesse caso. Um callback de falha anterior à numeração não traz nenhum dos dois, e só o nfseId concilia.
Modelo de erros
Os endpoints públicos retornam um array puro:
[{"codigo": "10018012", "mensagem": "Codigo de servico fora da lista oficial LC 116: 999999"}]
| Código | Significado | O que fazer |
|---|---|---|
10018001 | Validação de parâmetros recusada na aceitação (a mensagem indica o motivo) | Corrija conforme a mensagem |
NFSe0001 | Documento não encontrado: o nfseId não pertence a este emitente, ou a chave de entrada não está entre as notas recebidas dele | Confira nfseId / chaveAcesso contra empresaId |
10018004 | Emitente inapto (desativado / certificado inutilizável) | Verifique o status do emitente e o certificado |
10018005 | Emitente sem perfil de NFS-e | Crie-o antes em Registrar empresa com a seção emissaoNFSe |
10018010 | O padrão de NFS-e do município ainda não é suportado | Esse município ainda não pode emitir, fale com a plataforma |
10018012 | Código de serviço fora da lista LC 116 | Confira codigoTributacaoNacional |
10018013 | Documento do tomador inválido | Confira o CPF / CNPJ / NIF |
10018014 | Exportação de serviço sem país de destino | Informe servico.paisPrestacao |
10018015 | O documento substituído não pode ser substituído | Confira o status do documento substituído |
10018020 | Não foi possível determinar a alíquota de ISS | Envie servico.iss.aliquota ou o servico.codigoTributacaoMunicipal correto |
10018022 | Emitente do Simples não pode enviar a alíquota de ISS diretamente | Remova aliquota |
10018023 | A retenção federal não pode ser determinada; a mensagem lista tudo o que falta | Informe os campos listados ou envie os valores retidos em servico.retencoes |
10018030 | A mesma requisição já está em processamento | Tente de novo mais tarde |
10018031 | Esse pedido já tem nota, ou o mesmo id traz conteúdo diferente | Use outro número de pedido ou confira o conteúdo |
10018040 | Já há uma análise de cancelamento em andamento | Aguarde o veredito |
10018041 | O documento já foi substituído | Nenhuma outra operação é permitida |
10018042 | O status atual não permite este evento | Confira o status do documento |
10018063 | A mensagem do DPS não atende ao XSD oficial (o detalhe traz linha, coluna, chave do erro e nome do elemento) | Corrija conforme o detalhe: em geral texto fora do Latin-1, endereço incompleto, ou valor fora da tabela oficial |
10018064 | A mensagem de evento da NFS-e não atende ao XSD oficial | Confira o tamanho de motivo (15-255), o valor de codigoMotivo e o conjunto de caracteres |
10018065 | Os dados de referência fiscal da NFS-e de que esta nota precisa não foram importados, recusa na aceitação; a mensagem lista cada item com uma seta para o campo da requisição que o substitui | Envie na requisição os campos após a seta, ou confirme com a plataforma que os dados foram importados; para iss-local-incidencia, basta enviar servico.iss.municipioIncidencia |
Erros de autenticação e autorização (10009xxx) estão em Autenticação; a tabela completa está em Códigos de erro.
Checklist de integração
- Registre o emitente (com
emissaoNFSe) → vincule o certificado → registre o webhook. - Emita uma nota mínima em
Homologacao(só os campos obrigatórios), confirme que onfse.authorizedchega e que o XML e o DANFSe baixam. - Envie o mesmo
idoutra vez e confirme que nenhuma segunda nota é emitida. - Envie um código de serviço inexistente e confirme a recusa síncrona
10018012, e não umaNegadaassíncrona. - Cancele uma nota autorizada e confirme que ela chega a
CanceladaouEmProcessoDeCancelamentoconforme a janela. - Consulte um documento que falhou e confirme que ele concilia por
identificacaoDps, não porchaveAcesso. - Manifeste sobre uma nota recebida com
tipo=Confirmacaoe veja o detalhe trazermanifestacao.status=Confirmada; envietipo=Rejeicaona mesma nota e confirme o10018042(cada parte manifesta uma vez).
