Create an upload
First step to send a large PDF, up to 10 MB, that does not fit in one request (the body is limited to 4.5 MB, so multipart takes PDFs of up to 4 MB).
apiKeyAuthorizationBearer <token>API key in the Authorization: Bearer cf_live_... header. Create and revoke keys in the dashboard, under Desenvolvedores > Chaves de API (Developers > API keys).
Idempotency-Key?stringA unique value per operation, such as the invoice id in your system or a UUID. If you repeat the request with the same key within 24 hours, the API returns the first response instead of creating another object. Recommended on every POST. Up to 255 characters.
length <= 255application/json- body
Details of the PDF you are about to send. The response carries an upload_url you send the file to with a PUT; then use the upload’s id in a letter with document.type: upload.
filename*stringThe PDF’s file name, such as fatura-outubro.pdf. It shows in the letter’s document.filename and in the dashboard. From 1 to 255 characters.
1 <= length <= 255size*integerThe file size in bytes, from 1 to 10485760 (10 MB). Above that, the API answers 422 with out_of_range.
1 <= value <= 10485760The upload was created. Send the file to upload_url within 2 hours.
application/json- response
A place to send a large PDF before creating the letter. Send the file with a PUT to upload_url within 2 hours and use the id in a letter within 24 hours. Each upload belongs to your account and is good for one letter only.
id*stringUnique identifier of the upload. Use it as document.upload_id when creating the letter. Always starts with upl_.
^upl_[A-Za-z0-9]+$object*stringObject type. Always upload.
filename*stringThe file name, as you sent it.
size*integerThe file size in bytes, as you declared it.
upload_url*stringSigned HTTPS URL to send the file to. Send the PDF bytes in the body of a PUT, with the Content-Type: application/pdf header and no Authorization header: the signature is already in the URL. A 2xx response confirms the file arrived. It works for 2 hours (until upload_url_expires_at). Treat the URL as a secret and do not store it: it is not shown anywhere else.
uriupload_url_expires_at*stringUntil when upload_url accepts the file: 2 hours after creation. If the time runs out before you send it, create another upload.
date-timeexpires_at*stringUntil when the upload can be used in a letter: 24 hours after creation. After that, document.upload_id gets a 422 with upload_expired.
date-timecreated_at*stringWhen the upload was created.
date-timecurl -X POST "https://api.cartaflow.com.br/v1/uploads" \ -H "Authorization: Bearer $CARTAFLOW_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "filename": "fatura-outubro.pdf", "size": 7340032}'{ "id": "upl_6Np3Vx8Rk2Tq", "object": "upload", "filename": "fatura-outubro.pdf", "size": 7340032, "upload_url": "https://files.cartaflow.com.br/uploads/upl_6Np3Vx8Rk2Tq?token=4f8a2c91d7", "upload_url_expires_at": "2026-10-13T16:20:00Z", "expires_at": "2026-10-14T14:20:00Z", "created_at": "2026-10-13T14:20:00Z"}