Skip to main content

Events: Cancellation and Correction Letter

Tutorial for cancelling an authorized NF-e or issuing a Correction Letter (CC-e) through the NF-e SP connector.

Overview

After an NF-e is authorized, you may need to either annul it (cancellation) or fix a non-monetary field (Carta de Correção / CC-e). Both go through SEFAZ as events, identified by a tp_evento code.

The connector provides two high-level actions that take the minimum required input and assemble the full event payload internally:

ActionEvent codeUse for
nfe_cancelar110111Cancel an authorized NF-e
nfe_carta_correcao110110Correct typos and informational fields (CC-e)

For any other event (EPEC 110140, manifesto do destinatário 210xxx, etc.) use recepcao_evento with the full payload — see Advanced events below.

Important: Both actions require the authorization protocol (n_prot) of the NF-e you're acting on. Get it via nfe_consulta_protocolo if you don't have it stored — see Getting the protocol.

Cancelling an NF-e

Cancellation annuls an authorized NF-e. Only allowed within SEFAZ's window after authorization (24h regular, 168h in contingency).

from abstra.connectors import run_connection_action

result = run_connection_action(
"nfe-sp",
"nfe_cancelar",
{
"ch_nfe": "35260112345678000100550010000000011123456780", # Access key (44 digits)
"n_prot": "123456789012345", # Authorization protocol
"x_just": "Pedido cancelado pelo cliente em 02/06/2026", # Justification (min 15 chars)
},
)

That's it — ch_nfe, n_prot and x_just are the only fields you need to provide.

Required fields

FieldTypeRule
ch_nfestringExactly 44 digits
n_protstringAuthorization protocol of the NF-e being cancelled (from nfe_consulta_protocolo or stored when you authorized it)
x_juststringJustification text. Between 15 and 255 characters

Optional fields

FieldTypeDefault
cnpjstring (14 digits)Extracted from positions 6–19 of ch_nfe
n_seq_eventostring (number)"1". Increase only when retrying after a rejection on the same NF-e
dh_eventostring (ISO 8601)Current time in São Paulo timezone (-03:00)

Reusable helper

from abstra.connectors import run_connection_action


def cancelar_nfe(chave: str, protocolo: str, justificativa: str) -> dict:
"""Cancela uma NF-e autorizada. Retorna a resposta da SEFAZ."""
return run_connection_action(
"nfe-sp",
"nfe_cancelar",
{
"ch_nfe": chave,
"n_prot": protocolo,
"x_just": justificativa,
},
)


result = cancelar_nfe(
chave="35260112345678000100550010000000011123456780",
protocolo="123456789012345",
justificativa="Pedido cancelado - estoque indisponível em 02/06/2026",
)

Reading the response

A successful response carries c_stat 135 (event registered and linked) or 136 (registered, will link asynchronously). Both mean the cancellation went through.

ret = result["soap_envelope"]["soap_body"]["nfe_result_msg"]["ret_env_evento"]

# Batch-level status (acceptance of the lote)
print(ret["c_stat"], "-", ret["x_motivo"]) # e.g. "128 - Lote de Evento Processado"

# Event-level status (the actual cancellation outcome)
inf_evento = ret["ret_evento"][0]["inf_evento"] if isinstance(ret.get("ret_evento"), list) else ret["ret_evento"]["inf_evento"]
print(inf_evento["c_stat"], "-", inf_evento["x_motivo"]) # e.g. "135 - Evento registrado e vinculado a NF-e"
print("Cancellation protocol:", inf_evento.get("n_prot"))
c_statMeaning
135Event registered and linked to the NF-e (success)
136Event registered, not yet linked (success — will link asynchronously)
573Cancellation already registered (idempotent — treat as success)

Issuing a Correction Letter (CC-e)

A CC-e (Carta de Correção Eletrônica) fixes typos and informational fields on an authorized NF-e. Up to 20 CC-e are allowed per NF-e.

result = run_connection_action(
"nfe-sp",
"nfe_carta_correcao",
{
"ch_nfe": "35260112345678000100550010000000011123456780",
"n_prot": "123456789012345",
"x_correcao": "Onde se le 'Rua das Flores 100', leia-se 'Rua das Flores 200'.",
},
)

Required fields

FieldTypeRule
ch_nfestringExactly 44 digits
n_protstringAuthorization protocol of the NF-e
x_correcaostringCorrection text. Between 15 and 1000 characters

Optional fields

FieldTypeDefault
cnpjstring (14 digits)Extracted from ch_nfe
n_seq_eventostring (number)"1". Must increase by 1 for each new CC-e on the same NF-e (max 20)
dh_eventostring (ISO 8601)Now in São Paulo timezone
x_cond_usostringStandard legal text per §1º-A, art. 7º, Convênio S/N. Only override if you have a specific need

What a CC-e CANNOT correct

A CC-e is not allowed for:

Cannot correct via CC-eUse instead
Tax variables (base de cálculo, alíquota, valor do imposto, preço, quantidade)Cancel and re-issue
Cadastral data of emitter or recipient (CNPJ, name, address of the other party)Cancel and re-issue
Emission date or shipping dateCancel and re-issue

If your correction falls in this table, use nfe_cancelar and emit a new invoice with the right data.

Multiple CC-e on the same NF-e

For the second CC-e on the same invoice, increment n_seq_evento:

# First CC-e
run_connection_action("nfe-sp", "nfe_carta_correcao", {
"ch_nfe": chave,
"n_prot": protocolo,
"x_correcao": "Primeira correção: ...",
# n_seq_evento defaults to "1"
})

# Second CC-e on the SAME NF-e
run_connection_action("nfe-sp", "nfe_carta_correcao", {
"ch_nfe": chave,
"n_prot": protocolo,
"x_correcao": "Segunda correção: ...",
"n_seq_evento": "2",
})

Getting the protocol

If you don't already have n_prot stored from when the NF-e was authorized, query SEFAZ:

consulta = run_connection_action(
"nfe-sp",
"nfe_consulta_protocolo",
{
"tp_amb": "1", # "1" producao, "2" homologacao
"x_serv": "CONSULTAR",
"ch_nfe": "35260112345678000100550010000000011123456780",
"versao": "4.00",
},
)

ret_cons = consulta["soap_envelope"]["soap_body"]["nfe_result_msg"]["ret_cons_sit_nfe"]
n_prot = ret_cons["prot_nfe"]["inf_prot"]["n_prot"]

Advanced events

For events other than cancellation and CC-e (EPEC 110140, manifesto do destinatário 210200/210210/210220/210240, etc.) use recepcao_evento directly. The full structure is:

run_connection_action("nfe-sp", "recepcao_evento", {
"evento": [{
"inf_evento": {
"cnpj": "12345678000100",
"ch_nfe": "35260112345678000100550010000000011123456780",
"tp_evento": "110111", # event code
"det_evento": {
"n_prot": "123456789012345",
"x_just": "Justificativa...",
# event-specific fields go here
},
}
}]
})

The connector auto-fills deterministic fields when omitted: id_lote, versao (envelope and evento), c_orgao, tp_amb, dh_evento, n_seq_evento, ver_evento, and inf_evento.id. For events 110110 and 110111 it also fills det_evento.versao and det_evento.desc_evento. For cancellation and CC-e, prefer nfe_cancelar / nfe_carta_correcao — they require 3 fields instead of 15.

Auto-computed fields

The connector handles these so you don't have to. Do not pass them — they will be overwritten or generated:

FieldHow the connector computes it
inf_evento.idID + tp_evento (6 digits) + ch_nfe (44 digits) + n_seq_evento zero-padded to 2 digits → 52 digits total. c_orgao is NOT part of the Id — a common mistake that triggers rejection 225
inf_evento.c_orgaoFirst 2 digits of ch_nfe (UF code, e.g. "35" for SP)
inf_evento.tp_amb"1" if the connection's environment is producao, "2" if homologacao
inf_evento.dh_eventoCurrent time in São Paulo timezone (-03:00), ISO 8601
inf_evento.ver_evento"1.00"
det_evento.versao"1.00" (XML attribute on <detEvento>)
det_evento.desc_evento"Cancelamento" for 110111, "Carta de Correcao" for 110110
evento.versao"1.00"
id_loteUnix timestamp in seconds

For LLM tooling: if you're generating a payload for nfe_cancelar or nfe_carta_correcao, only emit the 3 required fields plus any optional ones the user mentioned. Do not invent values for the auto-computed fields above.

Validation before SEFAZ

The connector throws a BadRequestError (HTTP 400) before sending to SEFAZ when:

  • ch_nfe is missing or not exactly 44 digits
  • n_prot is missing
  • (nfe_carta_correcao) x_correcao is missing

These are validated locally to give a clearer error than SEFAZ's generic 225 - Falha no Schema XML.

Idempotency

Both nfe_cancelar and nfe_carta_correcao are safe to retry. If SEFAZ has already registered the event, it returns c_stat=573 ("Evento registrado anteriormente") — treat this as success.

Common errors

See Troubleshooting for cancellation/CC-e specific errors. The most common are:

c_statMeaningFix
218Cancellation window expiredCannot cancel — emit a return invoice (fin_nfe: "4")
225Schema validation failureCheck that you used nfe_cancelar / nfe_carta_correcao (not raw recepcao_evento with a malformed id)
573Event already registeredIdempotent — treat as success
597Wrong protocol for this access keyRe-query n_prot via nfe_consulta_protocolo