StarReel Developer Docs开发者文档

StarReel Production APIStarReel 短剧产线 API

Turn a script into a finished, downloadable short-drama episode — programmatically. Drive the whole pipeline (storyboards → frames → video → final cut) from an AI agent over MCP, or from your own code over REST. One key powers both. 把剧本变成一集可下载的成片 — 全程可编程。用 AI agent 走 MCP,或从你自己的代码走 REST,驱动整条产线(分镜 → 帧 → 视频 → 成片)。一把 Key 通用。

The pipeline产线一览

One episode, the full pipeline — nothing skipped. Set the raw script, let AI rewrite it into a shootable draft (you can review & edit), extract the cast/scenes/props, lock character portraits (the consistency anchor), then storyboards → frames → video → final cut. Each spending stage gives you a quote first; you confirm, then it runs in the background. 一集短剧,走完整工作流、不跳步。设原始剧本 → AI 改写成可拍稿(可审阅/改稿)→ 提取角色/场景/道具 → 锁角色定妆图(一致性锚)→ 分镜 → 首帧 → 视频 → 成片。每个花钱阶段先报价,你确认后后台执行。

Three execution tiers — so your agent doesn't ask at every step.Project settings (free — do them first): project_type / setting_brief / ethnicity / aspect & resolution / consistency anchors — all free, the foundation that steers every later generation; the agent should set these up front, not build an empty shell. ② Pipeline backbone (metered, in order): portraits → frames → videos → TTS → compose — spending stages still quote-then-confirm. ③ Optional boosts (metered — the agent should offer them): world concept, art bible, scene images, lipsync, posters, SFX … — the agent should proactively tell you these are available and show a quote, then run on your OK — neither silently skipped nor auto-charged. 三档执行策略 — 让 agent 不用每步都问你。项目设定(免费·先做好):project_type / setting_brief / ethnicity / 画幅分辨率 / 一致性锚 — 全免费,是驱动后续所有生成的地基;agent 应建剧时先设好,别建空壳。② 产线主干(收费·按序):定妆图 → 首帧 → 视频 → 配音 → 终拼 — 花钱阶段仍先报价、你确认。③ 可选增强(收费·agent 应主动提示):世界观图 / 美术圣经 / 场景图 / 口型 / 海报 / 音效 … — agent 应主动告知这些可做并给报价,你同意才跑 — 既不默默跳过、也不擅自扣费。
Two lock rules.Aspect ratio is locked at the drama level — set it once at create_drama; every image / video / final cut then uses it. Don't change it mid-way or already-rendered content won't match (defaults to 9:16 if unset). ② Each shot runs 5–7s on purpose (tuned for AI video generation) — don't mistake a "long" shot for a bug and re-split. generate_storyboards replaces ALL existing shots (rendered frames wasted, re-paid); with shots already present the server blocks it unless you pass confirm_replace=true. 两条锁定纪律。画幅比例 drama 级锁定create_drama 时定一次,之后所有出图/出视频/成片都用它;别中途改,否则已生成内容画幅不一致(不设默认 9:16)。② 每镜 5–7 秒是刻意的(为 AI 出视频优化)— 别把「镜偏长」当 bug 就重拆。generate_storyboards 会**替换整集所有分镜**(已出图白费、要重花钱),已有分镜时后端会拦、需带 confirm_replace=true
剧本  create_drama → set_script(原始) → rewrite_script(AI改写) → [get_script / edit_rewritten_script]
      → extract_assets(角色/场景/道具) → generate_portraits_and_sheets(定妆图+设定图) → assign_voices(分配音色·配音前必做)
制作  → storyboards → frames → videos → compose → 成片.mp4(COS 下载链接)

免费(DB/ffmpeg):create_drama · set_script · get_* · edit · update设定 · compose · 多画幅 · 音效/特效/转场 · 交付物      按量后付·无报价(不足即402):rewrite · extract · tts配音 · 海报/封面/三视图 · 世界观/美术/色彩/动作等风格锁 · MV故事/剧本
报价·确认(quote_* + generate_*):storyboards · frames · videos · character_portraits · scene_images
项目类型:create_drama 传 project_type = drama(短剧) / ad(商业广告) / mv(音乐) / brand_film(品牌短片)
★广告(ad)专属必做:add_product 建产品库(广告主体)+ generate_product_sheet 出设定图,否则镜头产品漂移;MV:set_mv_lyrics→generate_mv_story→generate_mv_script
get_pipeline_status 按项目类型返回专属步骤(广告 build_product_library/set_cta,MV 歌词/故事)——查它就知道还差什么

Both paths share the same key, scopes, and billing (below). Base URL: https://api.shortreelai.com两条路径共用同一套 Key、scope 与计费(见下)。基址:https://api.shortreelai.com

Authentication鉴权

Create a long-lived API key in Settings → API Key (srk_live_…, shown once). You never send the key to business endpoints — you exchange it for a short 15-minute bearer token, then send that token. Re-exchange when it expires. 设置 → API Key 创建长期 Key(srk_live_…,只显示一次)。Key 不直接调业务端点 — 先换一枚 15 分钟短期令牌,再带令牌调用。过期就重新换。

POST/v1/agent/token
curl -X POST https://api.shortreelai.com/v1/agent/token \
  -H 'content-type: application/json' \
  -d '{"api_key":"srk_live_..."}'

# 200
{ "code": 0, "data": {
    "access_token": "eyJ...",
    "token_type": "Bearer",
    "expires_in": 900,
    "scopes": "produce,read" } }
import time, requests

BASE = "https://api.shortreelai.com"
API_KEY = "srk_live_..."
_tok = {"v": None, "exp": 0}

def token():
    """Exchange the API key for a 15-min token, cached until ~1 min before expiry."""
    if _tok["v"] and time.time() < _tok["exp"] - 60:
        return _tok["v"]
    r = requests.post(f"{BASE}/v1/agent/token", json={"api_key": API_KEY})
    r.raise_for_status()
    d = r.json()["data"]
    _tok["v"] = d["access_token"]
    _tok["exp"] = time.time() + d["expires_in"]
    return _tok["v"]

def auth():
    return {"authorization": f"Bearer {token()}"}
const BASE = "https://api.shortreelai.com";
const API_KEY = "srk_live_...";
let _tok = { v: null, exp: 0 };

// Exchange the API key for a 15-min token, cached until ~1 min before expiry.
export async function token() {
  if (_tok.v && Date.now() < _tok.exp - 60000) return _tok.v;
  const r = await fetch(BASE + "/v1/agent/token", {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify({ api_key: API_KEY }),
  });
  if (!r.ok) throw new Error("token exchange failed: " + r.status);
  const d = (await r.json()).data;
  _tok = { v: d.access_token, exp: Date.now() + d.expires_in * 1000 };
  return _tok.v;
}
export const auth = async () => ({ authorization: "Bearer " + (await token()) });
Cache the token and reuse it — the exchange endpoint is rate-limited to 30/min per IP. Revoking a key blocks new exchanges immediately. 缓存并复用令牌 — 交换端点限流 30/分/IP。吊销 Key 后交换立即失败。

Scopes授权范围

A key's power is set by the scopes you pick when creating it. Out-of-scope calls return 403.Key 权限由创建时选的 scope 决定,越权返回 403

scopeUnlocks解锁能力
readRead-only: identity (GET /v1/me) and balance (GET /v1/entitlement).只读:身份(GET /v1/me)与余额(GET /v1/entitlement)。
produceAI pipeline (/v1/ai/*): chat, image, TTS, video. Incurs charges.AI 产线(/v1/ai/*):文本、图片、语音、视频。会扣费。
localizeOverseas localization pipeline (used by the MCP tools).出海本地化产线(MCP 工具用)。
Tokens exchanged from a key cannot create/manage keys (no self-replication) and cannot reach admin endpoints. 换出的令牌不能创建/管理 Key(防自我繁殖),也进不了管理端点。

Billing — prepaid, no overdraft计费 — 先充值,不欠费

StarReel is prepaid. You need balance to generate, and the account never goes negative. Cost is authorized against your balance before the vendor runs; if you can't afford it the call returns 402 and no vendor cost is incurred. When the balance runs out mid-use, the account stops until you recharge. Usage is billed to the same balance as the web app. StarReel 预付制。生成需有余额,账户永不为负。成本在厂商运行之前对余额预授权;付不起则 402 且不产生厂商成本。余额用尽即停,充值后恢复。用量计入与网页端同一套余额。

Path A · MCP setup路径A · MCP 接入

For AI agents. After setup, the agent discovers and calls the tools on its own — you just talk to it.给 AI agent。接入后 agent 自行发现并调用工具 — 你只管对它说话。

Claude Code

claude mcp add starreel -e STARREEL_API_KEY=srk_live_... -- npx -y @starreel/mcp

Cursor / other MCP clientsCursor / 其他 MCP 客户端

Add to your client's MCP config (e.g. mcp.json):加进客户端的 MCP 配置(如 mcp.json):

{
  "mcpServers": {
    "starreel": {
      "command": "npx",
      "args": ["-y", "@starreel/mcp"],
      "env": { "STARREEL_API_KEY": "srk_live_..." }
    }
  }
}

MCP tools — the pipelineMCP 工具 — 整条产线

Needs produce scope. Follow the full workflow in order — poll get_pipeline_status to see the 10 stages. Big-ticket stages (portraits / storyboards / frames / videos / scene-images) split into quote_* + generate_* so the agent shows you the quote first; other AI-generation steps have no quote — they meter by usage and return 402 mid-run if the balance can't cover them (never overdraft). Long stages run in the background.produce scope。照完整工作流按序推进,用 get_pipeline_status 看 10 步进度。大额阶段(定妆图/分镜/首帧/视频/场景图)拆成 quote_* + generate_*,agent 先给你报价;其余 AI 生成步无报价,按用量后付、余额不足执行中 402(不欠费)。长阶段后台异步。

Free vs. metered at a glance. Free (DB + ffmpeg, no vendor call): create / set_script / all get_* / edit / update_project_settings · compose_episode · get_final_cut / get_export · render_multi_aspect · generate_sfx / generate_effects / generate_transitions (local-library match) · generate_deliverables (ffmpeg re-cuts) · add_product / list_products. Metered (every AI generation): all images (portraits, storyboards, frames, scene & world images, character/prop sheets, posters, covers), all video (shots, scene groups, lipsync, edits/regen), TTS voiceover / voice swap / BGM, and all LLM text (rewrite, extract, art-bible, visual-lock, setting-brief, style/color/motion locks, MV story/script, subtitle translation). Stages with a quote_* are pre-quoted; the rest meter by usage and 402 if short. 免费 vs 收费一览。免费(纯 DB + ffmpeg,不调厂商):建剧 / set_script / 所有 get_* / 改稿 / update_project_settings · compose_episode 终拼 · get_final_cut / get_export · render_multi_aspect 多画幅 · generate_sfx / generate_effects / generate_transitions(本地库匹配)· generate_deliverables(ffmpeg 切规格)· add_product / list_products收费(一切 AI 生成):所有出图(定妆·分镜·首帧·场景·世界观·三视图·海报·封面)、所有出视频(镜头·场景组·口型·编辑/重生)、TTS 配音/换音色/配乐、所有 LLM 文本(改写·提取·美术圣经·视觉锁·设定brief·风格/色彩/动作锁·MV故事/剧本·字幕翻译)。带 quote_* 的先报价;其余按用量后付、不足即 402
Tool工具What it does作用
list_project_optionsList project types / aspect ratios / video resolutions (labels + defaults) — call before create_drama to let the user choose. Free.列项目类型/画幅/分辨率的全部可选项(带标签+默认值)——建剧前调,给用户挑。免费。
create_dramaCreate a drama (+ empty episodes); returns episode_ids. Pick project_type: drama / ad / mv / brand_film. Free.建剧(+空集),返回 episode_ids。可选 project_type:drama/ad/mv/brand_film。免费。
set_scriptSet an episode's raw script (the input to AI rewrite). Free.设一集的原始剧本(AI 改写的输入)。免费。
rewrite_scriptAI-rewrite raw → shootable draft (picks the rewriter by project_type). Metered text.AI 改写:原始 → 可拍稿(按类型选改写 agent)。文本后付。
get_script / edit_rewritten_scriptRead raw + rewritten draft / edit the AI draft yourself. Free.读原始+改写稿 / 客户改 AI 稿。免费。
extract_assetsExtract characters / scenes / props (the consistency foundation). Metered text.提取角色/场景/道具(一致性地基)。文本后付。
quote_character_portraits / generate_character_portraitsLock character portraits (a single identity image per character). Needed — but not enough on its own; also do sheets (next row).出角色定妆图(每角色单张身份图)。必需 — 但只有它不够,还要出设定图(见下一行)。
generate_character_sheets / generate_portraits_and_sheets★ Character sheets = the shot consistency anchor. Multi-view turnarounds that every shot frame & video references (2.5 uses their slices for the face + full-body wardrobe lock). Portraits alone → characters drift across angle / lighting / wardrobe. generate_character_sheets does the whole cast (skips any already sheeted, no double-charge); generate_portraits_and_sheets is the one-call standard — portraits first, then call again for sheets once portraits are ready (sheets need the portrait as anchor). Metered (image).★ 设定图 = 镜头一致性根锚。多视角 turnaround,每个镜头帧和视频都引用(2.5 用其切片做脸+全身服装锁)。只出定妆图 → 人物换角度/换光/服装会漂移。generate_character_sheets 批量出全剧(已有的自动跳过,不重复扣费);generate_portraits_and_sheets 一键标配 — 先出定妆图,就绪后再调一次出设定图(设定图需定妆图当锚)。收费(出图)。
quote_storyboards / generate_storyboardsBreak the shootable draft into storyboards (shots).把可拍稿拆成分镜。
get_storyboards / get_pipeline_statusReview shots + frame/video readiness / see the 10-stage progress. Free.审阅分镜+帧/视频就绪度 / 看 10 步进度。免费。
Storyboard QC / AI ops分镜质量/AI操作Two free gates (recommended before frames): run_precheck (moderation / readiness — catch shots the vendor will reject, before you pay) · get_health_report (duration overrun / motif coverage / problem shots). Then AI boosts (metered): autofill_storyboards (fill empty fields, doesn't overwrite existing) · enhance_shot_prompts & complete_ending_motifsoptional, not required, and they rewrite existing content — run BEFORE generate_frames or already-rendered images go stale.两个免费闸(出图前推荐):run_precheck(合规/敏感/就绪 — 把会被厂商拒的镜提前揪出,防白花钱)· get_health_report(时长超标/母题覆盖/问题镜)。再是 AI 增强(收费):autofill_storyboards(补空缺字段,默认不覆盖已有)· enhance_shot_promptscomplete_ending_motifs非必须,且会改写已有内容 — 务必 generate_frames 之前做,否则已出图陈旧需重生。
quote_frames / generate_framesGenerate frames for a whole episode (frame_type: first_frame default / last_frame / both).整集批量出帧(frame_type:默认 first_frame / last_frame / both)。
quote_shot_frame / generate_shot_frameRedraw one frame of one shot — the right way to fix a shot that came out wrong. Keeps the identity/style anchors and the frame audit.重画某一镜的某一帧 —— 修某镜画面的正路,保留身份/画风锚与帧审计。
quote_videos / generate_videosGenerate the video for the whole episode (the big cost; quote == charge).整集出视频(大头;报价==扣费)。
compose_episode / get_final_cut / get_exportMerge into the final cut (free), fetch the download link + master status.终拼成片(免费)、拿下载链接+母版状态。
update_project_settings / create_dramaSet project settings (at creation or after). Beyond aspect / resolution / worldview brief / ethnicity / director style, now the whole project-settings page: consistency anchors (cinematography_prompt, art_bible, visual_lock, video_style_prompt/video_negative_prompt, motifs), audio (bgm_source own-vs-clip / bgm_volume_preset / use_clip_audio), subtitles (show_subtitles, bilingual, position, margin, animation), transitions. Free. (Internal pipeline/cost switches stay gated.)设项目设定(建剧时或建后)。除画幅/分辨率/世界观Brief/族裔/导演风格外,现覆盖项目设定页全部:整剧视觉一致性锚(cinematography_prompt 摄影DNA/art_bible 美术圣经/visual_lock 视觉锁定/video_style_prompt·video_negative_prompt 视频风格正负向/motifs 视觉母题)、音频(bgm_source 自有vs原生/bgm_volume_preset 音量/use_clip_audio 用视频原声)、字幕(show_subtitles/双语/位置/边距/动效)、转场。免费。(内部产线/成本开关仍不放行。)
Optional boosts可选增强generate_world_concept · generate_art_bible · extract_visual_lock · generate_color_script · generate_motion_templates · quote/generate_scene_images — drama-level consistency & style locks. All metered (world_concept = image; the rest LLM text; scene_images is quoted).generate_world_concept · generate_art_bible · extract_visual_lock · generate_color_script · generate_motion_templates · quote/generate_scene_images —— 剧目级一致性/风格锁。均收费(world_concept 出图;其余 LLM 文本;scene_images 有报价)。
Read back读取/查询list_dramas · get_drama · get_characters · get_scenes · get_assets · get_jobs (queue progress) · get_cost_estimate · get_budget_status. All free.list_dramas(列剧)· get_drama · get_characters · get_scenes · get_assets · get_jobs(任务进度)· get_cost_estimate · get_budget_status。均免费。
Upload your images上传自有图片upload_image · set_character_portrait · upload_shot_frame · upload_scene_image · upload_prop_sheet — auto-upload a local file to our COS + register as portrait/frame/scene/prop.upload_image · set_character_portrait · upload_shot_frame · upload_scene_image · upload_prop_sheet —— 本地图自动传 COS + 登记为定妆图/首尾帧/场景/道具。
Audio音频assign_voices (assign every character a voice — required before TTS; voiceStyle is not auto-filled) · generate_tts (episode voiceover — required before final cut) · replace_shot_dialogue · generate_bgm · translate_subtitles. All meteredgenerate_tts is a required paid voiceover step before the final cut (not free like compose); voice swap / BGM / subtitle translation are metered too.assign_voices(给每个角色分配音色·配音前必做,音色不是自动填的)· generate_tts(整集配音·成片前必做)· replace_shot_dialogue(换音色)· generate_bgm(配乐)· translate_subtitles(字幕翻译)。均收费——generate_tts 是成片前必做且收费的配音步(不像 compose 免费);换音色/配乐/字幕翻译同样收费。
Voice cloning声音克隆clone_voice (clone a voice from an authorized audio sample — billed per voice, auto-refunded on failure) · list_voices · delete_voice · set_character_voice (bind a cloned voice to a character; generate_tts then speaks in it). ⚠️ The sample must be a consented/licensed voice.clone_voice(从已授权音频样本克隆音色 — 按平台价每音色计费,失败自动退款)· list_voices · delete_voice · set_character_voice(把克隆音色绑到角色;之后 generate_tts 用它配音)。⚠️ 样本必须是本人/持权人同意授权的声音。
Edit / cut视频编辑/剪辑get_edit_capabilities · quote/edit_video_shot (in-place edit + segment replace) · quote/regenerate_shot_video · split_shot · trim_shot · rerender_episode. edit_video_shot / regenerate_shot_video are quoted video spends; split_shot / trim_shot / rerender_episode are free (ffmpeg).get_edit_capabilities · quote/edit_video_shot(就地编辑+区间替换)· quote/regenerate_shot_video(单镜重生)· split_shot · trim_shot · rerender_episode(成片重拼)。edit_video_shot/regenerate_shot_video 有报价、出视频收费;split_shot/trim_shot/rerender_episode 免费(ffmpeg)。
Refine assets资产精修update_character · delete_character · update_scene · delete_scene · generate_character_sheet (3-view) · generate_prop_sheet. update/delete are free; the two sheets are metered (image).update_character · delete_character · update_scene · delete_scene · generate_character_sheet(三视图)· generate_prop_sheet(道具设定图)。改/删免费;两个 sheet 收费(出图)。
Drama-level assets剧目级资产Prop library (drama props — not the ad product library): get_props / create_prop / update_prop / delete_prop / mark_signature_prop / generate_prop_sheet. Read back generated shared assets: get_color_scripts / get_motion_templates (pair with generate_color_script / generate_motion_templates). CRUD & reads are free; only sheet / AI generation is metered.道具库(剧目道具,广告商品库):get_props/create_prop/update_prop/delete_prop/mark_signature_prop(招牌道具)/generate_prop_sheet读回已生成的剧目共享资产:get_color_scripts/get_motion_templates(配 generate_color_script/generate_motion_templates 生成)。增删改/读取免费;仅出图/AI 生成收费。
Music video (project_type=mv)MV 专属set_mv_lyricsgenerate_mv_storygenerate_mv_script · get_mv — MV skips the standard rewrite and uses this lyrics→story→script flow, then the normal extract→storyboards→… pipeline. set_mv_lyrics / get_mv are free; generate_mv_story / generate_mv_script are metered (LLM text).set_mv_lyricsgenerate_mv_storygenerate_mv_script · get_mv —— MV 跳过标准改写,走 歌词→故事→剧本,再接标准 提取→分镜→… 产线。set_mv_lyrics/get_mv 免费;generate_mv_story/generate_mv_script 收费(LLM 文本)。
Continuity连续性/场景组chain_frames (frames inherit prev shot's last frame) · get_scene_group_plan · generate_scene_groups · render_multi_aspect (re-render vertical/landscape/square). Watch out: generate_scene_groups is a large video spend (batch group videos); chain_frames is metered when a shot pair needs a re-rendered frame; get_scene_group_plan and render_multi_aspect are free (ffmpeg).chain_frames(首帧承接上镜尾帧)· get_scene_group_plan · generate_scene_groups(场景组)· render_multi_aspect(多画幅重渲)。注意:generate_scene_groups大额出视频(批量分组视频);chain_frames 在镜对需重渲首帧时收费;get_scene_group_planrender_multi_aspect 免费(ffmpeg)。
Polish口型/海报/音效lipsync_shot · lipsync_episode · get_lipsync_status · generate_episode_poster · generate_drama_poster · generate_cover · generate_sfx · generate_effects · generate_transitions. lipsync_* / posters / cover are metered (video / image); get_lipsync_status and generate_sfx / generate_effects / generate_transitions are free (local-library match, no vendor).lipsync_shot/lipsync_episode(口型)· get_lipsync_status · generate_episode_poster/generate_drama_poster/generate_cover(海报封面)· generate_sfx(音效)· generate_effects(特效)· generate_transitions(转场)。lipsync_*/海报/封面 收费(出视频/图);get_lipsync_statusgenerate_sfx/generate_effects/generate_transitions 免费(本地库匹配,不调厂商)。
Brand film / Ad品牌片/广告get_deliverables · generate_deliverables (brand-film deliverable tree) · add_product · list_products (ad product library). generate_deliverables / add_product / list_products are free; add_product only stores a catalog row (required for ads — the product is the subject), then generate_product_sheet (metered) makes its sheet, or the product drifts across shots.get_deliverables/generate_deliverables(品牌片交付物树)· add_product/list_products(广告商品库)。generate_deliverables/add_product/list_products 免费;add_product 仅建条目(广告必做——产品是广告主体),再用 generate_product_sheet(收费)出设定图,否则镜头产品漂移。
Frames — first frame required, last frame optional (you do NOT generate both). generate_frames makes one first frame per shot (the i2v identity anchor) and never makes last frames. generate_videos needs at least one first frame in the episode or it is blocked (400); any shot left without a first frame degrades to anchorless t2v (wasted spend, lost consistency), so give every shot a first frame. A last frame is optional and never produced by default — ask for one only to pin a shot's ending, e.g. a big camera move or a reveal (the engine then uses a first+last keyframe pair); subtle motion uses the first frame alone. To get one, generate it on-platform: generate_frames with frame_type=last_frame (batch, shots that already have a first frame) or generate_shot_frame (one shot). To fix a shot that came out wrong, redraw it with generate_shot_frame — that path carries the shot's character identity anchors, scene/prop references, style lock and frame audit. Generating the image in some other tool and pushing it in with upload_shot_frame bypasses all of it (faces, wardrobe and style drift); upload_shot_frame is for art the customer already owns. When a shot carries a reference video/image, first/last frames are dropped (vendor-exclusive), so most shots need no last frame. 帧规则 — 首帧必需、尾帧可选(不需要两张都生)。generate_frames 每镜只出一张首帧(i2v 身份锚),不产尾帧。generate_videos 要求整集至少一张首帧,否则拦(400);任何缺首帧的镜会退化成无锚点 t2v(白花钱、丢一致性),所以最好每镜都有首帧。尾帧可选、默认不出 — 只在想固定某镜结尾画面(如大运镜/揭示镜)时才要(引擎随即启用首+尾双关键帧);细微运动只用首帧。要尾帧就让平台生成:generate_framesframe_type=last_frame(整集批量,只给已有首帧的镜)或 generate_shot_frame(单镜)。某一镜画错了要修,用 generate_shot_frame 重画 —— 这条路带着该镜的角色身份锚、场景/道具参考、画风锁与帧审计;拿别的工具出图再用 upload_shot_frame 贴进来会绕开这一整套(人脸/服装/画风会漂),upload_shot_frame 只用于客户自有素材。镜头带参考视频/图时,首/尾帧会被剥离(厂商互斥),故多数镜无需尾帧。

Every MCP tool maps 1:1 to a REST endpoint under /v1/produce/* (same names, same params). The REST reference below covers authentication and the core flow; the tools above are the full surface.每个 MCP 工具与 /v1/produce/* 下的一个 REST 端点一一对应(同名同参)。下面 REST 章节讲鉴权与主干流程;上表即完整工具面。

Agent skill & disciplinesAI agent 操作 Skill 与纪律

A drop-in operating skill for any AI agent driving this pipeline — the ordered workflow, ten hard disciplines, and the one failure decision. It keeps an agent on the full pipeline, inside budget, compliant, and correct when a shot fails. 任何驱动本产线的 AI agent 的一份即插即用操作 Skill — 完整工作流顺序、十条硬纪律、失败时的唯一决策。让 agent 照产线走、不超支、不违规、镜头失败时判得对。

Three ways to load it: (1) MCP clients that support Skills auto-load SKILL.md shipped inside @starreel/mcp; (2) any other platform (Coze / Dify / GPTs / your own agent) — paste the block below into the system prompt; (3) it is this page's Billing + Troubleshooting contract, condensed. 三种加载方式:(1)支持 Skill 的 MCP 客户端会自动读取 @starreel/mcp 包内的 SKILL.md;(2)其他任意平台(Coze / Dify / GPTs / 自研 agent)—把下方文本块整段贴进 system prompt;(3)它就是本页「计费 + 常见问题处理」契约的浓缩。

The ten disciplines十条纪律

  1. Prepaid, never overdraft.先充值,永不欠费。 On 402 insufficient_credits, stop and ask the user to recharge — never loop-retry a 402; it can't succeed.402 insufficient_credits 立即停并提示充值 — 绝不循环重试 402,它不可能成功。
  2. Quote before you spend; the quote is the charge.先报价再花钱;报价即扣费。 Big-ticket stages (portraits / storyboards / frames / videos / scene-images) are quote_* then generate_* — show the quote first. Other AI-generation steps (TTS, posters, sheets, style locks …) have no quote but still bill by usage. Show the user before any spend; don't auto-approve large ones.大额阶段(定妆图/分镜/首帧/视频/场景图)是 quote_*generate_*——先报价。其余 AI 生成步(TTS、海报、三视图、风格锁…)无报价但按用量照样收费。任何花钱前先告知用户;不替用户默认同意大额。
  3. retryable decides retry-vs-change.retryable 一锤定音:重试还是改内容。 false (moderation / copyright / quota / overdue) → change content or stop; true (KYC-queue / rate-limit / transient) → back off, retry. Never blind-retry.false(审核/版权/配额/欠费)→ 改内容或停;true(KYC 排队/限流/偶发)→ 退避后重试。绝不盲目重试。
  4. Content must be compliant.内容必须合规。 No copyrighted characters, trademarks, real-person likenesses, or sensitive content. On rejection, rewrite toward generic, original imagery — don't fight the gate.不生成版权角色、商标、真人特征或敏感内容。命中拒收就改成通用原创形象 — 不硬刚审核门。
  5. Voice cloning needs consent.声音克隆须授权。 Only clone a sample the user is authorized to use (own voice or rights-holder consent). Never clone a third party's voice without permission.只克隆用户有权使用的样本(本人或持权人同意)。绝不未经授权克隆第三方声音。
  6. Follow the order; don't skip.照顺序走,不跳步。 Lock character portraits and sheets and frames before video — portraits alone leave characters drifting (sheets are the shot consistency anchor); no first frame degrades to anchorless t2v. Both waste money.出视频先锁定妆图和设定图和首帧——只出定妆图人物会漂(设定图才是镜头一致性根锚);无首帧退化无锚点 t2v。都白花钱。
  7. Poll, don't block or hammer.轮询,别阻塞也别打爆。 Long steps are async; poll get_pipeline_status / get_jobs / get_storyboards with backoff. Stable counts = done.长步骤异步;带退避轮询 get_pipeline_status / get_jobs / get_storyboards。数量稳定=完成。
  8. Idempotency — don't double-charge.幂等 — 不重复扣费。 A quote_id is one-time (~15 min). Never generate_* the same intent twice; read current state before regenerating.quote_id 一次性(约 15 分钟)。同一意图绝不 generate_* 两次;重生前先读现状。
  9. Stay in your tenant.只碰自己的资源。 Someone else's id returns 404 by design (probes never leak existence). Don't guess ids.别人的 id 一律 404(探测不泄漏存在性)。别猜 id。
  10. Be transparent; keep secrets safe.对用户透明;守好密钥。 Report the quote, the failure reason, and actual spend — never fake success. Keep the API key in env / secrets, never in code or logs.如实呈现报价、失败原因、实际花费 — 绝不伪造成功。API key 放环境变量/密钥管理,绝不进代码或日志。
  11. Content is the user's, not yours.内容属于用户,不是你编的。 Never invent character names, titles, or dialogue — drive the pipeline from the user's script and choices.绝不自行编造角色名、剧名或台词 — 一切以用户的剧本与选择驱动产线。

Drop-in skill — copy into any agent's system prompt可整段复制 — 贴进任意 agent 的 system prompt

You are an agent driving StarReel, a PREPAID AI short-drama pipeline. You turn a
raw script into a downloadable episode via StarReel tools/endpoints.

PIPELINE (full, never skip):
create_drama → set_script(raw) → rewrite_script → extract_assets →
generate_portraits_and_sheets → storyboards → frames → videos →
generate_tts → compose_episode → final cut. Always generate frames BEFORE
videos. project_type = drama/ad/mv/brand_film (call list_project_options first).

TEN DISCIPLINES:
1. Prepaid, never overdraft. On 402 insufficient_credits, STOP and ask the user
   to recharge. Never loop-retry a 402.
2. Quote before you spend; the quote is the charge. Big-ticket stages
   (portraits/storyboards/frames/videos/scene-images) are quote_* then generate_*;
   other AI steps (TTS/posters/sheets/style locks) have no quote but still bill.
   Show the user before any spend; don't auto-approve large ones.
3. retryable decides retry-vs-change. false (moderation/copyright/quota/overdue)
   → change content or stop. true (KYC/rate-limit/transient) → back off, retry.
   Never blind-retry.
4. Content must be compliant. No copyrighted characters, trademarks, real-person
   likenesses, or sensitive content. On rejection, rewrite toward generic
   original imagery; do not fight the gate.
5. Voice cloning needs consent. Only clone a sample the user is authorized to
   use. Never clone a third party's voice without permission.
6. Follow the order; do not skip. Lock portraits and frames before video, or
   video degrades to anchorless t2v (wasted money).
7. Poll, do not block or hammer. Long steps are async; poll get_pipeline_status
   / get_jobs / get_storyboards with backoff. Stable counts = done.
8. Idempotency. A quote_id is one-time (~15 min). Never double-generate the same
   intent. Read current state before regenerating.
9. Stay in your tenant. Others' ids return 404 by design. Do not guess ids.
10. Be transparent; keep secrets safe. Report quote, failure reason, and actual
    spend; never fake success. Keep the API key in env, never in code or logs.

ON FAILURE: read message / fail_reason / retryable.
moderation | identity | copyright → change content;
overdue | token → not self-healable (tell user / wait);
network | timeout | transient → retry. Failed spends are auto-refunded.

Docs: https://api.shortreelai.com/docs/mcp

These disciplines apply to REST integrations too — the same billing, moderation, and tenancy rules hold on /v1/produce/*.这些纪律同样适用于 REST 接入 — /v1/produce/* 上的计费、审核、租户规则完全一致。

Path B · REST API路径B · REST API

Plain HTTPS from any language. Every request carries the bearer token from Authentication. Switch the code samples with the curl / Python / Node.js selector at the top right. 任意语言的普通 HTTPS。每个请求带 鉴权换来的令牌。用右上角 curl / Python / Node.js 切换示例语言。

Base URL & response format基址与响应格式

Account账户

GET/v1/me
GET/v1/entitlement
# identity
curl -H "authorization: Bearer $TOKEN" \
  https://api.shortreelai.com/v1/me

# plan + spendable balance
curl -H "authorization: Bearer $TOKEN" \
  https://api.shortreelai.com/v1/entitlement
# 200 -> { "code":0, "data":{ "allowed":true, "plan":"pro",
#          "spendable":42000, "credits_balance":42000 } }
me = requests.get(f"{BASE}/v1/me", headers=auth()).json()["data"]
ent = requests.get(f"{BASE}/v1/entitlement", headers=auth()).json()["data"]
print(me["email"], "balance:", ent["spendable"])
const me  = await (await fetch(BASE + "/v1/me", { headers: await auth() })).json();
const ent = await (await fetch(BASE + "/v1/entitlement", { headers: await auth() })).json();
console.log(me.data.email, "balance:", ent.data.spendable);

Pipeline endpoints产线端点

All under /v1/produce/*, need produce scope. Spending stages follow one pattern: quote → confirm → poll. The quote returns a quote_id and the estimated points; show the user, then pass the quote_id to the matching generate call. Long stages run in the background. 全在 /v1/produce/* 下,需 produce scope。花钱阶段一个套路:报价 → 确认 → 轮询。报价返回 quote_id 和预估点数;给用户看,再把 quote_id 传给对应的 generate。长阶段后台异步。

Endpoint端点Purpose用途
POST /v1/produce/dramasCreate drama (+episodes) → episode_ids. Free.建剧(+集)→ episode_ids。免费。
PUT /v1/produce/episodes/:id/scriptSet script. Free.灌本。免费。
GET /v1/produce/episodes/:id/storyboardsRead shots (+ frame/video readiness). Free.读分镜(+帧/视频就绪)。免费。
POST /v1/produce/episodes/:id/storyboards/quote · /generateBreak script into storyboards.拆镜。
POST /v1/produce/episodes/:id/frames/quote · /generateFirst frame per shot.每镜首帧。
POST /v1/produce/episodes/:id/videos/quote · /generateVideos for the episode (quote == charge).整集视频(报价==扣费)。
POST /v1/produce/episodes/:id/composeMerge into final cut. Free.终拼成片。免费。
GET /v1/produce/episodes/:id/final-cutStatus + download link when done.状态+完成时的下载链接。

Every response is wrapped as { "code": 0, "data": {…} }.响应统一包成 { "code": 0, "data": {…} }

Quote → confirm → poll报价 → 确认 → 轮询

The video stage, shown three ways. Frames and storyboards work identically — just change the path segment. 以视频阶段为例(三种语言)。帧和分镜用法一样 — 改路径段即可。

# 1) quote — returns estimated_points + quote_id
Q=$(curl -s -X POST https://api.shortreelai.com/v1/produce/episodes/250/videos/quote \
  -H "authorization: Bearer $TOKEN")
echo "$Q"   # { "data": { "estimated_points": 1059, "quote_id": "q_..." } }

# 2) show the user the points, then confirm with the quote_id
QID=$(echo "$Q" | jq -r .data.quote_id)
curl -s -X POST https://api.shortreelai.com/v1/produce/episodes/250/videos/generate \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d "{"quote_id":"$QID"}"          # -> { "data": { "status": "generating" } }

# 3) poll until every shot has a video_url
curl -s -H "authorization: Bearer $TOKEN" \
  https://api.shortreelai.com/v1/produce/episodes/250/storyboards
def stage(ep, name, poll_field=None):
    q = requests.post(f"{BASE}/v1/produce/episodes/{ep}/{name}/quote", headers=auth()).json()["data"]
    print(f"{name}: {q['estimated_points']} credits")     # show the user, get their OK
    requests.post(f"{BASE}/v1/produce/episodes/{ep}/{name}/generate",
                  headers=auth(), json={"quote_id": q["quote_id"]})
    while poll_field:                                     # poll storyboards until ready
        sbs = requests.get(f"{BASE}/v1/produce/episodes/{ep}/storyboards", headers=auth()).json()["data"]
        if sbs and all(s.get(poll_field) for s in sbs): break
        time.sleep(10)

stage(250, "frames", poll_field="first_frame_image")
stage(250, "videos", poll_field="video_url")
async function stage(ep, name, pollField) {
  const q = (await (await fetch(`${BASE}/v1/produce/episodes/${ep}/${name}/quote`,
    { method: "POST", headers: await auth() })).json()).data;
  console.log(`${name}: ${q.estimated_points} credits`);   // show the user, get their OK
  await fetch(`${BASE}/v1/produce/episodes/${ep}/${name}/generate`,
    { method: "POST", headers: { ...(await auth()), "content-type": "application/json" },
      body: JSON.stringify({ quote_id: q.quote_id }) });
  while (pollField) {
    const sbs = (await (await fetch(`${BASE}/v1/produce/episodes/${ep}/storyboards`,
      { headers: await auth() })).json()).data;
    if (sbs.length && sbs.every(s => s[pollField])) break;
    await new Promise(r => setTimeout(r, 10000));
  }
}
await stage(250, "frames", "first_frame_image");
await stage(250, "videos", "video_url");

Full run — script to download link整条跑通 — 从剧本到下载链接

# create -> set script -> storyboards -> frames -> videos -> compose -> download
# (each stage: quote, then generate with the quote_id; poll between stages)
# see the Python / Node tabs for a runnable end-to-end script.
d = requests.post(f"{BASE}/v1/produce/dramas", headers=auth(),
                  json={"title": "My Drama", "total_episodes": 1}).json()["data"]
ep = d["episodes"][0]["episode_id"]
requests.put(f"{BASE}/v1/produce/episodes/{ep}/script", headers=auth(),
             json={"script_content": my_script})
stage(ep, "storyboards", poll_field=None)      # background; poll get_storyboards for shots
# ... wait for storyboards, then:
stage(ep, "frames", poll_field="first_frame_image")
stage(ep, "videos", poll_field="video_url")
requests.post(f"{BASE}/v1/produce/episodes/{ep}/compose", headers=auth())
while True:
    fc = requests.get(f"{BASE}/v1/produce/episodes/{ep}/final-cut", headers=auth()).json()["data"]
    if fc.get("download_url"): print("done:", fc["download_url"]); break
    time.sleep(8)
const d = (await (await fetch(`${BASE}/v1/produce/dramas`, { method: "POST",
  headers: { ...(await auth()), "content-type": "application/json" },
  body: JSON.stringify({ title: "My Drama", total_episodes: 1 }) })).json()).data;
const ep = d.episodes[0].episode_id;
await fetch(`${BASE}/v1/produce/episodes/${ep}/script`, { method: "PUT",
  headers: { ...(await auth()), "content-type": "application/json" },
  body: JSON.stringify({ script_content: myScript }) });
await stage(ep, "storyboards");                 // then poll get_storyboards
await stage(ep, "frames", "first_frame_image");
await stage(ep, "videos", "video_url");
await fetch(`${BASE}/v1/produce/episodes/${ep}/compose`, { method: "POST", headers: await auth() });
let fc;
do { await new Promise(r => setTimeout(r, 8000));
  fc = (await (await fetch(`${BASE}/v1/produce/episodes/${ep}/final-cut`,
    { headers: await auth() })).json()).data;
} while (!fc.download_url);
console.log("done:", fc.download_url);
The download link is a direct CDN URL to the finished mp4. Merge (compose) is free; a failed generate auto-refunds its pre-authorized cost. 下载链接是成片 mp4 的 CDN 直链。终拼(compose)免费;生成失败会自动退回预扣成本。

Upload your own images (portraits, frames, scenes, props)上传自有图片(定妆图/首帧/场景/道具)

Bring your own reference art instead of AI-generating it. The headline case is character portraits: an uploaded portrait becomes that character's identity anchor (source user_upload, priority over AI — later AI regens won't overwrite it), auto-invalidates & rebuilds derived assets (character sheet, hair/body refs) and registers a face-lock. Shot frames / scene images / prop sheets work the same way. 用你自己的参考图,而不是 AI 生成。最典型是角色定妆图:上传的定妆图成为该角色的身份锚(来源 user_upload,优先级高于 AI — 之后 AI 重生默认不覆盖),并自动失效重建派生资产(三视图设定图、发型/身材参考)、登记人脸锁。首帧/场景图/道具设定图同理。

MCP — one call: set_character_portrait({character_id, file_path}) uploads a local file to COS and registers it in one step (or pass image_url for an already-hosted image). Likewise upload_shot_frame / upload_scene_image / upload_prop_sheet. All free. MCP — 一次调用:set_character_portrait({character_id, file_path}) 把本地文件传 COS 并登记,一步搞定(或传 image_url 用已托管的图)。upload_shot_frame / upload_scene_image / upload_prop_sheet 同理。均免费。

REST — three steps: presign → PUT the bytes straight to COS → register.REST — 三步:拿预签名 → PUT 字节直传 COS → 登记。

POST/v1/produce/upload-url
POST/v1/produce/characters/:id/portrait
# 1) presign — 拿直传 URL(图片字节不过业务服务器)
curl -X POST https://api.shortreelai.com/v1/produce/upload-url \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"filename":"portrait.jpg","content_type":"image/jpeg","size":204800,"kind":"image"}'
# 200 -> { "code":0, "data":{ "put_url":"https://cos...", "public_url":"https://cos.../portrait.jpg",
#          "headers":{"content-type":"image/jpeg"} } }

# 2) 用 put_url PUT 文件字节(带 data.headers 里要求的头)
curl -X PUT "$PUT_URL" -H 'content-type: image/jpeg' --data-binary @portrait.jpg

# 3) 用 public_url 登记为该角色定妆图(身份锚)
curl -X POST https://api.shortreelai.com/v1/produce/characters/42/portrait \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"image_url":"https://cos.../portrait.jpg"}'
pre = requests.post(f"{BASE}/v1/produce/upload-url", headers=auth(), json={
    "filename": "portrait.jpg", "content_type": "image/jpeg",
    "size": 204800, "kind": "image"}).json()["data"]
requests.put(pre["put_url"], data=open("portrait.jpg", "rb").read(),
             headers=pre.get("headers") or {"content-type": "image/jpeg"})
requests.post(f"{BASE}/v1/produce/characters/42/portrait", headers=auth(),
              json={"image_url": pre["public_url"]})
const pre = (await (await fetch(BASE + "/v1/produce/upload-url", {
  method: "POST", headers: { ...(await auth()), "content-type": "application/json" },
  body: JSON.stringify({ filename: "portrait.jpg", content_type: "image/jpeg",
    size: 204800, kind: "image" }) })).json()).data;
await fetch(pre.put_url, { method: "PUT",
  headers: pre.headers || { "content-type": "image/jpeg" }, body: fileBytes });
await fetch(BASE + "/v1/produce/characters/42/portrait", {
  method: "POST", headers: { ...(await auth()), "content-type": "application/json" },
  body: JSON.stringify({ image_url: pre.public_url }) });

The same upload-url presign works for any image / video / audio; register with the matching endpoint (/storyboards/:id/frame, /scenes/:id/image, /props/:id/sheet). Uploads are free — you only pay when you later generate from them.同一个 upload-url 预签名适用于任意图片/视频/音频,再用对应端点登记(/storyboards/:id/frame/scenes/:id/image/props/:id/sheet)。上传免费 — 只有之后据它生成才计费。

Troubleshooting常见问题处理

Every failure surfaces as a human-readable message (the MCP client throws Error(message); REST returns { code, message } or, on the metered /v1/ai/* layer, { error: { message, type, needed?, retryable? } }). The message is written for your agent to act on — read it, don't blindly retry. Failed spends are auto-refunded (pre-hold → refund on failure), so you never need to compensate manually.所有失败都带一段人类可读的 message(MCP 客户端抛 Error(message);REST 返回 { code, message },计费层 /v1/ai/* 返回 { error: { message, type, needed?, retryable? } })。这段 message 是给 agent 行动用的 —— 照它做,别盲目重试。失败的扣费一律自动退款(预扣→失败退款),不用手动补偿。

★ Shot images / videos: rejected vs. failed — how to tell & what to do★ 镜头图片 / 视频:拒收 vs 失败 —— 怎么判、怎么办

Generation is async: call generate_frames / generate_videos, then poll get_storyboards. Each shot now carries structured status so you don't parse text: frame_status / video_status (ready/pending/authorizing/rejected/failed/none), fail_reason (the enum in the table below), retryable (the one flag that decides retry-vs-change), and fail_hint (human message). Retrying a rejection is useless; retrying a transient failure is correct.生成是异步的:调 generate_frames / generate_videos 后轮询 get_storyboards每镜现在直接带结构化状态,不用解析文案:frame_status / video_status(ready/pending/authorizing/rejected/failed/none)、fail_reason(下表的枚举)、retryable(一锤定音:该重试还是该改)、fail_hint(人读文案)。拒收去重试是白费;偶发失败去重试才对。

What you see (message)现象(真实文案)Cause根因Agent actionagent 应对
「…未通过厂商内容审核(判定为含敏感信息)…」"…failed content moderation (sensitive)…" retryable:false画面命中敏感内容(终态)Frame hit sensitive content❌ 别重试 → 改画面内容/换参考图,重生该帧Don't retry → change the picture / swap the reference image, regenerate the frame
「…未通过厂商人脸一致性核验…」"…failed face-consistency…"定妆图与已授权人物不是同一人Portrait ≠ authorized person换定妆图 / 确认同一人后重生Swap the portrait / confirm same person
「…文字描述被判定为敏感(判的是文字,不是画面)…」"…text judged sensitive (the text, not the picture)…"prompt 文本敏感(任务未创建,未扣费)Prompt text is sensitive改 prompt 措辞(不是换图),重试Reword the prompt (not the image), retry
「…判定可能涉及版权或敏感形象,已自动拦截并退还本次积分…改为通用/原创形象…」"…possible copyright/sensitive likeness, auto-blocked & refunded…use generic/original…"版权角色/商标/真人特征Copyright / trademark / real-person改成通用原创形象;避免可识别的版权角色/商标/真人Use generic original imagery; avoid recognizable IP/trademark/real person
「人物帧正在完成人脸授权(KYC),约 1 分钟后重试即可」"face frame finishing KYC, retry in ~1 min" 503 retryable:true含人脸帧走 KYC 授权排队(不是拒)Face frame queuing for KYC (not a rejection)✅ 等 ~1 分钟后重试Wait ~1 min, retry
「上游账户欠费/余额不足,厂商拒绝生成(与 prompt 无关)」"upstream account overdue, vendor refused (unrelated to prompt)" 502火山 Ark 厂商账户欠费(平台级)Vendor (Ark) account overdue给 Ark 账户充值;不改 prompt。★ 别把欠费当敏感去改画面Recharge the Ark account; don't touch the prompt. ★ Don't mistake overdue for sensitive
「…平台侧厂商素材库配额已满…换图或重试都不会改变结果…」"…vendor asset-store quota full…retry won't help…" retryable:false平台配额满(基建)Platform quota exhausted重试无效,联系运营Retry is useless, contact ops
BestOfN 全失败 / frame-promotion-rejectedBestOfN all-failed / quality gate偶发/质量闸未过Transient / quality gate✅ 可直接重试(regenerate_shot_video / 重出帧)Retry (regenerate)

The one signal that decides it: the retryable flag. true (KYC-queuing, rate-limit) → back off and retry; false (moderation, copyright, quota) → change content / swap image, retrying will never work.一锤定音的信号:retryable 字段。true(KYC 排队、限流)→ 退避后重试;false(审核、版权、配额)→ 改内容/换图,重试永远无效。

Billing — 402 vs 403计费 —— 402 与 403

Vendor / edit 400 / auth / async厂商 / 区间替换 400 / 鉴权 / 异步

Facade 4xx you'll hit most (order matters)最常撞的门面 4xx(顺序很重要)

Agent handling principlesAI agent 通用处理原则

Status codes状态码

CodeMeaning & what to do含义与处理
401Key invalid/revoked (indistinguishable by design), or token expired → re-exchange.Key 无效/已吊销(响应一致),或令牌过期 → 重新交换。
402Insufficient balance — recharge. Response includes needed.余额不足 — 请充值。响应带 needed
403Scope insufficient (code 4031) → use a key with the right scope.scope 不足(code 4031)→ 换带对应 scope 的 Key。
409Active key limit reached (5) → revoke an unused one.活跃 Key 达上限(5)→ 吊销不用的。
429Rate-limited (token exchange 30/min/IP) → cache your token.限流(交换 30/分/IP)→ 缓存令牌。

Security安全