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

Emissão assíncrona

A solicitação retorna imediatamente; o processamento continua em background.

A emissão de NFS-e é assíncrona. O POST /v1/invoices responde 202 imediatamente com a nota registrada/enfileirada — normalmente com status: "queued" (ou processing) —, mas o sucesso HTTP não significa autorização fiscal: o processamento continua em background.

Como acompanhar

  • GET /v1/invoices/:id — consulte o status e, quando disponível, accessKey/nfseNumber.
  • GET /v1/invoices/:id/events — histórico de transições de status da nota.
  • Webhooks — nfse.invoice.authorized, nfse.invoice.documents_ready, nfse.invoice.email_sent etc. (veja Recebendo webhooks).
  • GET /v1/billing/usage — confira canEmit antes de novas emissões.

Idempotency-Key

O header Idempotency-Key é opcional na emissão e na solicitação de email, mas recomendado: ele torna a repetição segura. Use uma chave estável por operação de negócio (por exemplo, o id do pedido no seu sistema) e mantenha a mesma chave e o mesmo payload em toda repetição.

Mesma chave, conta e ambiente com conteúdo equivalente ao hash calculado recupera a mesma nota; conteúdo diferente retorna 409 (ERROR_IDEMPOTENCY_CONFLICT). O hash é calculado antes da normalização fiscal, com canonização das chaves JSON e da data de competência — não altere a representação dos campos ao repetir (CNPJ com e sem pontuação pode gerar hashes diferentes).

javascript

async function emitirComRetry(payload, key, tentativas) {
  for (let i = 0; i < tentativas; i++) {
    const res = await fetch(`${BASE_URL}/invoices`, {
      method: "POST",
      headers: {
        "X-API-Key": process.env.CORVO_API_KEY,
        "Content-Type": "application/json",
        // mesma chave em toda repetição — deduplicação no servidor
        "Idempotency-Key": key,
      },
      body: JSON.stringify(payload),
    });

    if (res.ok) {
      const body = await res.json();
      return body.data.id; // { data: Invoice }
    }
    if (res.status !== 429 && res.status !== 503) {
      throw new Error(`HTTP ${res.status}`);
    }
    await new Promise((r) => setTimeout(r, 1000 * 2 ** i)); // backoff exponencial
  }
  throw new Error("esgotado");
}

// uso: chave estável por operação de negócio
const invoiceId = await emitirComRetry(pedido, `pedido_${pedido.externalId}_emissao`, 5);