文件与集合
公共 URL
通过 Files API 上传的每个文件默认都存储在私有存储中 — 获取文件需要您的 API 密钥。公共 URL 将存储的文件转换为 xAI CDN 上的永久、可共享链接,任何人都可以打开 — 无需 API 密钥。
创建后,您仍可完全控制:
- 随时撤销:通过一次 API 调用立即使 URL 失效。
- 自动过期:通过设置
expires_after(1 小时至 30 天)或让 URL 继承文件自身的过期时间,使两者同时消失。
创建公共 URL 不会修改底层的私有文件,撤销它也不会删除文件 — 两者生命周期独立。
如果您需要访问控制(例如仅限登录用户),请保持文件私有,并通过您自己的后端使用经过身份验证的 GET /v1/files/{file_id}/content 端点来提供服务。
TIP
使用 Imagine API 生成图像或视频?您 可以通过 storage_options.public_url 在生成资源的同一请求中创建公共 URL。参见 Imagine → Files API 集成。
快速开始
import os
from xai_sdk import Client
client = Client(api_key=os.getenv("XAI_API_KEY"))
# 1. Upload (or reference an existing) file
file = client.files.upload("/path/to/diagram.png")
# 2. Create the public URL
resp = client.files.create_public_url(file.id)
print(resp.public_url)
# https://files-cdn.x.ai/<token>/file_abc123.png
# 3. When you're done sharing, revoke it
client.files.revoke_public_url(file.id)# 1. Upload (or reference an existing) file
FILE_ID=$(curl -s https://api.x.ai/v1/files \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-F purpose=assistants \\
-F file=@/path/to/diagram.png | jq -r '.id')
# 2. Create the public URL (empty JSON body uses defaults)
curl -s -X POST "https://api.x.ai/v1/files/$FILE_ID/public-url" \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{}'
# {"public_url":"https://files-cdn.x.ai/<token>/file_abc123.png"}
# 3. When you're done sharing, revoke
curl -s -X POST "https://api.x.ai/v1/files/$FILE_ID/public-url/revoke" \\
-H "Authorization: Bearer $XAI_API_KEY"WARNING
公共 URL 只能为已存在于您的 Files API 存储中的文件创建。您 无法在上传过程中创建公共 URL — 请先上传文件,然后调用 create_public_url (或在 Imagine 请求中使用 storage_options.public_url)。
过期行为
您可以在创建时通过 expires_after(以秒为单位)选择性地设置公共 URL 的过期时间。一旦截止时间过去,URL 将自动撤销 — 后续请求将返回 404,您无需进行后续的 API 调用来清理。底层文件不受影响,仍可通过经过身份验证的 Files API 访问。
URL 的实际过期时间来自两个输入:您在创建时是否传递了 expires_after,以及底层文件是否有自己的过期时间。
- 文件无过期时间,未设置
expires_after— URL 永不过期。它将一直存在,直到您明确调用revoke_public_url或删除底层文件。 - 文件无过期时间,
expires_after设置为N— URL 将在 N 秒后自动撤销。文件本身不受影响。 - 文件在时间
T有自己的过期时间,未设置expires_after— URL 继承文件的过期时间。两者在T时同时消失。 - 文件在时间
T有自己的过期时间,expires_after设置为N— URL 将在 N 秒后自动撤销。N必须 ≤ 文件的剩余生命周期,否则请求将被拒绝。
expires_after 必须在 3600 秒(1 小时) 和 2592000 秒(30 天) 之间。公共 URL 的寿命不可能超过其文件 — 请求的 expires_after 大于文件的剩余生命周期将被拒绝。
import os
from datetime import timedelta
from xai_sdk import Client
client = Client(api_key=os.getenv("XAI_API_KEY"))
file = client.files.upload("/path/to/photo.png")
# 1. Indefinite: omit expires_after on a file with no expiry.
# Must call revoke_public_url to explicitly revoke the public URL.
resp = client.files.create_public_url(file.id)
assert not resp.HasField("expires_at")
# 2. URL-bound: pass expires_after as int seconds or a timedelta
resp = client.files.create_public_url(file.id, expires_after=timedelta(hours=24))
print(f"Expires at: {resp.expires_at.seconds}")
# 3. Inherited: file has its own expiration, omit expires_after on the URL
ttl_file = client.files.upload(
b"\\x89PNG\\r\\n\\x1a\\n" + b"\\x00" * 32,
filename="short-lived.png",
expires_after=timedelta(hours=2),
)
resp = client.files.create_public_url(ttl_file.id)
# resp.expires_at matches the file's expires_at# 1. Indefinite — file has no expiry.
# Must call POST /public-url/revoke to explicitly revoke.
curl -s -X POST "https://api.x.ai/v1/files/$FILE_ID/public-url" \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-H "Content-Type: application/json" -d '{}'
# {"public_url":"..."} <- no expires_at field
# 2. URL-bound (24h)
curl -s -X POST "https://api.x.ai/v1/files/$FILE_ID/public-url" \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-H "Content-Type: application/json" \\
-d '{"expires_after": 86400}'
# {"public_url":"...","expires_at":1755600000}
# 3. Inherited: upload with file expiration, then create with no expires_after
FILE_ID=$(curl -s https://api.x.ai/v1/files \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-F expires_after=7200 \\
-F purpose=assistants \\
-F file=@/path/to/photo.png | jq -r '.id')
curl -s -X POST "https://api.x.ai/v1/files/$FILE_ID/public-url" \\
-H "Authorization: Bearer $XAI_API_KEY" \\
-H "Content-Type: application/json" -d '{}'
# {"public_url":"...","expires_at":<matches file expiry>}幂等性
一个文件一次最多只能有一个活动的公共 URL。对已有公共 URL 的文件调用 create_public_url 会返回现有 URL 而不创建新的 — 可以安全地重复调用。
如果在后续调用中传递不同的 expires_after,现有 URL 的过期时间将就地更新。URL 中的令牌保持不变。
import os
from xai_sdk import Client
client = Client(api_key=os.getenv("XAI_API_KEY"))
file_id = "file_abc123"
# First call creates the URL
resp1 = client.files.create_public_url(file_id, expires_after=86400) # 1 day
# Second call returns the same URL, no re-upload
resp2 = client.files.create_public_url(file_id, expires_after=86400)
assert resp1.public_url == resp2.public_url
# Calling again with a different expires_after extends/shortens the expiry
# while keeping the same URL
resp3 = client.files.create_public_url(file_id, expires_after=604800) # 7 days
assert resp1.public_url == resp3.public_url
assert resp3.expires_at.seconds > resp1.expires_at.seconds撤销公共 URL
撤销会使 URL 无效并从文件的元数据中清除。原始文件不受影响,继续通过经过身份验证的端点可访问。
import os
from xai_sdk import Client
client = Client(api_key=os.getenv("XAI_API_KEY"))
# Revoke a public URL
resp = client.files.revoke_public_url("file_abc123")
print(f"Revoked: {resp.revoked}") # True
print(f"Was URL: {resp.public_url}") # the URL that just stopped working
# The file itself is still available via authenticated endpoints
file = client.files.get("file_abc123")
print(file.filename)
# Revoke is idempotent and safe to call on:
# - files that never had a public URL (returns revoked=False)
# - files whose URL was already revoked (returns revoked=False)
# - files that have been deleted
client.files.revoke_public_url("file_abc123") # no-op, no errorcurl -s -X POST "https://api.x.ai/v1/files/file_abc123/public-url/revoke" \\
-H "Authorization: Bearer $XAI_API_KEY"
# {"id":"file_abc123","revoked":true,"public_url":"https://files-cdn.x.ai/..."}
# Calling again is safe — returns revoked=false
curl -s -X POST "https://api.x.ai/v1/files/file_abc123/public-url/revoke" \\
-H "Authorization: Bearer $XAI_API_KEY"
# {"id":"file_abc123","revoked":false}撤销是全部或无的。 一个文件一次只能有一个公共 URL,因此撤销会使所有拥有该链接的人都无法访问。如果链接泄露给不当方,唯一的补救措施是撤销并创建新 URL — 新 URL 将有新的令牌,而旧 URL 将永久失效。
查找具有公共 URL 的文件
get_file 和 list_files 总是返回文件的当前公共 URL 状态。对于每个具有活动公共 URL 的文件,public_url 和 public_url_expires_at 字段都会被填充。
您还可以在 list_files 上使用 filter 参数来查找有或没有活动公共 URL 的文件:
import os
from xai_sdk import Client
client = Client(api_key=os.getenv("XAI_API_KEY"))
# All files that currently have a public URL
with_url = client.files.list(filter="public_url != null")
for f in with_url.data:
print(f.id, f.filename)
# All files that do not currently have a public URL
without_url = client.files.list(filter="public_url = null")# URL-encode the filter
curl -s "https://api.x.ai/v1/files?filter=public_url%20!%3D%20null" \\
-H "Authorization: Bearer $XAI_API_KEY"限制
- 最大文件大小:50 MiB。 更大的文件仍可通过经过身份验证的 Files API 访问,但不能公开。
- 受限制的内容类型。 只有以下类型符合条件:
image/png(.png)image/jpeg(.jpg)video/mp4(.mp4)application/pdf(.pdf)
- 过期时间必须在 1 小时至 30 天之间,且公共 URL 的寿命不能超过其文件。
- 删除文件会自动撤销公共 URL。 文件删除后(手动或通过过期),您无法保持公共 URL 有效。
- 每个文件一次只能有一个公共 URL。
create_public_url是幂等的,重复调用返回相同的 URL。撤销后,下一次create_public_url会发布新令牌 — 任何先前共享的 URL 将永久无效。 - 每个团队最多 1,000 个活动公共 URL。 在创建新 URL 之前,请撤销不再需要的 URL。
相关
- 管理文件 — 上传、列出、检索和删除文件。
- Imagine → Files API 集成 — 将存储的文件引用为 Imagine 输入,持久化生成的资源,并在单个请求中创建公共 URL。
- Files API 参考 — 完整的 REST 端点文档。