Documentação

Convenções

As regras que valem para todos os endpoints, para você não precisar adivinhar nenhuma.

Todos os endpoints da API seguem as mesmas regras. Depois de ler esta página, você sabe o formato de qualquer requisição e de qualquer resposta.

Requisições

  • A URL base é https://api.cartaflow.com.br/v1. Só HTTPS.
  • O corpo é JSON em UTF-8, com o cabeçalho Content-Type: application/json.
  • Há duas exceções, os endpoints que recebem um PDF: POST /v1/letters e POST /v1/letters/quote. Eles também aceitam multipart/form-data, para você enviar o arquivo junto com os dados, sem converter para base64. Veja Enviar um PDF com multipart.
  • Qualquer outro Content-Type recebe 400 com unsupported_content_type.
  • O corpo pode ter até 4,5 MB. Um PDF maior que 4 MB vai por URL ou pelo upload em duas etapas (POST /v1/uploads), que aceitam até 10 MB. Veja Documento e área do endereço.
  • Campos desconhecidos são recusados com 422 e o código unknown_parameter. Assim um erro de digitação, como postal_cod, nunca passa em silêncio.

Enviar um PDF com multipart

Em POST /v1/letters e POST /v1/letters/quote, você pode enviar o corpo como multipart/form-data. O PDF vai na parte file, com até 4 MB. Os outros campos são os mesmos do JSON, um por parte, com os campos de dentro de objetos escritos entre colchetes e as listas repetindo o campo com []:

No JSONNo multipart
{ "to": { "name": "Destinatário Exemplo" } }to[name]=Destinatário Exemplo
{ "to": { "postal_code": "01001-000" } }to[postal_code]=01001-000
{ "variables": { "nome": "Destinatário Exemplo" } }variables[nome]=Destinatário Exemplo
{ "metadata": { "customer_id": "1842" } }metadata[customer_id]=1842
{ "color": true }color=true
{ "postal_services": ["registered", "return_receipt"] }postal_services[]=registered e postal_services[]=return_receipt

Booleanos vão como o texto true ou false. As regras de validação, as respostas e os erros são os mesmos do JSON.

cURL
curl -X POST https://api.cartaflow.com.br/v1/letters \
  -H "Authorization: Bearer $CARTAFLOW_API_KEY" \
  -F "file=@exemplo-a4.pdf" \
  -F "to[name]=Destinatário Exemplo" \
  -F "to[postal_code]=01001-000" \
  -F "to[number]=128" \
  -F "color=true"

Com curl -F, o cabeçalho Content-Type: multipart/form-data é enviado automaticamente.

Nomes em inglês, mensagens no seu idioma

Os nomes de campos, valores, eventos e códigos de erro estão em inglês e em snake_case: postal_code, in_production, letter.posted, insufficient_balance. É o padrão da maioria das APIs, e o seu código fica igual para equipes no Brasil e fora dele.

O que é escrito para pessoas, como error.message, vem em português ou em inglês, conforme o cabeçalho Accept-Language. Sem esse cabeçalho, a API responde em português.

IDs

Todo objeto tem um id com um prefixo que diz o tipo. Guarde o id inteiro, como texto.

PrefixoObjetoExemplo
ltr_Correspondêncialtr_8Kq2wX4mN7pR
upl_Upload de um PDF (POST /v1/uploads)upl_6Np3Vx8Rk2Tq
ver_Verificação de endereçover_3Hd9Kp2qZ6tW
evt_Eventoevt_6Tq1Yz8Wm3Rb
btx_Movimentação do saldobtx_4Lm8Qw2Zx9Kd
acc_Contaacc_7Jw3Nf8Xq2Lp
req_Requisição (cabeçalho Request-Id e error.request_id)req_9Vb4Xk2Lq8Mz

Todo objeto também tem o campo object, com o tipo por extenso: letter, upload, verification, event, balance_transaction, account. Listas têm object: "list".

Datas

  • Datas com hora seguem a ISO 8601, em UTC: 2026-10-13T14:20:00Z. Converta para o fuso do seu usuário na hora de mostrar.
  • send_date, a data de agendamento de uma correspondência, é só a data: 2026-10-20, no formato AAAA-MM-DD, no horário de Brasília.
  • Os filtros created_after e created_before recebem data e hora ISO 8601.

Valores em dinheiro

Valores são números inteiros em centavos, sempre com o campo currency, que vale BRL. Assim não há erro de arredondamento.

{ "currency": "BRL", "total": 1690 }

1690 são R$ 16,90. Para mostrar, divida por 100 e formate em reais.

Todos os campos sempre aparecem

Uma resposta traz todos os campos documentados do objeto, sempre. Quando um campo não se aplica, ele vem com null, nunca some. Por exemplo, send_date é null em uma correspondência enviada na hora, e cancellation_reason é null enquanto ela não foi cancelada.

metadata sem dados vem como objeto vazio, {}. Booleanos são sempre true ou false, sem aspas.

Métodos HTTP

MétodoPara que serveExemplo
GETConsultar um objeto ou uma lista. Nunca muda nada.GET /v1/letters/{letter_id}
POSTCriar um objeto ou executar uma ação.POST /v1/letters, POST /v1/letters/{letter_id}/cancel

Status HTTP

StatusQuando
200Deu certo: consulta, listagem, alteração ou ação, como cancelar ou calcular o preço.
201Um objeto foi criado: correspondência, upload ou verificação.
400Não conseguimos ler a requisição: JSON malformado, Content-Type não aceito ou Idempotency-Key inválida.
401A chave de API está ausente, inválida ou revogada.
402O saldo não cobre a operação.
403A conta não pode fazer a operação agora, por exemplo porque está suspensa.
404O objeto não existe na sua conta, ou o endpoint não existe.
409O estado atual do objeto não permite a operação, ou a Idempotency-Key conflita com outra requisição.
413O corpo passa de 4,5 MB. Envie o PDF por URL ou com POST /v1/uploads.
422Um ou mais campos têm valores inválidos. error.details lista todos.
429Requisições demais por segundo. Espere o tempo de Retry-After.
500Erro inesperado na CartaFlow. Repita com a mesma Idempotency-Key.
503API temporariamente indisponível. Repita depois de Retry-After.

Toda resposta de erro tem o mesmo formato. Veja Erros.

Cabeçalhos

O que você envia:

CabeçalhoObrigatórioPara que serve
AuthorizationSimBearer seguido da chave de API. Veja Autenticação.
Content-TypeQuando há corpoapplication/json. Em POST /v1/letters e POST /v1/letters/quote, também multipart/form-data.
Idempotency-KeyNão, mas recomendado em todo POSTEvita criar o mesmo objeto duas vezes quando você repete uma requisição. Veja Idempotência.
Accept-LanguageNãopt-BR (padrão) ou en. Define o idioma de error.message.

O que a API devolve:

CabeçalhoO que traz
Request-IdO id da requisição, como req_9Vb4Xk2Lq8Mz. Envie ao suporte quando precisar de ajuda.
RateLimit-LimitQuantas requisições por segundo a conta pode fazer, somando todas as chaves.
RateLimit-RemainingQuantas ainda restam na janela atual.
RateLimit-ResetEm quantos segundos a janela recomeça.
Retry-AfterEm respostas 429 e 503: quantos segundos esperar antes de repetir.
Idempotent-Replayedtrue quando a resposta é a repetição de uma requisição anterior com a mesma Idempotency-Key.

A API cresce sem quebrar a sua integração

A versão 1 recebe novos campos, novos valores de enums, novos eventos e novos códigos de erro sem aviso prévio, porque isso não quebra uma integração bem feita. Para isso, o seu código precisa:

  • ignorar campos que ele não conhece nas respostas e nos webhooks;
  • tratar um valor desconhecido de status como "em andamento", e um error.code desconhecido pelo error.type;
  • ignorar eventos de tipos que ele não usa.

Mudanças que quebram integrações só acontecem em uma nova versão. Veja Versões e compatibilidade.

Nesta página