影片 API 完整調用規範
88API 統一影片生成介面。
本頁是 88API 對客戶開放的統一影片生成規範,適用於 88API 提供的各類影片模型。客戶只需從自己的 API Key 可見的模型清單取得 model ID,再使用本頁的統一 API 即可。
目前所有影片任務共用「查詢模型 → 提交 → 輪詢 → 下載」流程。不同帳號看到的模型 ID 可能不同,各模型支援的時長、比例、解析度與參考素材數量也可能不同;請勿把某個模型的能力直接套用到其他模型。
更新於 2026-10-10。各品牌模型的專屬參數與範例已拆分為獨立頁面,請見下方各品牌呼叫規範。建議流程:先呼叫
GET /v1/models取得目前 Key 可用的模型 ID;已有可用的 HTTPS 素材可直接引用;本機素材先上傳 → 提交生成 → 輪詢取得結果 URL → 播放、下載或作為下一輪的參考素材。上傳成功不代表模型一定支援該素材類型;模型能力與儲存能力是兩回事。
統一串接規則:先以
GET /v1/models回傳的精確id填入model,再用POST /v1/videos建立任務,保存回應中的id,並透過GET /v1/videos/{id}輪詢。新串接請勿使用舊的/v1/video/generations,不要依賴task_id,也不要把callback_url當成所有模型都支援的功能;需要穩定相容時,一律採用輪詢。
1. 統一串接的最低規則
如果同一套用戶端需要串接多個影片模型,只要固定下列流程:
- 以目前的 API Key 請求
GET /v1/models。 - 從回傳結果中選擇客戶實際具備權限的模型
id;不要把模型廣場名稱、舊名稱或其他帳號看到的名稱寫死成全域設定。 - 以同一套
POST /v1/videos請求格式提交任務。 - 只用回應中的公開
id查詢任務;不要解析或拼接任何其他任務 ID。 - 透過完成回應中的
url、video_url或result_url取得影片。
建議使用的通用欄位如下:
| 用途 | 建議欄位 | 說明 |
|---|---|---|
| 模型 | model | 必須是目前 Key 從 /v1/models 取得的精確模型 ID |
| 文字 | prompt | 純文字生成影片通常為必填;能否留空取決於模型 |
| 時長 | duration 或 seconds | 二擇一,單位為秒;優先使用 duration |
| 比例 | ratio 或 aspect_ratio | 建議用於設定畫面比例;實際可用值以目標模型的能力為準 |
| 參考圖片 | images | 建議使用公開的 HTTPS 網址或已上傳的 assets.88api.ai URL |
| 參考影片 | metadata.referenceVideos | 僅在目標模型支援時使用 |
| 參考音訊 | metadata.referenceAudios | 僅在目標模型支援時使用 |
| 首尾影格 | metadata.firstFrame、metadata.lastFrame | 必須同時遵守目標模型的首尾影格與素材互斥規則 |
上表是多數模型通用的寫法。部分品牌的欄位不同(例如萬相的首影格、尾影格和參考素材建議使用 media 陣列,無法識別的素材欄位會回傳 400),請以各品牌呼叫規範為準。
size 是部分模型與舊版用戶端使用的相容欄位。新用戶端應優先使用 ratio 或 aspect_ratio,並依目標模型的能力說明選擇實際的值。
本頁後續範例中的 <MODEL_ID>,都代表依上述步驟從 /v1/models 取得的真實模型 ID,並不是要求所有客戶使用同一個固定字串。
2. API 速查
| 用途 | 方法與路徑 | 說明 |
|---|---|---|
| 取得模型 | GET https://api.88api.ai/v1/models | 回傳目前 API Key 可見的模型 ID;以回傳結果為準 |
| 提交生成 | POST https://api.88api.ai/v1/videos | 提交文字與參考素材,回傳任務 id |
| 查詢任務 | GET https://api.88api.ai/v1/videos/{id} | 查詢狀態、進度與錯誤 |
| 申請素材上傳 | POST https://api.88api.ai/v1/media/uploads | 傳送檔案摘要、位元組數與 MIME,取得短效上傳憑證 |
| 上傳素材二進位檔 | PUT {upload_url} | 使用回傳的專用上傳標頭,不要傳送 API Key |
| 取得影片 | GET {url} | 優先使用完成回應中的結果 URL,不要自行拼接路徑 |
| 舊內容入口 | GET https://api.88api.ai/v1/videos/{id}/content | 已封存影片的相容重新導向;不是所有結果通用的下載方式 |
| 終態回呼 | 提交時設定 callback_url | 僅限支援回呼的型號;其餘請使用輪詢 |
請求標頭
Authorization: Bearer sk-你的API金鑰
Content-Type: application/json
Accept: application/jsonAPI 金鑰必須保存在伺服器端,不得寫進瀏覽器、小程式或 App 的前端套件。
| 操作 | 驗證方式 |
|---|---|
| 建立、查詢任務;申請上傳憑證 | Authorization: Bearer ...,只傳給 api.88api.ai API |
| 上傳檔案 | 原樣使用 headers 中的 X-Media-Upload-Token 與 Content-Type |
| 讀取公開媒體 | assets.88api.ai 網址不需要 Bearer、Cookie 或登入 |
可匿名讀取不等於可匿名上傳,也不會公開任務詳情。取得公開媒體 URL 的人可以在有效期限內讀取檔案;請勿把 URL 當成嚴格的隱私隔離機制。不要把自己的 API Key 轉送給媒體網址、官方結果網址或重新導向的目標。
先取得目前帳號可用的模型 ID
模型 ID 並非所有帳號都相同。用戶端首次串接或定期更新模型清單時,請先執行:
curl 'https://api.88api.ai/v1/models' \
--header 'Authorization: Bearer sk-xxxx'從回應中的 data[].id 選擇模型,並把該值原樣填入後續 POST /v1/videos 的 model 欄位。不要依模型顯示名稱自行拼出 ID,也不要以為其他帳號或舊文件中的模型名稱在目前帳號一定可用。
{
"object": "list",
"data": [
{
"id": "<MODEL_ID>",
"object": "model",
"owned_by": "88api"
}
]
}3. 標準提交請求
最簡文字生成影片請求
curl --request POST 'https://api.88api.ai/v1/videos' \
--header 'Authorization: Bearer sk-xxxx' \
--header 'Content-Type: application/json' \
--data-raw '{
"model": "<MODEL_ID>",
"prompt": "雨夜城市中的銀色跑車,低角度跟拍,霓虹倒影,電影感",
"duration": 8,
"ratio": "16:9"
}'duration 也可以改用字串形式的 seconds:
{
"model": "<MODEL_ID>",
"prompt": "日出時的海岸空拍,雲層緩緩移動",
"seconds": "8",
"ratio": "16:9"
}通用請求欄位
| 欄位 | 型別 | 必填 | 說明 |
|---|---|---|---|
model | string | 是 | 目前 API Key 透過 GET /v1/models 取得的精確模型 ID |
prompt | string | 視情況 | 文字提示詞;僅部分模型在提供參考素材時允許留空 |
negative_prompt | string | 否 | 多參考模型的負面提示詞;Veo 也可寫成 metadata.negativePrompt |
duration | integer | 否 | 影片時長,單位為秒;與 seconds 二擇一 |
seconds | string | 否 | 字串形式的影片時長,例如 "8" |
ratio | string | 否 | 建議使用的畫面比例欄位,例如 16:9、9:16 |
aspect_ratio | string | 否 | ratio 的相容別名;實際可用值以目標模型的能力為準 |
size | string | 否 | 相容欄位;新串接不要依賴它傳遞比例 |
resolution | string | 否 | 僅在目標模型支援時使用,例如 480p、720p、1080p、4k |
image | string | 否 | 單張參考圖片 URL |
images | string[] | 否 | 參考圖片 URL 陣列,建議用法 |
video | string | 否 | 單段參考影片 URL;Gemini Omni 必須使用這個頂層欄位 |
videos | string[] | 否 | 參考影片陣列;其他多參考模型使用 metadata.referenceVideos |
seed | integer | 否 | 隨機種子 |
generateAudio / generate_audio | boolean | 否 | 在支援的模型上同步生成音訊;僅在模型能力允許時使用 |
camera_control | object | 否 | 鏡頭控制;僅在對應模型明確支援時使用 |
callback_url | string | 否 | 僅在目標模型明確支援回呼時使用;新串接預設不要傳送 |
metadata | object | 否 | 參考影片、音訊、首尾影格等擴充欄位 |
如何指定解析度
建立任務的 API 都相同,但不同模型選擇解析度的方式可能不同。請先以 GET /v1/models 回傳的模型 ID 與模型能力說明為準。
固定解析度模型:以模型 ID 選擇解析度
部分模型已在模型名稱或模型 ID 中固定輸出規格。客戶應先從 GET /v1/models 取得目前帳號實際可用的 ID,再直接選擇對應規格的模型:
{
"model": "<FIXED_RESOLUTION_MODEL_ID>",
"prompt": "城市夜景中,汽車緩緩駛過街道",
"duration": 8,
"ratio": "16:9"
}對固定解析度模型而言,resolution 無法臨時改變輸出規格。即使用戶端帶上 resolution,也不要把它當成覆寫模型能力的方法。
可選解析度模型:使用 resolution 欄位
部分模型可能支援多種解析度,此時請在請求中傳入小寫的 resolution:
{
"model": "<MULTI_RESOLUTION_MODEL_ID>",
"prompt": "城市夜景中,汽車緩緩駛過街道",
"duration": 8,
"resolution": "720p",
"ratio": "16:9"
}實際可用的解析度與取值,仍以目前 API Key 的 /v1/models、模型說明及伺服器端驗證為準。若用戶端需要相容多個模型,可以保留 resolution 欄位:支援此欄位的模型會用它選擇輸出規格,固定規格的模型則以 model 為準。請勿使用 quality、vquality 或自行修改模型名稱來繞過模型能力限制;不支援的組合會回傳 400。
4. 參考圖片、影片與音訊
3.1 參考圖片
多張圖片一律使用頂層 images 陣列:
{
"model": "<MODEL_ID>",
"prompt": "保持人物的臉部、服裝與配色一致,在海邊緩步行走,電影級柔光",
"duration": 10,
"ratio": "16:9",
"images": [
"https://cdn.example.com/character-front.jpg",
"https://cdn.example.com/character-side.jpg"
]
}單張圖片也可以使用 image 或 input_reference,但新串接建議一律使用 images 陣列。
3.2 參考影片
能力表中支援多段參考影片的模型,請放在 metadata.referenceVideos:
{
"model": "<MODEL_ID>",
"prompt": "參考鏡頭節奏與運鏡,但保持主體外觀不變",
"duration": 8,
"ratio": "16:9",
"images": ["https://cdn.example.com/subject.jpg"],
"metadata": {
"referenceVideos": [
"https://cdn.example.com/camera-motion.mp4"
]
}
}3.3 參考音訊
能力表中支援參考音訊的模型,請放在 metadata.referenceAudios:
{
"model": "<MODEL_ID>",
"prompt": "人物依照參考音訊的節奏演唱,口型自然",
"duration": 10,
"ratio": "16:9",
"images": ["https://cdn.example.com/singer.jpg"],
"metadata": {
"referenceAudios": [
"https://cdn.example.com/voice-reference.mp3"
]
}
}MiniMax H3 的參考圖片不要用頂層 images,請依 MiniMax 影片 API 規範使用 metadata.referenceImages。
3.4 多參考模型的混合素材
{
"model": "<MODEL_ID>",
"prompt": "使用參考圖的產品外觀、參考影片的鏡頭節奏與參考音訊的聲音氛圍,製作科技廣告",
"duration": 12,
"ratio": "16:9",
"images": [
"https://cdn.example.com/product-front.jpg",
"https://cdn.example.com/product-detail.jpg"
],
"metadata": {
"referenceVideos": [
"https://cdn.example.com/motion-reference.mp4"
],
"referenceAudios": [
"https://cdn.example.com/sound-reference.mp3"
]
}
}同一類素材請勿同時使用多個別名欄位。例如不要同時提交頂層 images 與 metadata.referenceImages;多個相容欄位同時存在時,閘道只會採用其中一組,不保證合併。
3.5 素材 URL 要求
- 參考影片與音訊請使用可匿名下載的公開 HTTPS URL。
blob:、本機路徑、data:video/...都不是通用的參考影片協定;本機檔案請依下一節先上傳。 - URL 不能依賴 Cookie、瀏覽器登入狀態、Referer 或自訂請求標頭。
- 不能使用
localhost、私有 IP、Docker 服務名稱或只有你的內部網路才能存取的位址。 - URL 在整個任務生成期間都必須有效,建議有效期限不少於 60 分鐘。
- 圖片建議使用 JPG、PNG 或 WebP;影片建議 MP4/MOV;音訊建議 MP3/WAV。
- 影片建議每段不超過 50 MB,音訊建議每段不超過 15 MB;素材過大可能在下載或審核階段失敗。
- 引用第三方素材前,請確認已取得必要的著作權、肖像權與使用授權。
素材頁面打得開,不代表影片位元組可以下載:目標必須回傳實際的媒體檔案,而不是 HTML 分享頁。URL 可用也不代表其編碼、時長或尺寸符合目標模型的要求。Google 影片模型的圖片還可以使用 Base64 或檔案上傳,請見 Google 影片 API 規範;參考影片仍只接受 URL。
3.6 本機素材上傳:先申請,再 PUT
這個 API 提供暫存媒體空間,不會生成影片、轉碼、壓縮或自動擷取影格。
第一步:在伺服器端申請上傳憑證。
POST https://api.88api.ai/v1/media/uploads
Authorization: Bearer sk-xxxx
Content-Type: application/json{
"size": 1234567,
"mime_type": "video/mp4",
"sha256": "<檔案原始位元組的SHA-256,以不含padding的Base64URL編碼>"
}| 欄位 | 規則 |
|---|---|
size | 原始檔案的位元組數,整數,1–100,000,000;不是 Base64 字串長度 |
mime_type | 必須與實際檔案格式及上傳時的 Content-Type 一致 |
sha256 | 將 SHA-256 的 32 位元組摘要做 Base64URL 編碼,不帶 =;不是 64 位的十六進位字串 |
可上傳的類型:video/mp4、video/webm、video/quicktime;audio/mpeg、audio/wav、audio/ogg、audio/mp4、audio/flac;image/png、image/jpeg、image/webp、image/gif。上傳上限不等於模型的參考素材上限,仍須符合目標模型更嚴格的限制。
HTTP 200 回應範例(尖括號為預留位置,不是可直接使用的真實值):
{
"url": "https://assets.88api.ai/media/reference-media/<object-id>.mp4",
"upload_url": "https://assets.88api.ai/media/reference-media/<object-id>.mp4",
"method": "PUT",
"headers": {
"Content-Type": "video/mp4",
"X-Media-Upload-Token": "<scoped-upload-token>"
},
"expires_at": 1789373400
}這裡的 expires_at 是 上傳憑證的到期時間(Unix 秒,約 10 分鐘),不是檔案的保存期限;此時的 url 也不代表檔案已上傳完成。憑證只允許寫入指定的檔案,無法存取整個儲存貯體。
第二步:在憑證到期前上傳原始二進位檔。 原樣使用回應中的 upload_url、method 與 headers:
# 以下變數取自申請憑證的回應;請勿把 API_KEY 傳給上傳網址。
curl --request PUT "$UPLOAD_URL" \
--header 'Content-Type: video/mp4' \
--header "X-Media-Upload-Token: $UPLOAD_TOKEN" \
--data-binary @reference.mp4這不是 multipart/form-data,不使用 -F,也不是 JSON Base64。必須傳送與申請時一致的 Content-Length、MIME 與檔案位元組;瀏覽器可以直接傳送 File/Blob,由瀏覽器產生 Content-Length。伺服器端的串流用戶端也必須提供正確的長度,不要使用長度未知的 chunked 上傳。
HTTP 201 代表上傳完成,回傳 url、size、mime_type、expires_at。這次的 expires_at 才是素材的到期時間(Unix 秒,自該物件上傳起算 30 天)。確認成功後,再把 url 填入目標模型要求的參考欄位。瀏覽器應由自家後端申請憑證後直接上傳,不能在前端暴露長期有效的 API Key。
同一個上傳網址不允許覆寫:重複 PUT 會回傳 409,請重複使用已上傳成功的網址;遇到不確定結果的網路中斷時,先以匿名 HEAD 檢查該 URL,不要馬上重新申請新物件。上傳與引用都不會產生新的生成任務。
5. 支援模型的首尾影格模式
首影格與尾影格放在 metadata.firstFrame 與 metadata.lastFrame:
下例適用於支援這些欄位的多參考模型。Veo 與 Gemini Omni 同樣接受 metadata.firstFrame 與 metadata.lastFrame,其他寫法請見 Google 影片 API 規範。
{
"model": "<MODEL_ID>",
"prompt": "從清晨空曠的廣場平順轉場到夜晚燈火亮起的同一構圖",
"duration": 10,
"ratio": "16:9",
"metadata": {
"firstFrame": "https://cdn.example.com/start.jpg",
"lastFrame": "https://cdn.example.com/end.jpg"
}
}規則:
lastFrame不能單獨使用,必須同時提供firstFrame。- 大多數支援首尾影格的模型,不允許首尾影格與一般參考圖片/影片/音訊混用。
- 模型能力表標示為「互斥」時,請在首尾影格與一般參考素材之間擇一。
6. 目前影片模型能力表
下列表格說明已整理的公開模型能力,並非客戶請求時的固定模型 ID。實際請求必須使用目前 API Key 從 /v1/models 取得的 id。不同帳號可能看到不同的模型 ID;只要使用統一的 /v1/videos 協定,用戶端無須了解伺服器端如何選擇模型。
各品牌呼叫規範
不同品牌的參數寫法與素材欄位不完全相同,串接前請先閱讀對應的品牌頁:
| 品牌頁 | 模型 |
|---|---|
| Seedance 官方版 | seedance-2.5官方版、seedance-2.0官方版、seedance-2.0-fast官方版、seedance-2.0-mini官方版 |
| SD 雲廠商版 | SD2.5、SD2.0 |
| Seedance 官轉 | Seedance 2.0 Mini(多解析度)、Seedance 2.0(多解析度)、Seedance 2.0 Fast(多解析度)、Seedance 2.5(多解析度) |
veo-3.1、veo-3.1-fast、gemini-omni-flash、gemini-omni-flash-1.1 | |
| 可靈 Kling | kling-3.0-turbo |
| MiniMax | minimax-h3(同 minimax_h3) |
| 萬相 Wan | wan3.0-video、wan3.0-video-prime |
| Grok | grok-imagine-video、grok-imagine-video-1.5 |
模型能力總表
| 序號 | 模型能力/公開名稱 | 時長 | 比例 | 輸出 | 圖/影片/音訊上限 | 首尾影格 | 音訊控制 |
|---|---|---|---|---|---|---|---|
| 1 | seedance-2.5官方版 | 4–30 秒,預設 4 秒 | 16:9 9:16 1:1 4:3 3:4 21:9 | 720P | 30 / 10 / 10 | 支援,與一般素材互斥 | 無法設定 |
| 2 | seedance-2.0官方版 | 4–15 秒,預設 4 秒 | 同上 | 720P | 9 / 3 / 3 | 支援,與一般素材互斥 | 無法設定 |
| 3 | seedance-2.0-fast官方版 | 4–15 秒,預設 4 秒 | 同上 | 720P | 9 / 3 / 3 | 支援,與一般素材互斥 | 無法設定 |
| 4 | seedance-2.0-mini官方版 | 4–15 秒,預設 5 秒 | 同上 | 480P/720P,預設 480P | 9 / 3 / 3 | 模型說明未列出首尾影格模式 | 不提供生成音訊開關 |
| 5 | SD2.5 | 4–30 秒 | 必須指定:16:9 9:16 1:1 4:3 3:4 21:9 | 480P/720P/1080P,預設 480P | 30 / 10 / 10 | 支援,與一般素材互斥 | 支援 generate_audio |
| 6 | SD2.0 | 4–15 秒 | 1:1(預設) 21:9 16:9 9:16 3:4 4:3 | 480P/720P/1080P/4K,預設 480P | 9 / 3 / 3,三類合計最多 12 | 支援,與一般素材互斥 | 無法設定 |
| 7 | Seedance 2.0 Mini(多解析度) | 4–15 秒;支援 -1,預設 5 秒 | adaptive(預設) 16:9 4:3 1:1 3:4 9:16 21:9 | 480P/720P | 9 / 3 / 3 | 支援,與一般素材互斥 | 預設帶音訊,可關閉 |
| 8 | Seedance 2.0(多解析度) | 4–15 秒;支援 -1,預設 5 秒 | 同上 | 480P/720P/1080P/4K | 9 / 3 / 3 | 支援,與一般素材互斥 | 預設帶音訊,可關閉 |
| 9 | Seedance 2.0 Fast(多解析度) | 4–15 秒;支援 -1,預設 5 秒 | 同上 | 480P/720P | 9 / 3 / 3 | 支援,與一般素材互斥 | 預設帶音訊,可關閉 |
| 10 | Seedance 2.5(多解析度) | 4–30 秒;支援 -1,預設 -1(自動) | 同上 | 480P/720P/1080P | 30 / 10 / 10 | 支援,與一般素材互斥 | 預設帶音訊,可關閉 |
| 11 | veo-3.1-fast | 4/6/8 秒,參考圖固定 8 秒,延長每次增加 7 秒 | 16:9 9:16 | 720P/1080P/4K | 3 / 0 / 0 | 支援首影格、首尾影格與參考圖 | 原生音訊,可用 generate_audio 關閉 |
| 12 | veo-3.1 | 4/6/8 秒,參考圖固定 8 秒,延長每次增加 7 秒 | 16:9 9:16 | 720P/1080P/4K | 3 / 0 / 0 | 支援首影格、首尾影格與參考圖 | 原生音訊,可用 generate_audio 關閉 |
| 13 | gemini-omni-flash | 3–10 秒 | 16:9 9:16 | 720P | 10 / 1 / 0 | 支援首影格、首尾影格 | 不支援 |
| 14 | gemini-omni-flash-1.1 | 3–10 秒,延長每次增加約 10 秒 | 16:9 9:16 | 720P/1080P/4K | 10 / 3 / 0 | 支援首影格、首尾影格 | 不支援 |
| 15 | kling-3.0-turbo | 4–15 秒 | 16:9 9:16 1:1 | 720P/1080P/2K/4K,預設 720P | 30(含首尾影格)/ 10 / 0 | 支援,可與參考圖並用 | 支援 generate_audio |
| 16 | minimax-h3 | 4–15 秒,預設 5 秒 | 16:9(預設) 9:16 1:1 4:3 3:4 21:9 | 768P/1080P/2K(超解析度),預設 768P | 9 / – / 3 | 支援,與一般素材互斥 | 成品自帶音軌,無法設定 |
| 17 | wan3.0-video | 2–30 秒,預設 5 秒;支援 -1 | adaptive(預設) 16:9 9:16 1:1 4:3 3:4 21:9 | 480P/720P/1080P,預設 1080P | 10 / 5 / 5(使用 media 陣列) | 支援,與一般素材互斥 | 無法設定 |
| 18 | wan3.0-video-prime | 同上 | 同上 | 同上 | 同上 | 同上 | 無法設定 |
| 19 | grok-imagine-video | 1–15 秒,預設 8 秒 | 16:9 9:16 1:1 4:3 3:4 3:2 2:3(使用 aspect_ratio) | 480P/720P | 1 / 0 / 0 | 不支援 | 不支援 |
| 20 | grok-imagine-video-1.5 | 1–15 秒,預設 8 秒 | 同上 | 480P/720P/1080P | 1 / 0 / 0 | 不支援 | 不支援 |
表中序號從 1 開始,只是為了方便閱讀,不是請求參數。表中的公開名稱與能力系列也僅供對照;實際呼叫時必須使用目前 API Key 從
/v1/models回傳的精確id,不要自行拼接名稱或推測對應關係。
模型專屬規則
各品牌的欄位差異很大,以下是最容易出錯的幾點,完整規則請見上方各品牌頁:
- 萬相
wan3.0-video*的首影格、尾影格和參考素材建議放在media陣列;也接受metadata.firstFrame/lastFrame/referenceImages/referenceVideos/referenceAudios(含底線寫法)、頂層firstFrame/first_frame/lastFrame/last_frame和頂層images(第 1 張首影格、第 2 張尾影格,最多 2 張),都會轉換為media。無法識別的素材欄位會回傳 400。 - Grok 的
aspect_ratio與ratio等效,同時填寫多個比例欄位時值必須一致;最多 1 張輸入圖片。 minimax-h3的參考圖片使用metadata.referenceImages,首尾影格使用metadata.firstFrame/lastFrame;頂層images的含義會隨分配的線路而不同,請勿依賴。480P、4K 已下架。- Veo 與 Gemini Omni 的參考影片使用頂層
video/videos,不使用metadata.referenceVideos。 - Seedance 官轉也接受單數欄位
image、input_reference、video、audio作為參考素材,同一素材重複填寫只計一次;size與ratio、aspect_ratio或resolution衝突時回傳 400。該組模型還支援虛擬人像庫、2.5 樣片、尾影格、聯網搜尋、取消排隊任務和官方任務 ID,見 Seedance 官轉。 SD2.5必須明確指定比例,不支援auto。- Seedance 官方版、
SD2.5、SD2.0與kling-3.0-turbo每個系列只有一個模型名稱,以resolution選擇規格並依規格計費;未傳時使用該系列最低規格,不支援的規格回傳 400。先前帶有規格後綴的舊名稱(如SD2.5 720P、SD2.0 4K)仍可呼叫,但固定為名稱中的規格,已不在模型廣場顯示;可靈帶規格後綴的舊名稱已下架。
7. 提交回應
提交成功後會立即回傳公開的任務 ID:
{
"id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"object": "video",
"model": "<MODEL_ID>",
"status": "queued",
"progress": 0,
"created_at": 1788249600
}請保存 id。標準 API 不保證回傳 task_id,新串接必須使用 id。
HTTP 200 代表「任務已受理」,不代表影片已生成完成。
8. 輪詢任務
curl 'https://api.88api.ai/v1/videos/task_xxxxxxxxxxxxxxxxxxxxxxxx' \
--header 'Authorization: Bearer sk-xxxx'統一狀態
status | 意義 | 用戶端動作 |
|---|---|---|
queued | 已受理,排隊中 | 繼續等待 |
in_progress | 生成中 | 繼續等待 |
completed | 已完成 | 讀取回傳的 url,播放、下載或再次引用 |
failed | 已失敗 | 讀取 error.code 與 error.message |
unknown | 狀態未知 | 短暫重試,若持續出現請聯絡客服 |
完成回應範例:
{
"id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"object": "video",
"model": "<MODEL_ID>",
"status": "completed",
"progress": 100,
"created_at": 1788249600,
"completed_at": 1788250200,
"url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4",
"video_url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4",
"result_url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4"
}失敗回應範例:
{
"id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"object": "video",
"model": "<MODEL_ID>",
"status": "failed",
"progress": 100,
"error": {
"code": "video_generation_failed",
"message": "影片生成失敗"
}
}輪詢策略
- 提交後等待 3–5 秒再進行第一次查詢。
- 建議每 10–15 秒查詢一次,不要每秒輪詢。
- 互動式用戶端可採用 15 分鐘的等待上限,伺服器端可持久保存任務 ID 後繼續查詢或接收回呼。用戶端停止等待,不代表任務失敗、取消或退款。
- 任務處於
queued或in_progress期間,請勿重複提交同一任務,否則可能重複計費。 - 同時設定回呼時,輪詢可作為備援機制。
單次 HTTP 請求逾時、用戶端總等待時間與伺服器端任務期限是不同的概念。不要把 15 分鐘寫成伺服器端必定終止的保證,也不要只憑 progress=100 判斷成功;請以 status 為準。頁面或網路恢復後,可以繼續查詢原任務。
9. 回呼(Webhook)
本節僅適用於明確支援回呼的型號。Google 影片模型(Veo、Gemini Omni)以及其他未明確支援回呼的模型請使用輪詢,不要設定 callback_url。
提交時設定
{
"model": "<MODEL_ID>",
"prompt": "賽博龐克城市中的無人機空拍",
"duration": 8,
"size": "16:9",
"callback_url": "https://api.customer.example/webhooks/88api/video"
}callback_url 必須:
- 是可從公開網路存取的 HTTP(S) URL,正式環境強烈建議使用 HTTPS;
- 不超過 2048 個字元;
- 不能指向私有 IP、
localhost、鏈路本地位址或受限制的連接埠; - 能在 15 秒內回傳任一
2xx回應。
回呼只會在終態時傳送:
video.completedvideo.failed
回呼請求標頭
Content-Type: application/json
User-Agent: NewAPI-Task-Callback/1.0
X-NewAPI-Event: video.completed
X-NewAPI-Delivery: evt_task_xxx_completed
X-NewAPI-Timestamp: 1788250200
X-NewAPI-Signature: sha256=<hex-hmac>完成事件
{
"id": "evt_task_xxxxxxxxxxxxxxxxxxxxxxxx_completed",
"type": "video.completed",
"created_at": 1788250200,
"data": {
"task_id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"model": "<MODEL_ID>",
"status": "completed",
"progress": "100%",
"output_url": "https://assets.88api.ai/media/task-videos/2026/09/<object-key>.mp4",
"created_at": 1788249600,
"completed_at": 1788250200
}
}失敗事件
{
"id": "evt_task_xxxxxxxxxxxxxxxxxxxxxxxx_failed",
"type": "video.failed",
"created_at": 1788250200,
"data": {
"task_id": "task_xxxxxxxxxxxxxxxxxxxxxxxx",
"model": "<MODEL_ID>",
"status": "failed",
"progress": "100%",
"error": "影片生成失敗",
"created_at": 1788249600,
"completed_at": 1788250200
}
}驗證回呼簽章
簽章金鑰是提交該任務時使用的完整 API Key(包含 sk- 前綴)。簽章原文為:
X-NewAPI-Timestamp + "." + 原始請求主體位元組Node.js 驗證範例:
import crypto from "node:crypto";
import express from "express";
const app = express();
// 必須先保留原始請求主體,再解析 JSON。
app.use(
express.json({
verify: (req, _res, buffer) => {
req.rawBody = buffer;
},
}),
);
app.post("/webhooks/88api/video", (req, res) => {
const timestamp = req.header("X-NewAPI-Timestamp") || "";
const timestampNumber = Number(timestamp);
if (
!Number.isFinite(timestampNumber) ||
Math.abs(Date.now() / 1000 - timestampNumber) > 300
) {
return res.status(401).send("stale timestamp");
}
const received = (req.header("X-NewAPI-Signature") || "").replace(
/^sha256=/,
"",
);
const secret = process.env.API_KEY; // 完整的 sk-xxxx
const signed = Buffer.concat([
Buffer.from(`${timestamp}.`, "utf8"),
req.rawBody,
]);
const expected = crypto
.createHmac("sha256", secret)
.update(signed)
.digest("hex");
const valid =
received.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected));
if (!valid) return res.status(401).send("invalid signature");
// 以 X-NewAPI-Delivery 或 req.body.id 做冪等去重。
console.log(req.body.type, req.body.data.task_id);
return res.sendStatus(204);
});回呼重試與冪等
- 回呼逾時、發生網路錯誤或回傳非
2xx時,88API 會以指數退避重試。 - 單次請求逾時為 15 秒,最多嘗試 8 次,退避上限為 15 分鐘。
- 同一事件可能被投遞多次。用戶端必須以
X-NewAPI-Delivery或事件id做冪等去重。 - 建議拒絕與本機時間相差超過 5 分鐘的回呼,以降低重放攻擊風險。
- 建議先驗證簽章、保存事件並立即回傳
2xx,耗時的業務邏輯放進自己的非同步佇列。
10. 取得影片檔案
任務進入 completed 後,優先使用查詢回傳的 url;相容用戶端可退而讀取 video_url/result_url,回呼則使用 data.output_url。這些欄位是伺服器端交付的結果,請勿從任務 ID 或內部 ID 自行組出媒體路徑。
# RESULT_URL 原樣取自完成回應,請勿向媒體伺服器傳送 API Key。
curl --fail --location "$RESULT_URL" --output result.mp4說明:
- 用戶端應允許 HTTP 3xx 重新導向,
curl需要加上--location。 - 本站封存的結果使用
https://assets.88api.ai/media/...匿名網址;符合安全直連條件的官方結果會保留原始 URL,不會強制改成本站網域。 - 其他無法直接公開或無法明確對應的產出,可能仍會回傳帶有存取權限參數的相容網址。請完整保留伺服器回傳的 URL 與必要參數,不要自行刪除參數或替換網域;也不要替 assets 網址額外加上查詢參數(會回傳 400)。
- 舊的
/v1/videos/{id}/content只為已封存影片提供 307 相容重新導向,不應視為官方直連網址或所有產出的必經入口;回傳 404 時請重新查詢任務取得實際結果網址,不要盲目重新生成。 - 回呼中的
output_url是不透明的結果網址,可能有有效期限;請勿解析其網域或路徑結構。 - 不要拼接、保存或依賴任何其他任務 ID;只使用提交回應回傳的公開
id。 - 若需要長期保存成品,請在完成後下載到自己的物件儲存空間。
9.1 保存、播放與跨模型引用
- 本站上傳的素材與封存影片,自各自物件上傳起保存 30 天;重複讀取、查詢舊任務或重複引用都不會延長期限,也不會重新上傳一份。官方結果 URL 依其來源本身的有效期限處理,不保證 30 天。
- 沒有簽章參數、無須登入,不代表會永久保存;檔案到期後回傳 410,被生命週期規則清除後可能回傳 404。任務記錄仍在,也不代表二進位檔案仍然存在。
- 公開媒體支援 GET、HEAD、單段 Range 與瀏覽器跨來源讀取。可讀取
X-Media-Expires-At(Unix 秒);Range 成功時通常回傳 206。快取不會延長原本的到期時間,也不保證各地區下載速度相同。 - Veo 生成的結果可以作為其他支援參考影片的模型的輸入,前提是網址仍然有效,且格式、尺寸、時長符合目標模型的要求。直接把結果 URL 填入該模型的參考欄位即可,無須先下載再上傳;Veo 本身只在延長影片時接受輸入影片,不支援參考影片。
{
"model": "<MODEL_ID>",
"prompt": "保持參考影片的主體與動作,延續鏡頭",
"duration": 4,
"ratio": "16:9",
"metadata": {
"referenceVideos": ["<上一個任務回傳的完整HTTPS結果URL>"]
}
}11. JavaScript 完整輪詢範例
需要 Node.js 22 以上;請在伺服器端設定 API_KEY、MODEL_ID 與 REFERENCE_FILE(MP4 檔案路徑)。MODEL_ID 應取自目前 API Key 的 GET /v1/models 回應。設定 TASK_ID 可直接接續舊任務,不會重新上傳或生成。此範例會建立一次付費生成,最後只印出下一輪的請求主體,不會自動發起第二次生成。為方便閱讀,範例會把檔案讀入記憶體;大量處理大型檔案時請限制並行數。
// video-api-example.mjs — Node.js 22+, run with API_KEY, MODEL_ID, and REFERENCE_FILE.
import { readFile, stat } from "node:fs/promises";
import { createHash } from "node:crypto";
const apiKey = process.env.API_KEY;
if (!apiKey) throw new Error("Set API_KEY on your server");
const baseUrl = "https://api.88api.ai";
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
async function apiJSON(path, body) {
// No automatic POST retry: a timed-out create may already have been accepted.
const response = await fetch(baseUrl + path, {
method: "POST",
headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" },
body: JSON.stringify(body),
signal: AbortSignal.timeout(120000),
});
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
return response.json();
}
async function uploadMedia(file, mimeType) {
const info = await stat(file);
if (!info.isFile() || info.size < 1 || info.size > 100000000) {
throw new Error("File must contain 1–100000000 bytes");
}
const bytes = await readFile(file);
const permit = await apiJSON("/v1/media/uploads", {
size: bytes.length, mime_type: mimeType,
sha256: createHash("sha256").update(bytes).digest("base64url"),
});
const target = new URL(permit.upload_url);
if (target.origin !== "https://assets.88api.ai" || permit.method !== "PUT") {
throw new Error("Unexpected upload destination; do not send credentials");
}
const response = await fetch(target, {
method: "PUT", headers: permit.headers, body: bytes,
redirect: "error", signal: AbortSignal.timeout(120000),
});
// A 409/ambiguous upload is not automatically retried; HEAD permit.url first.
if (response.status !== 201) throw new Error(`Upload HTTP ${response.status}`);
return response.json();
}
async function waitForVideo(id, budgetMs = 15 * 60 * 1000) {
const deadline = Date.now() + budgetMs;
let delay = 4000;
while (Date.now() < deadline) {
await sleep(Math.min(delay, deadline - Date.now()));
const remaining = deadline - Date.now();
if (remaining <= 0) break;
let response, state;
try {
response = await fetch(`${baseUrl}/v1/videos/${encodeURIComponent(id)}`, {
headers: { Authorization: `Bearer ${apiKey}` },
signal: AbortSignal.timeout(Math.min(30000, remaining)),
});
if (response.ok) state = await response.json();
} catch {
delay = Math.min(delay * 2, 60000);
continue; // Retry a read, never create a replacement task.
}
if (response.status === 429 || response.status >= 500) {
const retryAfter = response.headers.get("Retry-After");
const seconds = retryAfter && /^\d+$/.test(retryAfter)
? Number(retryAfter)
: (Date.parse(retryAfter || "") - Date.now()) / 1000;
delay = Number.isFinite(seconds) && seconds > 0
? Math.max(1000, seconds * 1000)
: Math.min(delay * 2, 60000);
await response.body?.cancel();
continue;
}
if (!response.ok) throw new Error(`Task ${id}: HTTP ${response.status}`);
if (state.status === "completed") {
const result = state.url || state.video_url || state.result_url;
if (typeof result !== "string" || new URL(result).protocol !== "https:") {
throw new Error(`Task ${id} completed without a usable HTTPS result URL`);
}
return result; // Keep official URLs and capability query parameters intact.
}
if (state.status === "failed") {
throw new Error(`Task ${id}: ${state.error?.message || "video generation failed"}`);
}
if (!["queued", "in_progress", "unknown"].includes(state.status)) {
throw new Error(`Task ${id}: unexpected status ${state.status}`);
}
delay = 12000;
}
throw new Error(`Stopped waiting for ${id}; save this ID and query later. Not cancelled.`);
}
async function main() {
// Resume a saved task without uploading or creating another paid task.
let id = process.env.TASK_ID;
if (!id) {
if (!process.env.MODEL_ID) throw new Error("Set MODEL_ID from GET /v1/models");
if (!process.env.REFERENCE_FILE) throw new Error("Set REFERENCE_FILE");
const media = await uploadMedia(process.env.REFERENCE_FILE, "video/mp4");
const task = await apiJSON("/v1/videos", {
model: process.env.MODEL_ID, prompt: "保持參考影片的主體與動作,延續鏡頭",
duration: 4, ratio: "16:9", metadata: { referenceVideos: [media.url] },
});
id = task.id;
if (!id) throw new Error("Create response did not contain a task ID; do not blindly retry");
console.log("Save task ID:", id); // Persist to your database in production.
}
const resultURL = await waitForVideo(id);
console.log("Result URL:", resultURL); // This grants media access; do not log publicly.
// This only shows the NEXT request body; it does not create a second paid task.
console.log(JSON.stringify({
model: process.env.MODEL_ID, prompt: "保持參考影片的主體與動作,延續鏡頭",
duration: 4, ratio: "16:9", metadata: { referenceVideos: [resultURL] },
}, null, 2));
}
await main();12. 錯誤處理與重試
| 情況 | 處理建議 |
|---|---|
| HTTP 400 | 檢查模型名稱、時長、比例、素材數量與欄位位置 |
| HTTP 401 | API Key 缺少、錯誤或已失效 |
| HTTP 403 | 目前的 Key 沒有該模型或群組的權限 |
| HTTP 404 | 任務不存在、不屬於目前帳號,或成品尚未就緒 |
| 上傳 HTTP 409 | 指定物件已存在且不可覆寫;先以 HEAD 確認,再重複使用已成功的網址 |
| 媒體 HTTP 410 | 檔案已到期;讀取與重複引用都不會延長期限,清除後也可能回傳 404 |
| 上傳 HTTP 415 | 檔案簽章與宣告的 MIME 不符;不能只改副檔名來冒充其他格式 |
| 媒體 HTTP 416 | Range 超出檔案範圍或格式不受支援;請重新以 HEAD 確認檔案大小 |
| HTTP 429 | 請求過於頻繁或觸及額度限制;依 Retry-After 或以指數退避重試 |
| HTTP 5xx | 暫時性服務錯誤;查詢請求可退避後重試 |
status=failed | HTTP 查詢成功但生成失敗;請讀取 error.message |
| 素材下載失敗 | 確認 URL 可從公開網路存取、尚未過期,且沒有防盜連結或驗證依賴 |
unsupported_reference_media | 模型不支援該參考素材類型,上傳或更換網域都無法解決 |
must be a public HTTPS URL | 本機檔案請先上傳,不能提交 Blob、Data URL、HTTP 或需要登入的網址 |
input_download_failed | 檢查目標服務實際上是否可達、DNS/網路狀況與媒體有效期限,而不只是本機能否開啟 |
| 內容安全攔截 | 調整提示詞或參考素材,不要原封不動地無限重試 |
POST /v1/videos 目前不提供客戶自訂冪等鍵的保證。如果已送出完整請求後遇到網路逾時,請勿盲目立即重送,否則可能生成並計費多個任務。