GraphQL Files

Use the Files API to query media, upload binaries, register remote media, edit metadata, move managed files between public and private storage, and publish file versions. File IDs are UUIDs.

Start with PagibleAI GraphQL API for authentication, CSRF and JSON scalar handling. See Frontend Access Control before exposing private media to visitors.

File fields

File

Field
Type
Meaning
id
ID!
File UUID
disk
FileDisk!
Logical public or private storage
mime
String
Detected MIME type
lang
String
ISO language code
name
String
Display name
description
JSON
JSON-encoded descriptions keyed by language
transcription
JSON
JSON-encoded transcriptions keyed by language
path
String!
Managed path or remote URL
previews
JSON!
JSON-encoded generated preview paths
editor
String!
Last editor
created_at / updated_at
String!
Creation and update times
deleted_at
String
Soft-deletion time
byelements / bypages
[Element!]! / [Page!]!
Content using the file
byversions
[Version!]!
Versions using the file
byversions_count
Int!
Number of referencing versions
latest
Version
Latest file version
versions
[Version!]!
Version history
changed
JSON
Conflict details after an overlapping save

Query one file

query FileDetail($id: ID!) {
  file(id: $id) {
    id
    disk
    mime
    lang
    name
    path
    previews
    description
    transcription
    byversions_count
    changed
    latest { id published publish_at }
  }
}

Query a file list

query Images($first: Int!, $page: Int!) {
  files(
    filter: {mime: ["image/jpeg", "image/png", "image/webp"], lang: "en"}
    publish: DRAFT
    trashed: WITHOUT
    sort: [{column: NAME, order: ASC}]
    first: $first
    page: $page
  ) {
    data {
      id
      disk
      mime
      name
      path
      previews
      latest { id published }
    }
    paginatorInfo {
      currentPage
      lastPage
      total
    }
  }
}

Filter and sort files

Effective FileFilter fields

Field
Type
Matches
id
[ID!]
Any listed file UUID
mime
[String!]
One or more exact MIME types
lang
String
ISO language code
editor
String
Last editor
any
String
Indexed name, description and transcription text

The current resolver applies the fields listed above. MIME values are exact, so list each accepted type; use any to search file names, descriptions and transcriptions. publish and trashed are arguments of the files query, not fields inside FileFilter. Supported sort columns are ID, NAME, MIME, LANG, EDITOR and BYVERSIONS_COUNT.

FileInput fields

FileInput

Field
Type
Purpose
lang
String
ISO language code
name
String
Display name
path
String
Remote URL or managed storage path
previews
JSON
JSON-encoded preview paths
description
JSON
JSON-encoded descriptions keyed by language
transcription
JSON
JSON-encoded transcriptions keyed by language

Publication state is stored on versions, not in FileInput. The previews, description and transcription JSON scalars accept and return JSON-encoded strings. Use pubFile to publish or schedule the latest file version.

Upload a file

Uploads follow the GraphQL multipart request specification. Send null for each upload variable in the operations JSON, map multipart file fields to those variables, and include the binary parts.

mutation UploadFile(
  $file: Upload!
  $preview: Upload
  $input: FileInput
  $disk: FileDisk!
) {
  addFile(
    file: $file
    preview: $preview
    input: $input
    disk: $disk
  ) {
    id
    disk
    mime
    name
    path
    previews
    latest { id published }
  }
}
{
  "file": null,
  "preview": null,
  "disk": "private",
  "input": {
    "name": "Product manual",
    "lang": "en",
    "description": "{\"en\":\"Installation and maintenance instructions\"}"
  }
}

Upload with curl

After completing the login workflow from the overview, reuse its cms.cookies file and CSRF token. Do not set Content-Type yourself; curl adds the multipart boundary.

BASE='https://your-domain.example'
ENCODED=$(awk '$6 == "XSRF-TOKEN" {print $7}' cms.cookies | tail -1)
TOKEN=$(php -r 'echo urldecode($argv[1]);' "$ENCODED")

curl --silent --show-error \
  --cookie cms.cookies \
  --cookie-jar cms.cookies \
  --header 'Accept: application/json' \
  --header "X-XSRF-TOKEN: $TOKEN" \
  --form 'operations={"query":"mutation UploadFile($file: Upload!, $preview: Upload, $input: FileInput, $disk: FileDisk!) { addFile(file: $file, preview: $preview, input: $input, disk: $disk) { id disk mime name path previews latest { id published } } }","variables":{"file":null,"preview":null,"disk":"private","input":{"name":"Product manual","lang":"en","description":"{\"en\":\"Installation and maintenance instructions\"}"}}}' \
  --form 'map={"0":["variables.file"],"1":["variables.preview"]}' \
  --form '0=@./manual.pdf;type=application/pdf' \
  --form '1=@./manual-preview.jpg;type=image/jpeg' \
  "$BASE/graphql"
{
  "data": {
    "addFile": {
      "id": "018f2567-8508-7a62-9309-41708fbfe5fa",
      "disk": "private",
      "mime": "application/pdf",
      "name": "Product manual",
      "path": "018f2567-8508-7a62-9309-41708fbfe5fa/manual.pdf",
      "previews": "{\"1024\":\"018f2567-8508-7a62-9309-41708fbfe5fa/preview.webp\"}",
      "latest": {
        "id": "0198d332-19f6-7616-b3a0-a570d62e1b89",
        "published": false
      }
    }
  }
}

The configured upload size and MIME allowlist are enforced for the main file and preview. disk defaults to public; choose private when access-controlled delivery is required.

Register a remote file

For a remote URL, omit the upload and put the URL in input.path. PagibleAI validates the URL and MIME type and may generate local previews.

mutation AddRemoteFile {
  addFile(input: {
    name: "Company logo"
    lang: "en"
    path: "https://assets.example.com/logo.svg"
    description: "{\"en\": \"Company logo\"}"
  }) {
    id
    mime
    path
    previews
    latest { id published }
  }
}

Save metadata or replace media

saveFile accepts partial metadata plus optional replacement file and preview uploads. Pass the version ID you originally read as latestId for conflict detection.

mutation SaveFile($id: ID!, $latestId: ID!, $input: FileInput!) {
  saveFile(id: $id, latestId: $latestId, input: $input) {
    id
    name
    description
    transcription
    changed
    latest { id published }
  }
}
{
  "id": "018f2567-8508-7a62-9309-41708fbfe5fa",
  "latestId": "0198d332-19f6-7616-b3a0-a570d62e1b89",
  "input": {
    "name": "Product manual, second edition",
    "description": "{\"en\":\"Updated installation and maintenance instructions\"}"
  }
}
{
  "data": {
    "saveFile": {
      "id": "018f2567-8508-7a62-9309-41708fbfe5fa",
      "name": "Product manual, second edition",
      "description": "{\"en\":\"Updated installation and maintenance instructions\"}",
      "transcription": "{}",
      "changed": null,
      "latest": {
        "id": "0198d40a-c567-7d9f-b04f-abd353f71982",
        "published": false
      }
    }
  }
}

Update several files

bulkFile applies one partial FileInput to up to 1,000 files and creates a draft version for every successful item.

mutation SetFileLanguage($ids: [ID!]!) {
  bulkFile(id: $ids, input: {lang: "en"}) {
    ids
    latest
    data
    failed
  }
}

Move between public and private storage

relocateFile moves managed binaries, previews and stored versions to another logical disk. You can relocate up to 100 files at once. Remote hot-linked files cannot be relocated.

mutation ProtectFiles($ids: [ID!]!) {
  relocateFile(id: $ids, disk: private) {
    id
    disk
    path
  }
}

Moving to private requires file view and save permission; moving to public requires file view and publish permission.

Deliver private files

A private file’s raw path is not a public URL. PagibleAI’s frontend creates a page-aware asset URL, checks the visitor’s access to the referencing page and returns a private, no-store response. Remote disks use temporary URLs whose expiry is capped by the page-access token. A custom headless frontend must preserve that authorization step; never expose the storage path directly.

Publish files

mutation PublishFiles($ids: [ID!]!, $at: DateTime) {
  pubFile(id: $ids, at: $at) {
    id
    name
    latest { id published publish_at }
  }
}

Omit at to publish now or provide a DateTime to schedule the latest versions.

Trash, restore and purge

mutation TrashFiles($ids: [ID!]!) {
  dropFile(id: $ids) { id name deleted_at }
}

mutation RestoreFiles($ids: [ID!]!) {
  keepFile(id: $ids) { id name deleted_at }
}

mutation PurgeFiles($ids: [ID!]!) {
  purgeFile(id: $ids) { id }
}

Trash is reversible. Purge permanently removes database records and managed storage paths, so inspect bypages, byelements, byversions or byversions_count before purging.

Troubleshoot file operations

Common file problems

Symptom
Likely cause
Resolution
HTTP 419 on upload
Missing CSRF header
Refresh the session and send the decoded XSRF token
Upload variable is null
The multipart map does not target the variable
Map each file field to variables.file or variables.preview
File type is not allowed
Detected MIME type is outside cms.upload.mimetypes
Check the actual binary type and upload policy
File or preview is too large
The configured upload limit was exceeded
Resize or compress it, or review the server policy
Invalid image
The binary is unreadable or exceeds the pixel limit
Validate the image and dimensions before uploading
Remote file rejected
URL validation, bounded fetch or MIME validation failed
Use an allowed HTTPS URL serving the expected type
Private relocation rejected
The file is remote or the caller lacks target-disk permission
Use a managed file and check file:view plus save/publish permission
changed is not null
Another editor saved after latestId
Re-read, merge metadata and retry
File still unavailable publicly
A draft was saved but not published
Review the latest version and call pubFile