---
title: "Files and Tasks API Reference"
description: "Upload files and read file URLs, and follow long-running jobs such as contact exports and Google Calendar syncs with getTask and taskUpdated."
canonical_url: https://chatfuel.com/docs/public-api/files-and-tasks
markdown_url: https://chatfuel.com/docs/public-api/files-and-tasks.md
last_updated: 2026-10-06
lang: en
site: https://chatfuel.com/docs
llms_txt: https://chatfuel.com/llms.txt
---

# 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.

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 [#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`:

```bash
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 "file=@contacts.csv"
```

The response describes the stored file (some fields are left out here):

```json
{
  "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 [#how-to-read-a-file]

```graphql
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`: `url` points to the file.
* `NotDownloaded`: the file is still with the external service. Call `fileStartDownload` and 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 [#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**).

```graphql
type Query {
  getTask(id: TaskID!): Task!
}

type Subscription {
  taskUpdated(id: TaskID!): Task!
}
```

```graphql
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 [#common-issues]

### The upload returns 400 [#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 [#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" [#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.
