Estes três grupos estão em liberação. Confirme com o suporte se já estão ativos na sua conta antes de alterar sua integração — enviá-los antes da liberação faz os campos serem ignorados, e a nota sai sem o grupo.
Medicamentos, rastreabilidade e retenções federais
Esta página cobre três grupos do leiaute da NF-e que costumam aparecer juntos na distribuição farmacêutica e na venda a órgãos públicos:
| Grupo | Tag | Onde entra no payload |
|---|---|---|
| Medicamentos | med (K01) | items[].medicineDetail |
| Rastreabilidade de lote | rastro (I80) | items[].trackingDetails[] |
| Retenção de tributos federais | retTrib (W23) | totals.withheldTaxes |
Medicamento e rastreabilidade são dois grupos, não um
Até 2018, lote, validade e fabricação ficavam dentro do grupo de medicamentos. A NT 2018.005 separou os dois:
- O grupo
medficou apenas com registro ANVISA, motivo da isenção e preço máximo ao consumidor. - Lote, quantidade, fabricação e validade passaram para o grupo
rastro, que é o mesmo usado por agrotóxicos, produtos veterinários, bebidas e embalagens.
Vale conferir esse ponto na sua modelagem: é comum a integração ser construída tratando tudo como um grupo só, o que resulta em XML recusado.
medicineDetail obriga informar trackingDetailsÉ a regra K01-20 do Manual de Orientação ao Contribuinte. Medicamento sem os campos de
rastreabilidade é recusado com a rejeição 873 ("Operação com medicamentos e não informado os
campos de rastreabilidade"). Nossa API valida isso na entrada e devolve 400 com mensagem
explícita, antes de enviar o documento à SEFAZ.
O caminho inverso é livre: trackingDetails sozinho é válido para qualquer produto rastreável.
Grupo de medicamentos (medicineDetail)
| Campo | Tag | Obrigatório | Observação |
|---|---|---|---|
anvisaCode | cProdANVISA | Sim | 11 ou 13 dígitos, ou o literal ISENTO |
exemptionReason | xMotivoIsencao | Não | Até 255 caracteres. Para medicamento isento, informe o número da decisão (por exemplo, a RDC da ANVISA) |
maximumPrice | vPMC | Sim no leiaute | Se não houver preço tabelado, informe 0 — omitido, é emitido como 0.00 |
Grupo de rastreabilidade (trackingDetails)
É uma lista: aceita até 500 lotes por item. Vários lotes numa mesma linha da nota é o caso normal em distribuição hospitalar.
| Campo | Tag | Obrigatório | Observação |
|---|---|---|---|
batchNumber | nLote | Sim | 1 a 20 caracteres |
batchQuantity | qLote | Sim | Maior que zero, até 8 dígitos inteiros e 3 decimais |
manufactureOn | dFab | Sim | Emitido no XML como AAAA-MM-DD |
expireOn | dVal | Sim | Emitido como AAAA-MM-DD. Se a validade não especificar o dia, informe o último dia do mês |
aggregationCode | cAgreg | Não | Até 20 caracteres |
Exemplo — item de medicamento com dois lotes
{
"code": "MED-001",
"description": "FOLINATO DE CALCIO 10MG/ML 30ML INJ",
"ncm": "30045010",
"cfop": 5102,
"unit": "CX",
"quantity": 5,
"unitAmount": 120.00,
"totalAmount": 600.00,
"unitTax": "CX",
"tax": {
"icms": { "origin": "0", "cst": "00", "baseTax": 600.00, "rate": 18.00, "amount": 108.00 }
},
"medicineDetail": {
"anvisaCode": "1004310310091",
"maximumPrice": 0
},
"trackingDetails": [
{
"batchNumber": "188918",
"batchQuantity": 2.000,
"manufactureOn": "2026-06-17",
"expireOn": "2028-06-01"
},
{
"batchNumber": "190455",
"batchQuantity": 3.000,
"manufactureOn": "2026-07-02",
"expireOn": "2028-07-01"
}
]
}
O leiaute aceita no máximo um entre medicineDetail, vehicleDetail e fuelDetail por item.
A API não recusa o envio de mais de um: ela resolve o conflito sozinha, na ordem de precedência
medicamento → veículo → combustível, e os demais grupos simplesmente não saem no XML — sem erro
e sem aviso. Garanta na sua integração que só um deles é preenchido.
O grupo trackingDetails não faz parte dessa exclusividade — ele é irmão deles e pode acompanhar
qualquer um.
Retenção de tributos federais (withheldTaxes)
Aplica-se quando a fonte pagadora retém tributos federais — tipicamente a venda a órgão ou hospital público (IN SRF 480/2004; Lei 10.833/2003, arts. 30 a 36; Lei 7.450/85, art. 52).
| Campo | Tag | Observação |
|---|---|---|
pisAmount | vRetPIS | Valor retido de PIS |
cofinsAmount | vRetCOFINS | Valor retido de COFINS |
csllAmount | vRetCSLL | Valor retido de CSLL |
irrfBasis | vBCIRRF | Base de cálculo do IRRF |
irrfAmount | vIRRF | Valor retido do IRRF |
socialSecurityBasis | vBCRetPrev | Base de cálculo da retenção da Previdência Social |
socialSecurityAmount | vRetPrev | Valor da retenção da Previdência Social |
Todos os campos são opcionais e todos aceitam no máximo 13 dígitos inteiros.
A plataforma não apura retenção federal. O que você enviar é o que vai para o documento. Se precisar do cálculo automático, fale com o suporte — hoje isso não é feito pela API.
O leiaute tipa esses campos de um jeito que não aceita zero — 0 e 0.00 são recusados pelo
schema da SEFAZ. Por isso, campo com valor zero é omitido do XML, e o grupo inteiro desaparece
quando nenhum valor é informado. Não é preciso tratar isso na sua integração — pode enviar zero à
vontade, que a plataforma cuida de omitir.
Exemplo — totais com IRRF retido
{
"totals": {
"icms": {
"invoiceAmount": 600.00
},
"withheldTaxes": {
"irrfBasis": 600.00,
"irrfAmount": 9.00,
"pisAmount": 3.90,
"cofinsAmount": 18.00,
"csllAmount": 6.00
}
}
}
retTrib registra o que a fonte pagadora retém do pagamento. O valor do documento (vNF) e o
total com reforma tributária (vNFTot) permanecem inalterados — mesmo comportamento do ISS retido
(vISSRet).
Rejeições que esses grupos evitam
| Código | Descrição | Causa comum | Recusado antes da SEFAZ? |
|---|---|---|---|
| 215 | Falha no schema do XML | anvisaCode fora do padrão (11/13 dígitos ou ISENTO) | ✅ 400 na entrada |
| 215 | Falha no schema do XML | Valor de retenção acima de 13 dígitos inteiros, ou negativo | ✅ 400 na entrada |
| 215 | Falha no schema do XML | Lote sem batchNumber, batchQuantity, manufactureOn ou expireOn; batchNumber acima de 20 caracteres | ✅ 400 na entrada |
| 873 | Operação com medicamentos e não informado os campos de rastreabilidade | medicineDetail enviado sem trackingDetails | ✅ 400 na entrada |
Em todos esses casos a API recusa na entrada, com 400 e a mensagem apontando o campo — você não
descobre o problema só depois da ida à SEFAZ.
Valor de retenção igual a zero não está nesta lista: ele não gera rejeição nem 400, porque a
plataforma omite a tag antes de montar o XML (ver o aviso acima).