NCM API · Docs

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).

~11k
NCMs oficiais
27
UFs cobertas
500
produtos por batch
REST
JSON / HTTP
URL base
https://api.seu-dominio.com.br
📋
Aviso de responsabilidade fiscal. As classificações de NCM, CEST, ST e alíquotas retornadas pela API são sugestões baseadas em IA + validação contra bases oficiais (Siscomex, Convênio CONFAZ 142/2018, IBPT, TIPI vigente, LC 214/2025). A responsabilidade fiscal final é sempre do contribuinte.

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

1

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).

2

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" }'
3

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...
⚠️ Guarde sua chave em segredo. Ela é mostrada uma única vez na emissão. Se perder, peça uma nova ao admin (a antiga será revogada).

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:

ncm_live_ Produção
  • ✓ 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
ncm_test_ Homologação
  • ✓ 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/:codigoconfigurável*
GET /ncm/:codigo/tributacaoconfigurável*
GET /cest/:ncmconfigurável*
Qualquer chamada em homologação0

* Definido pelo plano (default 0). Confirme com o admin.

💡 Cache compartilhado: O sistema mantém cache global das classificações. Se outro cliente já consultou o mesmo produto, sua chamada responde mais rápido. O crédito é consumido normalmente (cache hit cobra 1 crédito, assim como uma classificação nova).
⚠️ Sem rollover: créditos não consumidos não acumulam quando a assinatura é renovada. Planeje seu volume mensal.

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

POST /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

CampoTipoDescriçã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

CampoDescrição
ncmCódigo NCM de 8 dígitos sem pontos
ncm_validadotrue = NCM existe na tabela oficial
ncm_vigentetrue = NCM está vigente hoje
cestCEST de 7 dígitos, ou null
tem_sttrue = sujeito a Substituição Tributária
confianca"alta" / "media" / "baixa"
fonte"cache" / "gemini" / "mock_homologacao"
Como interpretar confianca no seu ERP:
  • 🟢 alta + ncm_validado:true — preenche automaticamente
  • 🟡 media — preenche destacado em amarelo, exige revisão
  • 🔴 baixa ou ncm_validado:false — bloqueia o save até confirmação manual
POST /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"
}
GET /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
}
GET /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

ParamValoresDefault
uf *AC, AL, AM, ... SP, TOobrigatório
regimesimples / presumido / realpresumido
cfop_internoCFOP 4 dígitos começando com 5 (ex: 5102, 5405)opcional
cfop_externoCFOP 4 dígitos começando com 6 (ex: 6102, 6404)opcional
atividadecomercio ou industria — afeta o IPIopcional* — Simples → comercio, Normal → industria
💡 Sobre 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):
  1. ?atividade= na query string (override pontual)
  2. Atividade cadastrada no tenant (configurada uma vez no painel admin)
  3. Default por regime: simples → comercio, presumido/real → industria
🎯 Recomendado: configure uma vez no painel admin do tenant (campo "Atividade fiscal") e nunca mais precise passar na query.
💡 Sobre os CFOPs: sem informá-los, a API sugere CFOPs em 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"
🚨 Atenção fiscal: nunca use o campo 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
Simples101Tributada c/ permissão crédito❌ false0
Simples102Tributada sem crédito (venda comum)❌ false0
Simples201/202/203Substituto (emitente recolhe ST)✅ truenominal
Simples300Imune❌ false0
Simples400Não tributada❌ false0
Simples500Substituído (ST já recolhida)false0
Normal00Tributação integral✅ truenominal
Normal10Tributada c/ cobrança ST✅ truenominal
Normal20Tributada c/ redução base✅ truenominal reduzida
Normal40/41Isenta / Não tributada❌ false0
Normal50/51Suspensão / Diferimento❌ false0
Normal60Substituído (ST já recolhida)false0

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).

GET /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 ERPLó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.
GET /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

StatusSignificado
400Requisição malformada (campo faltando, UF inválida, lote > 500)
401API key ausente, inválida ou revogada
402Créditos insuficientes ou assinatura vencida
403Tenant suspenso ou API key bloqueada
404Recurso não encontrado (ex: NCM não existe na tabela)
500Erro 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.

SDK oficial

Delphi (Object Pascal)

XE8+

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)
Outras linguagens

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: