Documentação

Erros

O formato dos erros, o que cada código significa e quando repetir uma requisição.

Toda resposta de erro tem o mesmo formato, em qualquer endpoint. O status HTTP diz a categoria, e error.code diz o erro exato. Quando o problema está nos campos, a lista details traz todos os campos com problema de uma vez, para você corrigir tudo em uma tentativa.

O formato

422: dois campos com problema
{
  "error": {
    "type": "validation_error",
    "code": "invalid_parameters",
    "message": "2 campos têm problemas. Veja details.",
    "request_id": "req_9Vb4Xk2Lq8Mz",
    "doc_url": "https://docs.cartaflow.com.br/errors#invalid_parameters",
    "details": [
      {
        "param": "to.postal_code",
        "code": "postal_code_not_found",
        "message": "Não encontramos o CEP 01001-999. Confira os 8 dígitos."
      },
      {
        "param": "document.url",
        "code": "address_area_not_blank",
        "message": "Há conteúdo na área do endereço da primeira página. Deixe a área em branco ou use address_placement: extra_page."
      }
    ]
  }
}
CampoO que é
typeA categoria do erro. Cada tipo corresponde a um status HTTP (tabela abaixo).
codeO erro exato. Use este campo no seu código: um código nunca muda de significado. Novos códigos podem ser criados; trate um código desconhecido pelo type.
messageExplicação para pessoas. O texto pode mudar, então não compare mensagens no seu código.
request_idO id da requisição, o mesmo do cabeçalho Request-Id. Envie ao suporte quando precisar de ajuda.
doc_urlLink para a explicação do código nesta página.
detailsOs campos com problema, cada um com param (o campo, em notação de pontos), code e message. Só existe em validation_error; nos outros tipos vale null.

Quando há um erro, nada é criado nem cobrado.

Idioma das mensagens

message vem em português por padrão. Para receber as mensagens em inglês, envie o cabeçalho Accept-Language: en. Os códigos são sempre os mesmos, em qualquer idioma.

curl "https://api.cartaflow.com.br/v1/letters/ltr_inexistente" \
  -H "Authorization: Bearer $CARTAFLOW_API_KEY" \
  -H "Accept-Language: en"

Tipos de erro

HTTPerror.typeO que significa
400, 413invalid_request_errorNão conseguimos ler a requisição: o JSON está malformado, o cabeçalho está errado ou o corpo é grande demais.
401authentication_errorA chave de API está ausente, inválida ou revogada.
402billing_errorO saldo da conta não cobre a operação.
403permission_errorA conta não pode fazer esta operação agora.
404not_found_errorO objeto ou o endpoint não existe.
409conflict_errorA requisição é válida, mas o estado atual do objeto não permite a operação.
422validation_errorLemos a requisição, mas um ou mais campos têm valores inválidos. A lista details diz quais e por quê.
429rate_limit_errorA conta passou do limite de requisições por segundo.
500, 503api_errorAlgo falhou do lado da CartaFlow. Não é um problema da sua requisição.

Códigos de erro

O valor de error.code. O link doc_url de cada erro leva para a linha dele nesta tabela.

error.codeHTTPO que aconteceuComo resolver
invalid_json400O corpo da requisição não é um JSON válido.Confira aspas, vírgulas e chaves. Gere o corpo com a função de JSON da sua linguagem em vez de montar o texto à mão.
unsupported_content_type400O cabeçalho Content-Type não é aceito neste endpoint.Envie application/json. Só POST /v1/letters e POST /v1/letters/quote aceitam também multipart/form-data, para enviar o PDF junto.
invalid_idempotency_key400O cabeçalho Idempotency-Key está vazio ou tem mais de 255 caracteres.Use um identificador único e curto, como o id da fatura no seu sistema ou um UUID.
request_too_large413O corpo da requisição passa de 4,5 MB, o máximo que a API recebe numa requisição.Envie o PDF por URL (document.type = url) ou com POST /v1/uploads (document.type = upload). As duas formas aceitam PDFs de até 10 MB.
api_key_missing401A requisição não tem o cabeçalho Authorization.Envie Authorization: Bearer seguido da sua chave de API.
api_key_invalid401A chave não existe ou está escrita de forma errada.Copie a chave de novo no painel, em Desenvolvedores > Chaves de API. Ela começa com cf_live_.
api_key_revoked401A chave foi revogada no painel.Crie uma chave nova no painel e atualize a variável de ambiente do seu sistema.
insufficient_balance402O saldo disponível é menor que o preço do envio.Recarregue o saldo no painel. Consulte GET /v1/balance antes de envios grandes.
account_suspended403A conta está suspensa e não pode criar envios.Fale com o suporte da CartaFlow pelo painel.
resource_not_found404Não existe objeto com esse id na sua conta.Confira o id, letra por letra. Cada conta só vê os próprios objetos: o id de um objeto de outra conta também recebe 404.
endpoint_not_found404O caminho ou o método HTTP não existe na API.Confira a URL, o prefixo /v1 e o método HTTP indicado na referência.
postal_code_not_found404O CEP consultado não existe na base de CEPs dos Correios.Confira os 8 dígitos com a pessoa ou com o cadastro de origem.
letter_not_cancelable409O status da correspondência não é mais scheduled nem received: ela já entrou em produção, foi postada ou falhou.Consulte a correspondência para ver o status atual. Depois da produção não é possível cancelar.
verification_not_cancelable409A verificação terminou sem confirmação (failed ou expired) e não pode ser cancelada nem revogada.Consulte a verificação para ver o status atual. Para tentar de novo, crie uma verificação nova.
verification_not_awaiting_code409A verificação não está esperando código: a correspondência ainda não foi postada, ou a verificação já terminou, foi cancelada ou foi revogada.Só confira códigos quando o status for awaiting_code. A mensagem de erro informa o status atual.
idempotency_key_reused409Essa Idempotency-Key já foi usada com outro corpo ou em outro endpoint nas últimas 24 horas.Use uma chave nova para cada operação diferente. Repita a mesma chave só para repetir exatamente a mesma requisição.
idempotency_key_in_use409Uma requisição com a mesma Idempotency-Key ainda está sendo processada.Espere um segundo e repita. Você vai receber a resposta da primeira requisição.
invalid_parameters422Um ou mais campos têm valores inválidos.Leia a lista details: cada item traz o campo (param), um código e uma mensagem.
rate_limit_exceeded429A conta fez mais requisições por segundo do que o limite.Espere os segundos indicados no cabeçalho Retry-After e repita. Para envios grandes, distribua as chamadas.
internal_error500Erro inesperado na CartaFlow.Repita com a mesma Idempotency-Key. Se continuar, envie o request_id ao suporte.
service_unavailable503A API está temporariamente indisponível, por manutenção ou sobrecarga.Repita depois do tempo do cabeçalho Retry-After, com a mesma Idempotency-Key.

Códigos de detalhe

Em um validation_error, cada item de details tem um destes códigos, junto com o campo em param.

details[].codeO que há de errado no campoComo resolver
requiredCampo obrigatório ausente.Envie o campo indicado em param.
unknown_parameterO campo não existe neste endpoint.Confira a grafia. A API rejeita campos desconhecidos para que um erro de digitação não passe em silêncio.
invalid_typeO tipo do valor está errado, como um texto onde se espera um número.Envie o tipo indicado na referência. Booleanos são true ou false, sem aspas.
invalid_valueO valor não é aceito: não está na lista de valores permitidos ou não combina com outro campo da requisição, como letter e document juntos numa verificação.Use um dos valores listados na referência do campo. A mensagem explica o motivo.
invalid_formatO formato está errado: URL, data, base64, CEP ou código.Siga o formato e o exemplo da referência do campo.
too_shortO texto ou a lista está abaixo do tamanho mínimo.Confira o mínimo na referência do campo.
too_longO texto ou a lista passa do tamanho máximo.Confira o máximo na referência do campo e abrevie, se for um endereço.
out_of_rangeO número ou a data está fora do intervalo permitido, como um send_date que não seja de amanhã até 180 dias à frente.Confira o mínimo e o máximo na referência do campo.
requires_registeredreturn_receipt e restricted_delivery só funcionam com registered: o aviso de recebimento e a mão própria são serviços da carta registrada.Inclua registered em postal_services, ou tire os serviços que dependem dele.
postal_code_not_foundO CEP não existe na base dos Correios.Confira os 8 dígitos. Você pode testar o CEP antes com GET /v1/postal-codes/{postal_code}.
address_incompleteNão foi possível completar o endereço: o campo não veio na requisição e o CEP não o informa. Acontece com CEPs que valem para uma cidade inteira, que não têm logradouro nem bairro.Envie o campo indicado em param, como street e neighborhood.
document_unreachableNão conseguimos baixar o PDF da URL em 10 segundos, ou o servidor respondeu com erro.Use uma URL HTTPS pública ou assinada (S3, GCS, Azure) válida por pelo menos 10 minutos.
upload_not_foundNão existe upload com esse id na sua conta.Confira o upload_id. Use o id devolvido por POST /v1/uploads, com a mesma conta da chave de API.
upload_expiredO upload foi criado há mais de 24 horas e não pode mais ser usado.Crie um upload novo com POST /v1/uploads e envie o arquivo de novo.
upload_already_usedO upload já foi usado por outra correspondência. Cada upload serve para uma correspondência só.Crie um upload novo para cada correspondência. Para repetir a mesma criação com segurança, use a mesma Idempotency-Key.
upload_file_missingO arquivo nunca foi enviado para o upload_url do upload.Envie o PDF com PUT para o upload_url, com o cabeçalho Content-Type: application/pdf, e espere a resposta 2xx antes de criar a correspondência. Se o link expirou (ele vale 2 horas), crie um upload novo.
document_invalidO arquivo não é um PDF válido: está corrompido ou é de outro formato.Abra o arquivo em um leitor de PDF para conferir. Em base64, envie só o conteúdo, sem o prefixo data:application/pdf;base64,.
document_encryptedO PDF está protegido por senha.Gere o PDF sem senha e sem restrições de impressão.
document_too_largeO PDF passa do tamanho máximo da forma de envio: 10 MB por URL ou com POST /v1/uploads, 4 MB em multipart/form-data e 3 MB em base64 (depois de decodificado).Reduza a resolução das imagens para 300 dpi, o máximo que a impressão aproveita. Para um PDF grande, use URL ou POST /v1/uploads, que aceitam até 10 MB.
document_page_sizeAlguma página não é A4 em retrato (210 x 297 mm).Exporte o PDF em A4, orientação retrato, em todas as páginas.
too_many_sheetsA correspondência passaria de 6 folhas, o máximo que cabe em um envelope.Use double_sided: true para imprimir frente e verso, ou divida o conteúdo em mais de uma correspondência.
address_area_not_blankHá texto ou imagem na área do endereço da primeira página, onde a CartaFlow imprime o destinatário.Deixe a área em branco no seu layout ou use address_placement: extra_page.
variable_missingO PDF tem uma marcação, como {{nome}}, que não veio em variables.Envie um valor para cada marcação do PDF. Para deixar uma em branco, envie uma string vazia.
variable_not_foundVocê enviou uma variável que o PDF não tem.Confira o nome, letra por letra. Num PDF feito no Word, abra o PDF e confira se a marcação aparece inteira, com as chaves, como texto selecionável.
document_text_unreadableO PDF não tem texto selecionável: é uma imagem ou uma digitalização. Sem texto, não conseguimos encontrar as marcações, como as variáveis ou o {{OTP_CODE}} de uma verificação.Exporte o PDF direto do editor (no Word: Arquivo > Salvar como > PDF), em vez de imprimir em PDF a partir de uma imagem ou digitalizar.
otp_code_missingO PDF de uma verificação não tem a marcação {{OTP_CODE}}, o lugar onde a CartaFlow imprime o código.Escreva {{OTP_CODE}}, em maiúsculas e com as chaves, onde o código deve aparecer, e exporte o PDF de novo com texto selecionável. Ou crie a verificação sem document, com o modelo da CartaFlow.

Quando repetir uma requisição

Alguns erros são passageiros e vale repetir. Outros só passam quando você muda a requisição.

SituaçãoO que fazer
429 (rate_limit_exceeded)Espere os segundos do cabeçalho Retry-After e repita.
500 (internal_error) e 503 (service_unavailable)Repita com espera crescente: 1, 2, 4, 8 segundos, até umas 5 vezes. No 503, respeite Retry-After.
Falha de rede ou tempo esgotado, sem respostaRepita como no 500. Você não sabe se a primeira chegou, e a Idempotency-Key garante que nada seja criado em dobro.
409 com idempotency_key_in_useA primeira requisição com a mesma chave ainda está em andamento. Espere um segundo e repita.
Qualquer outro 4xxNão repita igual. Corrija a requisição conforme o código.

Sempre repita com a mesma Idempotency-Key. Assim, se a primeira tentativa chegou a criar a correspondência, a repetição devolve a mesma correspondência em vez de criar outra. Veja Idempotência.

Um exemplo de tratamento

import { randomUUID } from 'node:crypto';

const RETRYABLE = new Set([429, 500, 503]);

async function cartaflow(path, { method = 'GET', body, idempotencyKey } = {}) {
  // Uma chave por operação, criada uma vez e reaproveitada em todas as tentativas.
  const key = idempotencyKey ?? (method === 'POST' ? randomUUID() : undefined);

  for (let attempt = 0; attempt < 5; attempt++) {
    let response;
    try {
      response = await fetch(`https://api.cartaflow.com.br/v1${path}`, {
        method,
        headers: {
          Authorization: `Bearer ${process.env.CARTAFLOW_API_KEY}`,
          ...(body ? { 'Content-Type': 'application/json' } : {}),
          ...(key ? { 'Idempotency-Key': key } : {}),
        },
        body: body ? JSON.stringify(body) : undefined,
      });
    } catch {
      await sleep(2 ** attempt * 1000); // falha de rede: repita com a mesma chave
      continue;
    }

    if (response.ok) return response.json();

    const { error } = await response.json();
    const inUse = response.status === 409 && error.code === 'idempotency_key_in_use';
    if (!RETRYABLE.has(response.status) && !inUse) {
      // Erro que não passa sozinho: registre e mostre a quem precisa corrigir.
      throw Object.assign(new Error(error.message), { code: error.code, details: error.details, requestId: error.request_id });
    }

    const retryAfter = Number(response.headers.get('Retry-After'));
    await sleep(retryAfter > 0 ? retryAfter * 1000 : 2 ** attempt * 1000);
  }

  throw new Error('A API da CartaFlow não respondeu depois de 5 tentativas.');
}

const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

Pedir ajuda ao suporte

Toda resposta, de sucesso ou de erro, traz o cabeçalho Request-Id, e os erros também trazem error.request_id. Registre esse valor nos seus logs. Ao falar com o suporte, envie o request_id: com ele encontramos a requisição exata.

Nesta página