Skip to content
ChatfuelSDK
ReferenceChatfuel API

Files and tasks

How a file gets into the Chatfuel API — REST upload, then a FileID a mutation can reference — the File lifecycle, and how a long-running job reports its progress.

GraphQL never accepts file bytes, so every file starts as a REST upload that hands back a FileID a mutation can then reference.

type File {
  id: FileID!
  url: String!
  type: FileType!
  """
  if the status is Expired - do not request any other fields of this file. The file does not exist
  """
  status: FileStatus!
  """in bytes"""
  size: Int
}

Uploading

Every endpoint is a POST with a multipart file field and the same Authorization: Bearer <token> header the GraphQL endpoint takes. fileType is one of Image, Video, Audio, Document.

EndpointWhat it is for
{base}/api/filestorage/upload/livechat?fileType=&botID=&contactID=Chat attachments.
{base}/api/filestorage/upload/bot?fileType=&botID=CSV imports, catalog images, specialist avatars.
{base}/api/filestorage/upload/plugin?...WhatsApp template header media, and flow-builder block media, where pluginID is the block element's id.
{base}/api/filestorage/upload/widget?...The web widget's avatar.
{base}/api/filestorage/upload/useraccount?...User profile pictures.

Upload failures mirror the GraphQL codes: a non-2xx response carries FileTooBig or FileContentTypeNotSupported in its body. The success shape is less settled — the SDK's helper accepts id, fileID or fileId, either at the top level or nested one level under file, result or data, because the endpoint's response key is not pinned by any documentation.

Expired means the file is gone

enum FileStatus {
  """the file was either deleted because it expired, or never existed."""
  Expired
  NotDownloaded
  DownloadInProgress
  Downloaded
  Failed
}

On Expired, stop: do not request and do not render any other field of that file. For a remote file whose bytes were never fetched, fileStartDownload(id:) asks the platform to fetch them, and file(id:) polls until the status reads Downloaded.

Tasks

A long-running job — a CSV contact export, a specialist's Google Calendar sync — returns a Task.

type Task {
  id: TaskID!
  """
  holds the status history of the process.
    If you need the current status - take the most recent one by date
  """
  statuses: [TaskStatus!]!
  """number of already completed points out of the total (totalPoints)"""
  completedPoints: Int!
  """
  the maximum number of points that have to be completed within this process.
    It is set when the process is created and never changes afterwards.
    The ratio of completedPoints to totalPoints shows the current progress of the process.
  """
  totalPoints: Int!
  data: TaskData!
  """
  after this date the process should be treated as failed by timeout (even if there is no explicit failed status)
  """
  deadline: Time!
}
FieldHow to read it
statusesA history, not a value. The current status is the entry with the latest startedAt — not statuses[0]. The types are Created, InProgress, Paused, Cancelled, Failed, Finished.
completedPoints / totalPointsApproximate. completedPoints can exceed totalPoints, and a task can finish before the two converge, so render progress defensively.
deadlineA wall-clock cutoff, not a hint.
dataA federated interface. Select __typename and the concrete type's fields — ... on CSVContactsExport { file { ... } }. An UnavailableTaskData branch means the caller has no access to that task, or it has been deleted.

Track a task with getTask(id:) polling or the taskUpdated(id:) subscription. Cancellation is not on Task: it lives in the domain that owns the job, as with csvContactExportCancel, and it is itself asynchronous — wait for a Cancelled status rather than assuming the call took effect.

A task past its deadline has failed, and it may never receive a Failed status to say so. A poller that only watches statuses waits forever on a job that timed out.

The three async patterns

PatternHow completion arrivesExamples
Task-trackedThe mutation returns a Task; you poll getTask or subscribe to taskUpdated.CSV contact export, Google Calendar sync.
Domain subscriptionThe mutation returns the entity or a Boolean; completion arrives on a subscription of its own.csvContactImportUpdated, whatsAppBusinessPhoneNumberUpdated, metaAdsSyncStateUpdated, fbPagesSyncStatusUpdated.
Timestamp pollingA fire-and-forget mutation, then poll a ...LastUpdatedAt field until it advances.whatsAppEntitiesStartRefetch, then whatsAppEntitiesLastUpdatedAt.

Which one applies is written in the mutation's return type and doc comment in the bundled schema.

On this page