Conceitos
Boas práticas
O que guardar, como tratar valores fiscais e como integrar o GetTax a um emissor de documentos fiscais.
Envie a operação real#
- Envie o CFOP da operação que vai ser emitida. Não use um CFOP de venda como padrão para tudo: devolução, transferência e remessa podem ter outro CST.
- Envie
sectorquando souber o setor do seu cliente final. Sem setor, vêm todas as alternativas, de qualquer setor. - Valide o dígito verificador do GTIN antes de enviar. Um GTIN inválido não consome franquia, mas custa uma ida e volta.
Trate os quatro status#
- Só
CLASSIFIEDé resultado concluído.IN_REVIEWpode trazer alternativas calculadas, mas não deve ser emitido automaticamente. - Sem classificação concluída, não presuma tributação integral nem preencha alíquotas por conta própria.
- Com mais de uma alternativa, a escolha é do emissor, pela condição em
applicability. Nunca pela posição na lista.
const res = await fetch(`${process.env.GETTAX_URL}/v1/classifications/resolve`, { method: "POST", headers: { Authorization: `Bearer ${process.env.GETTAX_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ gtin: "7891000315507", cfop: "5102", sector: "VAREJO_GERAL" }),}); if (!res.ok) { const { error } = await res.json(); // { "error": "INVALID_REQUEST" }, etc. throw new Error(`GetTax ${res.status}: ${error}`);} const decision = await res.json(); switch (decision.status) { case "CLASSIFIED": // Todas as alternativas pertinentes. A ordem não é recomendação: // com mais de uma, o emissor escolhe pela condição em `applicability`. await saveDecision(decision); break; case "IN_REVIEW": // Pode trazer alternativas, mas o resultado não está concluído. await sendToReview(decision); break; case "PENDING": // Produto fora do catálogo. Consulte de novo mais tarde, sem loop. await retryLater(decision.gtin, decision.retryAfterSeconds); break; case "NOT_FOUND": // A GS1 não conhece o GTIN: confira o cadastro do item. await flagInvalidGtin(decision.gtin); break;}Guarde a decisão com o documento#
Junto de cada documento fiscal emitido, guarde:
decisionVersion: identifica a decisão na trilha de auditoria do GetTax.referenceDate,cfopesectorusados na consulta.- Da alternativa aplicada:
cst,cClassTrib,rule.id,rule.version,taxClassification.sourceVersione ossourceVersionderates[]. - Os valores de
components[]como vieram.
É o que permite explicar depois de onde veio cada número, mesmo que a regra ou a alíquota mude.
decisionVersion é novo a cada consulta, mesmo com a mesma entrada e o mesmo resultado. Ele identifica a consulta, não a classificação: para saber se a classificação mudou, compare cst, cClassTrib, rule.id e rule.version.
Valores fiscais como decimal#
Alíquotas e reduções chegam como strings de fração decimal ("0.009000" = 0,9%). Mantenha a precisão:
- Converta direto para um tipo decimal exato e guarde como decimal ou texto. Nunca passe por
floatoudouble. - Não converta para percentual inteiro antes de guardar. Se precisar exibir, formate só na tela.
- Recalcule, se quiser conferir, com a fórmula
effectiveRate = standardRate × (1 − reductionPct), em decimal.
using System.Globalization; // "0.003600" -> 0.003600m, sem passar por doublevar effectiveRate = decimal.Parse(component.GetProperty("effectiveRate").GetString()!, CultureInfo.InvariantCulture);from decimal import Decimal effective_rate = Decimal(component["effectiveRate"]) # Decimal('0.003600')Em JavaScript, Number("0.003600") é ponto flutuante. Mantenha a string ou use uma biblioteca decimal.
Reaproveite as respostas#
A classificação depende de GTIN, CFOP, setor e data de referência, não do seu cliente final. Guarde a resposta no seu banco e reutilize entre os seus clientes:
- Use como chave o GTIN de 14 dígitos, o CFOP e o setor (ou a ausência dele).
- A decisão vale enquanto a data de referência estiver dentro da vigência de tudo o que ela usou: o menor
effectiveToentre a regra, a linha de cClassTrib e as alíquotas.nullquer dizer sem término previsto. - A curadoria publica regras e versões novas. Reconsulte periodicamente, e sempre que a data passar de um
effectiveTo. - Não guarde em cache
PENDINGnemIN_REVIEWcomo resultado final.
Escolha a rota certa#
- Consulta unitária para o dia a dia: item novo no cadastro, conferência antes da emissão. Pode buscar na GS1 um produto que ainda não está no catálogo, quando a busca está ativa no ambiente, por isso pode levar alguns segundos a mais nesse caso.
- Lote para carga e revisão de catálogo: até 100 itens por requisição, sem busca na GS1. Itens
PENDINGdo lote podem ser reconsultados depois, pela consulta unitária. - Lista de setores para validar a chave e checar a saúde da integração, sem consumir franquia.
Integração robusta#
- Chame a API pelo seu backend e guarde a chave num cofre de segredos. Ver Autenticação.
- Configure timeout no seu cliente HTTP e repita só
500e503, com backoff. Ver Erros e novas tentativas. - Trate enums como abertos: novos setores e componentes podem surgir. Leia os setores de
GET /v1/enums/sectors. - Ignore campos que você não conhece na resposta, em vez de falhar.
