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
Português

Invoices

Issue NFS-e, fetch status, download documents and request email delivery.

Permissions: nfse.invoices.issue to issue/request email; nfse.invoices.view for fetches, documents and signed URLs.

POST/v1/invoices202 Accepted
full_accessinvoices_issueinvoices_read_write

Requests NFS-e issuance. Issuance is asynchronous: HTTP success means the request was registered/queued — it does not mean fiscal authorization. These examples use the CNPJ (companyTaxId) of a company registered with municipalityCode and defaultServiceCode. The issuer municipality always comes from the company.

FieldTypeRequiredDescription
companyIdstring UUIDSend this field or companyTaxId; if both exist, companyId takes precedence.
companyTaxIdstringCNPJ of a company already registered in the account/environment; punctuation optional.
externalIdstringReference from the integrating system; does not replace the idempotency key.
customerobjectOptional: omit it or send {} for an invoice without tomador (the customer is left out of the DPS). When sent with any data, taxId is required (valid CPF or CNPJ, normalized); name is optional, email (optional; required when email sending is enabled; no email format validation in this DTO/domain) and address (optional: street, city, state, zip, country are optional strings; if you fill in city or state, fill in both; state must be valid).
serviceobject✓code is optional: without it the company defaultServiceCode is used and, if the company has none, 100901 (LC 116 item 10.09, representation of any nature); exactly 6 digits when provided. municipalityCode inherits the company municipality; when provided, exactly 7 digits and sets the service location. description is optional: when empty, the name of the service code is used. Empty, null or invalid values of the other fields do not use the defaults.
amountnumber✓Value in reais, positive, up to 9999999999.99 with at most 2 decimals.
competenceDatestring ISO 8601✓Valid competence date. Without options.type it cannot be in the future (422 ERROR_FUTURE_DATE). With options.type: "SCHEDULE" a future date is accepted (see Scheduled invoices).
discountnumberUnconditional discount in BRL, from 0 up to the invoice amount, at most 2 decimal places.
deductionnumberDeduction from the ISS base declared by the issuer, in BRL: greater than 0 and less than amount minus discount, at most 2 decimal places (0 is the same as omitting it). Sent in the DPS as vDedRed/vDR, it reduces the ISS tax base. The invoice is still issued for the full amount. The issuer is responsible for the declared value; Corvo does not check whether the deduction is allowed. IBS/CBS is still calculated on the amount without the deduction. See ISS base deduction.
emailbooleanRequests a notification; defaults to false.
options.email.sendbooleanWhen set, takes precedence over email.
options.typestringIMMEDIATE (default) or SCHEDULE. SCHEDULE schedules issuance for a future competenceDate; see Scheduled invoices.
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 } }
  }'

Response — 202 Accepted

{
  "data": {
    "id": "6c4d2e81-0a3b-4c5d-9e7f-1a2b3c4d5e6f",
    "companyId": "3f1c8a90-6b2e-4d5a-9c11-8e2f0a7b4d11",
    "environment": "test",
    "externalId": "pedido_123",
    "idempotencyKey": "pedido_123_emissao",
    "status": "queued",
    "amount": 150.5,
    "currency": "BRL",
    "competenceDate": "2026-10-01T00:00:00.000Z",
    "stage": "pending",
    "createdAt": "2026-10-10T12:00:00.000Z"
  }
}
POST/v1/invoices/batches202 Accepted
full_accessinvoices_issueinvoices_read_write

Requests the issuance of **1 to 50 invoices in a single call**, for one company or for several. Each item has the same fields as POST /v1/invoices plus an optional idempotencyKey. Items are checked one by one: valid items are saved together in a single transaction, invalid items come back as rejected with the reason and are **not** saved. Issuance stays asynchronous, as in POST /v1/invoices.

FieldTypeRequiredDescription
invoicesarray✓List of 1 to 50 items. Each item takes the fields of POST /v1/invoices (companyId or companyTaxId, service, amount, competenceDate, optional customer, discount, deduction, options...). Items can belong to different companies of the account. Fewer than 1 or more than 50 items returns 400 ERROR_VALIDATION for the whole request.
invoices[].idempotencyKeystringIdempotency key of the item (up to 255 characters). With the same key and the same content, repeating the batch returns the invoice already saved with replayed: true instead of issuing again. The Idempotency-Key header is not used by this route.
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"
      }
    ]
  }'

Response — 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

Calculates the taxes of an invoice **without issuing it**: it stores no invoice, uses no credit, reserves no DPS number, schedules nothing and does not call Sefin. Use it to check the fiscal setup and show the amount to the customer before POST /v1/invoices.

FieldTypeRequiredDescription
(corpo)objeto✓Same body as POST /v1/invoices (company, service, amount, competenceDate, optional customer, discount, deduction). Requires the nfse.invoices.issue permission. It does not require a certificate or a ready company.
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": "Haircut" },
    "amount": 50,
    "competenceDate": "2026-10-13"
  }'

Response — 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
      }
    ]
  }
}

Scheduled invoices

Use options.type: "SCHEDULE" with a future competenceDate to have the invoice issued only on that day. Corvo releases issuance at 00:00 America/Sao_Paulo on the competenceDate. Until then the invoice stays status: "queued" and scheduledFor holds the release instant (ISO); for immediate invoices scheduledFor is null.

SituationResult
No options.type (or IMMEDIATE) and a future competenceDate422 with ERROR_FUTURE_DATE in details[].code.
SCHEDULE and a future competenceDate within the limit202, status: queued, scheduledFor set; issuance happens on that date.
SCHEDULE and a competenceDate beyond the limit (default 15 days ahead)422 with ERROR_SCHEDULE_HORIZON_EXCEEDED in details[].code.
SCHEDULE and a competenceDate of today or in the pastImmediate issuance, scheduledFor: null.

Schedule an invoice

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

ISS base deduction

The issuer can declare in deduction an amount that the municipality's legislation allows to be deducted from the ISS tax base. The value is sent in the DPS as vDedRed/vDR and reduces the ISS base; the invoice is still issued for the full amount (amount).

Field / taxHow it is handled
amountTotal amount of the invoice.
deductionAmount to deduct from the ISS base. Greater than 0 and less than amount minus discount; 0 is the same as omitting it.
ISSBase = amount − discount − deduction.
Federal withholdingsBase unchanged: amount − discount.
IBS/CBSCalculated on the amount without the deduction.
Net receivableDoes not change with the deduction.
Validation errors422 with out_of_range (negative, or not less than amount minus discount) or invalid_decimal_places in details[].code, on field: "deduction".
ResponseThe invoice echoes deduction when one was declared.

Invoice with a deduction

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

Invoice schema

Each invoice has these fields:

FieldsType / notes
id, companyIdIdentification strings.
environmenttest or live.
externalId, idempotencyKeyString or null.
statusEnum described below.
customerSnapshottaxId, name, email?, address?: { city, state, country? }.
serviceSnapshotdescription, code, municipalityCode.
taxSnapshotFiscal information object.
amount, currency, competenceDateNumber in reais, currency and ISO 8601 date-time (the competence date at midnight UTC, e.g. 2026-10-01T00:00:00.000Z).
discount, deductionOptional numbers in reais: the unconditional discount and the issuer-declared deduction from the ISS base (see ISS base deduction).
dpsId, dpsSeries, dpsNumberString/string/number or null.
accessKey, nfseNumberString/number or null.
fiscalProvider, fiscalSchemaVersionStrings.
issuedAt, authorizedAtISO date or null.
emailSnapshotOptional object with send.
lastErrorCode, lastErrorMessage, lastErrorProviderString or null.
documentsReadyAtISO date or null.
lastEmailStatus, lastEmailSentAtqueued, sent, failed or null; ISO date or null.
documentsStatusDerived state: pending or ready.
emailStatusDerived state: queued, sent, failed or null.
stageDerived state: pending, authorized, documents_ready, completed, failed.
scheduledForISO release date of a scheduled invoice, or null.
cancellationReason, cancellationDescriptionReason (issue_error, service_not_provided or other) and justification of the cancellation request, or null.
cancelledAtISO date when the invoice reached cancelled, or null.
cancellationRequestedAtISO date of a cancellation requested while the invoice was processing, or null. The invoice is cancelled at the Sefin as soon as it is authorized.
createdAt, updatedAtISO dates.
documentKeyVersionOptional number, when present in the snapshot.

requestHash is removed from serialization. The current response uses documentsReadyAt/documentsStatus, not the documentsReady boolean shown by a Swagger DTO. There is no lastEmail object in the current JSON — use the fields above. stage: completed can also occur with the email in failed; check emailStatus to know whether a send succeeded.

Fiscal statuses: queued, processing, authorized, rejected, retry_pending, reconciliation_required, manual_review, failed, cancelling, cancelled. Do not treat authorization as immediate availability of every document.

GET/v1/invoices200 OK
full_accessinvoices_viewinvoices_read_write

Lists invoices, newest first.

FieldTypeRequiredDescription
companyIdstring UUIDFilters by company.
statusstringOne of the fiscal statuses above.
fromstring ISO 8601Inclusive filter by competence date — not by createdAt.
tostring ISO 8601Inclusive filter by competence date — not by createdAt.
externalIdstringExact match.
limitintegerInteger between 1 and 1000; defaults to 50.
cursorstringnextCursor from the previous page, keeping the same filters.
curl "$BASE_URL/invoices?status=authorized&limit=50" \
  -H "X-API-Key: $CORVO_API_KEY"

Response — 200 OK

{
  "data": [
    {
      "id": "6c4d2e81-0a3b-4c5d-9e7f-1a2b3c4d5e6f",
      "status": "authorized",
      "amount": 150.5,
      "competenceDate": "2026-10-01T00:00:00.000Z",
      "createdAt": "2026-10-10T12:00:00.000Z"
    }
  ],
  "pagination": {
    "limit": 50,
    "hasMore": true,
    "nextCursor": "eyJ2IjoxLCJjcmVhdGVkQXQiOiIyMDI2LTEwLTA5VDEyOjAwOjAwLjAwMDAwMFoiLCJpZCI6IjNmMWM4YTkwIn0"
  }
}
GET/v1/invoices/:id200 OK
full_accessinvoices_viewinvoices_read_write

Fetches a single invoice by id.

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

Response — 200 OK

{
  "data": {
    "id": "6c4d2e81-0a3b-4c5d-9e7f-1a2b3c4d5e6f",
    "status": "authorized",
    "stage": "documents_ready",
    "documentsStatus": "ready",
    "accessKey": "35260712345678900000350010000000011000000019",
    "nfseNumber": 123
  }
}
GET/v1/invoices/:id/xml200 OK
full_accessinvoices_viewinvoices_read_write

Downloads the XML of an authorized invoice.

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

Downloads the PDF of an authorized invoice.

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

Fetches the status history of an invoice, oldest first. Paginated like any list (limit, cursor).

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

Response — 200 OK

{
  "data": [
    {
      "id": "e1d2c3b4-5a6f-4b7c-8d9e-0f1a2b3c4d5e",
      "invoiceId": "6c4d2e81-0a3b-4c5d-9e7f-1a2b3c4d5e6f",
      "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

Generates a short-lived signed URL for the invoice documents.

FieldTypeRequiredDescription
formatstring✓"pdf" or "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" }'

Response — 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

Requests email delivery of the invoice to the address stored in customerSnapshot.email; no alternative recipient is accepted. The invoice must be authorized with documents ready.

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

Response — 202 Accepted

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

Cancels an invoice. A queued invoice (scheduled or not yet processed) is cancelled immediately; an authorized NFS-e moves to cancelling while event 101101 is sent to the Sefin. A processing invoice (being issued) registers the request: 202, still processing, with cancellationRequestedAt set.

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":"Service amount was informed incorrectly"}'

Response — 202 Accepted

{
  "data": {
    "id": "6f1c0e2a-4b7d-4c1e-9a55-2b8f7c3d9e10",
    "status": "cancelling",
    "stage": "completed",
    "cancellationReason": "issue_error",
    "cancellationDescription": "Service amount was informed incorrectly",
    "cancelledAt": null,
    "cancellationRequestedAt": null
  }
}