Pular para o conteúdo principal

Caracteres especiais nos campos de texto da NFS-e

🇺🇸 This page is also available in English: Special characters in NFS-e text fields.

Campos de texto livre da NFS-e — descrição do serviço, informações complementares, razão social e endereço do tomador — aceitam conjuntos de caracteres diferentes conforme o município de emissão. Um mesmo texto pode ser aceito num município e recusado em outro.

Esta página descreve como a plataforma trata cada caso, para você saber o que enviar e o que fazer quando uma nota é recusada.

Em uma frase

Se todos os seus textos usarem apenas letras, números, pontuação comum e acentos do português (o conjunto Latin-1, de U+0000 a U+00FF), eles são aceitos em todos os provedores. Os problemas vêm de caracteres que parecem inofensivos mas estão fora desse conjunto: travessão , aspas curvas " ", reticências , bullet , emoji e caracteres invisíveis.

Regra prática

Acento é seguro. Aspas curvas, travessão e emoji não são.

As três camadas de validação

Um texto enviado na emissão passa por três verificações independentes, nesta ordem:

OrdemCamadaO que fazQuando falha
1APIRecusa o que é impossível representar em documento fiscal eletrônicoHTTP 400 na hora da requisição
2PlataformaNormaliza o texto para o formato que o provedor do município exige— (ajuste silencioso, quando é seguro)
3Provedor municipalValida contra o schema da prefeituraNota recusada, com mensagem no webhook

Camada 1 — Validação na API

Acontece no momento da requisição, antes de qualquer processamento.

Corpo precisa estar em UTF-8

O JSON deve ser enviado codificado em UTF-8. Corpo em outra codificação é recusado com HTTP 400:

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"$": ["O corpo da requisicao nao esta em UTF-8. Reenvie o JSON codificado em UTF-8."]
},
"traceId": "00-1f3a…-b7c2…-01"
}

A resposta segue o formato application/problem+json, o mesmo dos demais erros de validação da API. Guarde o traceId: é por ele que o suporte localiza a requisição.

Causa mais comum

Texto originado em sistemas legados que usam Windows-1252 e é enviado sem conversão. Acentos viram bytes inválidos no meio do caminho.

Caracteres impossíveis em XML são recusados

A NFS-e é transmitida à prefeitura como XML. Alguns caracteres não existem em XML 1.0 — o principal é o caractere nulo U+0000, mas a regra vale para todos os caracteres de controle proibidos pelo padrão.

Quando o corpo contém um deles, a resposta é HTTP 400 nomeando a propriedade e o code point:

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"errors": {
"description": [
"Contém o caractere U+0000, inválido em XML 1.0 e não permitido em documento fiscal eletrônico. Remova o caractere e reenvie a requisição."
]
},
"traceId": "00-1f3a…-b7c2…-01"
}

Até 10 ocorrências distintas são reportadas de uma vez, para você corrigir tudo numa passada em vez de descobrir um campo por tentativa.

Quando a chave vem como $

A chave do objeto errors é o nome da propriedade em que o caractere apareceu. Quando ele não pertence ao valor de nenhuma propriedade — está numa chave do JSON ou num elemento solto de array —, a chave vem como $, que é a convenção da API para erro de corpo sem caminho de propriedade. Nomes de propriedade muito longos são truncados na resposta.

Por que o code point aparece como U+XXXX

Vários desses caracteres são invisíveis. Se a mensagem imprimisse o caractere em si, você leria "contém o caractere " sem ver caractere nenhum. O code point é o que permite localizá-lo no seu payload.

O que é ajustado em vez de recusado

Caracteres que podem ser representados em XML, mas exigem tratamento — como &, < e > — são escapados automaticamente. Nada é removido do seu texto nessa etapa.


Camada 2 — Normalização pela plataforma

Quando o provedor do município exige um formato específico e a conversão é inequívoca, a plataforma ajusta o texto sozinha. O critério é não alterar o sentido do que você enviou.

Transliteração para Latin-1 (padrão nacional)

Nos municípios que usam o padrão nacional da NFS-e, os campos de texto seguem um tipo de schema que aceita apenas U+0020 a U+00FF e não admite quebra de linha nem tabulação. Antes do envio, a plataforma aplica:

EntradaViraObservação
Quebra de linha, tabulação, CRespaçoEspaços consecutivos colapsam em um
(travessão, bullet)-Hífen comum
' ' (aspas simples curvas)'Apóstrofo reto
" " (aspas duplas curvas)"Aspas retas
(reticências)...Três pontos
Emoji, ideogramas, símbolos sem equivalenteespaçoNão há conversão possível
Acentos, ç, ª, ºinalteradoLatin-1 passa intacto

O texto é aparado no início e no fim. Nada é truncado nesta etapa — o limite de tamanho é validado separadamente, por campo.

A descrição do serviço é a exceção

No padrão nacional, o campo de discriminação do serviço usa um tipo de schema mais permissivo e aceita quebras de linha. A normalização acima não se aplica a ele. Já as informações complementares seguem a regra restrita.

Campo que sanitiza para vazio é omitido

Se um campo contiver apenas caracteres sem equivalente (por exemplo, só emoji), o resultado da normalização é vazio — e o campo é omitido da nota, porque o schema exige ao menos um caractere. O texto não aparece no documento emitido.

Remoção de acentos

Uma parte dos provedores municipais não aceita acentuação. Para eles, a plataforma remove os sinais diacríticos automaticamente antes do envio: São Paulo vira Sao Paulo, informações vira informacoes. A letra base é preservada; nada é descartado.

Campos de largura fixa

Alguns municípios recebem a nota em formato de texto posicional, não XML. Nesses casos, além da remoção de acentos, cada campo é ajustado ao tamanho exato exigido pelo layout — texto mais longo é cortado no limite do campo.


Camada 3 — Validação do provedor municipal

Aqui a nota já saiu da plataforma. A recusa vem da prefeitura e chega até você pelo webhook e pela consulta da nota.

Provedores que recusam fora de Latin-1

Alguns provedores recusam a nota inteira quando qualquer campo de texto contém caractere acima de U+00FF, em vez de aceitar uma conversão. O caso mais relevante é o da Prefeitura de São Paulo (NFS-e Paulistana).

Nesse cenário a plataforma não translitera o texto: a recusa acontece antes do envio à prefeitura, com uma mensagem que nomeia campo, caractere e code point:

[E1002] A Prefeitura de São Paulo não aceita o caractere '–' (U+2013) no campo
Discriminação dos serviços (Discriminacao). Os campos de texto admitem apenas
caracteres do conjunto Latin-1 (ISO-8859-1). Substitua por um equivalente:
travessão por hífen '-', reticências por '...', aspas curvas por aspas retas,
caractere invisível pela remoção. Depois, reenvie a nota.

Até 10 ocorrências distintas são listadas por recusa.

Quando a recusa não vem nesse formato

Essa verificação prévia depende da configuração do município e do provedor. Onde ela não está em vigor, a nota é enviada e quem recusa é a própria prefeitura, com um erro de schema genérico — tipicamente [1001] XML não compatível com Schema — que não aponta o campo nem o caractere. O tratamento é o mesmo: procure caracteres fora do Latin-1 nos campos de texto, começando pelos invisíveis.

Por que recusar em vez de corrigir sozinho

Uma recusa você resolve em segundos reenviando o texto ajustado. Um texto alterado dentro de uma nota já autorizada pela prefeitura não tem volta — o documento fiscal fica com conteúdo diferente do que você enviou. Por isso, quando a conversão não é inequívoca, a plataforma prefere devolver o erro.

A regra vale para todos os campos de texto, não só a discriminação. Os mais afetados na prática:

  • Discriminação dos serviços
  • Razão social do tomador
  • Logradouro, número, complemento e bairro do endereço
  • E-mail do tomador e do intermediário

Provedores que exigem apenas ASCII

Um pequeno grupo de provedores rejeita qualquer caractere não-ASCII, inclusive acentos. Para eles, a plataforma converte automaticamente cada caractere acentuado em uma referência numérica — uma representação que o provedor reconverte no caractere original ao processar a nota. O acento aparece corretamente no documento final; a conversão é transparente para você.


Tabela de substituições recomendadas

Se o seu sistema gera texto a partir de editores (Word, Google Docs, navegadores) ou de conteúdo colado por usuários, estes são os caracteres que aparecem com mais frequência e que você deve substituir na origem:

CaractereNomeCode pointSubstitua por
Travessão curto (en dash)U+2013-
Travessão longo (em dash)U+2014-
' 'Aspas simples curvasU+2018 U+2019'
" "Aspas duplas curvasU+201C U+201D"
ReticênciasU+2026...
Marcador de listaU+2022-
SetaU+2192->
®Marca registradaU+2122 U+00AE(TM) / (R)® é Latin-1 e passa
(invisível)Word joinerU+2060remover
(invisível)Espaço de largura zeroU+200Bremover
(invisível)Marca de ordenaçãoU+200E U+200Fremover
😀 🙏Emojiacima de U+FFFFremover
Caracteres invisíveis são a causa mais difícil de diagnosticar

U+2060, U+200B e similares entram no texto por cópia e colagem e não aparecem na tela. Uma descrição visualmente idêntica a outra que funcionou pode ser recusada por causa deles. Por isso as mensagens de erro sempre trazem o code point.


Como diagnosticar uma rejeição

SintomaCamadaO que fazer
HTTP 400 com "não esta em UTF-8"APIConverta o corpo da requisição para UTF-8
HTTP 400 citando U+XXXX e inválido em XML 1.0APIRemova o caractere indicado do campo indicado
Nota recusada com [E1002]ProvedorSubstitua os caracteres listados pelos equivalentes Latin-1 e reenvie
Nota recusada por erro de schema sem campo identificado (ex.: [1001] XML não compatível com Schema)ProvedorVerifique quebras de linha e caracteres fora de Latin-1 nos campos de texto
Texto saiu sem acento no documentoPlataformaComportamento esperado para o provedor do município
Campo não apareceu no documentoPlataformaO conteúdo era só de caracteres sem equivalente e foi omitido
Como encontrar o caractere no seu payload

Use o code point da mensagem. Em JavaScript: texto.codePointAt(i).toString(16). Em C#: char.ConvertToUtf32(texto, i).ToString("X4"). Em Python: hex(ord(c)).


Boas práticas para a integração

  1. Normalize na origem. Aplique a tabela de substituições antes de enviar, não depois de uma recusa. O conjunto Latin-1 funciona em todos os provedores.
  2. Trate o texto colado por usuários. É de onde vêm aspas curvas, travessões e invisíveis.
  3. Não dependa de quebras de linha. Só a discriminação do serviço as aceita, e apenas em parte dos municípios. Use separadores como - ou | para estruturar o texto.
  4. Leia o webhook de falha. As mensagens nomeiam campo, caractere e code point — são suficientes para automatizar a correção.
  5. Valide o tamanho separadamente. A normalização de caracteres não trunca; o limite de cada campo é validado por conta própria.

Páginas relacionadas

NFE.io

A NFE.io é uma empresa de tecnologia que fornece soluções para automatizar e simplificar a emissão e gestão de notas fiscais eletrônicas. Com suas ferramentas, as empresas podem economizar tempo e reduzir erros, aumentando a eficiência e precisão do processo de emissão de notas fiscais.

Um dos principais cases de sucesso da NFE.io é a implementação da solução na empresa de transporte Rodonaves. Com a automatização da emissão e gestão de notas fiscais eletrônicas, a Rodonaves conseguiu reduzir em até 80% o tempo gasto nesse processo, o que se traduziu em uma significativa melhoria na eficiência operacional. Além disso, a empresa também conseguiu eliminar erros e atrasos na emissão de notas fiscais, o que melhorou a relação com seus clientes e aumentou a confiança dos órgãos fiscais.

Outro exemplo é a implementação da NFE.io na empresa de comércio eletrônico, a Loja Integrada. Com a automatização da emissão de notas fiscais, a Loja Integrada conseguiu aumentar a velocidade de emissão de notas em até 10 vezes, o que permitiu que a empresa atendesse a uma maior quantidade de clientes e, consequentemente, aumentar as suas vendas.

Além desses exemplos, a NFE.io também tem outros cases de sucesso com empresas de setores como indústria, construção, varejo e serviços, mostrando a versatilidade e eficácia da sua solução.

Em resumo, a NFE.io é uma empresa de tecnologia que oferece soluções para automatizar e simplificar a emissão e gestão de notas fiscais eletrônicas, ajudando as empresas a economizar tempo e reduzir erros, melhorando a eficiência e precisão do processo. Com cases de sucesso em diferentes setores, a NFE.io tem se destacado como uma empresa líder em automação fiscal.