Issuing an NFC-e¶
The NFC-e is the retail NF-e: same layout, same signature, same web services. The differences fit in a short list, and this guide is about them.
What changes compared to the NF-e¶
| NF-e (55) | NFC-e (65) | |
|---|---|---|
| Recipient | Mandatory | Optional — the consumer may stay anonymous |
| Operation | Internal, interstate or foreign | Internal only (idDest = 1) |
| Direction | Inbound or outbound | Outbound only |
| End consumer | Depends on the operation | Always (indFinal = 1) |
| Departure date | Allowed | Forbidden |
| Billing group | Allowed | Forbidden |
| Recipient's state registration | Allowed | Forbidden |
| Services with ISSQN | Allowed | Forbidden |
| QR Code | None | Mandatory, in the infNFeSupl group |
Validar checks all of those points when the model is nfe.ModeloNFCe.
The CSC¶
The Código de Segurança do Contribuinte is a shared secret between you and your state's SEFAZ. It never travels in the XML: it only enters the hash that authenticates the QR Code, proving the receipt was generated by whoever held the code.
You obtain it from the state SEFAZ portal, and you get two values: an identifier of up to six digits, which is public and appears in the QR Code, and the code itself.
The CSC is a secret
Whoever holds the CSC can forge QR Codes that pass the consumer's check. Guard it with the same care as the certificate password: out of the source code, out of version control, in a secrets vault.
Building the receipt¶
n := nfe.Nova(nfe.ModeloNFCe)
ide := &n.InfNFe.Ide
ide.NatOp = "VENDA AO CONSUMIDOR"
ide.Serie = 1
ide.NNF = 1
ide.DhEmi = tipos.AgoraEm(uf.RS.Fuso())
ide.CMunFG = 4314902
ide.TpAmb = nfe.Homologacao
ide.TpImp = nfe.DANFENFCe // receipt print format
ide.IndFinal = "1"
ide.IndPres = nfe.PresencaPresencial
n.InfNFe.Emit = nfe.Emit{ /* … */ }
// No consumer identification: simply leave the dest group empty.
n.InfNFe.Det = []nfe.Det{ /* … */ }
n.InfNFe.Transp = nfe.Transp{ModFrete: nfe.SemFrete}
n.InfNFe.Pag = &nfe.Pag{DetPag: []nfe.DetPag{{
TPag: nfe.PagamentoPIXDinamico,
VPag: total,
}}}
When the consumer asks for their CPF on the receipt, fill in the recipient without a state registration:
Order matters: prepare, QR Code, sign¶
The QR Code depends on the access key, and the infNFeSupl group that holds it
enters the document before signing. The sequence is always this:
// 1. Preparar builds the access key.
if err := n.Preparar(); err != nil {
return err
}
// 2. The QR Code uses that key and fills in infNFeSupl.
if err := nfce.PreencherSuplemento(n, nfce.Opcoes{CSC: csc}); err != nil {
return err
}
// 3. Validar now requires infNFeSupl.
if err := n.Validar(); err != nil {
return err
}
// 4. Only then sign.
documento, err := n.XML()
if err != nil {
return err
}
assinada, err := xmldsig.Assinar(documento, "infNFe", cert)
Swapping steps 2 and 4 produces a receipt whose signature does not check out,
because infNFeSupl would have been added after the digest was computed.
The QR Code¶
PreencherSuplemento produces two values:
fmt.Println(n.InfNFeSupl.QrCode)
// https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx?p=43260…|2|2|000001|f3a1…
fmt.Println(n.InfNFeSupl.UrlChave)
// https://www.sefaz.rs.gov.br/NFCE/NFCE-COM.aspx
The p parameter gathers, separated by vertical bars: the access key, the QR
Code version (2), the environment, the CSC identifier, and the SHA-1 hash of
the whole set concatenated with the CSC code. The code itself never appears in
the URL.
To check a QR Code — your own, while validating the configuration, or one from a receipt you received:
Rendering the image¶
The library produces the QR Code text, not the image. That keeps the core
free of graphics dependencies and lets you pick the rendering library you
already use. With github.com/skip2/go-qrcode, for instance:
Endpoints by state¶
The library ships a table with the QR Code and lookup addresses for all 27 states. States change these more often than the web services, so check before production:
If they differ from what your SEFAZ publishes, override them:
err := nfce.PreencherSuplemento(n, nfce.Opcoes{
CSC: csc,
URLQRCode: "https://endereco-correto/qrcode",
URLConsulta: "https://endereco-correto/consulta",
})
A wrong address does not prevent the invoice from being authorised — it produces a receipt whose QR Code the consumer cannot look up.
Offline contingency¶
The NFC-e allows offline issuing (tpEmis = 9), where the receipt is printed on
the spot and transmitted later. The QR Code for that mode uses a different set of
parameters, with the issue date, the value and the DigestValue embedded.
PreencherSuplemento refuses invoices with tpEmis = 9 and says why, rather
than silently generating a wrong QR Code. To build one, use the low-level
function with the parameters in the order given by the current Technical Note:
qr := nfce.MontarQRCode(urlBase, []string{
chaveAcesso,
nfce.VersaoQRCode,
string(ambiente),
// … the remaining offline contingency parameters
csc.Id,
}, csc.Codigo)
MontarQRCode handles joining with vertical bars and the hash; the order and
content of the parameters are up to you, precisely because that part changes
between versions of the Technical Note.
Complete example¶
exemplos/emitir-nfce
builds a snack bar receipt under Simples Nacional, with two items and payment by
PIX.