一个 endpoint 把你的图片、视频或音频上传到我们的公开 R2 URL,然后把这个 URL 喂给任何 /v1 生成端点(图生图、视频参考、配音、唇同步等)。无需自己搭存储。
两种模式由请求的 Content-Type 自动区分。视频或较大的图片必须走模式 1。
POST /api/v1/files
Authorization: Bearer <API_KEY>
Content-Type: application/json
{
"filename": "ref.mp4",
"contentType": "video/mp4",
"fileSize": 12345678
}| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
| filename | 必填 | string | 原始文件名(用于推断后缀) |
| contentType | 必填 | string | MIME 类型,如 image/png、video/mp4、audio/mpeg |
| fileSize | 可选 | number | 字节数;传入会先校验大小上限 |
{
"code": 200,
"msg": "success",
"data": {
"uploadUrl": "https://<account>.r2.cloudflarestorage.com/apimodels/uploads/<userId>/1717...xxxx.png?X-Amz-Signature=...",
"publicUrl": "https://r2.apimodels.app/uploads/<userId>/1717...xxxx.png",
"expiresAt": "2026-05-30T09:30:00.000Z"
}
}uploadUrl 有效期 10 分钟;publicUrl 上传完成后立即可用,保留 7 天。
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: video/mp4" \
--data-binary @ref.mp4⚠️ PUT 时的 Content-Type 必须和申请时的 contentType 完全一致,否则 R2 签名校验会失败。
cURL
# 1) Request a presigned PUT URL
RESP=$(curl -s -X POST https://apimodels.app/api/v1/files \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"filename": "ref.png",
"contentType": "image/png",
"fileSize": '"$(wc -c < ref.png)"'
}')
UPLOAD_URL=$(echo "$RESP" | jq -r .data.uploadUrl)
PUBLIC_URL=$(echo "$RESP" | jq -r .data.publicUrl)
# 2) PUT the file body directly to R2 (no Vercel size limit)
curl -X PUT "$UPLOAD_URL" \
-H "Content-Type: image/png" \
--data-binary @ref.png
# 3) Use PUBLIC_URL in any /v1 generation endpoint
echo "Public URL: $PUBLIC_URL"Python
import requests, os
API_KEY = os.environ["API_KEY"]
with open("ref.png", "rb") as f:
data = f.read()
# 1) Request presigned URL
r = requests.post(
"https://apimodels.app/api/v1/files",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"filename": "ref.png",
"contentType": "image/png",
"fileSize": len(data),
},
)
upload_url = r.json()["data"]["uploadUrl"]
public_url = r.json()["data"]["publicUrl"]
# 2) PUT directly to R2
requests.put(upload_url, data=data, headers={"Content-Type": "image/png"})
# 3) public_url is your reference for any generation call
print("Public URL:", public_url)Node.js
import fs from 'node:fs/promises'
const API_KEY = process.env.API_KEY
const file = await fs.readFile('ref.png')
// 1) Request presigned URL
const r = await fetch('https://apimodels.app/api/v1/files', {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
filename: 'ref.png',
contentType: 'image/png',
fileSize: file.length,
}),
})
const { data: { uploadUrl, publicUrl } } = await r.json()
// 2) PUT to R2 directly
await fetch(uploadUrl, {
method: 'PUT',
headers: { 'Content-Type': 'image/png' },
body: file,
})
console.log('Public URL:', publicUrl)POST /api/v1/files
Authorization: Bearer <API_KEY>
Content-Type: multipart/form-data; boundary=...
(form field "file" with the raw bytes)| 字段 | 必填 | 类型 | 说明 |
|---|---|---|---|
| file | 必填 | binary | 表单文件字段;Content-Type 由 multipart 自动带出 |
{
"code": 200,
"msg": "success",
"data": {
"publicUrl": "https://r2.apimodels.app/uploads/<userId>/1717...xxxx.png"
}
}cURL
curl -X POST https://apimodels.app/api/v1/files \
-H "Authorization: Bearer $API_KEY" \
-F "file=@ref.png"Python
import requests, os
r = requests.post(
"https://apimodels.app/api/v1/files",
headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
files={"file": open("ref.png", "rb")},
)
print(r.json()["data"]["publicUrl"])Node.js
import fs from 'node:fs'
const form = new FormData()
form.append(
'file',
new Blob([fs.readFileSync('ref.png')], { type: 'image/png' }),
'ref.png',
)
const r = await fetch('https://apimodels.app/api/v1/files', {
method: 'POST',
headers: { 'Authorization': `Bearer ${process.env.API_KEY}` },
body: form,
})
console.log((await r.json()).data.publicUrl)把上传得到的 publicUrl 直接传给任何 /v1 端点的 image_url / video_url / images[] 字段:
# 1) Upload your reference photo
PUBLIC_URL=$(curl -s -X POST https://apimodels.app/api/v1/files \
-H "Authorization: Bearer $API_KEY" \
-F "file=@photo.jpg" | jq -r .data.publicUrl)
# 2) Pass it into an image-to-image call
curl -X POST https://apimodels.app/api/v1/images/generations \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"model\": \"nanobanana2/gemini-3.1-flash-image-preview\",
\"prompt\": \"Make it Studio-Ghibli-style\",
\"image_url\": \"$PUBLIC_URL\"
}"同样适用于 /v1/video/generations 的 video_url、唇同步的 video_url、配音的 audio_url 等。
错误的形状统一为 { "code": <status>, "msg": "..." }。
| HTTP | msg | 触发条件 |
|---|---|---|
| 400 | filename and contentType are required | JSON 模式缺字段 |
| 400 | Only image/, video/, or audio/ content types are accepted | MIME 不在允许列表 |
| 400 | File too large (max 100MB) / (max 10MB) | 超过对应类型的大小上限 |
| 400 | No file provided (expected form field "file") | multipart 缺 file 字段 |
| 400 | Invalid JSON body | JSON 解析失败 |
| 400 | Expected multipart/form-data or application/json | Content-Type 无法识别 |
| 401 | Invalid or missing API key | 未带 key / key 已禁用 |
| 500 | Storage not configured | R2 env 未配置(通常不会发生) |