Documentação / NFS-e v1
API REST fiscal

NFS-e em um padrão único de API, do envio aos arquivos fiscais.

Esta documentação descreve a versão pública atual da API fiscal da Contora, com base compartilhada de empresas, certificados, chaves, filas, webhooks e artefatos para NF-e, NFC-e, NFS-e, CT-e e MDF-e. NF-e, NFC-e e NFS-e operam em produção regular; CT-e e MDF-e em produção assistida e controlada.

Atualizado em .

Status atual

Status da API Disponível Os endpoints públicos estão disponíveis em homologação e produção para empresas com cadastro fiscal e certificado A1 válidos.
Estado da superfície pública O payload único e os fluxos assíncronos de emissão, consulta e cancelamento podem ser integrados. A disponibilidade efetiva depende das regras e dos serviços fiscais do município emissor.

Superfície pública

A API pública de NFS-e permite rascunho, emissão, consulta, cancelamento e artefatos em homologação e produção. Recomendamos validar primeiro em homologação porque layouts e regras variam conforme o município.

GET https://fiscal.contora.com.br/api/v1/nfse/drafts (Global/Flat - Recomendado)
GET https://fiscal.contora.com.br/api/v1/companies/{company}/nfse/drafts (Hierárquico)
POST https://fiscal.contora.com.br/api/v1/nfse/drafts (Global - Recomendado)
POST https://fiscal.contora.com.br/api/v1/companies/{company}/nfse/drafts (Hierárquico)
GET https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/status (Global - Recomendado)
GET https://fiscal.contora.com.br/api/v1/companies/{company}/nfse/drafts/{document}/status (Hierárquico)
POST https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/dispatch (Global - Recomendado)
POST https://fiscal.contora.com.br/api/v1/companies/{company}/nfse/drafts/{document}/dispatch (Hierárquico)
POST https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/refresh (Sincronizar situação fiscal)
POST https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/cancel (Cancelar documento autorizado)
GET https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/artifacts (Listar XML e PDF disponíveis)
GET https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/artifacts/{artifact} (Download: xml_nfse, pdf_nfse ou xml_rps)
Nas rotas globais, envie X-Company-Document: CNPJ_SEM_MASCARA quando o token administrar mais de uma empresa. Nas operações POST, envie também uma Idempotency-Key única para repetir chamadas com segurança.

Como a plataforma trata NFS-e

A plataforma apresenta a fragmentação municipal por meio de um contrato JSON único. O integrador envia tomador, serviço, valores e retenções em um formato estável. A identificação do prestador — CNPJ, inscrição municipal, regime, nome e endereço — vem do cadastro da empresa vinculada ao token, e não do payload da nota. O Fiscal Contora executa as validações, o processamento fiscal e a comunicação necessária com o ambiente autorizador aplicável.

Na prática: não envie um bloco de emitente/prestador em payload. Mantenha esses dados em /companies; sua integração usa o mesmo contrato da API e acompanha o resultado pelos estados do documento, independentemente das particularidades do município emissor.

Quem informa os dados fiscais

O Fiscal Contora é o emissor técnico: recebe os dados definidos pelo cliente, valida o contrato, monta e assina o documento e o transmite ao ambiente autorizador. A plataforma não escolhe por conta própria o enquadramento fiscal da operação nem inventa códigos ou alíquotas.

ResponsávelO que informa ou executa
Cliente e contabilidade Descrição e valor do serviço, código nacional e municipal, CNAE, alíquota e retenção do ISS, regime aplicável e percentuais aproximados dos tributos.
Fiscal Contora Valida formato e coerência, aplica os padrões cadastrados pelo próprio cliente, calcula valores matemáticos derivados, gera e assina o XML, transmite, consulta e entrega status e artefatos.
Prefeitura ou Sistema Nacional Confere os dados contra o cadastro fiscal e autoriza ou rejeita a NFS-e.
Configuração padrão também é responsabilidade do cliente. Campos como settings.nfse_municipal_tax_code_default apenas evitam repetir o mesmo valor em todas as notas; o código guardado continua sendo fornecido e validado pelo cliente ou pela contabilidade.

Exemplo completo de homologação — MEI

Este primeiro exemplo pressupõe uma empresa cadastrada como mei em um município que usa o padrão nacional. Por isso a alíquota de ISS é zero e não aparece o grupo de tributos do não optante.

O number é opcional. Se você omitir, o próximo número de RPS livre da série é alocado no despacho e devolvido na resposta — não é preciso controlar a numeração do seu lado nem tratar recusa por número repetido. Informe o campo apenas quando precisar amarrar o RPS a uma numeração própria; nesse caso, um número já usado em nota emitida continua sendo recusado.
{
  "environment": "homologacao",
  "payload": {
    "number": 501,
    "series": 1,
    "service": {
      "description": "Serviço de implantação de software",
      "service_code": "01.05.01",
      "national_tax_code": "010501",
      "cnae": "6203100",
      "iss_rate": 0,
      "iss_withheld": false
    },
    "taker": {
      "name": "Cliente de Servicos LTDA",
      "document": "12345678000199",
      "email": "[email protected]",
      "address": {
        "street": "Rua de Exemplo",
        "number": "100",
        "district": "Centro",
        "city_code": "3550308",
        "state_code": "SP",
        "postal_code": "01001000"
      }
    },
    "amounts": {
      "service_amount": 1500,
      "net_amount": 1500
    }
  }
}
Padrão nacional: use national_tax_code com os 6 dígitos do código de tributação nacional. municipal_tax_code, quando exigido pelo município, deve conter exatamente 3 dígitos. Prestadores não-MEI do Rio de Janeiro precisam informá-lo no payload ou em settings.nfse_municipal_tax_code_default. Não confunda esses campos com o CNAE.

Exemplo de não optante no padrão nacional

Para empresas de Lucro Presumido ou Lucro Real, o cliente precisa informar também os percentuais aproximados por esfera. No Rio de Janeiro, o municipal_tax_code de três dígitos é obrigatório para prestadores não-MEI. O exemplo abaixo mostra o formato que foi efetivamente autorizado em homologação; os códigos e percentuais são ilustrativos e precisam ser confirmados para cada operação.

{
  "environment": "homologacao",
  "payload": {
    "service": {
      "description": "Serviço de publicidade e criação",
      "service_code": "170601",
      "national_tax_code": "170601",
      "municipal_tax_code": "002",
      "cnae": "7311400",
      "iss_rate": 5,
      "iss_withheld": false,
      "approximate_tax_percentages": {
        "federal": 0,
        "state": 0,
        "municipal": 5
      }
    },
    "taker": {
      "name": "Cliente de Serviços LTDA",
      "document": "44295808000119",
      "email": "[email protected]"
    },
    "amounts": {
      "service_amount": 1500,
      "net_amount": 1500
    }
  }
}
Não copie os percentuais do exemplo para produção. Os valores federal: 0, state: 0 e municipal: 5 demonstram apenas o formato aceito em homologação. O cliente ou a contabilidade deve informar a carga tributária aproximada correta da operação. A API valida e transmite esses números, mas não os determina a partir do ISS.

Exemplo de município com layout próprio

Salvador BA — veja o guia sobre CTISS, a diferença entre os códigos nacional e municipal e a tabela oficial da prefeitura.

Onde o município mantém layout próprio, os códigos mudam de lugar: o national_tax_code não é usado, e entram o item da lista e o código de tributação do município. Municípios que já adotaram os campos da reforma tributária exigem também o nbs_code. O exemplo abaixo é de Salvador/BA.

Repare que tax_classification_code e operation_indicator não aparecem no payload: a plataforma deriva os dois da correlação oficial do Anexo VIII, a partir do item da lista somado ao NBS. Envie-os apenas quando quiser sobrepor a derivação — o valor informado sempre vence.

{
  "environment": "producao",
  "payload": {
    "service": {
      "description": "Serviço de manutenção e reparação de motores elétricos",
      "item_list_code": "1401",
      "municipal_tax_code": "1401001",
      "nbs_code": "120015000",
      "cnae": "3313901",
      "iss_rate": 5,
      "iss_withheld": false
    },
    "taker": {
      "name": "Cliente de Servicos LTDA",
      "document": "12345678000199",
      "address": {
        "street": "Rua de Exemplo",
        "number": "100",
        "district": "Centro",
        "city_code": "2927408",
        "state_code": "BA",
        "postal_code": "40000000"
      }
    },
    "amounts": {
      "service_amount": 1500,
      "net_amount": 1500
    }
  }
}
O código de tributação do município não é o item da lista. Em Salvador o municipal_tax_code é o CTISS, com 7 dígitos e sem máscara — 1401001, do código 1401-0/01. Enviar ali o item da lista (1401) faz a prefeitura recusar com E163. Os valores de NBS, cClassTrib e INDOP saem da correlação com o item da LC 116 publicada no Anexo VIII do Sistema Nacional.
Municípios Betha Cloud (ex: Ouro Branco/MG): a emissão opera no padrão de Declaração de Prestação de Serviços (DPS) em nuvem, com sincronização ao Ambiente Nacional da NFS-e. O envio do endereço completo do tomador (logradouro, número, bairro e CEP) e telefone com DDD é obrigatório pelas validações municipais da Betha (rejeições e13 e e16 caso ausentes). No serviço, declare o código nacional de 6 dígitos em national_tax_code (ex: 140101) e, se aplicável, a NBS de 9 dígitos em nbs_code.

Descontos, deduções e informações complementares

O bloco amounts aceita mais do que o valor do serviço. Quando a nota tem desconto, o caminho correto é declarar o valor bruto em service_amount e o desconto em campo próprio, e não enviar apenas o valor já líquido: só assim o desconto aparece discriminado no DANFSe e no XML. O texto que não é descrição do serviço — número de ordem de serviço, pedido do cliente, referência de contrato — tem lugar próprio em service.additional_info, em vez de disputar espaço com a discriminação.

CampoPadrão nacionalLayout municipal (ABRASF)Efeito
amounts.ir_amount valores/trib/tribFed/vRetIRRF ValorIr Retenção de IRRF estruturada. Reduz o valor líquido, não a base do ISS.
amounts.pis_amount valores/trib/tribFed/piscofins/vPis ValorPis PIS destacado na DPS nacional. Por padrão opera como débito próprio (não reduz o líquido, para exclusão de IBS/CBS).
amounts.cofins_amount valores/trib/tribFed/piscofins/vCofins ValorCofins COFINS destacada na DPS nacional. Por padrão opera como débito próprio (não reduz o líquido, para exclusão de IBS/CBS).
amounts.unconditional_discount valores/vDescCondIncond/vDescIncond DescontoIncondicionado Reduz a base de cálculo do ISS e o valor líquido.
amounts.conditional_discount valores/vDescCondIncond/vDescCond DescontoCondicionado Reduz o valor líquido, não a base do ISS.
amounts.deductions valores/vDedRed/vDR ValorDeducoes Reduz a base de cálculo do ISS e o valor líquido.
service.additional_info serv/infoCompl/xInfComp InformacoesComplementares Texto livre, até 2000 caracteres. Não altera valor nem imposto.
{
  "environment": "producao",
  "payload": {
    "service": {
      "description": "Manutenção elétrica embarcada",
      "national_tax_code": "140101",
      "cnae": "3317102",
      "iss_rate": 3,
      "iss_withheld": false,
      "additional_info": "OS 4821 - Pedido do cliente 99-B"
    },
    "taker": {
      "name": "Cliente de Servicos LTDA",
      "document": "12345678000199"
    },
    "amounts": {
      "service_amount": 538.33,
      "unconditional_discount": 169.78
    }
  }
}

Nesse exemplo a DPS sai com vServ = 538.33, vDescIncond = 169.78 e o Sistema Nacional devolve vLiq = 368.55. O net_amount pode ser omitido: sem ele, o líquido é calculado como service_amount menos descontos e deduções. Se você informar os dois, o valor enviado é respeitado — mas a resposta traz um aviso quando ele diverge do cálculo, porque o engano mais comum é subtrair o desconto do bruto e ainda assim declará-lo.

Os três valores são conferidos antes do envio. Valor negativo é recusado, e a soma de descontos e deduções não pode ultrapassar o service_amount — sem essa checagem a recusa chegaria como erro de schema do provedor, apontando uma tag que você nunca escreveu.
Duas restrições que não são nossas. Prestador do Simples Nacional na condição de ME/EPP não pode declarar dedução/redução quando o município assim parametriza o código de serviço: o Sistema Nacional recusa com E0441. E o layout próprio de Salvador não tem campo de informações complementares — ali service.additional_info é recusado na validação, em vez de aceito e descartado, e o texto deve permanecer na description.
Retenções federais suportadas. amounts.ir_amount, amounts.inss_amount e amounts.csll_amount vão direto para vRetIRRF/vRetCP/vRetCSLL na DPS nacional e ValorIr/ValorInss/ValorCsll no ABRASF, abatendo do líquido — as três são passthrough simples do valor já apurado pelo integrador, sem cálculo de apuração próprio da plataforma (limiar, atividade elegível, base de retenção). PIS e COFINS (amounts.pis_amount e amounts.cofins_amount, com pis_rate/cofins_rate, pis_cst e pis_cofins_withheld) são suportados como débito próprio da operação — preenchem o grupo tribFed/piscofins com tpRetPisCofins=2 e não abatem do líquido. A retenção de ISS continua por service.iss_withheld.
Município de incidência, isenção/exportação e mais dois campos do tomador. service.incidence_city_code (7 dígitos, código IBGE) sobrepõe o município onde o ISS é devido quando o serviço foi prestado fora da sede da empresa — omitido, usa o município da própria empresa, como sempre. service.iss_tax_situation ganhou três valores exclusivos do layout municipal (ABRASF): isencao, susp_judicial e susp_administrativa — as duas últimas exigem service.process_number (o número do processo). No padrão nacional continuam valendo só tributavel/exportacao/nao_incidencia/imunidade. E dois campos do tomador que já funcionavam sem estarem documentados: taker.municipal_registration e taker.phone.

Padrão nacional ou layout municipal

A NFS-e tem dois caminhos, e o que decide não é o regime tributário da empresa: é o município. Onde o município aderiu ao Sistema Nacional da NFS-e, o documento vale pelo padrão nacional, seja o prestador MEI, Simples, Lucro Presumido ou Real. Só onde o município mantém layout próprio o caminho é o do provedor municipal.

O padrão nacional é o comportamento assumido por padrão. Alguns municípios são reconhecidos pelo código IBGE e encaminhados ao provedor municipal sem qualquer configuração — hoje Salvador/BA (2927408) e Currais Novos/RN (2403103). Para outros municípios que ainda usam layout próprio, configure settings.nfse_standard = "municipal" no cadastro da empresa.

O reconhecimento por código IBGE tem precedência sobre o cadastro. Num município dessa lista, um settings.nfse_standard = "nacional" deixado no cadastro não força o padrão nacional — ele seria recusado com E0039 de qualquer forma. Se a sua empresa está num município que não aderiu aos emissores públicos nacionais e a emissão volta com E0039, fale com o suporte: o município precisa ser habilitado no layout do provedor, e isso não é algo que se resolva pelo payload.
Tomador não identificado. No padrão nacional o bloco taker é opcional: omiti-lo representa a operação a consumidor não identificado — no leiaute nacional o grupo toma é opcional e o tomador sem identificação não pode ser representado de outra forma (o XSD exige CNPJ, CPF, NIF ou cNaoNIF quando o grupo existe). Se o bloco for informado, name e document continuam obrigatórios, e document vazio é recusado. Nos municípios de layout próprio o tomador segue obrigatório.
CampoPadrão nacionalLayout municipal
service.national_tax_code Obrigatório, 6 dígitos da lista nacional de serviços Não usado
service.municipal_tax_code Exatamente 3 dígitos quando o município exigir; obrigatório no Rio para não-MEI Código de tributação do município, no formato exigido por ele
service.service_code Código municipal do serviço, informativo Obrigatório, no formato do município
service.approximate_tax_percentages Obrigatório para não optante do Simples; percentuais federal, estadual e municipal Não usado pela integração atual
service.nbs_code Não usado Obrigatório onde o município já pede os campos da reforma
service.tax_classification_code Não usado Derivado — envie só para sobrepor
service.operation_indicator Não usado Derivado — envie só para sobrepor
O código nacional não é o municipal sem os pontos. Ele vem da lista de serviços do Sistema Nacional e traz item, subitem e desdobramento — 14.01 no município corresponde a 140101 no nacional, não a 140100. Um código de 6 dígitos que não exista na lista volta como E0310.

Situação no Simples Nacional

No padrão nacional o documento declara a situação do prestador perante o Simples Nacional, e o Sistema Nacional confere esse valor contra o cadastro do Simples na competência. A plataforma deriva a situação do regime tributário da empresa — mei declara Optante MEI, simples declara Optante ME/EPP, e os demais declaram Não Optante.

Quando o regime cadastrado aqui não corresponde à situação real (o cadastro do Simples é que vale), informe settings.nfse_simples_nacional_option no cadastro da empresa com 1 (não optante), 2 (optante MEI) ou 3 (optante ME/EPP). Divergência resulta na rejeição E0160.

Prestador ME/EPP: o padrão nacional não aceita o indicador de valor total de tributos para o ME/EPP — recusa com E0712 — e exige no lugar o percentual total de tributos do Simples Nacional. Ele não é a alíquota de ISS: é a carga total da faixa do Simples na competência, que só a sua contabilidade sabe. Informe em service.total_tax_rate_sn no payload, ou em settings.nfse_total_tax_rate_sn no cadastro para valer como padrão.
Prestador não optante: informe em service.approximate_tax_percentages os percentuais aproximados federal, state e municipal, cada um entre 0 e 100 e com ao menos um valor positivo. Eles formam o grupo pTotTrib da Lei 12.741 e não podem ser derivados apenas da alíquota de ISS. A ausência é bloqueada antes do envio para evitar a rejeição E0713.

Inscrição municipal

No padrão nacional a inscrição municipal só entra no documento quando o município tem informações complementares registradas no CNC NFS-e. Quando a opção settings.nfse_municipal_registration_in_cnc estiver ativa, grave em settings.municipal_registration a IM exatamente como consta no CNC, inclusive zeros à esquerda. O Sistema Nacional cruza município emissor, CNPJ/CPF e IM; uma versão abreviada ou com formatação diferente pode voltar como E0116, mesmo que a tag da IM tenha sido enviada.

Onde o município não mantém a IM no CNC, o Sistema Nacional recusa o envio com E0120. Nesse caso configure settings.nfse_municipal_registration_in_cnc = false no cadastro da empresa e a inscrição deixa de ser enviada e de ser exigida. Para o MEI a inscrição nunca é enviada: o cadastro nacional responde pelos dados do prestador.

Prestador na emissão própria: quando a empresa emite a própria DPS (tpEmit=1), o nome e o endereço do prestador são obtidos pelo Sistema Nacional a partir do cadastro fiscal. A plataforma omite esses campos automaticamente para evitar E0121; eles não devem ser acrescentados ao payload da NFS-e.

GET /companies/{company_id}/nfse/health mostra qual caminho está ativo para a empresa e o que ainda falta antes da primeira emissão.

São Paulo (SP) — Nota Fiscal Paulistana

São Paulo é o caso em que o município e o regime decidem juntos. A prefeitura aceita o padrão nacional apenas para o MEI; ME/EPP e demais prestadores emitem pelo sistema próprio dela. Um emitente não-MEI que tente o padrão nacional em São Paulo recebe E0120 e, corrigido isso, E0312 — sem ajuste de payload que resolva.

Por isso São Paulo não é encaminhada automaticamente ao provedor municipal como Salvador: isso quebraria os MEI que hoje emitem pelo nacional. Configure no cadastro da empresa:

PATCH /api/v1/companies/{company_id}
{
  "settings": {
    "nfse_standard": "municipal",
    "municipal_registration": "01234567"
  }
}

A inscrição municipal é o CCM. O schema da prefeitura exige exatamente 8 dígitos e a ficha do contribuinte costuma mostrar o número sem o zero à esquerda; a plataforma completa sozinha (1234567 vira 01234567), então grave como estiver na ficha.

Código de serviço

São Paulo mantém tabela própria de códigos, com 5 dígitos — não é o item da LC 116 e não é o código nacional. Envie em service.service_code ou service.item_list_code; as duas formas valem.

{
  "environment": "producao",
  "payload": {
    "service": {
      "description": "Licenciamento de uso da plataforma",
      "service_code": "02800",
      "cnae": "6201501",
      "iss_rate": 2.9
    },
    "taker": {
      "name": "Cliente Exemplo",
      "document": "12345678909"
    },
    "amounts": { "service_amount": 100.00, "net_amount": 100.00 }
  }
}
Confira a vigência do código. A tabela paulistana foi renumerada: códigos como 02798 e 02917 encerraram em 12/02/2018 e voltam com 335 — Código não vigente. Há ainda códigos exclusivos de pessoa física, que respondem 331 para uma empresa. Os códigos atribuídos à sua inscrição estão na ficha do CCM; a tabela oficial é o Anexo 1 da IN SF/SUREM nº 8/2011. Para licenciamento de software (item 1.05, pessoa jurídica) o código vigente é 02800, com alíquota de 2,9%.

Não existe ambiente de homologação

A prefeitura publica apenas o endereço de produção. O que faz as vezes de ensaio é a operação de envio de teste dela, que roda todas as validações e não gera nota. A plataforma usa esse caminho automaticamente quando o documento é de homologação:

{
  "environment": "homologacao",
  "payload": { ... }
}

O documento termina em built_signed, sem número de NFS-e, e provider.message explica o desfecho. É o jeito de validar cadastro, certificado, CCM e código de serviço antes da primeira nota real. Note que a chave de API precisa ser de produção (com allows_homologation ligado na empresa): produção nunca é relaxada, e uma chave de homologação não opera numa empresa de produção.

Cancelamento

Cancelamento por API, com justificativa obrigatória:

POST /api/v1/companies/{company_id}/nfse/drafts/{id}/cancel
{
  "reason": "Servico nao prestado."
}

O resultado aparece no bloco cancellation do endpoint de status. Repetir a chamada é seguro: numa nota já cancelada a prefeitura devolve o código 1301 e a plataforma mantém o documento como cancelado.

O ISS sai zerado na nota do optante pelo Simples Nacional — é o comportamento correto, já que o imposto é recolhido no DAS. O DANFSE gerado traz essa observação impressa.

Fluxo de emissão

  1. Cadastrar a empresa prestadora no console.
  2. Configurar certificado e dados fiscais da empresa.
  3. Enviar um payload padrão de NFS-e com tomador, serviço e valores.
  4. Disparar a emissão por fila, sem travar o ERP integrador.
  5. Acompanhar autorizacao, rejeicao ou cancelamento por status e webhook.
  6. Baixar o XML autorizado e o DANFSe v2.0 gerado a partir desse XML.
Retry seguro: depois de dispatch, consulte o status. Se houver timeout ou resultado técnico desconhecido, use refresh antes de tentar uma nova emissão. A plataforma reconcilia a DPS pelo RPS para evitar duplicidade.

Respostas e estados

Criação POST /nfse/drafts retorna 201 Created com o identificador estável do documento.
Processamento dispatch e cancel retornam 202 Accepted. O resultado final é assíncrono.
Situação fiscal lifecycle.status informa draft, as etapas de construção/envio, authorized ou error. O cancelamento fica no bloco cancellation.
Situação técnica processing_status informa se a solicitação está pendente, em processamento, concluída ou falhou.
Uma falha técnica não significa rejeição fiscal. Consulte last_error_code, last_error_message e, quando necessário, execute refresh antes de criar outro documento.

Número do RPS e número da NFS-e

O campo legado number continua sendo o número do RPS. Use rps_number quando quiser essa referência de forma explícita e nfse_number para o número fiscal atribuído pelo município ou pelo Sistema Nacional depois da autorização. display_number devolve o número da NFS-e quando disponível e, antes disso, o RPS.

access_key traz a chave de acesso nacional de 50 dígitos assim que o Sistema Nacional autoriza, no status e no GET do documento — não é preciso baixar e abrir o xml_nfse para conciliar a nota ou montar o link da consulta pública. Provedor municipal que não emite chave nacional devolve null e continua identificando a nota por provider.verification_code.

{
  "ok": true,
  "data": {
    "id": "UUID_DO_DOCUMENTO",
    "series": 1,
    "number": 501,
    "rps_number": 501,
    "nfse_number": "1",
    "display_number": "1",
    "access_key": "42082032250057049000159000000000000126083779781389",
    "lifecycle": {
      "status": "authorized",
      "processing_status": "completed",
      "requested_action": "submit"
    },
    "last_error_code": null,
    "last_error_message": null,
    "provider": {
      "number": "1"
    }
  }
}

Cancelamento

O cancelamento é aceito somente para uma NFS-e autorizada e também é processado de forma assíncrona.

curl --request POST \
  --url https://fiscal.contora.com.br/api/v1/nfse/drafts/ID_DO_DOCUMENTO/cancel \
  --header 'Authorization: Bearer SEU_TOKEN' \
  --header 'Content-Type: application/json' \
  --header 'Idempotency-Key: cancelamento-nfse-501' \
  --data '{"reason":"Serviço cancelado antes da execução."}'

A justificativa é obrigatória e deve conter entre 15 e 255 caracteres. Depois do 202 Accepted, acompanhe o bloco cancellation no status ou aguarde o webhook.

Nem todo município cancela por webservice. Onde o provedor municipal não oferece o serviço — Salvador é o caso —, o pedido volta como rejeição de negócio, com o código FISCAL-NFSE-CANCEL-UNSUPPORTED, e não como falha técnica: repetir a chamada não adianta. A NFS-e continua autorizada, e o cancelamento é feito no portal da prefeitura, com o certificado digital da empresa. Depois que a prefeitura registrar, use POST /nfse/drafts/{document}/refresh para sincronizar a situação.

Substituição

A substituição não tem endpoint próprio, e isso não é uma limitação da API: no padrão nacional ela é declarada dentro da DPS da nota nova, no grupo subst. Você cria um rascunho normal acrescentando o bloco substitution ao payload e despacha como qualquer outra NFS-e.

curl --request POST \
  --url https://fiscal.contora.com.br/api/v1/nfse/drafts \
  --header 'Authorization: Bearer SEU_TOKEN' \
  --header 'Content-Type: application/json' \
  --data '{
    "environment": "producao",
    "payload": {
      "substitution": {
        "replaced_access_key": "35503082267882130000176000000000005026082005262745",
        "reason_code": "05",
        "reason": "Nota rejeitada pelo tomador; reemissao com a descricao correta do servico."
      },
      "service": {
        "description": "Servico de suporte tecnico em informatica",
        "service_code": "1.07",
        "national_tax_code": "010701",
        "cnae": "6203100",
        "iss_rate": 0
      },
      "taker": { "name": "Tomador de Exemplo LTDA", "document": "12345678000190" },
      "amounts": { "service_amount": 1.00, "net_amount": 1.00 }
    }
  }'

Os três campos do bloco correspondem direto ao grupo subst da DPS:

  • replaced_access_key → chSubstda: chave da NFS-e substituída, 50 dígitos. Obrigatório.
  • reason_code → cMotivo: código de justificativa da substituição. Obrigatório.
  • reason → xMotivo: descrição do motivo. Opcional; quando enviada, entre 15 e 255 caracteres.

Os códigos de justificativa da substituição são próprios:

  • 01 — desenquadramento de NFS-e do Simples Nacional
  • 02 — enquadramento de NFS-e no Simples Nacional
  • 03 — inclusão retroativa de imunidade/isenção
  • 04 — exclusão retroativa de imunidade/isenção
  • 05 — rejeição da NFS-e pelo tomador ou pelo intermediário responsável pelo recolhimento
  • 99 — outros
Substituir não é cancelar e emitir de novo. Quando a substituta é autorizada, o Ambiente Nacional grava sozinho, na nota antiga, o evento 105102 — “Cancelamento de NFS-e por Substituição” — carregando a chave da substituta em chSubstituta. Cancelando e emitindo outra esse vínculo não existe: ficam duas notas soltas. Além disso o cancelamento tem prazo próprio e só admite os motivos 1, 2 e 9, que não cobrem os casos da substituição. Por isso o valor 9 é recusado aqui: 9 é “Outros” do cancelamento e 99 é “Outros” da substituição, e converter um no outro trocaria em silêncio o motivo declarado na sua nota. O inteiro sem o zero à esquerda é aceito — 5 vira 05.

Você não precisa cancelar a nota antiga: assim que a substituta é autorizada, a NFS-e substituída passa a responder com cancellation_status = "cancelled" e cancellation_status_code = "105102". A substituição existe apenas no padrão nacional; empresa em município de layout próprio recebe recusa antes do envio.

Para um passo a passo detalhado com exemplos de payload, diagrama de estados e integração com ERP, veja o Guia Completo de Substituição de NFS-e no Padrão Nacional (Grupo Subst).

XML e DANFSe (Pós-autorização)

Assim que o documento atinge o status authorized, todos os artefatos fiscais ficam imediatamente disponíveis para consulta e download pelo seu ERP.

Consulte GET https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/artifacts para listar os artefatos gerados:

{
  "ok": true,
  "data": [
    {
      "type": "xml_nfse",
      "label": "XML da NFS-e",
      "available": true,
      "filename": "nfse-1.xml",
      "download_url": "https://fiscal.contora.com.br/api/v1/nfse/drafts/ID_DO_DOCUMENTO/artifacts/xml_nfse"
    },
    {
      "type": "pdf_nfse",
      "label": "PDF da NFS-e",
      "available": true,
      "filename": "nfse-1.pdf",
      "download_url": "https://fiscal.contora.com.br/api/v1/nfse/drafts/ID_DO_DOCUMENTO/artifacts/pdf_nfse"
    },
    {
      "type": "xml_rps",
      "label": "XML do RPS",
      "available": true,
      "filename": "nfse-1.rps.xml",
      "download_url": "https://fiscal.contora.com.br/api/v1/nfse/drafts/ID_DO_DOCUMENTO/artifacts/xml_rps"
    }
  ]
}

Download direto dos arquivos

Para baixar diretamente no seu backend ou repassar ao cliente final:

  • XML da NFS-e: GET https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/artifacts/xml_nfse (Content-Type: application/xml)
  • DANFSe (PDF): GET https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/artifacts/pdf_nfse (Content-Type: application/pdf)
  • XML do RPS: GET https://fiscal.contora.com.br/api/v1/nfse/drafts/{document}/artifacts/xml_rps (Content-Type: application/xml)
# Baixar o XML autorizado
curl --request GET \
  --url https://fiscal.contora.com.br/api/v1/nfse/drafts/ID_DO_DOCUMENTO/artifacts/xml_nfse \
  --header 'Authorization: Bearer SEU_TOKEN' \
  --output nfse.xml

# Baixar o DANFSe (PDF)
curl --request GET \
  --url https://fiscal.contora.com.br/api/v1/nfse/drafts/ID_DO_DOCUMENTO/artifacts/pdf_nfse \
  --header 'Authorization: Bearer SEU_TOKEN' \
  --output danfse.pdf
Chave de Acesso e Consulta Pública: No Padrão Nacional, o identificador de consulta pública é a access_key de 50 dígitos, retornada diretamente no GET /status. A autenticidade pode ser consultada no Portal Nacional da NFS-e em https://www.nfse.gov.br/consultapublica.

Referência dos códigos de serviço

service_code Código municipal do serviço, na forma usada pelo cadastro da empresa — pode ser pontuado, como 01.05.01. No padrão nacional ele não substitui o national_tax_code.
national_tax_code Código nacional com 6 dígitos, sem pontuação. Exemplo: 010501.
municipal_tax_code Código complementar municipal. No padrão nacional, omita quando não existir; se exigido, deve ter 3 dígitos. No Rio ele é obrigatório para não-MEI e pode ficar no cadastro como nfse_municipal_tax_code_default. Não o deduza pelo código nacional, pois há mais de um desdobramento possível. No layout municipal ele é o código de tributação da prefeitura, e o tamanho é o que o município define — em Salvador, o CTISS de 7 dígitos, como 1401001.
approximate_tax_percentages Objeto com federal, state e municipal, de 0 a 100. Obrigatório no padrão nacional para prestador não optante do Simples, com ao menos um valor positivo. É a carga tributária aproximada da Lei 12.741, não somente a alíquota de ISS.
nbs_code Código NBS com 9 dígitos, sem pontuação — 120015000, de 1.2001.50.00. Obrigatório nos municípios de layout próprio que já adotaram os campos da reforma. É o único dos três que você precisa informar: ele distingue o tipo de serviço dentro do mesmo item da lista, e por isso não pode ser derivado. Pode ficar no cadastro da empresa como NBS padrão.
tax_classification_code e operation_indicator cClassTrib e INDOP, ambos com 6 dígitos. A plataforma deriva os dois do item da lista somado ao NBS, pela correlação do Anexo VIII — normalmente você não precisa enviá-los. Se a correlação admitir mais de um valor e o campo faltar, a emissão é recusada antes do envio, com as opções válidas na mensagem.
cnae e iss_rate CNAE deve ter 7 dígitos. A alíquota é percentual; para MEI, 0 é aceito quando esse for o enquadramento aplicável.

Preparação para produção

Para quem vai integrar NFS-e conosco, a melhor preparacao agora e organizar os cadastros de prestadores, serviços, tomadores, códigos municipais e cenários de retenção. Antes da primeira emissão em produção, valide o mesmo cenário em homologação e confirme as regras específicas do município emissor.