Kontrib DEVELOPERS
Introdução

Comece por aqui

A API da Kontrib conecta o seu ERP à inteligência fiscal da Reforma Tributária: envie notas de entrada e saída, sincronize o cadastro de produtos e consulte a classificação fiscal por código de barras — como o mercado classifica hoje e o enquadramento em CBS/IBS/IS com a carga da transição 2026→2033.

Base URLhttps://app.kontrib.com.br/api/v1/erp

Seu primeiro request

1. Crie uma chave no app (Importações → API ERP) — uma chave por empresa/CNPJ.
2. Chame o /ping:

cURL
curl -s https://app.kontrib.com.br/api/v1/erp/ping \
  -H "X-Api-Key: r360_SUACHAVE"

# 200 OK
{ "ok": true, "empresaId": "1c2f0a9e-..." }
  • Formato JSON (UTF-8), exceto o envio de notas (XML/ZIP).
  • Datas ISO-8601 em UTC · decimais com ponto · percentuais em escala 0–100.
  • Contrato estável: campos podem ser adicionados às respostas — ignore os desconhecidos.
Introdução

Autenticação

Toda requisição leva a chave no header X-Api-Key. A chave:

  • é criada no app em Importações → API ERP, uma por empresa/CNPJ;
  • é exibida uma única vez (formato r360_...) — guarde em cofre de segredos;
  • identifica a empresa: notas e produtos enviados são vinculados a ela automaticamente;
  • pode ser revogada a qualquer momento (crie outra para rotacionar sem downtime);
  • tem o uso medido por dia e endpoint, visível na tela de chaves.
Nunca envie a chave em URL, logs ou repositórios. Só o hash SHA-256 fica armazenado do nosso lado — se perder a chave, revogue e crie outra.
Introdução

Erros e limites

Erros seguem o padrão Problem Details (RFC 7807) — leia sempre o campo detail:

422 Unprocessable Content
{
  "status": 422,
  "title": "Unprocessable Content",
  "detail": "O envio tem 7000 itens; o máximo por chamada é 5000. Envie em páginas e aguarde a resposta de cada uma."
}
CódigoQuando aconteceO que fazer
400ZIP sem XML válido · lote acima de 10.000 XMLsCorrigir/dividir e reenviar
401Chave ausente, inválida ou revogadaConferir a chave
404Job de outra empresa · GTIN fora da base
413Arquivo acima de 100 MBDividir o ZIP
422Paginação estourada · GTIN malformado · regime inválidoLer o detail
429Rate limit · lotes pendentes · força brutaEsperar o header Retry-After (segundos) e repetir

Limites de produção

LimiteValorEstouro
Requisições por minuto, por chave120429 + Retry-After: 60
Tamanho por envio de notas100 MB413
XMLs por ZIP10.000400
Lotes de notas processando ao mesmo tempo, por empresa5429 + Retry-After: 30
Produtos por chamada5.000422
GTINs por lote de classificação500422
O 429 nunca perde dado — é backpressure. Espere o Retry-After e repita a mesma chamada.
Notas fiscais

Enviar notas (entrada e saída)

POST/nfe

Aceita um XML de NF-e/NFC-e ou um ZIP com vários XMLs. Envie compras e vendas sem distinção — o vínculo é com a empresa da chave, e entrada × saída é detectado pelo emitente da nota. O processamento é sempre assíncrono: resposta 202 imediata.

HeaderValor
Content-Typeapplication/xml (um XML) ou application/octet-stream (ZIP)
Corpoos bytes do arquivo
cURL
# um XML
curl -s -X POST https://app.kontrib.com.br/api/v1/erp/nfe \
  -H "X-Api-Key: $KEY" -H "Content-Type: application/xml" \
  --data-binary @nota.xml

# um ZIP com milhares de XMLs
curl -s -X POST https://app.kontrib.com.br/api/v1/erp/nfe \
  -H "X-Api-Key: $KEY" -H "Content-Type: application/octet-stream" \
  --data-binary @lote-2026-06.zip

# 202 Accepted
{ "jobId": "7e1b3c44-..." }
Idempotente por chave de acesso (44 dígitos): reenviar uma nota já importada conta como duplicada — nunca duplica dado nem gera erro. Se a carga cair no meio, reenvie o mesmo ZIP.
Notas fiscais

Status do lote

GET/nfe/{jobId}

Acompanhe o processamento até status = "CONCLUIDO". Faça polling com intervalo ≥ 5 s.

200 OK
{
  "jobId": "7e1b3c44-...",
  "status": "PROCESSANDO",
  "totalNotas": 9800,
  "processadas": 6210,
  "duplicadas": 3,
  "comErro": 1,
  "canceladas": 12,
  "finishedAt": null
}

XML que não parseia conta em comErro — o job conclui mesmo assim. canceladas são notas com evento de cancelamento detectado.

Notas fiscais

Receita para milhões de notas

  1. Gere ZIPs de até 10.000 XMLs (mês a mês costuma dar certo).
  2. Envie um ZIP → guarde o jobId → aguarde CONCLUIDO.
  3. Mantenha no máximo 5 lotes em voo; ao receber 429, espere o Retry-After.
  4. Carga caiu? Reenvie o mesmo ZIP — duplicadas não fazem mal.
  5. Produtos: páginas de 5.000, sequenciais.

Por trás: cada nota vira uma mensagem em fila (RabbitMQ) e o consumo é paralelo — a API responde rápido mesmo sob carga, e a proteção degrada com 429 em vez de derrubar o serviço.

Produtos

Cadastro de produtos em lote

POST/produtos

JSON com até 5.000 itens por chamada (síncrono). Só codigo (ou ncm) é obrigatório; reenvio atualiza o cadastro existente (casamento por código).

Request
[
  { "codigo": "P001", "descricao": "ARROZ BRANCO TIPO 1 5KG",
    "ncm": "10063021", "cfop": "5102",
    "valorUnitario": 22.90, "quantidade": 1 }
]

# 200 OK
{ "importados": 4980 }
Classificação fiscal

Classificação por código de barras

GET/classificacao/{gtin}· opcional ?regime=SIMPLES|MEI|PRESUMIDO|REAL

Envie o GTIN (8/12/13/14 dígitos) e receba três blocos: como o mercado classifica hoje (base de 5,2 milhões de códigos de barras, cortada pelo regime), o enquadramento na reforma pelas regras versionadas da Kontrib, e a carga da transição 2026→2033 calculada pelo mesmo motor auditável das análises.

Sem o parâmetro regime, vale o regime cadastrado da empresa da chave. Simples/MEI recebem csosn; Presumido/Real recebem CST de ICMS, PIS/COFINS com natureza de receita e IPI.

200 OK — arroz, regime normal
{
  "gtin": "7891234500017",
  "descricao": "ARROZ BRANCO TIPO 1 5KG",
  "regime": "REAL",
  "consenso": {
    "ncm": "10063021",  "ncmConcordancia": 96.5,
    "cest": "1704700", "origem": "0",
    "cstIcms": "00",     "cstIcmsConcordancia": 88.0,
    "aliquotaIcms": 7.00,
    "cstPis": "06", "aliquotaPis": 0.00,
    "cstCofins": "06", "aliquotaCofins": 0.00,
    "naturezaReceita": "407",
    "cstIpi": "53", "aliquotaIpi": 0.00,
    "fontes": 210
  },
  "reforma": {
    "cclasstrib": "200003", "cstIbsCbs": "200",
    "rotulo": "Cesta básica nacional — Anexo I (alíquota zero)",
    "enquadramento": "Alíquota zero",
    "impostoSeletivo": false, "monofasicoHoje": false,
    "aliquotaCbs2033": 0.00, "aliquotaIbs2033": 0.00,
    "aliquotaTotal2033": 0.00
  },
  "transicao": [
    { "ano": 2026, "cargaFuturaPct": 0.00 },
    { "ano": 2027, "cargaFuturaPct": 0.00 },
    "... um por ano até 2033"
  ],
  "atualizadoEm": "2026-07-12T03:00:00Z",
  "aviso": "Consenso de mercado da base Kontrib + sugestão pelas regras versionadas da reforma. Orientativo — a responsabilidade pela classificação é do contribuinte; confirme com o seu contador antes de aplicar no ERP."
}

Como interpretar

BlocoO que é
consensoComo a maioria das empresas da base classifica ESTE código de barras hoje. ncmConcordancia/fontes medem a força — abaixo de ~80%, trate como sugestão fraca. A aliquotaIcms não tem dimensão de UF (referência, não parametrização).
reformaEnquadramento pelas regras versionadas (base legal pública na /metodologia): cclasstrib/cstIbsCbs prontos para o leiaute 2026 da NF-e, enquadramento (Alíquota zero · Redução 60% · Integral), Imposto Seletivo e alíquotas do modelo pleno.
transicaoCarga futura efetiva (% sobre o valor) ano a ano, 2026→2033, para venda interna típica (CFOP 5102) no regime aplicado. Em 2026 o ano-teste é neutralizado (CBS/IBS compensáveis).
Exiba o aviso ao usuário final. Consenso de mercado não é verdade fiscal — a responsabilidade pela classificação é do contribuinte, e a resposta existe para ACELERAR a decisão dele, não para substituí-la.

Erros: 404 GTIN fora da base (não é cobrado) · 422 GTIN malformado ou regime inválido.

Classificação fiscal

Catálogo inteiro (lote)

POST/classificacao/lote

Até 500 GTINs por chamada. Cada item tem o mesmo formato do GET, sem o bloco transicao (use o GET unitário para o detalhe ano a ano).

cURL
curl -s -X POST https://app.kontrib.com.br/api/v1/erp/classificacao/lote \
  -H "X-Api-Key: $KEY" -H "Content-Type: application/json" \
  -d '{"gtins":["7891234500017","7891149100103","7890000000000"],"regime":"SIMPLES"}'

# 200 OK
{
  "itens": [ { "gtin": "7891234500017", "..." } ],
  "naoEncontrados": ["7890000000000"],
  "aviso": "Consenso de mercado da base Kontrib + ..."
}
Cobrança por consulta: cada GTIN encontrado conta 1 item medido. GTIN fora da base volta em naoEncontrados e não é cobrado.
Referência

Versionamento e mudanças

  • O contrato /api/v1/erp é estável: campos novos podem ser adicionados às respostas (ignore campos desconhecidos); nada é removido ou renomeado dentro da v1.
  • Mudança de regra fiscal não muda o contrato: reflete nos VALORES (reforma/transicao), sempre versionada por vigência e publicada na /metodologia com base legal e changelog.
  • Especificação viva gerada da própria aplicação: Swagger UI · /v3/api-docs.
Referência

Segurança

  • Tráfego 100% HTTPS; a chave nunca em URL.
  • Só o hash SHA-256 da chave é armazenado; a chave em claro aparece uma única vez.
  • A chave resolve a empresa e todo acesso a dados passa pelo Row-Level Security do banco — isolamento por cliente garantido na camada mais baixa.
  • Força bruta bloqueada por IP (429); rate limit por chave; sobrecarga degrada com 429 + Retry-After, nunca derruba nem silencia dados.
  • Auditoria: toda importação e uso de chave ficam registrados (LGPD desde o primeiro commit).