NCM API
Classificação fiscal brasileira por IA — NCM, CEST, Substituição Tributária, IBPT e regimes ICMS/PIS/COFINS/IPI + IBS/CBS/IS (Reforma Tributária).
https://api.seu-dominio.com.br
Recomendamos que os dados gerados sejam avaliados pelo contador da empresa, profissional mais habilitado a validar a classificação tributária e o cumprimento das obrigações acessórias. Trate o retorno da API como ponto de partida que acelera o trabalho — não como decisão final isolada. Especialmente quando o campo
confianca
vier "media" ou "baixa",
ou em produtos com regime tributário especial (ST específica, IS, cesta básica, monofásicos).
Quickstart em 3 passos
Obtenha sua API Key
Solicite ao administrador a emissão de uma API Key. Você receberá uma
chave única no formato ncm_live_xxxxxxxxx…
(produção) ou ncm_test_xxxxxxxxx…
(homologação).
Faça sua primeira chamada
curl -X POST https://api.seu-dominio.com.br/ncm/buscar \
-H "X-API-Key: SUA_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "produto": "coca cola lata 350ml" }'
Receba o NCM classificado
{
"produto": "coca cola lata 350ml",
"ncm": "22021000",
"descricao_ncm": "Águas gaseificadas adicionadas de açúcar",
"ncm_validado": true,
"ncm_vigente": true,
"cest": "0300700",
"tem_st": true,
"confianca": "alta",
"fonte": "gemini"
}
Autenticação
Toda requisição precisa enviar sua chave em um destes headers (use apenas um):
| Header | Valor |
|---|---|
| X-API-Key | ncm_live_xxxxxxxx... (recomendado) |
| Authorization | Bearer ncm_live_xxxxxxxx... |
Produção × Homologação
Cada cliente pode ter chaves nos dois ambientes. Os endpoints são os mesmos — o que muda é o comportamento, definido pelo prefixo da chave:
- ✓ Classifica via Google Gemini AI
- ✓ Valida contra tabela NCM oficial (Siscomex)
- ✓ Identifica ST via tabela CEST
- ✓ Consume créditos do seu plano
- ✓ Resultados reais e auditáveis
- ✓ Retorna NCMs fictícios determinísticos
- ✓ Mesma estrutura de resposta da produção
- ✓ Não consome créditos
- ✓ Ideal para testes de integração e CI
- ✓ Resposta tem
"fonte":"mock_homologacao"
Em homologação, o mesmo nome de produto sempre gera o mesmo NCM (de um pool pré-definido), permitindo testes determinísticos no seu pipeline.
Créditos e cobrança
Cada conta possui um saldo de créditos definido pelo plano contratado. Veja quanto cada chamada consome:
| Endpoint | Créditos |
|---|---|
POST /ncm/buscar (1 produto) | 1 |
POST /ncm/batch (N produtos) | N |
GET /ncm/:codigo | configurável* |
GET /ncm/:codigo/tributacao | configurável* |
GET /cest/:ncm | configurável* |
| Qualquer chamada em homologação | 0 |
* Definido pelo plano (default 0). Confirme com o admin.
Headers de quota
Toda resposta bem-sucedida em produção traz seu saldo atual nestes headers:
HTTP/1.1 200 OK
X-NCM-Quota-Total: 5000
X-NCM-Quota-Used: 437
X-NCM-Quota-Remaining: 4563
X-NCM-Quota-Reset: 2026-06-12 # ou "never" se sem expiração
Content-Type: application/json
Use esses headers no seu monitoramento para emitir alertas internos antes de atingir o limite.
Referência de endpoints
/ncm/buscar
Classifica um produto pelo nome comercial. Retorna NCM sugerido, validação contra a tabela oficial, CEST associado e flag de ST.
Request body
| Campo | Tipo | Descrição |
|---|---|---|
| produto | string * | Nome comercial do produto, ex: "coca cola lata 350ml" |
Exemplos
curl -X POST https://api.seu-dominio.com.br/ncm/buscar \
-H "X-API-Key: ncm_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "produto": "coca cola lata 350ml" }'
Resposta (200 OK)
{
"produto": "coca cola lata 350ml",
"ncm": "22021000",
"descricao_ncm": "Águas gaseificadas adicionadas de açúcar",
"ncm_validado": true,
"ncm_vigente": true,
"cest": "0300700",
"descricao_cest": "Refrigerantes e bebidas não alcoólicas",
"segmento": "Bebidas",
"tem_st": true,
"confianca": "alta",
"justificativa": "Refrigerante classificado como bebida não alcoólica",
"fonte": "gemini"
}
Campos da resposta
| Campo | Descrição |
|---|---|
| ncm | Código NCM de 8 dígitos sem pontos |
| ncm_validado | true = NCM existe na tabela oficial |
| ncm_vigente | true = NCM está vigente hoje |
| cest | CEST de 7 dígitos, ou null |
| tem_st | true = sujeito a Substituição Tributária |
| confianca | "alta" / "media" / "baixa" |
| fonte | "cache" / "gemini" / "mock_homologacao" |
confianca no seu ERP:
- 🟢
alta+ncm_validado:true— preenche automaticamente - 🟡
media— preenche destacado em amarelo, exige revisão - 🔴
baixaouncm_validado:false— bloqueia o save até confirmação manual
/ncm/batch
Processa até 500 produtos em uma única requisição. Recomendado para cargas iniciais de catálogo. Internamente o sistema agrupa em lotes para o Gemini.
Request body
{
"produtos": [
"coca cola lata 350ml",
"arroz tio joão 5kg",
"detergente ypê 500ml"
]
}
cURL
curl -X POST https://api.seu-dominio.com.br/ncm/batch \
-H "X-API-Key: ncm_live_xxxxxxxx" \
-H "Content-Type: application/json" \
-d '{ "produtos": ["coca cola lata 350ml", "arroz tio joão 5kg"] }'
Resposta (200 OK)
{
"resultado": [
{
"produto": "coca cola lata 350ml",
"ncm": "22021000",
"descricao_ncm": "Águas gaseificadas adicionadas de açúcar",
"cest": "0300700",
"tem_st": true,
"ncm_validado": true,
"ncm_vigente": true,
"confianca": "alta",
"fonte": "gemini"
},
{
"produto": "arroz tio joão 5kg",
"ncm": "10063021",
"descricao_ncm": "Arroz semibranqueado ou branqueado",
"cest": null,
"tem_st": false,
"ncm_validado": true,
"ncm_vigente": true,
"confianca": "alta",
"fonte": "gemini"
}
],
"stats": {
"qtd_total": 2,
"qtd_cobravel": 2,
"qtd_cache_hit": 0,
"qtd_gemini": 2,
"qtd_descartado": 0,
"qtd_invalido": 0
}
}
Comportamento de erro por item
Se um produto individual falhar (Gemini não retornou NCM, cota se esgotou no meio
do lote, etc.), o item do array vem com chave erro em vez dos campos
normais. Os demais continuam normalmente:
{
"produto": "produto qualquer",
"erro": "cota_insuficiente"
}
/ncm/:codigo
Detalhes de um NCM específico a partir da tabela oficial local (sem chamar Gemini). Útil para validar um NCM já cadastrado no ERP.
cURL
curl https://api.seu-dominio.com.br/ncm/22021000 \
-H "X-API-Key: ncm_live_xxxxxxxx"
Resposta (200 OK)
{
"codncm": "22021000",
"descricao": "Águas gaseificadas adicionadas de açúcar ou aromatizadas",
"validade_ini": "2022-04-01",
"validade_fim": null,
"vigente": true,
"tipoato": "Resolução",
"numeroato": "125",
"anoato": 2022,
"cests": [
{ "codcest": "0300700", "descricao": "Refrigerantes...", "segmento": "Bebidas" }
],
"tem_st": true
}
/ncm/:codigo/tributacao
Tributação completa: ICMS/PIS/COFINS/IPI do regime atual, carga IBPT (Lei 12.741/2012) e alíquotas IBS/CBS/IS da Reforma Tributária (LC 214/2025).
Query parameters
| Param | Valores | Default |
|---|---|---|
| uf * | AC, AL, AM, ... SP, TO | obrigatório |
| regime | simples / presumido / real | presumido |
| cfop_interno | CFOP 4 dígitos começando com 5 (ex: 5102, 5405) | opcional |
| cfop_externo | CFOP 4 dígitos começando com 6 (ex: 6102, 6404) | opcional |
| atividade | comercio ou industria — afeta o IPI | opcional* — Simples → comercio, Normal → industria |
atividade:
Comerciante (varejista/atacadista) não é contribuinte do IPI — não destaca.
Apenas indústria (e equiparados) recolhem IPI.Precedência (a API resolve nesta ordem):
?atividade=na query string (override pontual)- Atividade cadastrada no tenant (configurada uma vez no painel admin)
- Default por regime:
simples → comercio,presumido/real → industria
cfop_sugerido.
Se você passar cfop_interno e/ou cfop_externo, a API adiciona
cfops_analisados com a interpretação de cada um:
tipo de operação (venda, ST como substituto/substituído, bonificação, amostra…),
CST/CSOSN apropriado, e alertas quando o CFOP não bate com a sujeição a ST do produto.
cURL — sem CFOP (sugestão automática)
curl "https://api.seu-dominio.com.br/ncm/22021000/tributacao?uf=PE®ime=simples" \
-H "X-API-Key: ncm_live_xxxxxxxx"
cURL — com CFOPs do ERP
curl "https://api.seu-dominio.com.br/ncm/22021000/tributacao?uf=PE®ime=simples&cfop_interno=5405&cfop_externo=6404" \
-H "X-API-Key: ncm_live_xxxxxxxx"
aliquota
direto pra preencher o <vICMS>/<vPIS>/<vCOFINS> da NF-e.
Use sempre aliquota_destacada_nfe + a flag
destacar_na_nfe.
Por quê? No Simples Nacional o ICMS próprio é recolhido via DAS — não se destaca na NF-e (vICMS=0), mesmo quando a alíquota nominal do estado é 18% ou 22%. Idem para CSOSN 500 (substituído) e CST 60. Destacar indevidamente pode gerar autuação (Lei 9.430/96, multa 75%-225%).
Os 4 campos retornados em cada bloco de tributo
| Campo | Significado | Como usar |
|---|---|---|
| aliquota | Alíquota nominal/estatutária do estado (referência IBPT/Lei 12.741) | Exibir na tela como referência. Nunca destacar direto na NF-e. |
| aliquota_destacada_nfe | O valor que deve ir no <vICMS> da NF-e |
Usar este ao gerar o XML. |
| destacar_na_nfe | Boolean: true se destaca, false se zera |
Use como condição if. |
| obs | Explicação fiscal (CSOSN/CST aplicado e motivo) | Logar em auditoria — protege contra fiscalização. |
Tabela de comportamento por CST/CSOSN
| Regime | CST / CSOSN | Descrição | destacar_na_nfe | aliquota_destacada_nfe |
|---|---|---|---|---|
| Simples | 101 | Tributada c/ permissão crédito | ❌ false | 0 |
| Simples | 102 | Tributada sem crédito (venda comum) | ❌ false | 0 |
| Simples | 201/202/203 | Substituto (emitente recolhe ST) | ✅ true | nominal |
| Simples | 300 | Imune | ❌ false | 0 |
| Simples | 400 | Não tributada | ❌ false | 0 |
| Simples | 500 | Substituído (ST já recolhida) | ❌ false | 0 |
| Normal | 00 | Tributação integral | ✅ true | nominal |
| Normal | 10 | Tributada c/ cobrança ST | ✅ true | nominal |
| Normal | 20 | Tributada c/ redução base | ✅ true | nominal reduzida |
| Normal | 40/41 | Isenta / Não tributada | ❌ false | 0 |
| Normal | 50/51 | Suspensão / Diferimento | ❌ false | 0 |
| Normal | 60 | Substituído (ST já recolhida) | ❌ false | 0 |
Mesma lógica aplica para PIS/COFINS no Simples Nacional (recolhidos via DAS, nunca destacam).
O bloco IPI tem apenas destacar_na_nfe (sem alíquota separada — usa a alíquota TIPI direto).
Resposta (200 OK) — resumo
{
"ncm": "22021000",
"descricao": "Águas gaseificadas adicionadas de açúcar",
"uf": "PE",
"regime": "simples",
"tem_st": true,
"cest": "0300700",
"regime_atual": {
"icms": {
"aliquota": 18.00,
"aliquota_destacada_nfe": 0, // ← o que vai no da NF-e
"cst": "500",
"tem_st": true,
"destacar_na_nfe": false,
"obs": "Simples + substituído: ICMS-ST já recolhido anteriormente. NF-e NÃO destaca ICMS (vICMS=0)..."
},
"pis": {
"aliquota": 0.00,
"aliquota_destacada_nfe": 0,
"cst": "07",
"destacar_na_nfe": false,
"obs": "Simples Nacional: PIS recolhido via DAS."
},
"cofins": { "aliquota": 0.00, "aliquota_destacada_nfe": 0, "cst": "07", "destacar_na_nfe": false },
"ipi": {
"aliquota": 0.00,
"cst": "53", // ← Simples comércio: CST 53 (saída não tributada)
"destacar_na_nfe": false,
"fundamento": "Comerciante não-contribuinte do IPI (art. 24 do RIPI).",
"obs": "Comerciante (varejista/atacadista) não é contribuinte do IPI..."
}
},
"ibpt": {
"versao": "25.2.E",
"fed_nacional": 3.65,
"estadual": 18.00,
"municipal": 0.00,
"carga_total": 21.65
},
"reforma_tributaria": {
"ano_referencia": 2026,
"fase": "transicao",
"cbs": { "aliquota_efetiva": 0.90, "cst": "01" },
"ibs": { "aliquota_efetiva": 0.12, "cst": "01" },
"is": { "tem_is": true, "aliquota": 20.00 },
"total_ibs_cbs": 1.02
},
"cst_sugerido": { "icms": "500", "pis": "07", "cofins": "07", "ipi": "50", "ibs_cbs": "01" },
"cfop_sugerido": { "venda_interna": "5405", "venda_interestadual": "6404", "obs": "...sujeita a ST" },
"cfops_analisados": {
"interno": {
"cfop": "5405",
"conhecido": true,
"descricao": "Venda de mercadoria c/ ST já recolhida (substituído, interna)",
"dentro_uf": true,
"tipo_operacao": "venda_st_substituido",
"tem_st": true,
"cst_icms_sugerido": "500",
"alerta": null
},
"externo": {
"cfop": "6404",
"conhecido": true,
"descricao": "Venda de mercadoria c/ ST já recolhida (substituído, interestadual)",
"dentro_uf": false,
"tipo_operacao": "venda_st_substituido",
"tem_st": true,
"cst_icms_sugerido": "500",
"alerta": null
}
}
}
O bloco cfops_analisados só aparece quando você passa os parâmetros.
O campo alerta não-nulo indica inconsistência entre CFOP escolhido
e situação tributária do NCM (ex: produto com ST mas CFOP de venda comum).
/quota
cortesia (não cobra)
Consulta o saldo do tenant sem consumir créditos. Útil para o ERP exibir o saldo na tela, validar antes de iniciar batch, ou bloquear UI quando o saldo estiver baixo.
cURL
curl https://api.seu-dominio.com.br/quota \
-H "X-API-Key: ncm_live_xxxxxxxx"
Resposta (200 OK)
{
"tenant": {
"id": "uuid-do-tenant",
"nome": "Padaria do Zé",
"atividade": "comercio",
"status": "ativo"
},
"api_key": {
"nome": "Chave do ERP principal",
"prefix": "ncm_live_a1b2c3d4",
"ambiente": "producao"
},
"assinatura": {
"plano": "PRO",
"status": "ativa",
"vigencia_fim": "2026-06-12",
"dias_para_vencer": 31,
"vencida": false
},
"saldo": {
"total": 2500,
"usado": 437,
"disponivel": 2063,
"percentual_usado": 17.48,
"percentual_disponivel": 82.52,
"creditos_extras": 0
},
"custos": {
"ncm_buscar_por_produto": 1,
"ncm_batch_por_produto": 1,
"ncm_get": 0,
"ncm_tributacao": 0,
"cest_get": 0,
"quota_consulta": 0
},
"homologacao_gratis": false,
"consulta_em": "2026-05-13T22:30:00.000Z"
}
Os mesmos headers X-NCM-Quota-* que vêm em todas as outras respostas
também são incluídos aqui — você pode escolher ler do JSON ou dos headers.
Casos de uso típicos
| No ERP | Lógica sugerida |
|---|---|
| Status bar de tela principal | Chama 1× ao abrir o sistema, atualiza a cada chamada bem-sucedida lendo o header X-NCM-Quota-Remaining. |
| Validar antes de batch | Operador seleciona 200 produtos → ERP chama /quota → se disponivel < 200, alerta antes de chamar o batch. |
| Alerta de saldo baixo | Se percentual_disponivel < 10, dispara notificação local + WhatsApp do gestor. |
| Bloqueio preventivo | Se assinatura.vencida = true ou disponivel == 0, desabilita o botão "Classificar NCM" da tela. |
/cest/:ncm
Lista todos os CESTs associados a um NCM (Convênio ICMS 142/2018).
cURL
curl https://api.seu-dominio.com.br/cest/22021000 \
-H "X-API-Key: ncm_live_xxxxxxxx"
Resposta (200 OK)
{
"ncm": "22021000",
"tem_st": true,
"cests": [
{
"codcest": "0300700",
"descricao": "Refrigerantes e bebidas não alcoólicas",
"segmento": "Bebidas"
}
]
}
Códigos de erro
| Status | Significado |
|---|---|
| 400 | Requisição malformada (campo faltando, UF inválida, lote > 500) |
| 401 | API key ausente, inválida ou revogada |
| 402 | Créditos insuficientes ou assinatura vencida |
| 403 | Tenant suspenso ou API key bloqueada |
| 404 | Recurso não encontrado (ex: NCM não existe na tabela) |
| 500 | Erro interno — tente novamente ou contate o suporte |
Formato do erro
{
"error": "limite de créditos atingido",
"creditos_total": 5000,
"creditos_usados": 5000,
"disponivel": 0
}
Para erros 402 a resposta inclui o detalhamento do saldo
para você poder tratar e exibir ao usuário final.
SDKs e exemplos
Para acelerar sua integração, fornecemos clientes prontos. Baixe e cole no seu projeto — sem dependências externas.
Delphi (Object Pascal)
Unit reutilizável uNcmAPI.pas com classe
TNcmAPI completa: cobre todos os
endpoints, trata códigos HTTP, expõe headers de quota, integra com
TIniFile e
TTask.
- ✓ Sem dependência externa (HTTPS nativo via WinHTTP)
- ✓ Records tipados para todas as respostas
- ✓ Exceções específicas:
ENcmAPIQuota,ENcmAPIUnauthorized, … - ✓ Exemplos: cadastro, importação em lote, NF-e
- ✓ Compatível com Indy se necessário (ver guia)
cURL / Node / Python / qualquer cliente HTTP
A API é REST/JSON padrão — basta um cliente HTTP qualquer. Veja os exemplos prontos nas tabs de cada endpoint logo acima.
Precisa de SDK em outra linguagem (PHP, C#, Java, Go, Python pronto)? Solicite pelo e-mail de suporte — avaliamos a demanda.
Snippet rápido — Delphi
uses uNcmAPI;
var Api: TNcmAPI;
R: TNcmResultado;
begin
Api := TNcmAPI.Create('https://api.seu-dominio.com.br',
'ncm_live_xxxxxxxx');
try
R := Api.BuscarNCM('coca cola lata 350ml');
if R.Sucesso then
begin
edtNCM.Text := R.NCM;
edtCEST.Text := R.CEST;
chkST.Checked := R.TemST;
end
else
ShowMessage('Erro: ' + R.Erro);
// Saldo atualizado a cada chamada:
StatusBar.Panels[0].Text :=
Format('NCM API: %d/%d créditos', [Api.QuotaRemaining, Api.QuotaTotal]);
finally
Api.Free;
end;
end;
FAQ
Posso usar a API key diretamente no front-end?
Não. Sua API key dá acesso ao seu saldo de créditos — colocá-la em código JavaScript público expõe a chave. Faça as chamadas a partir do seu back-end (ERP, microsserviço, etc.) e proxy para o front se necessário.
Quantos produtos posso enviar por dia?
Depende do plano contratado (campo "créditos incluídos" da sua assinatura).
Os headers X-NCM-Quota-* em toda resposta mostram
o saldo atual. Para verificar antes mesmo de chamar, peça ao admin para
conferir no painel.
Quando devo usar /ncm/buscar vs /ncm/batch?
buscar para 1 produto pontual (cadastro avulso, formulário). batch para importações em massa ou primeira carga do catálogo — é mais eficiente, gasta menos tempo de rede e o sistema otimiza chamadas ao Gemini agrupando em lotes internos de 50.
Os NCMs retornados são definitivos / oficiais?
O NCM é sugerido por IA (Google Gemini) e validado contra a
tabela oficial do Siscomex. Mas a responsabilidade fiscal final é do contribuinte —
NCMs com confianca:"media" ou
"baixa" exigem revisão humana, especialmente em
produtos com características técnicas específicas (medicamentos, autopeças, etc.).
Vocês armazenam meu catálogo?
O texto do produto consultado é salvo em um log de auditoria (para suporte e billing) e o resultado é cacheado globalmente — assim consultas repetidas do mesmo produto (por qualquer cliente) ficam mais rápidas. Não armazenamos informação de preço, estoque ou ligação do produto com o cliente final.
Como faço rate limiting do meu lado?
O endpoint /ncm/batch aceita até 500 produtos por chamada
e a API gerencia internamente os limites do Gemini (15 RPM no free tier).
Para chamadas /ncm/buscar sequenciais, recomendamos no máximo
10 req/s do seu lado para evitar pressão na fila Gemini.
Como testar sem gastar créditos?
Use o ambiente de homologação. Peça ao admin uma chave
ncm_test_... — ela retorna NCMs fictícios
(mas com a mesma estrutura de resposta da produção) e não consome créditos.
Perfeita para CI, testes de integração e demonstrações.
Suporte
Dúvidas, emissão de chaves, alteração de plano ou problemas técnicos:
- 📧 E-mail: contato@uniquesistemas.com.br
- 📱 WhatsApp: +55 (XX) XXXX-XXXX
- 🌐 Status da API: /health