Files & Collections

Managing Files

The Files API provides a complete set of operations for managing your files. If your files are publicly accessible, you can reference them directly by URL in chat conversations — see Attaching Files. For files that aren't publicly accessible, upload them using one of the methods described below.

You can also view and manage all of your uploaded files from the Files page on the xAI Console.


Uploading Files

You can upload files in several ways: from a file path, raw bytes, BytesIO object, or an open file handle.

Upload from File Path

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Upload a file from disk
file = client.files.upload("/path/to/your/document.pdf")

print(f"File ID: {file.id}")
print(f"Filename: {file.filename}")
print(f"Size: {file.size} bytes")
print(f"Created at: {file.created_at}")

Upload from Bytes

Python

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Upload file content directly from bytes
content = b"This is my document content.\nIt can span multiple lines."
file = client.files.upload(content, filename="document.txt")

print(f"File ID: {file.id}")
print(f"Filename: {file.filename}")

Upload from file object

Python

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Upload a file directly from disk
file = client.files.upload(open("document.pdf", "rb"), filename="document.pdf")

print(f"File ID: {file.id}")
print(f"Filename: {file.filename}")

Upload with Expiration (TTL)

Files default to permanent storage until you delete them. To have the platform automatically delete a file after a fixed window, set expires_after at upload time. This is useful for short-lived attachments, ephemeral session data, and compliance windows.

How it works

expires_after is set in seconds, measured from upload time. It must be between 3600 (1 hour) and 2592000 (30 days), inclusive. Omit the field to keep the file permanently.

The response includes expires_at, the absolute UTC timestamp at which the file will be deleted. Once that time passes, the file is gone: it no longer appears in list responses, retrieving its metadata or content returns not found, and it can no longer be referenced by id in chat attachments.

You can also delete the file manually at any time before its TTL elapses.

Multipart field ordering matters: expires_after must appear before the file field in the multipart body. Requests that send expires_after after file are rejected with 400.

import os
from datetime import timedelta
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Upload a file that will be auto-deleted in 24 hours.
# expires_after accepts an int (seconds) or a datetime.timedelta.
file = client.files.upload(
    "/path/to/document.pdf",
    expires_after=timedelta(hours=24),
)

print(f"File ID: {file.id}")
print(f"Expires at: {file.expires_at.ToDatetime()}")

Upload with Progress Tracking

Track upload progress for large files using callbacks or progress bars.

Custom Progress Callback

Python

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Define a custom progress callback
def progress_callback(bytes_uploaded: int, total_bytes: int):
    percentage = (bytes_uploaded / total_bytes) * 100 if total_bytes else 0
    mb_uploaded = bytes_uploaded / (1024 * 1024)
    mb_total = total_bytes / (1024 * 1024)
    print(f"Progress: {mb_uploaded:.2f}/{mb_total:.2f} MB ({percentage:.1f}%)")

# Upload with progress tracking
file = client.files.upload(
    "/path/to/large-file.pdf",
    on_progress=progress_callback
)

print(f"Successfully uploaded: {file.filename}")

Progress Bar with tqdm

Python

import os
from xai_sdk import Client
from tqdm import tqdm

client = Client(api_key=os.getenv("XAI_API_KEY"))

file_path = "/path/to/large-file.pdf"
total_bytes = os.path.getsize(file_path)

# Upload with tqdm progress bar
with tqdm(total=total_bytes, unit="B", unit_scale=True, desc="Uploading") as pbar:
    file = client.files.upload(
        file_path,
        on_progress=pbar.update
    )

print(f"Successfully uploaded: {file.filename}")

Listing Files

Retrieve a list of your uploaded files with pagination and sorting options.

Available Options

  • limit: Maximum number of files to return. If not specified, uses the server default of 100. Maximum is 100.
  • order: Sort order. Either "asc" (ascending) or "desc" (descending). Defaults to "desc".
  • sort_by: Field to sort by. Options: "created_at", "filename", or "size". Defaults to "created_at".
  • pagination_token: Pass the pagination_token returned by the previous response to fetch the next page. Omit it for the first page.

The response always includes a pagination_token. When the returned page is shorter than limit, you've reached the end of the list.

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# List files with pagination and sorting
response = client.files.list(
    limit=10,
    order="desc",
    sort_by="created_at"
)

for file in response.data:
    expires = file.expires_at.ToDatetime() if file.HasField("expires_at") else "never"
    print(f"File: {file.filename} (ID: {file.id}, Size: {file.size} bytes, Expires: {expires})")

Paginating Through All Files

The List endpoint returns at most limit files per call (capped at 100). To enumerate every file, keep calling the endpoint with the pagination_token from the previous response until the response returns fewer than limit items.

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Walk every page until the API returns a short page.
page_size = 100
token = None
all_files = []

while True:
    response = client.files.list(
        limit=page_size,
        order="desc",
        sort_by="created_at",
        pagination_token=token,
    )
    all_files.extend(response.data)
    if len(response.data) < page_size:
        break
    token = response.pagination_token

print(f"Total files: {len(all_files)}")

Getting File Metadata

Retrieve detailed information about a specific file.

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Get file metadata by ID
file = client.files.get("file-abc123")

print(f"Filename: {file.filename}")
print(f"Size: {file.size} bytes")
print(f"Created: {file.created_at}")
# expires_at is only set when the file was uploaded with expires_after
if file.HasField("expires_at"):
    print(f"Expires at: {file.expires_at.ToDatetime()}")

Getting File Content

Download the raw bytes of an uploaded file. The endpoint streams the response, so it works for files of any supported size without buffering the whole payload in memory at the API layer.

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Returns the complete file content as bytes.
content = client.files.content("file-abc123")

# Save to disk
with open("downloaded.pdf", "wb") as f:
    f.write(content)

print(f"Saved {len(content)} bytes")

Deleting Files

Remove files when they're no longer needed.

import os
from xai_sdk import Client

client = Client(api_key=os.getenv("XAI_API_KEY"))

# Delete a file
delete_response = client.files.delete("file-abc123")

print(f"Deleted: {delete_response.deleted}")
print(f"File ID: {delete_response.id}")

The File Object

Every Files API endpoint that returns metadata (Upload, List, Get Metadata) returns the same file object shape:

FieldTypeDescription
idstringUnique file identifier (e.g. file_a128090d-f0c9-4873-bd84-e499777e7417). Use this anywhere a file_id is expected, including chat attachments.
filenamestringOriginal filename you supplied at upload time.
bytesintegerFile size in bytes.
created_atintegerUpload time as a Unix timestamp (seconds).
expires_atinteger or nullUnix timestamp at which the file will be deleted. null for permanent files; set when the file was uploaded with expires_after.
objectstringAlways "file". Returned for OpenAI compatibility.
purposestringEchoes the purpose value sent at upload time. xAI does not enforce or interpret this field; it is stored for OpenAI SDK compatibility. Setting "assistants" is the conventional choice.

Limitations and Considerations

File Size Limits

  • Maximum file size: 48 MB per file
  • Processing time: Larger files may take longer to process

File Retention

  • Cleanup: Delete files when no longer needed to manage storage
  • Access: Files are scoped to your team/organization

Supported Formats

While many text-based formats are supported, the system works best with:

  • Structured documents (with clear sections, headings)
  • Plain text and markdown
  • Documents with clear information hierarchy

Supported file types include:

  • Plain text files (.txt)
  • Markdown files (.md)
  • Code files (.py, .js, .java, etc.)
  • CSV files (.csv)
  • JSON files (.json)
  • PDF documents (.pdf)
  • And many other text-based formats

Next Steps

Now that you know how to manage files, learn how to use them in chat conversations:


Last updated: May 1, 2026