We use cookies to improve your experience and analyze site traffic. By clicking “Accept”, you agree to our use of cookies.

Learn more about our privacy practices
Corvo
English

Notas fiscais

Emita, consulte e acompanhe o ciclo de vida das NFS-e.

Permissões: nfse.invoices.issue para emitir/solicitar email; nfse.invoices.view para consultas, documentos e URL assinada.

POST/v1/invoices202 Accepted
full_accessinvoices_issueinvoices_read_write

Solicita a emissão de uma NFS-e. A emissão é assíncrona: o sucesso HTTP significa que a solicitação foi registrada/enfileirada, não autorização fiscal. Os exemplos usam o CNPJ (companyTaxId) da empresa cadastrada com municipalityCode e defaultServiceCode. O município do emitente sempre vem da empresa.

CampoTipoObrigatórioDescrição
companyIdstring UUIDCondicional: informe este campo ou companyTaxId; se ambos existirem, companyId prevalece.
companyTaxIdstringCNPJ da empresa já cadastrada na conta/ambiente; pontuação opcional.
externalIdstringReferência do sistema integrador; não substitui a chave de idempotência.
customerobjetoOpcional: omita ou envie {} para uma nota sem tomador (o tomador não vai na DPS). Quando enviado com qualquer dado, taxId é obrigatório (CPF ou CNPJ válido, normalizado); name é opcional, email (opcional; obrigatório quando o envio de email está habilitado; sem validação de formato neste DTO) e address (opcional: street, city, state, zip, country; se preencher cidade ou UF, preencha ambas).
serviceobjeto✓code é opcional: sem ele vale o defaultServiceCode da empresa e, se ela não tiver, 100901 (LC 116 item 10.09, representação de qualquer natureza); quando informado, exatamente 6 dígitos. municipalityCode herda o município da empresa; quando informado, exatamente 7 dígitos e define o local da prestação. description é opcional: se vazia, usa-se o nome do código de serviço. Vazio, null ou valor inválido dos demais campos não aciona o padrão.
amountnumber✓Valor em reais, positivo, até 9999999999.99 e no máximo 2 casas decimais.
competenceDatestring ISO 8601✓Data de competência válida. Sem options.type, não pode ser futura (422 ERROR_FUTURE_DATE). Com options.type: "SCHEDULE", aceita data futura (veja Notas agendadas).
discountnumberDesconto incondicional em reais, de 0 até o valor da nota, no máximo 2 casas decimais.
deductionnumberDedução da base do ISS declarada pelo emitente, em reais: maior que 0 e menor que amount menos discount, no máximo 2 casas decimais (0 equivale a omitir). Vai na DPS em vDedRed/vDR e reduz a base de cálculo do ISS. A nota continua sendo emitida pelo valor total. O emitente responde pelo valor declarado; a Corvo não confere se a dedução é permitida. O IBS/CBS segue calculado sobre o valor sem a dedução. Veja Dedução da base do ISS.
emailbooleanSolicita notificação; padrão false.
options.email.sendbooleanQuando definido, prevalece sobre email.
options.typestringIMMEDIATE (padrão) ou SCHEDULE. SCHEDULE agenda a emissão para a competenceDate futura; veja Notas agendadas.
curl -X POST "$BASE_URL/invoices" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: pedido_123_emissao' \
  -d '{
    "companyTaxId": "11222333000181",
    "externalId": "pedido_123",
    "customer": {
      "name": "Cliente Exemplo",
      "taxId": "52998224725",
      "email": "cliente@example.com",
      "address": { "city": "São Paulo", "state": "SP" }
    },
    "service": {
      "description": "Prestação de serviço"
    },
    "amount": 150.50,
    "competenceDate": "2026-10-01",
    "options": { "email": { "send": true } }
  }'

Resposta — 202 Accepted

{
  "data": {
    "id": "c7d2e9a1-4b5f-4a6c-8d9e-0f1a2b3c4d5e",
    "companyId": "3f1c8a90-6b2e-4d5a-9c11-8e2f0a7b4d11",
    "environment": "test",
    "externalId": "pedido_123",
    "status": "queued",
    "amount": 150.5,
    "competenceDate": "2026-10-01T00:00:00.000Z",
    "createdAt": "2026-10-10T12:00:00.000Z"
  }
}
POST/v1/invoices/batches202 Accepted
full_accessinvoices_issueinvoices_read_write

Solicita a emissão de **1 a 50 notas em uma única chamada**, de uma empresa ou de várias. Cada item tem os mesmos campos de POST /v1/invoices mais um idempotencyKey opcional. Os itens são conferidos um a um: os válidos são salvos juntos em uma única transação e os inválidos voltam como rejected com o motivo e **não** são salvos. A emissão continua assíncrona, como em POST /v1/invoices.

CampoTipoObrigatórioDescrição
invoicesarray✓Lista de 1 a 50 itens. Cada item recebe os campos de POST /v1/invoices (companyId ou companyTaxId, service, amount, competenceDate, customer, discount, deduction, options opcionais...). Os itens podem ser de empresas diferentes da conta. Menos de 1 ou mais de 50 itens devolve 400 ERROR_VALIDATION para a requisição inteira.
invoices[].idempotencyKeystringChave de idempotência do item (até 255 caracteres). Com a mesma chave e o mesmo conteúdo, repetir o lote devolve a nota já salva com replayed: true em vez de emitir de novo. O header Idempotency-Key não é usado nesta rota.
curl -X POST "$BASE_URL/invoices/batches" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{
    "invoices": [
      {
        "companyTaxId": "11222333000181",
        "idempotencyKey": "planilha-out-linha-2",
        "customer": { "name": "Cliente A", "taxId": "52998224725" },
        "service": { "description": "Consultoria" },
        "amount": 150.50,
        "competenceDate": "2026-10-01"
      },
      {
        "companyTaxId": "45723174000110",
        "idempotencyKey": "planilha-out-linha-3",
        "service": { "description": "Manutenção mensal" },
        "amount": 300,
        "competenceDate": "2026-10-01"
      }
    ]
  }'

Resposta — 202 Accepted

{
  "data": {
    "total": 3,
    "accepted": 2,
    "rejected": 1,
    "results": [
      {
        "index": 0,
        "status": "accepted",
        "invoice": {
          "id": "6c4d2e81-0a3b-4c5d-9e7f-1a2b3c4d5e6f",
          "companyId": "3f1c8a90-6b2e-4d5a-9c11-8e2f0a7b4d11",
          "environment": "test",
          "idempotencyKey": "planilha-out-linha-2",
          "status": "queued",
          "amount": 150.5,
          "currency": "BRL",
          "competenceDate": "2026-10-01T00:00:00.000Z",
          "stage": "pending",
          "createdAt": "2026-10-10T12:00:00.000Z"
        }
      },
      {
        "index": 1,
        "status": "accepted",
        "replayed": true,
        "invoice": {
          "id": "0b7a1f52-3c4d-4e6f-8a9b-2c3d4e5f6a7b",
          "status": "queued",
          "idempotencyKey": "planilha-out-linha-3",
          "amount": 300
        }
      },
      {
        "index": 2,
        "status": "rejected",
        "error": {
          "code": "ERROR_VALIDATION",
          "message": "Request validation failed",
          "details": [
            { "field": "amount", "code": "ERROR_OUT_OF_RANGE", "message": "amount must be greater than 0" }
          ]
        }
      }
    ]
  }
}
POST/v1/invoices/calculate200 OK
full_accessinvoices_issueinvoices_read_write

Calcula os tributos de uma nota **sem emitir**: não grava nota, não consome crédito, não reserva número de DPS, não agenda nem chama a Sefin. Use para conferir a configuração fiscal e mostrar o valor ao cliente antes de POST /v1/invoices.

CampoTipoObrigatórioDescrição
(corpo)objeto✓Mesmo corpo de POST /v1/invoices (empresa, service, amount, competenceDate, customer opcional, discount, deduction). Exige a permissão nfse.invoices.issue. Não exige certificado nem empresa pronta.
curl -X POST "$BASE_URL/invoices/calculate" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "companyTaxId": "11222333000181",
    "service": { "code": "060101", "description": "Corte de cabelo" },
    "amount": 50,
    "competenceDate": "2026-10-13"
  }'

Resposta — 200 OK

{
  "data": {
    "preEmission": true,
    "status": "ready",
    "disclaimer": "Pre-emission calculation. Values are not a fiscal document and may differ from the final validation by Sefin.",
    "competenceDate": "2026-10-13",
    "taxRegime": "MEI",
    "classification": {
      "serviceCode": "060101",
      "source": "official_catalog",
      "operationNature": "SERVICE",
      "nbsCode": null,
      "cst": null,
      "classCode": null,
      "serviceProfileId": null,
      "catalogValidated": false
    },
    "applicability": {
      "customerRequired": false,
      "strategy": "mei",
      "iss": {
        "status": "NOT_APPLICABLE",
        "reason": "ISS recolhido no DAS-MEI"
      },
      "federalWithholding": {
        "status": "NOT_APPLICABLE",
        "reason": "no federal withholding on payments to Simples Nacional/MEI optants (IN RFB 1.234/2012, art. 4, XI)"
      },
      "cbs": {
        "status": "NOT_APPLICABLE",
        "reason": "MEI não destaca IBS/CBS na fase de teste de 2026"
      },
      "ibs": {
        "status": "NOT_APPLICABLE",
        "reason": "MEI não destaca IBS/CBS na fase de teste de 2026"
      }
    },
    "taxes": {},
    "withholdings": [],
    "netReceivableAmount": "50.00",
    "collectionWaived": false,
    "calculation": {
      "source": "none",
      "calculatorVersion": null,
      "rulesVersion": "2026.10-r1",
      "legalReferences": [
        "Ato Conjunto RFB/CGIBS nº 4/2026; orientação CGNFS-e de 07/08/2026"
      ]
    },
    "warnings": [
      {
        "code": "CLASSIFICATION_NOT_CATALOG_VALIDATED",
        "message": "Service tax classification was not validated against the official catalog",
        "step": "ServiceTaxClassifier"
      }
    ],
    "pendingFields": [],
    "blocking": null,
    "trace": [
      {
        "step": "CompanyFiscalProfile",
        "status": "applied",
        "durationMs": 2.4
      },
      {
        "step": "ServiceTaxClassifier",
        "status": "applied",
        "durationMs": 7.1
      },
      {
        "step": "TaxApplicabilityResolver",
        "status": "applied",
        "durationMs": 0.3
      },
      {
        "step": "RtcTaxCalculator",
        "status": "skipped",
        "durationMs": 0.03,
        "reason": "MEI não destaca IBS/CBS na fase de teste de 2026"
      },
      {
        "step": "FiscalValidator",
        "status": "applied",
        "durationMs": 0.1
      }
    ]
  }
}

Notas agendadas

Use options.type: "SCHEDULE" com uma competenceDate futura para pedir que a nota seja emitida só naquele dia. A Corvo libera a emissão à 00:00 de America/Sao_Paulo da competenceDate. Até lá a nota fica com status: "queued" e scheduledFor traz o instante da liberação (ISO); em notas imediatas scheduledFor é null.

SituaçãoResultado
Sem options.type (ou IMMEDIATE) e competenceDate futura422 com ERROR_FUTURE_DATE em details[].code.
SCHEDULE e competenceDate futura até o limite202, status: queued, scheduledFor preenchido; a emissão acontece na data.
SCHEDULE e competenceDate além do limite (padrão 15 dias à frente)422 com ERROR_SCHEDULE_HORIZON_EXCEEDED em details[].code.
SCHEDULE e competenceDate de hoje ou passadaEmissão imediata, scheduledFor: null.

Agendar uma nota

curl -X POST "$BASE_URL/invoices" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido_123_agendada" \
  -d '{
    "companyTaxId": "11222333000181",
    "service": { "description": "Corte de cabelo" },
    "amount": 50,
    "competenceDate": "2026-10-20",
    "options": { "type": "SCHEDULE" }
  }'

Dedução da base do ISS

O emitente pode declarar em deduction um valor que a legislação do município permite abater da base de cálculo do ISS. O valor vai na DPS em vDedRed/vDR e reduz a base do ISS; a nota continua sendo emitida pelo valor total (amount).

Campo / tributoComo é tratado
amountValor total da nota.
deductionValor a abater da base do ISS. Maior que 0 e menor que amount menos discount; 0 equivale a omitir.
ISSBase = amount − discount − deduction.
Retenções federaisBase inalterada: amount − discount.
IBS/CBSCalculado sobre o valor sem a dedução.
Líquido a receberNão muda com a dedução.
Erros de validação422 com out_of_range (negativa, ou não menor que amount menos discount) ou invalid_decimal_places em details[].code, no field: "deduction".
RespostaA nota devolve deduction quando uma dedução foi declarada.

Nota com dedução

curl -X POST "$BASE_URL/invoices" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: pedido_123" \
  -d '{
    "companyTaxId": "11222333000181",
    "service": { "description": "Serviço de manutenção" },
    "amount": 100,
    "deduction": 40,
    "competenceDate": "2026-10-20"
  }'

Schema Invoice

Cada nota tem estes campos:

CamposTipo / observação
id, companyIdStrings de identificação.
environmenttest ou live.
externalId, idempotencyKeyString ou null.
statusEnum descrito abaixo.
customerSnapshottaxId, name, email?, address?: { city, state, country? }.
serviceSnapshotdescription, code, municipalityCode.
taxSnapshotObjeto de informações fiscais.
amount, currency, competenceDateNumber em reais, moeda e data-hora ISO 8601 (a data de competência à meia-noite UTC, ex.: 2026-10-01T00:00:00.000Z).
discount, deductionNumbers opcionais em reais: desconto incondicional e dedução da base do ISS declarada pelo emitente (veja Dedução da base do ISS).
dpsId, dpsSeries, dpsNumberString/string/number ou null.
accessKey, nfseNumberString/number ou null.
fiscalProvider, fiscalSchemaVersionStrings.
issuedAt, authorizedAtData ISO ou null.
emailSnapshotObjeto opcional com send.
lastErrorCode, lastErrorMessage, lastErrorProviderString ou null.
documentsReadyAtData ISO ou null.
lastEmailStatus, lastEmailSentAtqueued, sent, failed ou null; data ISO ou null.
documentsStatusEstado derivado: pending ou ready.
emailStatusEstado derivado: queued, sent, failed ou null.
stageEstado derivado: pending, authorized, documents_ready, completed, failed.
scheduledForData ISO da liberação de uma nota agendada, ou null.
cancellationReason, cancellationDescriptionMotivo (issue_error, service_not_provided ou other) e justificativa do pedido de cancelamento, ou null.
cancelledAtData ISO em que a nota chegou a cancelled, ou null.
cancellationRequestedAtData ISO do pedido de cancelamento feito enquanto a nota estava processing, ou null. A nota é cancelada na Sefin assim que for autorizada.
createdAt, updatedAtDatas ISO.
documentKeyVersionNumber opcional, quando presente no snapshot.

requestHash é removido da serialização. O retorno atual usa documentsReadyAt/documentsStatus, e não o boolean documentsReady indicado por um DTO de Swagger. Não há objeto lastEmail no JSON atual; use os campos acima. stage: completed também pode ocorrer com email em failed; verifique emailStatus para saber se houve envio bem-sucedido.

Status fiscais: queued, processing, authorized, rejected, retry_pending, reconciliation_required, manual_review, failed, cancelling, cancelled. Não interprete autorização como disponibilidade imediata de todos os documentos.

GET/v1/invoices200 OK
full_accessinvoices_viewinvoices_read_write

Lista notas com filtros e paginação por cursor.

Query

CampoTipoObrigatórioDescrição
companyIdstring UUIDUUID da empresa.
statusstringUm dos status fiscais: queued, processing, authorized, rejected, retry_pending, reconciliation_required, manual_review, failed, cancelling, cancelled.
from, tostring ISODatas ISO; filtro inclusivo pela competência, não por createdAt.
externalIdstringCorrespondência exata.
limitintegerInteiro entre 1 e 1000; padrão 50.
cursorstringnextCursor da página anterior, mantendo os mesmos filtros.
curl "$BASE_URL/invoices?status=authorized&limit=50" \
  -H "X-API-Key: $CORVO_API_KEY"

Resposta — 200 OK

{
  "data": [
    {
      "id": "c7d2e9a1-4b5f-4a6c-8d9e-0f1a2b3c4d5e",
      "status": "authorized",
      "amount": 150.5,
      "createdAt": "2026-10-10T12:00:00.000Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "hasMore": true,
    "nextCursor": "eyJ2IjoxLCJjcmVhdGVkQXQiOiIyMDI2LTEwLTA5VDEyOjAwOjAwLjAwMDAwMFoiLCJpZCI6IjNmMWM4YTkwIn0"
  }
}
GET/v1/invoices/:id200 OK
full_accessinvoices_viewinvoices_read_write

Consulta uma nota pelo id.

curl "$BASE_URL/invoices/$INVOICE_ID" \
  -H "X-API-Key: $CORVO_API_KEY"

Resposta — 200 OK

{
  "data": {
    "id": "c7d2e9a1-4b5f-4a6c-8d9e-0f1a2b3c4d5e",
    "status": "authorized",
    "accessKey": "352610123456789",
    "nfseNumber": 123,
    "documentsStatus": "ready"
  }
}
GET/v1/invoices/:id/xml200 OK
full_accessinvoices_viewinvoices_read_write

Baixa o XML da nota autorizada.

curl "$BASE_URL/invoices/$INVOICE_ID/xml" \
  -H "X-API-Key: $CORVO_API_KEY" --fail --output nfse.xml
GET/v1/invoices/:id/pdf200 OK
full_accessinvoices_viewinvoices_read_write

Baixa o PDF da nota autorizada.

curl "$BASE_URL/invoices/$INVOICE_ID/pdf" \
  -H "X-API-Key: $CORVO_API_KEY" --fail --output nota.pdf
GET/v1/invoices/:id/events200 OK
full_accessinvoices_viewinvoices_read_write

Consulta o histórico de transições de status da nota, do mais antigo ao mais recente. Paginado como qualquer lista (limit, cursor).

curl "$BASE_URL/invoices/$INVOICE_ID/events" \
  -H "X-API-Key: $CORVO_API_KEY"

Resposta — 200 OK

{
  "data": [
    {
      "id": "e1f2a3b4-0c5d-4e6f-8a9b-1c2d3e4f5a6b",
      "invoiceId": "c7d2e9a1-4b5f-4a6c-8d9e-0f1a2b3c4d5e",
      "fromStatus": "queued",
      "toStatus": "authorized",
      "reason": null,
      "createdAt": "2026-10-10T12:01:00.000Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "hasMore": false,
    "nextCursor": null
  }
}
POST/v1/invoices/:id/download-url200 OK
full_accessinvoices_viewinvoices_read_write

Gera uma URL assinada e temporária para baixar o documento.

CampoTipoObrigatórioDescrição
formatstring✓"pdf" ou "xml".
curl -X POST "$BASE_URL/invoices/$INVOICE_ID/download-url" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "format": "pdf" }'

Resposta — 200 OK

{
  "data": {
    "downloadUrl": "https://storage.example.com/documento-assinado",
    "expiresAt": "2026-10-10T15:00:00.000Z",
    "fileName": "nfse-123.pdf",
    "mimeType": "application/pdf"
  }
}
POST/v1/invoices/:id/email202 Accepted
full_accessinvoices_issueinvoices_read_write

Solicita o envio de email com os documentos para o endereço armazenado em customerSnapshot.email.

curl -X POST "$BASE_URL/invoices/$INVOICE_ID/email" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H 'Idempotency-Key: pedido_123_email'

Resposta — 202 Accepted

{
  "data": {
    "emailId": "pedido_123_email",
    "status": "queued"
  }
}
POST/v1/invoices/:id/cancel200 OK / 202 Accepted
full_accessinvoices_issueinvoices_read_write

Cancela uma nota. Uma nota queued (agendada ou ainda não processada) é cancelada na hora; uma NFS-e authorized passa a cancelling enquanto o evento 101101 é enviado à Sefin. Uma nota processing (em emissão) registra o pedido: 202, ainda processing, com cancellationRequestedAt preenchido.

curl -X POST "$BASE_URL/invoices/$INVOICE_ID/cancel" \
  -H "X-API-Key: $CORVO_API_KEY" \
  -H 'Content-Type: application/json' \
  -d '{"reason":"issue_error","description":"Valor do serviço informado incorretamente"}'

Resposta — 202 Accepted

{
  "data": {
    "id": "6f1c0e2a-4b7d-4c1e-9a55-2b8f7c3d9e10",
    "status": "cancelling",
    "stage": "completed",
    "cancellationReason": "issue_error",
    "cancellationDescription": "Valor do serviço informado incorretamente",
    "cancelledAt": null,
    "cancellationRequestedAt": null
  }
}