spicyapi文件
主要內容

Spicy Schema 規範

統一請求信封、canonical fields、表單 Schema、非同步狀態、錯誤、結果儲存與相容性規則。

Spicy Schema 是所有新媒體模型共用的公開契約。串接一個新模型時,變化應收斂在它的 modelinputSchema 和價格上;身分驗證、任務、結果、錯誤與下載流程保持不變。

即時目錄才代表可呼叫

本文規定契約形狀,不證明任何模型已經上線。建立付費任務前必須從已認證 GET /api/v1/models 讀取模型,並同時確認 enabled: trueavailable: true。規劃中或已停用的目錄條目不可呼叫。

公開邊界

一個公開模型識別碼描述穩定能力,格式為 <family>/<version-or-variant>/<task>provider 僅表示模型出品方,也就是模型的作者或研究機構。

公開回應、回呼、錯誤和下載結果只使用 SpicyAPI 自己的識別碼、錯誤碼與網址,不含內部處理細節、原始回應、原始錯誤或內部經營資料。任務結果先轉存到 SpicyAPI 的物件儲存,再以物件鍵回傳。

建立任務的統一信封

{
  "model": "MODEL_ID_FROM_CATALOG",
  "input": {
    "prompt": "slow camera push-in",
    "image_url": "spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "duration_seconds": 8,
    "resolution": "1080p",
    "generate_audio": true
  },
  "callBackUrl": "https://your-app.example.com/hooks/spicy"
}
欄位規則
model必須是已認證即時目錄回傳且目前可用的精確值
input必須通過同一目錄條目的目前 inputSchema;未知欄位會被拒絕
callBackUrl選填,公網可達的 HTTP(S) 回呼網址;v1 固定使用這個大小寫

Canonical fields

同一概念在所有新端點只使用一個 snake_case 名稱:

概念欄位型別
正向提示詞promptstring
負向提示詞negative_promptstring
主圖 / 尾幀image_url / last_image_urlURI 或已提交的 spicy:// URI
主影片 / 主音訊video_url / audio_urlURI 或已提交的 spicy:// URI
參考素材reference_image_urls / reference_video_urls / reference_audio_urlsURI array
輸出時長duration_secondsnumber 或 integer
解析度 / 畫面比例resolution / aspect_ratio文件列舉
原生音訊generate_audioboolean
隨機種子seedinteger
輸出數num_outputspositive integer
編碼格式output_format文件列舉

模型專屬的進階參數可以增加,但必須代表真實能力、不能重複 canonical 概念,欄位名稱也只描述能力本身。歷史端點若仍使用舊欄位,以其即時 inputSchema 為準;新端點不得繼續複製舊拼寫。

inputSchema 與 UI 註解

每個模型的 inputSchema 使用 JSON Schema 2020-12,同時驅動伺服器端驗證、Playground 表單、範例和報價。官方 TypeScript SDK 對公共請求信封與回應型別提供靜態型別;各模型的 input 仍是 Record<string, unknown>,必須按即時 Schema 驗證,不能假設 SDK 內建了每個模型的靜態欄位型別。

本站不維護逐模型的參數列。參數只有一個來源:GET /api/v1/models?includeSchema=1 回傳的 inputSchema,Playground 渲染的也是同一份。靜態副本會隨模型更新漂移,而漂移沒有任何檢查能發現。怎麼按它自己渲染表單,見模型目錄與 Schema

每份 Schema 必須:

  • 根節點是 object,預設 additionalProperties: false
  • 明確 required、型別、列舉、範圍、長度、陣列上限、URI 格式、預設值和已確認的條件相依關係;
  • 每個欄位都有非空的英文 description
  • 未確認的欄位直接省略,不猜預設值或能力;
  • 條件相依關係用根節點的 anyOf / allOf 表達(見下),而不是僅靠 UI 隱藏;
  • 不包含只影響內部處理方式的開關,也不包含內容過濾開關。

展示註解 x-ui

展示後設資料不是第二套驗證規則。它全部寫在欄位自己的 x-ui 物件裡,鍵一律 snake_case,取自一個封閉集合:

含義
widget控制項,取值見下
order欄位順序的唯一來源,數值大的在前,同一端點內不重複
label / placeholder覆寫預設標籤與輸入框的預留位置文字
rowstextarea 行數
step / unit數值步進與單位字尾(s / px
accept / max_size_mb上傳控制項的 MIME 過濾與單一檔案大小上限
advanced摺疊進「進階參數」
primary主輸入,置頂且不摺疊
affects_price改這個值需要重新報價
visible_when決定欄位顯示或隱藏的條件運算式
enum_labels列舉值 → 顯示文字

x-ui.widget 的取值是這 13 個:textareatextuploadmulti-uploadselectradioslidernumberswitchjsonobject-listchat-messageshidden。控制項與資料形狀保證一致,渲染器可以直接分派:select / radio 一定帶 enumslider 一定同時有 minimummaximum(不會只給 exclusiveMinimum / exclusiveMaximum);switch 一定是 booleanmulti-uploaditems.type: string 的陣列;object-listitems.type: object 且帶 items.properties 的陣列,每個子欄位自己也有 typedescriptionchat-messages 是陣列;hidden 表示欄位照常提交但不出現在表單裡。

不會出現在任何模型 inputSchema 裡的寫法:根節點的 x-order-properties(順序只由 x-ui.order 決定)、x-ui-componentx-ui.hint、以及 camelCase 的 x-ui.affectsPrice。它們是早期寫法,模型包驗證現在直接拒絕,伺服器端不再產出。用戶端仍應忽略未知的展示用擴充鍵——新增一個可忽略的 x-ui 鍵屬於向後相容變更。

{
  "type": "object",
  "required": ["prompt", "duration_seconds"],
  "additionalProperties": false,
  "properties": {
    "prompt": {
      "type": "string",
      "minLength": 1,
      "description": "Describes the scene and its motion.",
      "x-ui": { "widget": "textarea", "order": 100, "primary": true, "rows": 4 }
    },
    "duration_seconds": {
      "type": "integer",
      "enum": [5, 8, 10],
      "description": "Output duration in seconds.",
      "x-ui": { "widget": "radio", "order": 90, "unit": "s", "affects_price": true }
    }
  },
  "x-pricing": { "variantFields": ["duration_seconds"], "billingMode": "variant_matrix" }
}

每個欄位的 description 是英文的,可以直接當欄位說明展示。

x-ui.affects_price: true 表示修改該欄位後應重新報價。它不代表價格公式,也不能替代目錄中的 pricingquantityField。根節點的 x-pricing 是同一件事的伺服器端視角:variantFields 列出決定價格級距的欄位,始終是 affects_price: true 欄位集的子集;billingMode 說明這個端點按什麼計費。兩者都是提示,報價仍以目錄與任務回傳的金額為準。

條件欄位

條件相依關係只有兩種形態,都寫在根節點:

{
  "anyOf": [{ "required": ["image_url"] }, { "required": ["image_urls"] }],
  "allOf": [
    { "if": { "required": ["last_image_url"] }, "then": { "required": ["image_url"] } },
    { "if": { "properties": { "resolution": { "const": "4k" } } }, "then": { "required": ["seed"] } }
  ]
}

anyOf 的每個分支只含 required,讀作「這幾個裡至少給一個」。allOf 的每個分支是一條 ifthenifrequiredproperties.<欄位>.const 觸發,then 只宣告 required,讀作「給了 A 就必須給 B」。

oneOfnotdependentSchemasdependentRequired 不會出現在任何模型的 inputSchema 裡:它們表達得了約束,卻渲染不成表單,使用者只會在提交後拿到一個無法理解的 400。只實作上面這兩種形態就能涵蓋全部條件端點。

非同步生命週期

queued -> running -> succeeded
                  -> failed
                  -> expired

createTask 回傳 Spicy 任務 ID。用戶端透過 recordInfo 輪詢,或接收帶簽章的 Spicy webhook。queuedrunning 是非終態;其餘是終態。歷史 canceled 僅為讀取相容,新任務沒有取消操作。

模型內部出現新的未知非終態狀態時,SpicyAPI 會繼續對應為 running,直到明確終態或平台絕對截止時間。非冪等提交在回應未知時不會被盲目重放,以避免重複生成和重複計費。

統一回應與錯誤

所有 JSON API 使用同一個外殼:

{
  "code": 200,
  "msg": "success",
  "data": {},
  "request_id": "req_01k3m8x9q2z4v7n5p6r8s0t1w2"
}

同步失敗時不出現 data。程式只按 code 分支,不解析會變化的 msg;回報問題時提供 request_id。任務建立後發生的失敗透過 data.state: "failed" 和穩定的 errorCode 表達,errorMessage 只提供安全且經過正規化的說明,不包含內部服務名稱、網址、任務 ID 或原始錯誤。

結果與下載

成功結果只回傳第一方物件鍵和後設資料:

{
  "assets": [
    {
      "key": "tasks/2026/08/31/job_.../asset_....mp4",
      "mime": "video/mp4",
      "durationSeconds": 8,
      "bytes": 1234567
    }
  ]
}

output.assets[].key 不是 URL。呼叫 /api/v1/common/download-url 取得短期簽章網址。結果轉存期間可能回傳 pending: truekey 為空;多次轉存失敗後會標記 unavailable: true。公開結果一律由 SpicyAPI 自己的儲存空間提供。

使用者計費

公開目錄中的 pricingstartingPricequantityField 和任務的 estimatedCost / cost 只描述使用者價格,金額均為 USD 十進位字串。內部經營資料不屬於公開契約,也不會出現在目錄、任務、回呼或日誌匯出裡。

相容與棄用

以下變更向後相容:增加選填欄位、增加用戶端可忽略的回應欄位、增加未知 x-ui 提示。

以下變更需要新模型版本或已公告的棄用期:新增必填欄位、刪除列舉值、改變欄位語義或型別、縮小限制、改變公開模型識別碼。已發布識別碼保持不可變;遷移時提供相容別名或明確的轉址。

用戶端應快取已認證目錄最多 60 秒,並依 version / updatedAt 讓快取失效。不要永久快照模型 Schema,也不要在目錄沒有可用條目時改用靜態頁面頂替。

本頁目錄