Docs

Letters and statuses

The path of a letter from your request to its handover to Correios, and how to follow each step.

A letter is a document that CartaFlow prints, puts in an envelope and posts through Correios, the Brazilian national postal service, to an address in Brazil. You create a letter with POST /v1/letters, and it moves through a fixed sequence of statuses until it is posted.

The life of a letter

A letter only moves forward. It starts as scheduled when you schedule it with send_date, or straight as received when you send it right away. It then moves to in_production, printed and posted. While it is scheduled or received, it can still be canceled. If something goes wrong in production, it moves to failed and the amount goes back to your balance.

  1. Scheduledscheduled
    • Canceledcanceled
  2. Receivedreceived
    • Canceledcanceled
    • Failedfailed
  3. In productionin_production
    • Failedfailed
  4. Printedprinted
    • Failedfailed
  5. Postedposted
StatusWhat it meansFinalCancelable
scheduledScheduledThe letter was validated and is waiting for its send_date. It has not been charged yet. On that date, at 06:00 Brasília time, CartaFlow debits the balance and the letter moves to received. If the balance does not cover the price, it moves to canceled. It can be canceled at no cost.NoYes
receivedReceivedCartaFlow validated the document and the address, charged the letter to your balance and put it in the production queue. It can still be canceled, and the amount goes back to the balance.NoYes
in_productionIn productionThe letter is part of a print batch. From this point on it can no longer be canceled.NoNo
printedPrintedThe letter was printed, folded and put in its envelope. Posting is the next step.NoNo
postedPostedThe letter was handed to Correios, the Brazilian postal service. From here on delivery follows the postal service, and CartaFlow receives no further updates about it. A registered letter carries its Correios tracking code in tracking_code.YesNo
canceledCanceledThe letter was canceled before production and nothing was printed. cancellation_reason says why: you canceled it, or the balance did not cover a scheduled letter on its send date. If it had been charged, the amount went back to the balance.YesNo
failedFailedSomething went wrong in production and the letter will not be posted. failure_reason says why. The amount went back to the balance automatically.YesNo

A status never moves backwards. If a letter has to be printed again in production, for example because the paper jammed in the printer, it joins another print batch and keeps its status.

New statuses may appear

Treat a status you do not recognize as a step in progress. CartaFlow may add statuses without changing the API version, but it never changes the meaning of an existing one. See Versioning and compatibility.

When each step happened

The status_transitions field records when the letter reached each status, in UTC. Statuses the letter has not reached are null.

status_transitions of a posted letter
{
  "received_at": "2026-10-13T14:20:00Z",
  "in_production_at": "2026-10-13T21:00:00Z",
  "printed_at": "2026-10-14T10:42:00Z",
  "posted_at": "2026-10-14T16:05:00Z",
  "canceled_at": null,
  "failed_at": null
}
  • received_at is when the letter was charged. For a letter sent right away it equals created_at. For a scheduled letter it is the send date.
  • posted_at is when the letter was handed to Correios. It is the last record of a letter that was sent.
  • canceled_at is only set when the letter was canceled, and failed_at when it failed in production.

How to follow a letter

Use webhooks. CartaFlow POSTs to your URL on every status change, and when the letter is changed in the dashboard before production (letter.updated), with the full letter in the body, so you do not need to call the API afterwards.

EventWhen it is sent
letter.scheduledA letter was scheduled with send_date. It has not been charged yet.
letter.receivedA letter was charged and joined the production queue: right after creation or, if it was scheduled, on its send date. Covers letters created through the API and the dashboard.
letter.in_productionThe letter joined a print batch and can no longer be canceled.
letter.printedThe letter was printed and enveloped.
letter.postedThe letter was handed to Correios. It is the last event of a letter that was sent.
letter.canceledThe letter was canceled. Check cancellation_reason: requested when you canceled it, insufficient_balance when a scheduled letter could not be charged on its date.
letter.failedThe letter failed in production and will not be posted. The amount went back to the balance automatically. Check failure_reason.
letter.updatedThe letter was changed in the dashboard before production, without changing status: send date, address, file, variables, printing, Correios services or reference. data carries the letter as it is now. When the change altered the price of a scheduled letter, price has the new amount.

If you cannot receive webhooks, retrieve the letter with GET /v1/letters/{letter_id}. Production and posting take hours, so polling more than once an hour tells you nothing new. For many letters, use GET /v1/letters with the status filter instead of retrieving them one by one.

curl "https://api.cartaflow.com.br/v1/letters/ltr_8Kq2wX4mN7pR" \
  -H "Authorization: Bearer $CARTAFLOW_API_KEY"

Canceling

You can cancel a letter with POST /v1/letters/{letter_id}/cancel while it is scheduled or received. Nothing is printed.

  • A received letter has already been charged. The amount goes back to your balance right away, as a refund transaction.
  • A scheduled letter has not been charged yet, so there is nothing to refund.
  • From in_production on, the letter is part of a print batch. The API answers 409 with the code letter_not_cancelable, as it also does for a posted or failed letter.
  • Canceling a letter that is already canceled returns the same letter, with no error, so retrying the call is safe.
curl -X POST "https://api.cartaflow.com.br/v1/letters/ltr_8Kq2wX4mN7pR/cancel" \
  -H "Authorization: Bearer $CARTAFLOW_API_KEY"

Why a letter was canceled

Every canceled letter carries the reason in cancellation_reason. On other letters the field is null.

ValueWhat happened
requestedYou canceled it, through the API or the dashboard.
insufficient_balanceIt was a scheduled letter and, on the send date, the balance did not cover the price. Nothing was charged. See Scheduling.

Changing before production

Through the API, a letter does not change after it is created: to change something, cancel it and create another. In the dashboard, under Envios (Letters), people who can send letters can change one before production:

StatusWhat can change
scheduledEverything: the send date (or sending it right away, which charges it and moves it to received), address, file, variables, printing, Correios services and reference. No cost; the price is calculated again.
receivedOnly the address and the reference, which do not change the price. To change anything else, cancel it (the amount goes back to the balance) and create another.
in_production and laterNothing.

Every change sends the letter.updated event, with the letter as it is now and the same status. Sending a scheduled letter right away sends letter.received.

When production fails

If a letter cannot go out, because the file does not print, because it was damaged and could not be produced again, or because Correios refused it at posting, it moves to failed, a final status, and the amount goes back to your balance automatically, as a refund transaction. You receive the letter.failed event.

The reason is in failure_reason. On other letters the field is null.

ValueWhat happened
unprintable_documentThe file passed validation but could not be printed as it is.
damaged_in_productionThe letter was damaged in printing, folding or enveloping and could not be produced again.
refused_by_carrierCorreios refused the letter at posting.
otherAnother reason. Contact support from the dashboard for the details.

To send it again, create a new letter. Problems found before the charge, such as a PDF that breaks the rules or a postal code that does not exist, never reach failed: the API answers 422 at creation and nothing is charged.

Correios services

With no choice made, a letter goes as a simple letter ("carta simples"). With the postal_services field you add optional Correios services. Each one costs extra, with its own line in price. See Pricing and balance.

ValueServiceWhat changes
registeredRegistered letter ("carta registrada")The letter is posted with registration and gets a Correios tracking code, shown in tracking_code once it is posted.
return_receiptReturn receipt ("aviso de recebimento", AR)Correios returns a card signed by whoever received the letter to the sender printed on the envelope. Requires registered.
restricted_deliveryRestricted delivery ("mão própria", MP)Correios delivers only to the person named on the envelope. Requires registered.
Registered letter with return receipt
{
  "to": { "name": "Destinatário Exemplo", "postal_code": "01001-000", "number": "128" },
  "document": { "type": "url", "url": "https://arquivos.exemplo.com.br/notificacoes/contrato-5531.pdf" },
  "postal_services": ["registered", "return_receipt"],
  "reference": "contrato-5531"
}
  • return_receipt and restricted_delivery only work together with registered. Without it, the API answers 422 with requires_registered and nothing is created.
  • The return receipt goes back to the sender: the address you sent in from or, if you did not send one, the account’s default sender. Check that address before using AR. CartaFlow does not receive or scan the receipt.
  • In multipart/form-data, repeat the field once per service: postal_services[]=registered and postal_services[]=return_receipt.
  • The letter returns your choice in postal_services, always as a list: [] for a simple letter.

After posting

Once posted, the letter is with Correios and delivery follows the postal service. CartaFlow receives no further information about it, so posted is the last status of a letter that was sent. Delivery time depends on the postal service level and the distance to the destination, and CartaFlow does not guarantee it.

  • Registered letter: tracking_code carries the Correios tracking code, such as RA123456785BR, from posting on. Use it to follow the delivery with Correios.
  • Simple letter: there is no tracking after posting, and tracking_code is null.

When Correios cannot deliver a letter, it goes back to the sender address printed above the recipient. That is the address you sent in from or, if you did not send one, the account’s default sender. See Addresses in Brazil.

CartaFlow is not affiliated with Correios

CartaFlow prints, envelopes and posts letters through Correios, as any Correios customer does. It is not part of Correios.

The Letter object

The main fields of a letter. The full list, with the type and description of every field, is in Retrieve a letter.

FieldWhat it holds
idUnique identifier, starts with ltr_.
statusThe current step. See the status table above.
to and fromRecipient and sender, complete, as they are printed.
documentWhere the content came from: url, upload (multipart or POST /v1/uploads) or base64.
color, double_sided, address_placementHow the letter is printed. See Document and address area.
postal_servicesThe Correios services chosen, or [] for a simple letter.
pages and sheetsPages in your document and sheets of paper printed.
priceThe price, line by line. See Pricing and balance.
send_dateThe scheduled date, or null when the letter was sent right away.
cancellation_reasonWhy the letter was canceled, or null.
failure_reasonWhy the letter failed in production, or null.
tracking_codeThe Correios tracking code of a registered letter once posted, or null.
preview_urlLink to the final PDF, exactly as it will be printed.
reference and metadataYour own identifiers and data. See Metadata and reference.
status_transitionsWhen the letter reached each status.
created_atWhen the letter was created.

On this page