Documento e área do endereço
Como enviar o PDF de uma correspondência, o que ele precisa ter e onde a CartaFlow imprime o endereço.
O conteúdo de uma correspondência é um PDF. Ele vai como arquivo, em um envio multipart, ou no campo document de um corpo JSON. A CartaFlow imprime esse conteúdo do jeito que ele está: o layout, as cores, o logo e o texto são os do seu PDF. A CartaFlow só acrescenta o endereço, na área do endereço da primeira página, e os valores das variáveis, quando você envia variáveis.
Quatro formas de enviar o PDF
| Forma | Quando usar | Como | PDF de até |
|---|---|---|---|
| Arquivo na requisição | Você tem o PDF em disco ou em memória e ele é pequeno. É a forma mais simples. | multipart/form-data, com o PDF na parte file. | 4 MB |
| PDF por URL | O PDF já está em um armazenamento, como S3, Google Cloud Storage ou Azure. | JSON, document.type: url. | 10 MB |
| Upload em duas etapas | Você tem o PDF em disco ou em memória e ele é grande. | POST /v1/uploads, PUT do arquivo e JSON com document.type: upload. | 10 MB |
| PDF em base64 | O PDF é pequeno e você prefere mandar tudo em JSON. | JSON, document.type: base64. | 3 MB |
Por que os limites são diferentes
O corpo de uma requisição à API tem até 4,5 MB. Um PDF que vai dentro da requisição, em multipart ou em base64, precisa caber nesse limite junto com os outros campos (em base64, o arquivo fica cerca de um terço maior). Por URL ou pelo upload em duas etapas, o arquivo não passa pela requisição da API, e o limite é de 10 MB.
As quatro formas valem também para POST /v1/letters/quote, que recebe o mesmo corpo da criação.
Arquivo (multipart/form-data)
Envie o PDF na parte file, com até 4 MB, e os outros campos como partes do formulário, com os mesmos nomes do corpo JSON. Campos de objetos usam colchetes: to[name], to[postal_code], from[number], metadata[customer_id], variables[nome]. Listas repetem o campo com []: postal_services[]=registered. Booleanos vão como texto: true ou false. O campo document não existe nesta forma: o conteúdo é o arquivo.
curl -X POST "https://api.cartaflow.com.br/v1/letters" \
-H "Authorization: Bearer $CARTAFLOW_API_KEY" \
-H "Idempotency-Key: fatura-2026-10-0042" \
-F "file=@fatura-2026-10-0042.pdf" \
-F "to[name]=Destinatário Exemplo" \
-F "to[postal_code]=01001-000" \
-F "to[number]=128" \
-F "to[complement]=Ap. 52" \
-F "color=true" \
-F "reference=fatura-2026-10-0042" \
-F "metadata[customer_id]=1842"A resposta é a mesma da criação em JSON. Em document, a correspondência informa a forma usada: { "type": "upload", "filename": "fatura-2026-10-0042.pdf" }.
PDF por URL
A CartaFlow baixa o arquivo uma única vez, no momento da criação. A URL precisa ser HTTPS, pública ou assinada, e continuar válida por pelo menos 10 minutos. Esperamos até 10 segundos pelo download. O arquivo pode ter até 10 MB.
"document": {
"type": "url",
"url": "https://arquivos.exemplo.com.br/faturas/2026-10-0042.pdf"
}Upload em duas etapas
Para um PDF de até 10 MB que está com você, mas não cabe numa requisição, envie o arquivo antes e depois crie a correspondência:
- Crie um upload com POST /v1/uploads, informando o nome (
filename) e o tamanho em bytes (size) do arquivo. A resposta traz oiddo upload, que começa comupl_, e umupload_urlassinado. - Envie o arquivo com
PUTpara oupload_url: os bytes do PDF no corpo, o cabeçalhoContent-Type: application/pdfe sem o cabeçalhoAuthorization, porque a assinatura já está na URL. O link vale por 2 horas. Uma resposta 2xx confirma que o arquivo chegou. - Crie a correspondência com
document: { "type": "upload", "upload_id": "upl_..." }, em até 24 horas depois de criar o upload.
# Este exemplo usa jq para ler o JSON da resposta.
SIZE=$(wc -c < fatura-2026-10-0042.pdf | tr -d ' ')
# 1. Crie o upload com o nome e o tamanho do arquivo.
UPLOAD=$(curl -s -X POST "https://api.cartaflow.com.br/v1/uploads" \
-H "Authorization: Bearer $CARTAFLOW_API_KEY" \
-H "Content-Type: application/json" \
-d "{ \"filename\": \"fatura-2026-10-0042.pdf\", \"size\": $SIZE }")
UPLOAD_ID=$(echo "$UPLOAD" | jq -r .id)
UPLOAD_URL=$(echo "$UPLOAD" | jq -r .upload_url)
# 2. Envie o arquivo para o upload_url, sem o cabeçalho Authorization.
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: application/pdf" \
--data-binary "@fatura-2026-10-0042.pdf"
# 3. Crie a correspondência com o upload.
curl -X POST "https://api.cartaflow.com.br/v1/letters" \
-H "Authorization: Bearer $CARTAFLOW_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: fatura-2026-10-0042" \
-d "{
\"to\": { \"name\": \"Destinatário Exemplo\", \"postal_code\": \"01001-000\", \"number\": \"128\" },
\"document\": { \"type\": \"upload\", \"upload_id\": \"$UPLOAD_ID\" },
\"reference\": \"fatura-2026-10-0042\"
}"Regras do upload:
- Uma correspondência por upload. Depois que uma correspondência é criada com ele, o upload não serve para outra: a API responde 422 com
upload_already_used. Para repetir a mesma criação com segurança, use a mesmaIdempotency-Key. - Simular não consome o upload. Você pode usar o mesmo
upload_idem POST /v1/letters/quote quantas vezes quiser antes de criar a correspondência. Uma criação recusada, como um 422, também não consome o upload. - Prazos. O
upload_urlaceita o arquivo por 2 horas (upload_url_expires_at). O upload pode ser usado por 24 horas (expires_at); depois disso, a API respondeupload_expired. - O arquivo precisa ter chegado. Se você criar a correspondência sem ter enviado o arquivo, a API responde
upload_file_missing. - O arquivo é conferido na criação, com as mesmas regras de qualquer PDF: A4, sem senha, área do endereço em branco, até 6 folhas.
- Variáveis funcionam igual: envie
variablesdentro dedocument, junto comupload_id. - O upload é da sua conta. Um
upload_idde outra conta recebeupload_not_found.
Na correspondência criada, document traz { "type": "upload", "filename": "fatura-2026-10-0042.pdf" }, igual a um envio em multipart.
PDF em base64
O PDF vai dentro do corpo JSON, em base64 padrão, sem o prefixo data:application/pdf;base64,. O arquivo pode ter até 3 MB depois de decodificado (cerca de 4 MB em base64), para que o corpo inteiro caiba nos 4,5 MB da requisição. Para PDFs maiores, use URL ou o upload em duas etapas.
PDF=$(base64 < contrato-5531.pdf | tr -d '\n')
curl -X POST "https://api.cartaflow.com.br/v1/letters" \
-H "Authorization: Bearer $CARTAFLOW_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: contrato-5531" \
-d "{
\"to\": { \"name\": \"Destinatário Exemplo\", \"postal_code\": \"01001-000\", \"number\": \"128\" },
\"document\": { \"type\": \"base64\", \"data\": \"$PDF\" },
\"double_sided\": true,
\"reference\": \"contrato-5531\"
}"Variáveis dentro de um PDF
Um PDF pode ter marcações de variáveis, como {{nome}} ou {{valor_total}}. É o jeito mais simples de personalizar um documento feito no Word ou em outro editor: escreva a marcação no texto, exporte em PDF e envie as variáveis junto.
Olá, {{nome}}.
Sua fatura de {{mes}} vence em {{vencimento}}.A CartaFlow escreve cada valor no lugar da sua marcação, com o mesmo tamanho e a mesma cor, e o resto da linha se ajusta ao valor, como se ele tivesse sido digitado ali: sem buracos quando o valor é curto e sem sobreposição quando é longo. Uma linha centralizada continua centralizada, e o texto depois de uma tabulação e as outras linhas não saem do lugar. O valor não quebra linha: quando ele não cabe, o resto da linha é apertado um pouco, até 85% da largura, e, se ainda assim não couber, passa da margem. Isso nunca impede o envio; confira o resultado no preview_url da correspondência ou na prévia do painel.
- Em JSON, envie
variablesdentro dedocument, comtype: url,type: uploadoutype: base64. - Em multipart, envie uma parte por variável:
variables[nome],variables[mes]. - Nomes usam letras, números e sublinhado. Valores são textos ou números.
- Sem
variables, o PDF é impresso como está.
"document": {
"type": "url",
"url": "https://arquivos.exemplo.com.br/faturas/modelo-fatura.pdf",
"variables": {
"nome": "Destinatário Exemplo",
"mes": "outubro",
"vencimento": "20/10/2026"
}
}curl -X POST "https://api.cartaflow.com.br/v1/letters" \
-H "Authorization: Bearer $CARTAFLOW_API_KEY" \
-F "file=@modelo-fatura.pdf" \
-F "to[name]=Destinatário Exemplo" \
-F "to[postal_code]=01001-000" \
-F "to[number]=128" \
-F "variables[nome]=Destinatário Exemplo" \
-F "variables[mes]=outubro" \
-F "variables[vencimento]=20/10/2026"A conferência é rigorosa nos dois sentidos, para que nenhum documento saia com uma marcação esquecida:
| Situação | Resposta |
|---|---|
O documento tem uma marcação que não veio em variables. | 422 variable_missing |
| Você enviou uma variável que o documento não tem. | 422 variable_not_found |
| O PDF não tem texto selecionável: é uma imagem ou uma digitalização. | 422 document_text_unreadable |
Exporte o PDF direto do editor
No Word, use Arquivo > Salvar como > PDF. Digitalizar ou imprimir em PDF a partir de uma imagem gera um PDF sem texto, e a API não encontra as marcações. Para conferir as marcações sem custo, faça uma simulação com POST /v1/letters/quote com as mesmas variables.
Numa verificação de endereço com o seu próprio PDF, {{OTP_CODE}}, {{VERIFICATION_URL}} e {{QR_CODE}} são marcações reservadas, preenchidas pela CartaFlow com o código e o acesso à página de confirmação. Veja O seu próprio PDF.
O que o PDF precisa ter
- Tamanho A4 em retrato (210 x 297 mm) em todas as páginas.
- Dentro do limite da forma de envio: 10 MB por URL ou upload em duas etapas, 4 MB em multipart e 3 MB em base64. Imagens a 300 dpi são o máximo que a impressão aproveita.
- Até 6 folhas por correspondência, contando a folha que o endereço às vezes acrescenta. É o que cabe em um envelope.
- Sem senha e sem restrições de impressão.
- Fontes incorporadas. Exporte o PDF com as fontes embutidas para que o texto saia igual ao que você vê na tela.
- Margem de segurança. Mantenha textos e elementos importantes a pelo menos 5 mm das bordas.
- Área do endereço em branco na primeira página, quando
address_placementéfirst_page.
A área do endereço
O envelope tem uma janela. Pela janela aparece um retângulo da primeira página: a área do endereço. A CartaFlow imprime ali o remetente, em uma linha, e o destinatário logo abaixo. Por isso essa área precisa estar em branco no seu PDF.
Se o seu layout ocupa essa área, por exemplo porque a primeira página de uma fatura já tem outro conteúdo ali, use address_placement: extra_page.
address_placement | Onde o endereço é impresso | Custo |
|---|---|---|
first_page (padrão) | Na área do endereço da primeira página do seu documento. | Sem acréscimo. |
extra_page | Num lado só dele, o primeiro, que aparece pela janela, com o remetente e o destinatário. Ele ocupa um lado que ficaria em branco, quando há um; se não há, entra uma folha a mais no início. O seu documento vem em seguida. | Sem acréscimo, mesmo quando entra uma folha a mais. |
Quando a área do endereço não está em branco e address_placement é first_page, a API responde 422 com o código address_area_not_blank, e nada é criado nem cobrado.
Cor e frente e verso
color: trueimprime em cores. Comfalse, o padrão, a impressão é em preto e branco, e um PDF colorido sai em tons de cinza. A impressão colorida tem acréscimo por página impressa: cada lado impresso de uma folha conta como uma página.double_sided: trueimprime frente e verso: cada folha leva duas páginas do documento. A correspondência usa menos folhas e custa menos. Comfalse, o padrão, cada página vai em uma folha.
Quantas folhas uma correspondência usa
O campo sheets diz quantas folhas de papel vão no envelope. O preço conta só as folhas do seu documento: o endereço nunca é cobrado, mesmo quando acrescenta uma folha.
- Só frente: uma folha por página.
- Frente e verso: metade das páginas, arredondada para cima.
- Com
extra_page, só frente: o mesmo número de folhas. O endereço vai no verso da primeira página, e só essa folha é impressa dos dois lados. - Com
extra_page, frente e verso, número ímpar de páginas: o mesmo número de folhas. O endereço usa o lado que sobra. - Com
extra_page, frente e verso, número par de páginas: mais uma folha, só com o endereço e o verso em branco.
| Páginas do PDF | double_sided | address_placement | sheets |
|---|---|---|---|
| 1 | false | first_page | 1 |
| 3 | false | first_page | 3 |
| 3 | true | first_page | 2 |
| 2 | false | extra_page | 2 |
| 7 | true | extra_page | 4 |
| 2 | true | extra_page | 2: a folha do endereço não é cobrada |
| 7 | false | first_page | 7: passa do limite, too_many_sheets |
| 12 | true | extra_page | 7: passa do limite, too_many_sheets |
Com color: true, a linha color do preço conta páginas, não folhas: cada lado impresso é uma página. Um PDF de 3 páginas em frente e verso usa 2 folhas e 3 páginas coloridas. O lado do endereço nunca é colorido nem cobrado.
Quando a correspondência passaria de 6 folhas, contando a folha que o endereço acrescenta, a API responde 422 com o código too_many_sheets. Use double_sided: true ou divida o conteúdo em mais de uma correspondência.
Confira o resultado antes de enviar
- Simulação. POST /v1/letters/quote recebe exatamente o mesmo corpo da criação, valida o documento e as variáveis, conta as páginas e devolve o preço e o endereço completo. Nada é criado nem cobrado.
- PDF final. Toda correspondência traz em
preview_urlum link para o PDF exatamente como será impresso, já com o endereço. O link vale por 60 minutos; consulte a correspondência de novo para receber um link novo. O arquivo fica disponível por pelo menos 90 dias depois da criação (ou depois da data do envio, numa correspondência agendada).
Numa correspondência em preto e branco, o preview_url mostra as cores do PDF original: a conversão para tons de cinza acontece na impressão.
Enquanto a correspondência estiver em received (ou em scheduled, se foi agendada), você ainda pode cancelar: nada é impresso e, se ela já foi cobrada, o valor volta para o saldo. Veja Correspondências e status.
Erros de documento
Quando o documento tem um problema, a API responde 422 com validation_error, e cada item de details aponta o campo e o motivo. Nada é criado nem cobrado.
details[].code | O que aconteceu |
|---|---|
document_unreachable | Não conseguimos baixar o PDF da URL a tempo, ou o servidor respondeu com erro. |
upload_not_found | Não existe upload com esse upload_id na sua conta. |
upload_expired | O upload foi criado há mais de 24 horas. |
upload_already_used | O upload já foi usado por outra correspondência. |
upload_file_missing | O arquivo nunca foi enviado para o upload_url. |
document_invalid | O arquivo não é um PDF válido. Em base64, confira se não há o prefixo data:. |
document_encrypted | O PDF tem senha. |
document_too_large | O PDF passa do limite da forma de envio: 10 MB por URL ou upload, 4 MB em multipart, 3 MB em base64. |
document_page_size | Alguma página não é A4 em retrato. |
too_many_sheets | A correspondência passaria de 6 folhas. |
address_area_not_blank | Há conteúdo na área do endereço da primeira página. |
document_text_unreadable | Você enviou variables, mas o PDF não tem texto selecionável. |
variable_missing | O documento tem uma marcação que não veio em variables. |
variable_not_found | Você enviou uma variável que o documento não tem. |
Um corpo maior que 4,5 MB nem chega a ser lido: a API responde 413 com request_too_large. A lista completa de códigos está em Erros.