Referência · v1
API do KontNotas
REST sobre JSON. Toda a base em /api/v1. Esta página documenta apenas endpoints que existem hoje — o que está no roteiro fica fora dela até entrar no ar.
Autenticação
Chave de API no cabeçalho Authorization, formato Bearer. Cada chave pertence a uma organização e carrega escopos — que são as mesmas permissões do produto. Uma chave sem invoice.issue pode criar rascunho, mas não emite.
curl https://app.kontnotas.com.br/api/v1/invoices \
-H "Authorization: Bearer kn_live_SUA_CHAVE_AQUI"A chave é exibida uma única vez, no momento da criação. O servidor guarda apenas o hash — não há como recuperá-la depois, só gerar outra. Crie e revogue em Desenvolvedores → API.
Ambientes
O prefixo da chave define o ambiente: kn_test_ opera em sandbox, kn_live_ em produção. Uma chave de produção só funciona depois que a organização estiver efetivamente em produção — caso contrário a requisição é recusada com 422, em vez de emitir algo simulado como se fosse real.
Idempotência
Emissão de nota fiscal não pode ser repetida por acidente. Envie Idempotency-Key em todo POST que cria documento — um UUID por tentativa lógica, reutilizado nas repetições da mesma tentativa.
Mesma chave + mesmo corpo → devolve a resposta original (não cria de novo)
Mesma chave + corpo diferente → 409 KONTNOTAS_IDEMPOTENCY_CONFLICT
Mesma chave, ainda em curso → 409 (aguarde e consulte)Timeout não significa falha. Se a conexão cair antes da resposta, repita a requisição com a mesma chave — nunca com uma nova.
Erros
Todo erro devolve o mesmo envelope, com código estável, motivo e a ação sugerida. O campo requestId também vai no cabeçalho X-Request-Id e é o que permite correlacionar com o log do servidor no suporte.
{
"error": {
"code": "KONTNOTAS_FISCAL_CONFIG_INCOMPLETE",
"message": "A alíquota de ISS não está definida para este serviço.",
"reason": "O serviço svc_01J... não tem issRateBps e o perfil fiscal não define padrão.",
"action": "Defina a alíquota em Serviços ou em Configurações › Fiscal.",
"fields": null,
"requestId": "req_01J8XQ2K7M4N5P6Q7R8S9T0V"
}
}Erros de validação trazem fields preenchido, com a mensagem por campo. Segredos e detalhes internos nunca aparecem no envelope — eles vão para o log correlacionado.
Limites de uso
O limite varia por plano e é aplicado por chave. Toda resposta traz os cabeçalhos RateLimit-Limit, RateLimit-Remaining e RateLimit-Reset. Ao estourar, a resposta é 429 com Retry-After.
Notas fiscais
/api/v1/invoicesescopo invoice.createCria a nota e, por padrão, já solicita a emissão.
O cliente pode ser informado por customerId ou por customer.document — integrações costumam conhecer o CNPJ, não o id interno. Passe "issue": false para deixar em rascunho.
{
"customer": { "document": "11.222.333/0001-81" },
"documentType": "NFSE",
"description": "Consultoria de marketing — agosto/2026",
"competenceDate": "2026-08-31",
"items": [
{
"description": "Gestão de mídias sociais",
"quantityMilli": 1000,
"unitPriceCents": 350000,
"unit": "UN"
}
],
"issue": true
}Valores são inteiros em centavos e quantidades em milésimos (1 unidade = 1000). Não há ponto flutuante em lugar nenhum da API — é o que garante que R$ 0,01 nunca desapareça num arredondamento.
/api/v1/invoicesescopo invoice.viewLista as notas da organização, com filtros por status, período e cliente.
{
"object": "list",
"data": [ { "object": "invoice", "id": "inv_01J...", "status": "authorized", … } ],
"total": 128,
"hasMore": true
}/api/v1/invoices/{id}escopo invoice.viewRetorna uma nota com itens, tributos e dados de autorização.
O status segue a máquina de estados do documento: draft → pending → processing → authorized, com rejected, error e cancelled como desfechos. Enquanto estiver em processing, consulte — não reemita.
/api/v1/invoices/{id}/cancelescopo invoice.cancelSolicita o cancelamento, com motivo obrigatório.
O prazo e as regras de cancelamento são do município, não do KontNotas. Quando a nota está fora do prazo, a resposta explica isso em vez de tentar e falhar.
Clientes
/api/v1/customersescopo customer.manageCadastra um tomador. CPF e CNPJ são validados por dígito verificador.
{
"name": "Clínica Bella Estética Ltda.",
"documentType": "CNPJ",
"document": "11222333000181",
"email": "financeiro@clinicabella.com.br",
"address": {
"street": "Avenida Paulista",
"number": "1000",
"district": "Bela Vista",
"cityCode": "3550308",
"state": "SP",
"zipCode": "01310200"
}
}/api/v1/customersescopo customer.viewLista e busca clientes por nome ou documento.
Webhooks
Em vez de consultar em laço, receba os eventos. Configure os endpoints em Desenvolvedores → Webhooks, onde também ficam o histórico de entregas e o reenvio manual.
Cada entrega é assinada em X-KontNotas-Signature com HMAC-SHA256. O timestamp faz parte da mensagem assinada — o que impede replay de uma entrega capturada. Sempre valide a assinatura antes de agir sobre o payload, e compare em tempo constante.
import { createHmac, timingSafeEqual } from 'node:crypto';
function verify(rawBody, header, secret) {
const [tsPart, sigPart] = header.split(',');
const timestamp = tsPart.replace('t=', '');
const received = Buffer.from(sigPart.replace('v1=', ''), 'hex');
// O timestamp entra na mensagem: sem isso, uma entrega antiga
// continuaria com assinatura válida para sempre.
const expected = createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest();
const fresh = Math.abs(Date.now() / 1000 - Number(timestamp)) < 300;
return fresh && received.length === expected.length && timingSafeEqual(received, expected);
}Responda 2xx rapidamente e processe depois: entregas sem resposta são reenviadas com backoff. Trate os eventos como at least once — use o id do evento para descartar repetições.