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}")
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("XAI_API_KEY"),
base_url="https://api.x.ai/v1",
)
# Upload a file
with open("/path/to/your/document.pdf", "rb") as f:
file = client.files.create(
file=f,
purpose="assistants"
)
print(f"File ID: {file.id}")
print(f"Filename: {file.filename}")
import os
import requests
url = "https://api.x.ai/v1/files"
headers = {
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"
}
with open("/path/to/your/document.pdf", "rb") as f:
files = {"file": f}
data = {"purpose": "assistants"}
response = requests.post(url, headers=headers, files=files, data=data)
file_data = response.json()
print(f"File ID: {file_data['id']}")
print(f"Filename: {file_data['filename']}")
import OpenAI from "openai";
import fs from "fs";
const client = new OpenAI({
apiKey: process.env.XAI_API_KEY,
baseURL: "https://api.x.ai/v1",
});
// Upload a file
const file = await client.files.create({
file: fs.createReadStream("/path/to/your/document.pdf"),
purpose: "assistants",
});
console.log("File ID: " + file.id);
console.log("Filename: " + file.filename);
import fs from "fs";
const formData = new FormData();
formData.append("file", new Blob([fs.readFileSync("/path/to/your/document.pdf")]), "document.pdf");
formData.append("purpose", "assistants");
const response = await fetch("https://api.x.ai/v1/files", {
method: "POST",
headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` },
body: formData,
});
const file = await response.json();
console.log("File ID: " + file.id);
console.log("Filename: " + file.filename);
curl https://api.x.ai/v1/files \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-F file=@/path/to/your/document.pdf \\
-F purpose=assistants
Upload from Bytes
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
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.
[!WARNING]
Multipart field ordering matters:
expires_aftermust appear before thefilefield in the multipart body. Requests that sendexpires_afterafterfileare rejected with400.
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()}")
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("XAI_API_KEY"),
base_url="https://api.x.ai/v1",
)
# expires_after follows the OpenAI shape: an object anchored at "created_at".
with open("/path/to/document.pdf", "rb") as f:
file = client.files.create(
file=f,
purpose="assistants",
expires_after={"anchor": "created_at", "seconds": 86400}, # 24 hours
)
print(f"File ID: {file.id}")
print(f"Expires at: {file.expires_at}") # Unix seconds, 24h from now
import os
import requests
url = "https://api.x.ai/v1/files"
headers = {
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"
}
# expires_after MUST appear before file in the multipart body — see the note below.
with open("/path/to/document.pdf", "rb") as f:
response = requests.post(
url,
headers=headers,
data=[
("expires_after", "86400"), # 24 hours in seconds
("purpose", "assistants"),
],
files={"file": f},
)
file_data = response.json()
print(f"File ID: {file_data['id']}")
print(f"Expires at: {file_data['expires_at']}")
import OpenAI from "openai";
import fs from "fs";
const client = new OpenAI({
apiKey: process.env.XAI_API_KEY,
baseURL: "https://api.x.ai/v1",
});
const file = await client.files.create({
file: fs.createReadStream("/path/to/document.pdf"),
purpose: "assistants",
expires_after: { anchor: "created_at", seconds: 86400 }, // 24 hours
});
console.log("File ID: " + file.id);
console.log("Expires at: " + file.expires_at);
import fs from "fs";
const formData = new FormData();
// expires_after MUST be appended before the file field.
formData.append("expires_after", "86400"); // 24 hours in seconds
formData.append("purpose", "assistants");
formData.append(
"file",
new Blob([fs.readFileSync("/path/to/document.pdf")]),
"document.pdf",
);
const response = await fetch("https://api.x.ai/v1/files", {
method: "POST",
headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` },
body: formData,
});
const file = await response.json();
console.log("File ID: " + file.id);
console.log("Expires at: " + file.expires_at);
# -F fields are sent in declaration order.
# expires_after must come before file in the form body.
curl https://api.x.ai/v1/files \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-F expires_after=86400 \\
-F purpose=assistants \\
-F file=@/path/to/document.pdf
Upload with Progress Tracking
Track upload progress for large files using callbacks or progress bars.
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}")
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 thepagination_tokenreturned 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})")
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("XAI_API_KEY"),
base_url="https://api.x.ai/v1",
)
# List files
files = client.files.list()
for file in files.data:
print(f"File: {file.filename} (ID: {file.id})")
import os
import requests
url = "https://api.x.ai/v1/files"
headers = {
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"
}
response = requests.get(url, headers=headers)
files = response.json()
for file in files.get("data", []):
print(f"File: {file['filename']} (ID: {file['id']})")
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.XAI_API_KEY,
baseURL: "https://api.x.ai/v1",
});
// List files
const files = await client.files.list();
for (const file of files.data) {
console.log(\`File: \${file.filename} (ID: \${file.id})\`);
}
const response = await fetch("https://api.x.ai/v1/files", {
headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` },
});
const files = await response.json();
for (const file of files.data) {
console.log(\`File: \${file.filename} (ID: \${file.id})\`);
}
curl https://api.x.ai/v1/files \\
-H "Authorization: Bearer $XAI_API_KEY"
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)}")
import os
import requests
url = "https://api.x.ai/v1/files"
headers = {"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"}
page_size = 100
params = {"limit": page_size, "order": "desc", "sort_by": "created_at"}
all_files = []
while True:
response = requests.get(url, headers=headers, params=params).json()
all_files.extend(response.get("data", []))
if len(response.get("data", [])) < page_size:
break
params["pagination_token"] = response["pagination_token"]
print(f"Total files: {len(all_files)}")
const pageSize = 100;
const baseParams = { limit: String(pageSize), order: "desc", sort_by: "created_at" };
const allFiles = [];
let token;
while (true) {
const params = new URLSearchParams({ ...baseParams, ...(token ? { pagination_token: token } : {}) });
const response = await fetch(\`https://api.x.ai/v1/files?\${params}\`, {
headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` },
});
const page = await response.json();
allFiles.push(...page.data);
if (page.data.length < pageSize) break;
token = page.pagination_token;
}
console.log(\`Total files: \${allFiles.length}\`);
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()}")
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("XAI_API_KEY"),
base_url="https://api.x.ai/v1",
)
# Get file metadata
file = client.files.retrieve("file-abc123")
print(f"Filename: {file.filename}")
print(f"Size: {file.bytes} bytes")
# Unix seconds, or None if the file does not expire.
print(f"Expires at: {file.expires_at}")
import os
import requests
file_id = "file-abc123"
url = f"https://api.x.ai/v1/files/{file_id}"
headers = {
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"
}
response = requests.get(url, headers=headers)
file = response.json()
print(f"Filename: {file['filename']}")
print(f"Size: {file['bytes']} bytes")
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.XAI_API_KEY,
baseURL: "https://api.x.ai/v1",
});
// Get file metadata
const file = await client.files.retrieve("file-abc123");
console.log("Filename: " + file.filename);
console.log("Size: " + file.bytes + " bytes");
const response = await fetch("https://api.x.ai/v1/files/file-abc123", {
headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` },
});
const file = await response.json();
console.log("Filename: " + file.filename);
console.log("Size: " + file.bytes + " bytes");
curl https://api.x.ai/v1/files/file-abc123 \\
-H "Authorization: Bearer $XAI_API_KEY"
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")
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("XAI_API_KEY"),
base_url="https://api.x.ai/v1",
)
# Stream content straight to disk
client.files.content("file-abc123").write_to_file("downloaded.pdf")
import os
import requests
file_id = "file-abc123"
url = f"https://api.x.ai/v1/files/{file_id}/content"
headers = {"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"}
# Stream to disk so large files don't sit in memory
with requests.get(url, headers=headers, stream=True) as response:
response.raise_for_status()
with open("downloaded.pdf", "wb") as f:
for chunk in response.iter_content(chunk_size=1024 * 1024):
f.write(chunk)
import OpenAI from "openai";
import fs from "fs";
const client = new OpenAI({
apiKey: process.env.XAI_API_KEY,
baseURL: "https://api.x.ai/v1",
});
const response = await client.files.content("file-abc123");
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync("downloaded.pdf", buffer);
import fs from "fs";
const response = await fetch("https://api.x.ai/v1/files/file-abc123/content", {
headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` },
});
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync("downloaded.pdf", buffer);
curl https://api.x.ai/v1/files/file-abc123/content \\
-H "Authorization: Bearer $XAI_API_KEY" \\
--output downloaded.pdf
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}")
import os
from openai import OpenAI
client = OpenAI(
api_key=os.getenv("XAI_API_KEY"),
base_url="https://api.x.ai/v1",
)
# Delete a file
delete_response = client.files.delete("file-abc123")
print(f"Deleted: {delete_response.deleted}")
print(f"File ID: {delete_response.id}")
import os
import requests
file_id = "file-abc123"
url = f"https://api.x.ai/v1/files/{file_id}"
headers = {
"Authorization": f"Bearer {os.getenv('XAI_API_KEY')}"
}
response = requests.delete(url, headers=headers)
result = response.json()
print(f"Deleted: {result['deleted']}")
print(f"File ID: {result['id']}")
import OpenAI from "openai";
const client = new OpenAI({
apiKey: process.env.XAI_API_KEY,
baseURL: "https://api.x.ai/v1",
});
// Delete a file
const deleteResponse = await client.files.delete("file-abc123");
console.log("Deleted: " + deleteResponse.deleted);
console.log("File ID: " + deleteResponse.id);
const response = await fetch("https://api.x.ai/v1/files/file-abc123", {
method: "DELETE",
headers: { Authorization: \`Bearer \${process.env.XAI_API_KEY}\` },
});
const result = await response.json();
console.log("Deleted: " + result.deleted);
console.log("File ID: " + result.id);
curl -X DELETE https://api.x.ai/v1/files/file-abc123 \\
-H "Authorization: Bearer $XAI_API_KEY"
The File Object
Every Files API endpoint that returns metadata (Upload, List, Get Metadata) returns the same file object shape:
| Field | Type | Description |
|---|---|---|
bytes |
integer | File size in bytes. |
created_at |
integer | Upload time as a Unix timestamp (seconds). |
expires_at |
integer or null | Unix timestamp at which the file will be deleted. null for permanent files; set when the file was uploaded with expires_after. |
filename |
string | Original filename you supplied at upload time. |
id |
string | Unique file identifier (e.g. file_a128090d-f0c9-4873-bd84-e499777e7417). Use this anywhere a file_id is expected, including chat attachments. |
object |
string | Always "file". Returned for OpenAI compatibility. |
purpose |
string | Echoes 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