---
title: "Emissão de NFS-e no layout da Reforma Tributária com o SDK Python da NFE.io"
description: "Emita NFS-e no layout da Reforma Tributária do Consumo (IBS e CBS) com service_invoices.create e o grupo ibsCbs — o que foi provado ao vivo, o payload mínimo, retenções e o que depende da parametrização da empresa."
source_url: https://nfe.io/docs/desenvolvedores/bibliotecas/python/emissao-rtc/
product: bibliotecas
last_updated: 2026-10-14
tags: ["python", "how-to", "nfse", "emissao", "reforma-tributaria", "rtc"]
integration: ["sdk"]
---

# Emissão RTC (Reforma Tributária)

A NFS-e no layout da Reforma Tributária do Consumo (RTC) usa **o mesmo método** da emissão comum:
`client.service_invoices.create` (ou `create_and_wait`). Não há recurso, URL nem cabeçalho
diferente. O que liga o layout RTC é a **presença do grupo `ibsCbs`** no corpo. Com ele, a API
valida o grupo na hora e grava os códigos da Reforma na nota.

O tipo `ServiceInvoiceCreateParams` já aceita `ibsCbs` e `nbsCode`. Consulta, cancelamento, PDF e
XML funcionam igual.

## O que foi provado

Em 10/10/2026, notas RTC foram emitidas e canceladas com o SDK 0.1.0 numa empresa de teste
(Simples Nacional, ambiente de testes):

| Cenário | Resultado |
|---|---|
| Payload mínimo com `ibsCbs` | `202`, `Issued` em ~5 s; `ibsCbs` e `nbsCode` devolvidos na consulta |
| Com ISS retido e retenções federais | `Issued` em ~4 s; retido 8,15 e líquido 91,85 numa nota de 100,00 |
| `operationIndicator` com **7 dígitos** | **`400`**: `ibsCbs.operationIndicator must be exactly 6 digits`. Nenhuma nota criada |
| Sem `nbsCode` | Aceito no ambiente de testes (veja o alerta abaixo) |
| CNPJ do tomador como `str` com zeros à esquerda | Zeros preservados no XML |
| `cancel_and_wait` | `Cancelled` em ~3,5 s |

## Payload mínimo

```python
from decimal import Decimal

from nfeio import NfeClient
from nfeio.types import ServiceInvoiceCreateParams

client = NfeClient()
company_id = "ID_DA_EMPRESA"

params: ServiceInvoiceCreateParams = {
    "cityServiceCode": "10677",          # código de serviço do município
    "federalServiceCode": "01.01",       # item da LC 116, formato NN.NN
    "nbsCode": "115021000",              # NBS 1.1502.10.00, 9 dígitos sem pontos
    "description": "Desenvolvimento de software sob encomenda",
    "servicesAmount": Decimal("10.00"),
    "ibsCbs": {
        "operationIndicator": "100301",  # indicador da operação: exatamente 6 dígitos
        "classCode": "000001",           # classificação tributária (cClassTrib): 6 dígitos
    },
    "borrower": {
        "type": "LegalEntity",
        "name": "Tomador Exemplo Ltda",
        "federalTaxNumber": "11222333000181",  # str preserva zeros à esquerda
        "address": {
            "country": "BRA",
            "postalCode": "01310-200",
            "street": "Avenida Paulista",
            "number": "2000",
            "district": "Bela Vista",
            "city": {"code": "3550308", "name": "São Paulo"},
            "state": "SP",
        },
    },
}

invoice = client.service_invoices.create_and_wait(
    company_id, params, external_id="pedido-rtc-1001"
)
print(invoice.flow_status)                   # "Issued"
print(invoice["ibsCbs"]["operationIndicator"], invoice["nbsCode"])
```

O que cada campo pede:

| Campo | Formato | Observação |
|---|---|---|
| `ibsCbs.operationIndicator` | 6 dígitos, como `str` | Define o local de incidência e **qual endereço** a nota precisa trazer. `100301` (serviço prestado a distância) exige o endereço do tomador. |
| `ibsCbs.classCode` | 6 dígitos, como `str` | Classificação tributária do IBS/CBS (`000001` é tributação integral). Os 3 primeiros dígitos são o CST. |
| `nbsCode` | 9 dígitos, sem pontos | Precisa ser coerente com o item da LC 116 em `federalServiceCode`. |
| `federalServiceCode` | `NN.NN` | Item da LC 116. |
| `borrower.address` | `postalCode`, `street`, `city.code` (IBGE, 7 dígitos), `city.name`, `state` | Obrigatórios quando um endereço brasileiro é informado. |

Os valores de IBS e CBS não são enviados: a NFE.io calcula a partir de `operationIndicator`,
`classCode` e `servicesAmount`. Os campos opcionais do grupo (`purpose`, `destinationIndicator`,
compras governamentais, locação de bens móveis etc.) estão na
[documentação funcional do layout RTC](../../../documentacao/reforma-tributaria/conceitos-funcionais/nota-fiscal-de-servico/documentacao-layout-nfse-rtc.md).
O par `federalServiceCode` × `nbsCode` × `operationIndicator` × `classCode` sugerido para cada
serviço está na [tabela de correlação LC 116 × NBS](../../../documentacao/reforma-tributaria/conceitos-funcionais/tabelas-de-referencia/lc116-nbs-correlation-table-pt-br.md),
e os indicadores, na [tabela de indicador da operação](../../../documentacao/reforma-tributaria/conceitos-funcionais/tabelas-de-referencia/doc-ref-operationindicator-table-pt-br.md).

:::danger O indicador da operação tem 6 dígitos
Alguns exemplos de payload RTC publicados usam `operationIndicator` com 7 dígitos (`"1005011"`). A
API recusa com `400` e o SDK levanta `InvalidRequestError`. Use sempre 6 dígitos, como texto.
:::

## Com retenções

As retenções continuam nos campos da raiz durante a transição, e convivem com o `ibsCbs`. Alíquotas
são frações (`0.02` = 2%):

```python
from decimal import Decimal

from nfeio import NfeClient
from nfeio.types import ServiceInvoiceCreateParams

client = NfeClient()

params: ServiceInvoiceCreateParams = {
    "cityServiceCode": "10677",
    "federalServiceCode": "01.01",
    "nbsCode": "115021000",
    "description": "Consultoria em tecnologia",
    "servicesAmount": Decimal("100.00"),
    "ibsCbs": {"operationIndicator": "100301", "classCode": "000001"},
    "retentionType": "WithheldByBuyer",     # ISS retido pelo tomador
    "issRate": Decimal("0.02"),
    "issAmountWithheld": Decimal("2.00"),
    "irAmountWithheld": Decimal("1.50"),
    "pisAmountWithheld": Decimal("0.65"),
    "cofinsAmountWithheld": Decimal("3.00"),
    "csllAmountWithheld": Decimal("1.00"),
    "borrower": {
        "type": "LegalEntity",
        "name": "Tomador Exemplo Ltda",
        "federalTaxNumber": "11222333000181",
        "address": {
            "country": "BRA",
            "postalCode": "01310-200",
            "street": "Avenida Paulista",
            "number": "2000",
            "district": "Bela Vista",
            "city": {"code": "3550308", "name": "São Paulo"},
            "state": "SP",
        },
    },
}

invoice = client.service_invoices.create_and_wait(
    "ID_DA_EMPRESA", params, external_id="pedido-rtc-1002"
)
print(invoice.amount_net)          # 91.85 (Decimal)
print(invoice["amountWithheld"])   # 8.15 (float, como no JSON)
if str(invoice["retentionType"]).lower() != "withheldbybuyer":
    print("retenção diferente da enviada")
```

- Retenção de PIS/COFINS vai em `pisAmountWithheld`/`cofinsAmountWithheld`, nunca em
  `pisAmount`/`cofinsAmount`, que são o débito próprio.
- Se nenhum campo de imposto federal for informado, a NFE.io calcula as retenções pela configuração
  da empresa. Envie os campos só quando o seu sistema já tiver os valores.
- A API devolve `retentionType` com outra caixa (`withheldByBuyer`): compare sem diferenciar
  maiúsculas e minúsculas.
- Não existe campo de retenção de IBS/CBS no layout.

## Lendo a nota RTC

Os campos da Reforma não têm propriedade tipada na versão 0.1: leia pelo nome do JSON, como
`invoice["ibsCbs"]`, `invoice["nbsCode"]`, `invoice["federalServiceCode"]` e
`invoice["amountWithheld"]`. Valores com propriedade tipada (`invoice.amount_net`,
`invoice.services_amount`, `invoice.iss_tax_amount`) voltam como `Decimal`.

O CNPJ do tomador volta da API como número, sem os zeros à esquerda. Use a propriedade
`invoice.borrower.federal_tax_number`, que devolve `str` com 11 ou 14 dígitos.

## O que depende da empresa

O contrato da API está provado. O resto depende da parametrização da empresa na NFE.io, e **não**
do payload:

- **Para onde a nota vai.** A emissão pelo Ambiente Nacional depende do cadastro da inscrição
  municipal da empresa ("Emitir via Emissor Nacional de NFS-e"). Na empresa de teste, que não
  está no Emissor Nacional, a nota saiu no modelo municipal, com `CodigoNbs` mas **sem as tags de
  IBS/CBS** no XML.
- **Cálculo de IBS/CBS.** Nenhuma das notas de teste trouxe valores de IBS/CBS calculados. Isso é
  coerente com uma empresa do Simples Nacional em ambiente de testes: optantes pelo Simples
  Nacional e MEI, num primeiro momento, não testam as novas tags. Para validar o cálculo, use uma
  empresa do Lucro Presumido ou Real habilitada no Emissor Nacional, parametrizada pelo suporte.
- **`nbsCode`.** A API aceitou nota sem NBS no ambiente de testes, mas o Ambiente Nacional rejeita
  NBS ausente ou incoerente com o item da LC 116. Envie sempre.
- **ISS.** A alíquota vem do cadastro do código de serviço da empresa. Na empresa de teste (Simples
  Nacional, alíquota zero), `issTaxAmount` voltou `0`.

## Veja também

- [Reforma Tributária: visão geral](../../../documentacao/reforma-tributaria/index.md).
- [Referência da API de NFS-e RTC](/desenvolvedores/rest-api/reforma-tributaria/nota-fiscal-de-servico-rtc/api-de-emissao-de-nota-fiscal-de-servicos-eletronica-nfs-e-rtc).
- [Notas de serviço](./recursos/service-invoices.md): todos os métodos.
