---
title: "Processing, resilience, idempotency and contingency in detail"
description: "Written detail of NF-e and NFC-e processing, tax calculation (Taxes) and tax payment slips (Taxes Payment Forms): steps, resilience and idempotency rules, EPEC and offline contingency, configuration and the relationship between the products."
source_url: https://nfe.io/docs/emissao-nfe-nfce-processamento-resiliencia-e-contingencia-en/
last_updated: 2026-09-25
---

# Processing, Resilience, Idempotency and Contingency in Detail: NF-e, NFC-e, Taxes and Taxes Payment Forms

| | |
|---|---|
| **Product** | NFE.io Product Invoice Issuance (`dfetech-product-invoice-api`) |
| **Document** | 3 of 4: Detail of processing and of the resilience, idempotency and contingency rules |
| **Version** | 1.0 (2026-09-24) |
| **Audience** | Customers, architecture teams, IT, audit and tax departments |
| **Related documents** | [1 of 4: Architecture](./01-architecture.md) · [2 of 4: Processing flows](./02-processing-flows.md) · [4 of 4: Messaging and queues (Portuguese)](../04-mensageria-e-filas.md) · [Versão em português](../03-processamento-resiliencia-e-contingencia.md) |

## Contents

1. [Executive summary](#1-executive-summary)
2. [Concepts](#2-concepts)
3. [Government rules that govern issuance](#3-government-rules-that-govern-issuance)
4. [NF-e](#4-nf-e)
5. [NFC-e](#5-nfc-e)
6. [Taxes: tax calculation](#6-taxes-tax-calculation)
7. [Taxes Payment Forms: tax payment slips](#7-taxes-payment-forms-tax-payment-slips)
8. [Relationship between NF-e, NFC-e and Taxes](#8-relationship-between-nf-e-nfc-e-and-taxes)
9. [Resilience rules](#9-resilience-rules)
10. [Idempotency rules](#10-idempotency-rules)
11. [Contingency](#11-contingency)
12. [Customer responsibilities](#12-customer-responsibilities)
13. [Government references](#13-government-references)

---

## 1. Executive summary

- **Asynchronous issuance with an immediate response.** The NF-e and the NFC-e accept the request, return the invoice identifier (`id`) and continue issuance in the background. The result arrives by webhook and is available through the query endpoints. The NFC-e also has a synchronous mode, which returns the result in the same request within a 10-second limit for authorization processing.
- **Independent, resumable steps.** Creation and tax calculation, numbering, signing, submission, query and notification are separate steps. Each invoice is persisted as a sequence of events (Event Sourcing), and any step resumes from the last recorded event.
- **Resilience.** Transient failures (SEFAZ down, timeout, internal service unavailable) trigger new attempts with increasing waits. Permanent failures (SEFAZ rejection, validation error, expired certificate) close the invoice with the reason, with no pointless retries. In synchronous NFC-e without offline contingency enabled, SEFAZ unavailability closes the invoice with an error, so the point of sale is not kept waiting.
- **Idempotency.** An invoice is never resent blindly: on a timeout or a duplicate, the platform queries the invoice by its access key. A per-invoice lock and an admission control guarantee a single execution per invoice and per operation, and the consumer discards repeated messages.
- **Contingency.** The NF-e uses **EPEC** (tpEmis 4), activated by the customer (strategy `Manual`) or by NFE.io per UF (strategy `StateTaxAuthorityStatusUnavailable`). The NFC-e uses **offline contingency** (tpEmis 9), triggered automatically by a timeout or unavailability and, preventively, by a per-UF circuit breaker.
- **Relationship with Taxes.** The NF-e and the NFC-e call Taxes while the invoice is created, before numbering, when the customer requests automatic calculation on the items. If the calculation cannot be done, the invoice waits or is refused: it is never issued with a presumed tax.

## 2. Concepts

| Term | Meaning |
|---|---|
| **Access key** | 44-character identifier of the NF-e/NFC-e. It includes the UF, the year and month of issuance, the issuer's CNPJ, the model, the series, the number and the issuance type (tpEmis). |
| **cStat** | Status code returned by SEFAZ. Examples: 100 (authorized), 150 (authorized after the deadline), 204 and 539 (duplicate), 217 (invoice not found in the database), 301, 302 and 303 (use denied). |
| **tpEmis** | Issuance type: 1 (normal), 4 (EPEC), 6 (SVC-AN), 7 (SVC-RS) and 9 (NFC-e offline contingency), among others. |
| **dhCont and xJust** | Date and time of entry into contingency and the justification, both mandatory on invoices issued in contingency. |
| **EPEC** | Evento Prévio de Emissão em Contingência (prior contingency issuance event). It registers the invoice in the National Environment when the home SEFAZ is unavailable. |
| **Offline contingency** | NFC-e mode in which the invoice is issued and delivered to the consumer without prior authorization and transmitted later. |
| **State tax registration (IE)** | In the NFE.io registry, each IE (inscrição estadual) of the company defines the document type (NF-e or NFC-e), the series, the environment (production or homologation), the NFC-e CSC and the contingency strategy. |
| **CSC** | Código de Segurança do Contribuinte (taxpayer security code), used in the NFC-e QR Code. |
| **Event Sourcing** | Persistence model in which the invoice state is the sum of its events, recorded in order and never overwritten. |
| **Idempotency** | Guarantee that repeating an operation does not produce a duplicate effect. |
| **At-least-once** | "At least once" delivery guarantee: a message or webhook may arrive more than once, but is never lost. |

## 3. Government rules that govern issuance

| Topic | Rule | Source |
|---|---|---|
| Layout and validation | Layout 4.00 of the NF-e and the NFC-e and the MOC 7.0 validation rules, updated by Technical Notes (NT) | MOC 7.0, Annex I |
| Consumption Tax Reform | IBS, CBS and IS groups in the layout, per the current version of NT 2025.002 | NT 2025.002 |
| NF-e contingency | Modes FS-IA, EPEC, FS-DA, SVC-AN and SVC-RS. Under EPEC, the NF-e must be transmitted to the home SEFAZ within **168 hours** of issuance | MOC 7.0, Annex III; Ajuste SINIEF 07/05 |
| UF restriction for EPEC | From 2026-10-05, validation rule 2P10-20 prohibits EPEC for issuers in PR and PB | NT 2014.001 v1.41 |
| NFC-e contingency | An NFC-e in offline contingency must be transmitted by the **end of the first business day (dia útil) after** issuance. If rejected, it must be regenerated with the same number and series, without changing amounts, parties and dates. The numbering of an NFC-e issued in contingency cannot be disabled | Ajuste SINIEF 19/16; MOC 7.0, Annex IV |
| NF-e cancellation | Within **24 hours** of authorization, provided the goods have not moved. Cancellation after the deadline is at the discretion of each UF | Ajuste SINIEF 07/05 |
| NFC-e cancellation | Within 24 hours, a deadline each UF may shorten | Ajuste SINIEF 19/16 |
| Correction letter (CC-e) | Event 110110, only after authorization. It does not correct amounts that determine the tax, sender or recipient data, or issuance or exit dates. The most recent CC-e replaces the previous ones and must contain all corrections. Up to 20 CC-e per invoice. Does not apply to the NFC-e | Ajuste SINIEF 07/05 |
| Number disablement (inutilização) | For numbers that will not be used, by the 10th day of the following month | Ajuste SINIEF 07/05 and 19/16 |
| Service status query | Anyone polling SEFAZ availability in a loop must respect a minimum interval of 3 minutes | MOC 7.0, General Overview |

---

## 4. NF-e

### 4.1 Prerequisites

1. Company registered and active at NFE.io, with a valid **A1 (ICP-Brasil)** digital certificate.
2. Active state tax registration of type **NF-e**, with series and environment (production or homologation) defined.
3. API key with the Invoice profile.
4. Optionally, a webhook registered for the `product_invoice` event type.

### 4.2 Reception and validation (synchronous, in the API)

`POST /v2/companies/{companyId}/productinvoices` (or `.../statetaxes/{statetaxId}/productinvoices`, to choose the state tax registration) runs the following within the request:

1. Authentication of the API key and authorization by the product profile.
2. Payload conversion. A malformed payload returns **400** with the list of errors.
3. Reading the company and applying the payload and registry validation rules (for example, mandatory fields of the layout, of the Tax Reform and of return, credit and debit invoices). A violation returns **400**.
4. Generation of the invoice identifier (`id`) and storage of the original request.
5. Publication of the creation step to the issuance queue.

The response is **200** with the invoice resource and the `id`. From then on, processing is asynchronous. If publishing to the queue fails, the API responds **503** and no invoice is created, so the request can be resent safely.

Without `statetaxId` in the route, the platform uses the first state tax registration in the company's list. If it is not of type NF-e or is not active, the request is refused with **400**. When the company has more than one state tax registration, provide the `statetaxId`.

### 4.3 Invoice creation and tax calculation (worker)

1. The worker acquires the invoice lock (section 9.4).
2. If the invoice already exists in the event store, the request is treated as a repetition and the flow resumes from the invoice's current step.
3. It checks that the company and the state tax registration are active and that the IE is of type NF-e.
4. It applies the business checks (IE contingency strategy, credit and debit invoice rules, Manaus Free Trade Zone, mandatory IBS/CBS, complementary invoice totals).
5. It calculates the taxes in Taxes, when the customer requested it (section 8).
6. It checks whether EPEC contingency is active for the IE or for the UF (section 11.2). If so, the invoice is created flagged for EPEC.
7. It creates the aggregate and records the initial events. The invoice now exists with status `Created`.

Any permanent failure in this step **refuses** the invoice: it is recorded with status `Error` and the customer receives `product_invoice.issued_error` with the reason.

### 4.4 Numbering

- If the request provided the series and the number, they are used as received.
- If not, the series comes from the state tax registration and the number comes from the **numbering sequence** kept by the NFE.io registry for that IE and series.
- A permanent numbering failure (for example, an unregistered series) refuses the invoice.

:::caution Customer-provided numbering
When the customer provides the number, the platform does not query the sequence. A number already used by another invoice of the same series is rejected by SEFAZ as a duplicate (cStat 539). If your system controls numbering, ensure uniqueness per series on your side.
:::

### 4.5 Signing and authorization

1. Generation of the access key and the numeric code.
2. Retrieval of the company's A1 certificate from the custody service. The certificate validity is checked **before** signing: an expired or not-yet-valid certificate ends issuance with an error, with no call to SEFAZ.
3. Generation of the XML in layout 4.00, digital signature and validation against the official XSD schemas. A schema failure ends issuance with an error.
4. Storage of the signed XML.
5. Submission to the authorization Web Service (`NFeAutorizacao4`) of the authorizing SEFAZ for the issuer's UF, with **synchronous processing** (`indSinc=1`), over HTTPS with mutual TLS. The maximum time for each call is 120 seconds.

The authorizing SEFAZ is the UF's own or the Virtual SEFAZ that serves the UF (SVRS or SVAN), per the official list of Web Services on the NF-e National Portal. Issuers without a state tax registration (taxpayers, or *contribuintes*, liable only for IBS/CBS) are routed to SVRS.

### 4.6 Handling SEFAZ responses

| Response | Classification | What the platform does | What the customer sees |
|---|---|---|---|
| cStat 100 or 150 (authorized) | Success | Builds the `nfeProc` and notifies | `Issued`, `issued_successfully` |
| Batch received without a synchronous result | Inconclusive | Queries by access key | Waits |
| Timeout or inconclusive response | Inconclusive | Queries by access key. **Never resends** | Waits |
| 204 or 539 with this same invoice's key | Duplicate of the invoice itself | Queries by key and recovers the protocol | `Issued`, if authorized |
| 204 or 539 with another key | Rejection | Closes | `Error`, `issued_error` |
| No communication, SEFAZ unavailable | Transient | New submission attempt (section 9.1) | Waits |
| Validation rule rejection | Permanent | Stores the rejection XML and closes | `Error`, `issued_error` with cStat and reason |
| Use denied (301, 302, 303) | Permanent | Closes | `IssueDenied` (when identified in the query) or `Error` (when returned in the synchronous submission), always with `issued_error` and the denial cStat |
| Certificate refused in TLS | Permanent | Closes with no new attempts | `Error`, `issued_error` |
| Attempts exhausted | Permanent | Closes | `Error`, `issued_failed` |

**Query by access key.** The platform queries the invoice on the `NFeConsultaProtocolo4` Web Service with increasing waits (section 9.1). If the invoice is authorized, the protocol is recovered and the flow continues normally. If SEFAZ responds **217** (invoice not found in the database), the query is repeated up to **8 times**; if 217 persists, the invoice is closed with `issued_error` and cStat 217, and its number can be disabled.

### 4.7 Completion, files and notification

1. The authorization protocol is attached to the XML, forming the distribution XML (`nfeProc`), which is stored.
2. The invoice moves to `Issued` and the customer receives `product_invoice.issued_successfully`, with the full invoice resource.
3. The query index is updated next, for listings.
4. The **DANFE** is generated on the first request to `GET .../productinvoices/{id}/pdf` and stored for subsequent requests.
5. The authorized XML, the rejection XML and the EPEC event XML are available at the routes `.../xml`, `.../xml/rejection` and `.../xml-epec`.

### 4.8 Cancellation

- `DELETE .../productinvoices/{id}?reason=` responds **204** and processes in the background.
- It is accepted only for an `Issued` invoice. The justification (`reason`) must have 15 to 255 characters, counted after replacing characters that do not exist in the Latin-1 standard accepted by SEFAZ (Portuguese accents are kept); if omitted, the platform uses the default text "Erro de preenchimento".
- The worker signs event **110111** and sends it to the events Web Service of the authorizing SEFAZ.
- cStat 135, 136 or 155: the invoice moves to `Cancelled` and the customer receives `cancelled_successfully`. Rejection: `cancelled_error` with the reason. Unavailability: new attempts and, if exhausted, `cancelled_failed`.
- The legal deadline is validated by SEFAZ (section 3).

### 4.9 Correction letter (CC-e)

- `PUT .../productinvoices/{id}/correctionletter` with the correction text in the `reason` field (15 to 1,000 characters) responds **204**.
- It is accepted only for an `Issued` invoice. The worker signs event **110110** with the next sequence number and sends it to the authorizing SEFAZ.
- Result: `cce_successfully`, `cce_error` or `cce_failed`. The CC-e XML and PDF are at `.../correctionletter/xml` and `.../correctionletter/pdf`.
- Each CC-e replaces the previous one and must carry all corrections (section 3).

### 4.10 Number disablement

| Mode | Route | Processing | Rules |
|---|---|---|---|
| Per refused invoice | `POST .../productinvoices/{id}/disablement` | Asynchronous (**204**) | The invoice must be in `Error` and have a number. Result by webhook (`disabled_successfully`, `disabled_error`, `disabled_failed`) |
| Per range | `POST .../productinvoices/disablement` | **Synchronous** | Provide environment, UF, series, start and end number and justification. Responses: 204 (cStat 102 or range already disabled, 206/563), 400 (data rejection), 404, 409 (same range in processing), 422 (other rejection), 503 (SEFAZ unavailable) |

Range disablement is idempotent: repeating the request for a range already disabled returns success.

### 4.11 Purposes and special documents

- **Return, complementary, adjustment**: issued through the same `POST`, with the purpose provided in the payload and specific validations.
- **Credit invoice and debit invoice**: issued through the same `POST`. Credit invoices and debit invoices of types 01, 02, 03, 05 and 08 skip tax calculation. It is possible to link and list the credit invoices issued against an NF-e.
- **Tax Reform fiscal events** (NT 2025.002): the `.../authority-events` route records the issuer events defined in the NT. It is released when the feature is enabled.

---

## 5. NFC-e

### 5.1 Prerequisites

1. Active company, with a valid A1 certificate.
2. Active state tax registration of type **NFC-e**, with series, environment and **CSC** (identifier and code) registered.
3. IE authorizer switch strategy set to `Manual`. Any other strategy is refused with error code `40002`: in synchronous issuance, with **400** in the request itself; in asynchronous issuance, the invoice is refused during processing and the customer receives `issued_error`.

### 5.2 Asynchronous issuance

`POST /v2/companies/{companyId}/consumerinvoices` follows the same steps as the NF-e (sections 4.2 to 4.7), with these particularities:

- The issuance date and time (`dhEmi`) is the processing time.
- The XML includes the **QR Code** (version 2), generated with the CSC of the state tax registration.
- A timeout or SEFAZ unavailability triggers offline contingency when the IE is enabled (section 11.3).
- On 217 in the query by key made after a submission timeout, the NFC-e alternates query and resubmission for up to 10 cycles before closing with an error.
- Webhook event type: `consumer_invoice`. The `issued_contingency` action reports that the invoice was issued in offline contingency.

### 5.3 Synchronous issuance

`POST /v2/companies/{companyId}/consumerinvoices/sync` returns the result in the same request.

1. The **API** validates the payload, calculates the taxes (when requested) and creates the invoice.
2. The API triggers the worker through a direct internal call. The worker acquires the invoice lock, numbers, signs, generates the QR Code and sends the authorization to SEFAZ.
3. The deadline for the authorization call is calculated as follows:

   `SEFAZ deadline = the lesser of 8 s and (10 s − time already elapsed in the worker − 2 s reserve)`, with a minimum of 1 s.

   The 2-second reserve exists so that, if needed, the invoice can be issued in offline contingency within the total time.
4. Responses:

| Situation | HTTP | Invoice `status` |
|---|---|---|
| Authorized within the deadline | 200 | `Issued` |
| Deadline exceeded or SEFAZ unavailable, IE enabled for offline contingency | 200 | `IssuedContingency` (the invoice will be transmitted later) |
| Rejected by SEFAZ | 200 | `Error`, with the cStat and the reason |
| Invalid payload or registry | 400 | Not created |
| Tax calculation rejected | 422 (code `42201`) | `Error`: the invoice is recorded as refused |
| Invoice still processing when the call ends (deadline exceeded or duplicate with an IE not enabled for offline, lock busy or internal failure) | 503 | Stays `Processing` in the worker, which completes the flow (for example, by querying the invoice by key) |
| SEFAZ unavailable, IE not enabled for offline | 200 | `Error`: the invoice is refused; the request can be resent and the refused invoice's number must be disabled |
| Tax calculation service unavailable | 503 | Not created; the request can be resent |

:::caution HTTP 503 in synchronous issuance
A 503 does **not** mean the invoice no longer exists: it is still being handled and the result arrives by webhook. Before resending, check the company's invoice listing. A new `POST` creates a new invoice, with a new `id` and a new number.
:::

The 10-second limit applies to processing in the worker. Tax calculation and invoice creation, done in the API before this step, do not count toward it.

### 5.4 QR Code and NFC-e DANFE

- The QR Code uses version 2, with the CSC and its identifier registered on the IE. In offline contingency, the QR Code carries the data required for that mode (issuance day, total amount and *digest value*).
- The NFC-e DANFE is generated on the first request to `GET .../consumerinvoices/{id}/pdf`. In offline contingency, the DANFE shows the contingency issuance indication.

### 5.5 Cancellation and number disablement

- **Cancellation** (`DELETE .../consumerinvoices/{id}?reason=`): requires an `Issued` invoice, event 110111, same rules as the NF-e. An invoice in `IssuedContingency` not yet transmitted can only be cancelled after it is authorized.
- **Number disablement** per refused invoice or per range, as in the NF-e. The numbering of an NFC-e issued in contingency cannot be disabled (Ajuste SINIEF 19/16).
- The NFC-e has no correction letter.

### 5.6 Differences between NF-e and NFC-e

| Aspect | NF-e | NFC-e |
|---|---|---|
| Synchronous mode | No | Yes (`/sync`) |
| Contingency | EPEC (tpEmis 4) | Offline (tpEmis 9) |
| Contingency strategies accepted on the IE | `Manual` and `StateTaxAuthorityStatusUnavailable` | `Manual` only |
| QR Code and CSC | Not applicable | Mandatory |
| Issuance date | Can be provided in the request | Always the processing time |
| CC-e | Yes | No |
| Cycle on 217 | Up to 8 queries | Up to 10 query and resubmission cycles (after a submission timeout) |
| Webhook event type | `product_invoice` | `consumer_invoice` |

---

## 6. Taxes: tax calculation

### 6.1 Resources

| Route | Function |
|---|---|
| `POST /tax-rules/{tenantId}/engine/calculate` | Calculates taxes per item |
| `/{tenantId}/products` (POST) and `/{tenantId}/products/{productId}` (GET, PUT, PATCH) | Product tax registry |
| `GET /tax-codes/operation-code`, `.../acquisition-purpose`, `.../issuer-tax-profile`, `.../recipient-tax-profile` | Code tables used in the calculation request |

`tenantId` is the customer account: if it does not match the API key's account, the response is **403**.

### 6.2 How the calculation is done

The request provides the issuer and the recipient (tax regime, tax profile and UF), the operation type and, per item, the operation code, the acquisition purpose, the tax profiles, the SKU, the NCM, the CEST, the goods origin and the amounts (quantity, unit price, freight, insurance, discount and other expenses).

1. For each item, Taxes looks up the product in the tax registry (by SKU and origin). A registered product that is not active, or an unregistered product without NCM, returns **400**.
2. Taxes checks whether there is a recent reusable calculation for the same scenario (section 6.3).
3. For items without reuse, it queries the tax rules engine, which returns CFOP, CST/CSOSN, bases, reductions, rates and amounts.
4. It applies the product's custom taxation (`customTax`), when present (section 6.4).
5. It returns, per item: CFOP, CEST, tax benefit code (cBenef), ICMS (including ST, FCP, FCP-ST, deferral, exemption relief and single-phase), ICMS of the destination UF (DIFAL), IPI, PIS and COFINS, plus additional product information.

### 6.3 Calculation reuse and fallback during unavailability

- For eligible scenarios, a calculation result is stored per registered product (or, without a product, per NCM) and per scenario (operation type and code, regimes, profiles, origin and UFs), and reused for up to **500 hours**. On reuse, bases and amounts are always recalculated with the current request's values; what is reused is the rule (CST, rates, reductions).
- Reuse applies to Simples Nacional issuers, to enabled accounts and to the calculation done in the product registry. It is restricted to simple taxation scenarios (for example, CST 00, 40, 41 and 60 and CSOSN 102, 400 and 500, without IPI and with PIS and COFINS without a rate) and to specific issuer and recipient profiles. All other scenarios always query the engine.
- If the rules engine fails, Taxes uses, in this order: (a) the stored result, even if expired, when reuse applies to the scenario and there is a result for all items; (b) when the engine is unavailable or found no rule, the ICMS CST 40 rule registered on the product (with CFOP and PIS and COFINS CST), when it covers all items. Without either, the calculation fails with the original error: **nothing is presumed**.

### 6.4 Custom taxation and tax benefit

- The product registry can carry its own rules (`customTax`) per scenario (operation, regimes and profiles, intrastate or interstate operation). When the scenario matches, these rules replace the engine's: CFOP, CST/CSOSN, rates, base modality, base reduction, FCP, PIS and COFINS, tax benefit code and additional information.
- When the custom taxation defines CST 40 or 41, the engine indicates a tax benefit code (cBenef) for the scenario and the product does not provide its own code (`benefitCode`), Taxes responds **422** before issuance, avoiding the later SEFAZ rejection (cStat 930/931).

### 6.5 IBS and CBS

IBS and CBS are calculated by a dedicated NFE.io service, in a separate call made by the NF-e and the NFC-e for items that request the official calculation (`ibscbs.calculationMode = OfficialService`, with the tax classification code). The nominal rates follow the transition schedule of the Consumption Tax Reform.

### 6.6 Product registry

- The registry is validated asynchronously. A product without custom taxation is activated (`Active`). A product with custom taxation goes through `CustomTaxPending` while the rules are registered and checked in the engine and, at the end, becomes `Active` or `Error`.
- Status changes generate the `product_tax` webhook, with the actions `created_successfully` (active), `custom_rules_requested` (custom taxation under review) and `creation_failed` (error).

### 6.7 Error responses

| HTTP | Situation |
|---|---|
| 400 | Invalid data, product not active, product without NCM, unsupported tax profile, data refused by the rules engine |
| 403 | Route account differs from the API key account |
| 422 | Tax rule not found for the scenario, rules engine error or missing mandatory cBenef |
| 500 | Unexpected failure or communication failure with the rules engine; on the public route, also temporary engine unavailability |
| 503 | Rules engine temporarily unavailable, on the internal call made by issuance (treated as a transient failure, section 8.4) |

---

## 7. Taxes Payment Forms: tax payment slips

- **Purpose:** generate the tax payment slip for the interstate **DIFAL** (`vICMSUFDest`) from an authorized NF-e.
- **Input:** the `id` of an NF-e issued by NFE.io (`POST /v1/tax-payment-forms/{accountId}/{companyId}/gnre`, with payment date and due date) or the `nfeProc` XML (`.../gnre/xml`). The `accountId` must be the API key's.
- **Destination:** DUA at SEFAZ-ES for operations destined to Espírito Santo; GNRE batch at the GNRE Portal for the other UFs. The SP destination is not supported.
- **Validation:** the operation must be interstate and have DIFAL greater than zero; otherwise, the request is refused with **400**. The slip ends as unnecessary (`ErrorNotNeeded`) when the total amount due is zero or when the portal reports an amount below the minimum.
- **Steps:** `Created` → `Prepared` → `Transmitted` → `Generated`, with the slip PDF at the end. Any processing failure triggers a new attempt every 10 seconds, up to 100 times.
- **Default payment date:** the next business day, per the São Paulo holiday calendar. A payment date in the past is refused with 400.
- **Notification:** `tax_payment_form` webhook, with the actions `created_successfully`, `creation_failed` and `creation_not_needed`.
- Payment Forms is **not called** by NF-e or NFC-e issuance: the customer triggers it after the NF-e is authorized.

---

## 8. Relationship between NF-e, NFC-e and Taxes

### 8.1 How the customer requests the calculation

| Taxes | How to request it in the NF-e or NFC-e payload |
|---|---|
| ICMS, ICMS-ST, FCP, DIFAL, IPI, PIS and COFINS | Provide, on the item, the `taxDetermination` block (operation code, issuer and recipient tax profiles, origin and acquisition purpose). With this block, CFOP becomes optional |
| IBS and CBS | Provide, on the item, `tax.ibscbs.calculationMode = OfficialService` with the tax classification code |

Without these fields, the amounts provided in the payload are used as received and Taxes is not called.

### 8.2 When and where the calculation happens

| Product and mode | Where Taxes is called | When |
|---|---|---|
| NF-e | Worker | Creation step, before numbering and signing |
| Asynchronous NFC-e | Worker | Creation step |
| Synchronous NFC-e | API, within the customer's request | Before the invoice is created |

The result is applied to each item: CFOP (checked against the one the customer provided, if any), CST/CSOSN, bases, rates and amounts, cBenef and CEST (when the customer did not provide them). The additional product information is appended to the item's.

### 8.3 When calculation is skipped

- Credit invoices and debit invoices of types 01, 02, 03, 05 and 08 do not go through the engine.
- An issuer that is a taxpayer liable only for IBS/CBS (without a state tax registration) does not go through the ICMS, IPI, PIS and COFINS calculation, only the IBS and CBS one.

### 8.4 Calculation failures during issuance

| Taxes response | NF-e and asynchronous NFC-e | Synchronous NFC-e |
|---|---|---|
| Success | Issuance continues | Issuance continues |
| Rejection (4xx), for example, rule not found | Invoice refused (`Error`, `issued_error`) with "Error while calculating taxes" and the reason | 422 with code `42201`; the invoice is recorded as refused |
| Unavailable (5xx, network failure or service credential failure) | New attempts with increasing waits for up to 50 attempts (about 2.5 hours). Once exhausted, the invoice is refused | 503; no invoice is created and the request can be resent |
| IBS/CBS with credential failure | Up to 5 new attempts | 503 |
| IBS/CBS with another failure | Invoice refused | 422 |

In addition, each call to Taxes has up to 2 internal retries, 5 seconds apart, on network failures, request timeout (408) and server errors, except 503.

---

## 9. Resilience rules

### 9.1 Retries per step

Each step that ends in a transient failure is rescheduled. The first execution of each step is immediate; each repetition waits for the next rung of this ladder, and the count restarts when the invoice changes step:

| Step | Wait between attempts |
|---|---|
| Submission to SEFAZ | 5 s, 10 s, 15 s, 1 min, 5 min and, from then on, 10 min |
| Query by access key | 30 s, 1 min, 2 min, 4 min, 8 min, 16 min, 32 min and, from then on, 64 min |
| Receipt query (asynchronous batch) | 5 s, 10 s, 1 min, 5 min, 10 min, 1 h and, from then on, 13 min |
| Retransmission of NFC-e in offline contingency | Every 10 min |
| Other steps (creation, numbering, notification, cancellation, CC-e, number disablement and transmission of EPEC invoices to the home SEFAZ) | 5 s up to the 10th attempt, 1 min up to the 20th, 5 min up to the 50th and, from then on, 10 min |

Exceptions: in the contingency flow (transmission of EPEC invoices), submission and receipt query follow the ladder of the other steps; in the query by key that has just resent the invoice in the cStat 217 cycle (NFC-e), the submission ladder applies.

### 9.2 Limits

| Limit | Value | Effect when reached |
|---|---|---|
| Business attempts per step (submission, query, cancellation, CC-e, number disablement) | 100 | The invoice ends with the `_failed` action (for example, `issued_failed`). For submission, this corresponds to about 16 hours of continuous unavailability |
| Queries with 217 (NF-e) | 8 | `issued_error` with cStat 217 |
| Query and resubmission cycles with 217 (NFC-e) | 10 | `issued_error` with cStat 217 |
| Attempts while tax calculation is unavailable | 50 (about 2.5 hours) | Invoice refused |
| Technical ceiling of attempts per step | 150 | The invoice is closed with an error and the reason is recorded in the events |
| Immediate redeliveries of a failed message | 10 | The message goes to the error queue, without changing the invoice, and can be reprocessed by the operations team |

### 9.3 Failure classification

| Type | Examples | Handling |
|---|---|---|
| Transient | SEFAZ unavailable, no communication, internal service unavailable, tax calculation unavailable | Repeats the same step with increasing waits |
| Inconclusive | Timeout, batch received without a result, duplicate of the invoice itself | Query by access key |
| Permanent | SEFAZ rejection, schema error, expired or refused certificate, inactive registry, tax calculation rejection | Closes the invoice with the reason |

### 9.4 Per-invoice lock

- Every step runs under a distributed per-invoice lock, valid for 5 minutes.
- If the lock is taken, the step is rescheduled with waits of 2, 5, 15, 30, 60 and, from then on, 120 seconds (with 20% random jitter, so resumptions do not cluster), without consuming the step's attempt counter. After 30 reschedules (about 52 minutes), the invoice is closed with an error and the reason is recorded.
- In the API, operations that also require the lock (for example, DANFE generation) respond **409** with the `Retry-After: 2` header when the invoice is being processed.

### 9.5 Maximum times

| Call | Maximum time |
|---|---|
| SEFAZ Web Services | Up to 120 s per call |
| Authorization in synchronous NFC-e | Up to 8 s, within the 10 s total limit |
| Tax calculation (issuance call) | 260 s, with up to 2 retries of 5 s |
| Tax rules engine (Taxes call) | 200 s, with up to 2 retries of 5 s and short retries (up to 5, within 5 s) for transient responses |

### 9.6 Webhooks

- The notification step is repeated while the notification platform is unavailable.
- Delivery to the customer's endpoint is **at-least-once**, with automatic redelivery on network failure or a non-2xx response (up to 16 attempts over about 45 hours) and an HMAC signature. See the [webhook event catalog (Portuguese)](../../../webhooks/catalogo-de-eventos.md).
- If the customer has no webhook registered, the platform records this in the invoice history; the result remains available through the query endpoints.

### 9.7 Infrastructure

- API replicas with horizontal autoscaling.
- Liveness and readiness checks, which verify the event store, storage, broker, cache and the registry and certificate services.
- Per-product error queues for messages that exhaust their redeliveries.
- External heartbeat monitor and end-to-end distributed tracing.

---

## 10. Idempotency rules

### 10.1 Platform guarantees

| Guarantee | How it is achieved |
|---|---|
| A single execution per invoice and per operation | Admission control: the entry of an operation on an invoice (cancellation, CC-e, number disablement, event, credit invoice link) writes a conditional record per invoice and operation; a record with no activity for 24 hours is considered abandoned. A request repeated while the execution is alive is discarded with no new SEFAZ call and no new webhook. Right after completion, a 5-minute window prevents immediate readmission of the same work. For issuance, the control protects internal re-publications; each customer `POST` creates a new invoice (section 10.2) |
| Message processed once | The consumer records each processed message and discards redeliveries within a 5-minute window |
| One step at a time | Distributed per-invoice lock (section 9.4) |
| Nothing is lost or overwritten | Event Sourcing with optimistic concurrency control: two processes cannot write the same invoice version |
| Safe resumption | A repeated step starts from the recorded state: creating an invoice that already exists resumes the flow; signing is not redone if the XML is already signed |
| No blind resubmission | Timeout and duplicate lead to a query by access key. SEFAZ guarantees access key uniqueness; cStat 204 or 539 with the invoice's own key leads to a query by access key, which recovers the protocol when the invoice is authorized |
| Repeated range disablement | Returns success when the range is already disabled |
| Repeated webhook | The `X-Hook-Id` header identifies the notification for idempotent handling on the customer side |

### 10.2 What the customer is responsible for

- **Each issuance `POST` creates a new invoice**, with a new `id` and, if the number is not provided, a new number. The API has no idempotency key for the issuance request.
- Keep the returned `id` and use it as the reference for query, cancellation and reconciliation.
- If the issuance request ends without a response (timeout or dropped connection), **do not resend immediately**: check the company's invoice listing to see whether the invoice was created.
- If your system provides the invoice number, ensure uniqueness per series: a repeated number is rejected by SEFAZ with cStat 539.
- Handle webhooks idempotently and respond 2xx quickly.

---

## 11. Contingency

### 11.1 Overview

| Product | Mode used | tpEmis | How it is triggered |
|---|---|---|---|
| NF-e | EPEC | 4 | By the customer (strategy `Manual`) or by NFE.io, per UF (strategy `StateTaxAuthorityStatusUnavailable`) |
| NFC-e | Offline contingency | 9 | Automatically, on timeout or SEFAZ unavailability, and preventively by a per-UF circuit breaker, for enabled state tax registrations |

The SVC-AN and SVC-RS modes (tpEmis 6 and 7) and the security form modes (FS-IA and FS-DA) are not used by the platform.

### 11.2 NF-e: EPEC

#### Configuration

The contingency strategy is defined per state tax registration, in the `processingDetails.switchAuthorizerStrategy` field of the IE registry (Companies API, creation or update of the state tax registration):

| Strategy | Who decides when contingency starts and ends | How |
|---|---|---|
| `Manual` | The customer | `POST /v2/companies/{company_id}/statetaxes/{state_tax_id}/switch-authorizer` with `{"authorizer": "EPEC", "reason": "<justification>"}` to enter and `{"authorizer": "Normal", "reason": "<justification>"}` to exit. The response carries the previous authorizer, the new one, the justification and the date and time of the switch |
| `StateTaxAuthorityStatusUnavailable` | NFE.io | When it identifies instability at a UF's SEFAZ, the NFE.io operations team activates contingency for that UF. All companies in the UF with this strategy start issuing in EPEC, and return to normal when NFE.io ends the UF contingency |

- Under the `Manual` strategy, the justification provided (`reason`, 15 to 256 characters to enter EPEC) becomes the invoice's `xJust` and the date and time of the switch becomes the `dhCont`.
- Under the `StateTaxAuthorityStatusUnavailable` strategy, `xJust` and `dhCont` come from the activation done by NFE.io for the UF.
- The platform does not poll the SEFAZ status automatically: per-UF activation is a decision of the operations team, based on SEFAZ monitoring.

#### Application rules

- Contingency is applied **when the invoice is created**. Invoices created after activation are issued in EPEC.
- Invoices already in processing at the time of activation do **not** migrate to EPEC: they keep trying the home SEFAZ, under the retry rules of section 9, until SEFAZ is back.
- From **2026-10-05**, validation rule 2P10-20 of NT 2014.001 v1.41 prohibits EPEC for issuers in **PR** and **PB**. The platform already has this check implemented, to be activated on the effective date: from then on, EPEC issuance for these issuers is refused with a reference to the rule.

#### Flow

1. The NF-e is generated with tpEmis 4, `dhCont` and `xJust`.
2. The **EPEC (110140)** event is signed and sent to the National Environment's Event Reception Web Service.
3. With the event registered, the invoice gets status `IssuedContingency`, the event XML is available at `.../xml-epec` and the DANFE is printed with the contingency marking. The customer receives `product_invoice.issued_successfully` with `status` equal to `IssuedContingency`.
4. The goods can move with the EPEC DANFE.

#### Return to normal

- Contingency ends when the customer switches the authorizer to `Normal` (strategy `Manual`) or when NFE.io ends the UF contingency (strategy `StateTaxAuthorityStatusUnavailable`). New invoices are issued with tpEmis 1 again.
- An NF-e issued in EPEC must be transmitted to the home SEFAZ within **168 hours** of issuance (Ajuste SINIEF 07/05), keeping the same access key. The later transmission uses batch submission with receipt query; the invoice moves to `Issued` once authorized.
- The NFE.io operations team conducts the regularization of EPEC invoices when contingency ends. The customer follows the pending invoices through the `IssuedContingency` status.

### 11.3 NFC-e: offline contingency

#### Configuration

| Parameter | Production value | Who defines it |
|---|---|---|
| Offline contingency enablement | Per state tax registration | NFE.io, at the customer's request |
| IE authorizer switch strategy | `Manual` only | Customer, in the IE registry |
| Consecutive failures (timeout or unavailability) to open the UF circuit breaker | 5 | NFE.io |
| Retransmission interval | 10 minutes | NFE.io |
| Total synchronous issuance time in the worker | 10 s | NFE.io |
| Maximum authorization call deadline (synchronous) | 8 s | NFE.io |
| Time reserve for contingency (synchronous) | 2 s | NFE.io |

Offline contingency is enabled per state tax registration. An IE that is not enabled does not issue in contingency: on a timeout, the invoice follows the normal query-by-access-key flow; on SEFAZ unavailability, asynchronous issuance retries and synchronous issuance refuses the invoice (`Error`), which the customer must resend.

#### Reactive mode

1. Normal authorization (tpEmis 1) ends in a timeout or in SEFAZ unavailability.
2. The platform records the failure in the UF circuit breaker.
3. For an enabled IE, the invoice is **regenerated** with tpEmis 9: new access key, `dhCont` equal to the current date and time and `xJust` equal to "Intermitência na comunicação com a SEFAZ." ("Intermittent communication with SEFAZ."). The XML is signed again, with the contingency QR Code. The key of the normal attempt is kept as the "abandoned key".
4. The invoice moves to `IssuedContingency`. In asynchronous mode, the customer receives `consumer_invoice.issued_contingency`; in synchronous mode, the response is 200 with this status. The NFC-e DANFE can be delivered to the consumer.
5. If regeneration fails, the contingency invoice is not recorded and the normal attempt follows the rules for a non-enabled IE (paragraph before Reactive mode).

#### Proactive mode (per-UF circuit breaker)

- **Opening:** 5 consecutive failures by timeout or unavailability in the same UF, on any state tax registration, open the circuit breaker for that UF.
- **With the circuit breaker open:** invoices of enabled IEs go straight to tpEmis 9, without trying normal authorization, with `dhCont` equal to the date and time the circuit breaker opened. This spares the consumer from waiting on a SEFAZ that is already failing.
- **Closing:** any successful normal authorization in the UF or any authorized contingency retransmission closes the circuit breaker. As a safeguard, the circuit breaker state expires 24 hours after the last recorded failure.
- If the circuit breaker control is unreachable, the platform treats it as closed and proceeds with normal authorization.

#### Later transmission

1. The first transmission is immediate and the following ones happen every 10 minutes, sending the already-signed offline XML.
2. **Authorized:** the invoice moves to `Issued`, the customer receives `issued_successfully` and the UF circuit breaker is closed.
3. **Duplicate with the abandoned key:** if SEFAZ reports that the original normal attempt (tpEmis 1) was authorized, **the original invoice prevails**: the platform reconciles the invoice to the tpEmis 1 key, queries the protocol and completes it as `Issued`.
4. **Timeout or unavailability:** new transmission in the next cycle.
5. **Permanent rejection:** the invoice ends with `Error` and `issued_error`. Under Ajuste SINIEF 19/16, the taxpayer must regenerate the invoice with the same number and series, without changing amounts, parties and dates, and obtain authorization.
6. **Attempts exhausted:** when the limit of 100 submission attempts is reached (section 9.2), the invoice ends with `issued_failed` and requires handling.

The legal transmission deadline is the end of the first business day after issuance (Ajuste SINIEF 19/16). The 10-minute cycle exists to regularize the invoice well before that deadline as soon as SEFAZ is back.

#### Additional rules

- Cancellation is accepted only after the contingency invoice is authorized.
- The numbering of an NFC-e issued in contingency cannot be disabled.
- EPEC is not used for the NFC-e: the NFC-e IE strategy must be `Manual`, and the available contingency is offline.

### 11.4 Configuration summary

| Parameter | Product | Where it is configured | Values |
|---|---|---|---|
| `processingDetails.switchAuthorizerStrategy` | NF-e and NFC-e | State tax registration registry (Companies API) | `Manual`, `StateTaxAuthorityStatusUnavailable` (NF-e only) |
| `switch-authorizer` (`authorizer`, `reason`) | NF-e | `POST /v2/companies/{company_id}/statetaxes/{state_tax_id}/switch-authorizer` | `EPEC` or `Normal`, with justification |
| Per-UF contingency | NF-e | NFE.io operations | Active or inactive, with justification and start |
| Per-IE offline contingency | NFC-e | NFE.io operations, at the customer's request | Enabled or not |
| Per-UF circuit breaker threshold | NFC-e | Platform configuration | 5 consecutive failures (timeout or unavailability) |
| Retransmission interval | NFC-e | Platform configuration | 10 minutes |
| Synchronous issuance deadlines | NFC-e | Platform configuration | 10 s total, 8 s for SEFAZ, 2 s reserve |

---

## 12. Customer responsibilities

1. Keep the A1 certificate valid and the company and state tax registration data up to date (series, environment, NFC-e CSC, contingency strategy).
2. Keep the `id` of each invoice and do not resend requests without checking first (section 10.2).
3. Ensure numbering uniqueness per series when your system provides the number.
4. Register webhooks and handle them idempotently, responding 2xx quickly.
5. Under the NF-e `Manual` strategy, decide when EPEC contingency starts and ends and follow, through the `IssuedContingency` status, the regularization of the invoices within the legal deadline.
6. For NFC-e in offline contingency, deliver the NFC-e DANFE with the contingency indication to the consumer and regularize invoices that end in rejection.
7. Respect the legal deadlines for cancellation, CC-e and number disablement.

## 13. Government references

- Portal Nacional da NF-e (NF-e National Portal), Manual de Orientação do Contribuinte (MOC, Taxpayer Guidance Manual) version 7.0: https://www.nfe.fazenda.gov.br/portal/listaConteudo.aspx?tipoConteudo=ndIjl+iEFdE%3D
  - Anexo III, Manual de Contingência da NF-e (Annex III, NF-e Contingency Manual): https://www.confaz.fazenda.gov.br/legislacao/arquivo-manuais/moc7-anexo-iii-manual-contingencia-nf-e.pdf
  - Anexo IV, Manual de Contingência da NFC-e (Annex IV, NFC-e Contingency Manual): https://www.confaz.fazenda.gov.br/legislacao/arquivo-manuais/moc7-anexo-iv-manual-contingencia-nfc-e.pdf
- Portal Nacional da NF-e, Notas Técnicas (Technical Notes) (NT 2025.002, Reforma Tributária do Consumo (Consumption Tax Reform); NT 2014.001, EPEC): https://www.nfe.fazenda.gov.br/portal/listaConteudo.aspx?tipoConteudo=04BIflQt1aY%3D
- Portal Nacional da NF-e, Relação de Serviços Web (Web Services list): https://www.nfe.fazenda.gov.br/portal/webServices.aspx?tipoConteudo=OUC/YVNWZfo%3D
- CONFAZ, Ajuste SINIEF 07/05 (NF-e): https://www.confaz.fazenda.gov.br/legislacao/ajustes/2005/AJ007_05
- CONFAZ, Ajuste SINIEF 19/16 (NFC-e): https://www.confaz.fazenda.gov.br/legislacao/ajustes/2016/AJ_019_16
