Files and Tasks API Reference
Upload files and read file URLs, and follow long-running jobs such as contact exports and Google Calendar syncs with getTask and taskUpdated.
Last updated on
Files and tasks are the two helpers that the rest of the Chatfuel Public API relies on. Files are images, videos, audio and documents: you upload them over HTTP and pass their IDs to mutations, and you read files that contacts sent through their URLs. Tasks represent long-running jobs, such as a CSV contact export or a Google Calendar sync, that you start with a mutation and then follow until they finish.
How to upload a file
Uploads go to a separate HTTP endpoint as multipart/form-data, with the same Authorization: Bearer <token> header as GraphQL requests:
| Endpoint | Use it for | Lowest role |
|---|---|---|
POST /api/filestorage/upload/bot?botID=…&fileType=… | Images and videos in flows, catalog images, specialist photos, CSV files for contact import | Editor |
POST /api/filestorage/upload/livechat?botID=…&contactID=…&fileType=… | Attachments in chat messages | Agent |
POST /api/filestorage/upload/plugin?botID=…&pluginID=…&fileType=… | Header media of a filled WhatsApp template; pluginID is the FilledWhatsAppTemplateID | Agent |
POST /api/filestorage/upload/widget?widgetID=…&fileType=Image | The website widget avatar | Editor |
All of them live on https://panel.chatfuel.com. fileType is Image, Video, Audio or Document. An optional extension parameter sets the file extension without a dot, such as jpg or pdf:
curl -s "https://panel.chatfuel.com/api/filestorage/upload/bot?botID=$BOT_ID&fileType=Document&extension=csv" \
-H "Authorization: Bearer $CHATFUEL_VIRTUAL_USER_TOKEN" \
-F "[email protected]"The response describes the stored file (some fields are left out here):
{
"id": "6f1c…",
"type": "Document",
"status": "Downloaded",
"contentType": "text/csv",
"size": 48213,
"extension": "csv",
"createdAt": "2026-10-06T10:15:00Z",
"deleteAfter": "2026-10-06T12:15:00Z"
}Pass id as a FileID, for example to csvContactImportCreate, goodsProductCreate or whatsappAttachmentMessageSend. A file that is not used within two hours, shown in deleteAfter, is deleted.
How to read a file
type Query {
# A file by ID: { id url type status size }.
file(id: FileID!): File!
}
type Mutation {
# Starts downloading a file that is stored with an external service, such as media a contact sent on a channel.
fileStartDownload(id: FileID!): File!
}status tells you whether the file is ready:
Downloaded:urlpoints to the file.NotDownloaded: the file is still with the external service. CallfileStartDownloadand read the file again later.DownloadInProgress: Chatfuel is fetching it.Failed: the download failed.Expired: the file was deleted after its retention period, or never existed.
Store the file ID rather than the URL, and read url again when you need the file.
How to follow a task
Operations that take a while return a Task immediately and continue in the background: csvContactExportStartBySegment, csvContactExportStartByIDsList and specialistStartGoogleCalendarSync. A task belongs to its bot, and any virtual user of the bot can read it (Agent).
type Query {
getTask(id: TaskID!): Task!
}
type Subscription {
taskUpdated(id: TaskID!): Task!
}query Export($taskID: TaskID!) {
getTask(id: $taskID) {
id
completedPoints
totalPoints
deadline
statuses { type startedAt } # Created, InProgress, Paused, Cancelled, Failed, Finished
data {
__typename
... on CSVContactsExport { file { url status } }
}
}
}statuses is the history of the task; the last entry is the current status. Progress is completedPoints out of totalPoints. When a contact export reaches Finished, data.file is the CSV to download. Prefer the taskUpdated subscription over polling; if you poll, wait a few seconds between calls.
Common issues
The upload returns 400
A required query parameter such as botID, contactID, widgetID or fileType is missing or wrong, or the body is not multipart/form-data. Send the file as the first part of the form, as curl -F does.
"FileDoesNotExist" when using an uploaded file
The file was uploaded more than two hours ago and never used, so it was deleted. Upload it again right before the mutation that uses it.
A task stays in "InProgress"
Large exports and syncs can take several minutes. Check completedPoints to see that it is moving, and deadline for the latest time the task is expected to finish.