API for developers
Convert, compress, OCR and protect files from your own software. The API is part of the Business plan and includes 10,000 conversions a month. Create a key in your account.
How it works
Jobs are asynchronous. You create a job, upload the files straight to storage with the signed URLs you get back, start the job, then poll until it is done and download the results. Nothing is kept longer than your plan’s retention period, and you can delete a job at any time.
Authentication
Send the key in every request. Keys start with ff_live_; treat them like passwords. Revoke a key in your account and it stops working immediately.
Authorization: Bearer ff_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1. Create a job
action is an id from GET /v1/actions. List every file you are going to upload with its exact size in bytes. options depend on the action.
curl -X POST https://fileflint.app/v1/jobs \
-H "Authorization: Bearer $FILEFLINT_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "jpg-to-webp",
"files": [{ "name": "photo.jpg", "bytes": 482113, "contentType": "image/jpeg" }],
"options": { "quality": 80 }
}'{
"id": "cm1abc…",
"status": "awaiting_upload",
"expiresAt": "2026-10-30T12:00:00.000Z",
"uploads": [{
"fileId": "cm1def…",
"name": "photo.jpg",
"method": "PUT",
"url": "https://…signed…",
"headers": { "Content-Type": "image/jpeg" }
}]
}2. Upload the files
Send each file with PUT to its URL, with exactly the headers returned. The size must match what you declared.
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/jpeg" \
--data-binary @photo.jpg3. Start the job
Starting is what counts against your monthly allowance.
curl -X POST https://fileflint.app/v1/jobs/$JOB_ID/start \
-H "Authorization: Bearer $FILEFLINT_KEY"4. Poll and download
Poll every second or two. status goes queued, running, then done or failed. Download URLs are valid for one hour; ask again for fresh ones.
curl https://fileflint.app/v1/jobs/$JOB_ID -H "Authorization: Bearer $FILEFLINT_KEY"{
"id": "cm1abc…",
"action": "jpg-to-webp",
"status": "done",
"error": null,
"outputs": [{ "fileId": "…", "name": "photo.webp", "bytes": 201334, "url": "https://…signed…" }],
"expiresAt": "2026-10-30T12:00:00.000Z"
}A failed job has status: "failed" and an error code such as:
conversion_failed— the file is damaged or not what its extension says.pdf_password— the PDF is password-protected (or the password you sent is wrong).too_many_pages— more pages than the tool takes in one go (OCR: 150).timeout— the file took too long.
OCR
pdf-ocr makes a scanned PDF searchable, pdf-ocr-txt returns plain text; images have jpg-ocr-pdf, png-ocr-txt and so on. Set ocrLanguage to eng, pol, deu, pol+eng or deu+eng.
{ "action": "pdf-ocr", "files": [ … ], "options": { "ocrLanguage": "pol" } }PDF tools
protect-pdf—newPassword(required).unlock-pdf—currentPassword(leave empty for files that only restrict printing or editing).rotate-pdf—rotation:90,180or270.watermark-pdf—watermarkText,watermarkOpacity(10–80).number-pdf-pages—numberPosition,numberFormat.
Passwords are removed from our database as soon as the job finishes. Start a job within a few hours of creating it — a job left waiting for a day loses its passwords.
Batches
Put batch- in front of an action id (for example batch-jpg-to-webp) and send many files of the same type in one job. Every file gets the same settings; you get one ZIP with the results and a report.txt that lists what worked and what did not. A batch counts as one conversion per file. batchId in GET /v1/actions tells you which actions have one.
Other endpoints
GET /v1/actions— every action with its options, defaults and limits.GET /v1/usage— conversions used and left this month.DELETE /v1/jobs/:id— delete a job and its files right away.
Limits
- 10,000 conversions per calendar month (UTC), counted when a job starts. A merge counts as one; a batch as one per file.
- Up to 100 files per job and 5 GB per file.
- Request rate limits apply per address; a
429means slow down. - Errors are JSON:
{ "error": "code", "message": "…" }. Codes you may meet:invalid_api_key(401),plan_required(402),monthly_limit_reached(402),daily_limit_reached(402),invalid_optionsandoption_required(400).