API Key 异步媒体完整调用
H3 默认先优化再生成;说明显式关闭、任务查询和鉴权下载的完整服务端流程。
Account API Key 调用 H3 时,生成任务默认包含提示词优化:创建一次任务,平台先优化、再生成视频。无需额外调用优化接口;优化按实际用量单独计费。
要直接使用提交的文本,在生成请求顶层传 "optimizePrompt": false。它只接受 JSON 布尔值,不能写成字符串 "false"。关闭优化仍需内容安全审核;如果已单独优化并采用文本,也应传 false,避免重复优化。独立调用见提示词优化。
创建、查询和下载是同一条受保护调用链,后两步仍要携带创建任务时使用的 Account API Key。
调用规则
| 规则 | 正确做法 |
|---|---|
| 提示词优化 | H3 缺省或 true 开启;顶层 optimizePrompt: false 关闭。默认流程只创建一个 Job。 |
| API 入口 | 固定为 https://api.jusuanhub.com/v1,不使用 Portal,也不带历史 :10443。 |
| 任务地址 | 保存并原样使用创建响应中的绝对 jobUrl;不要删除 model 查询参数。 |
| 结果地址 | 保存并原样使用终态响应中的 outputs[].contentUrl。 |
| 鉴权 | 创建、查询和下载均发送 Authorization: Bearer $JUSP_API_KEY。 |
| 水印 | API Key 原样下载默认返回无可见水印的 source;只有显式 deliveryMode=marked 才生成带平台标识版本。 |
contentUrl 不是匿名公开 URL。未带 Key 的请求会以隐私保护方式返回 404,避免向未知调用方泄露资产是否存在。这个 404 不足以证明任务或资产不存在。
资源保存与空间配额
普通 Account API Key 与门户体验中心使用同一个人资源空间。主动上传和生成文件默认保存 30 天,分别从上传成功入库、产物成功提交起算;查询、重复上传、幂等重试和再次引用不会重新计时。在门户“我的资源”中可查看入库、到期时间并显式永久保存,永久保存仍占用空间。历史未记录新保存策略的资源在管理员明确生效前保持原策略;生效后从实际转换时刻起算,保留原入库时间及永久保存状态,不根据旧创建时间追溯到期。
| 选择 | 请求方式 | 保存与展示 |
|---|---|---|
| 默认保存 | 省略 storageMode,或传 personal_30d | 进入个人资源空间,首次入库起 30 天;可在门户永久保存。 |
| 一小时临时保存 | 显式传 temporary_1h | 需要平台已允许该账号或所属组织使用;不出现在个人长期资源列表,仍计入实际空间占用。 |
| 公网 URL 参考输入 | 使用支持的 URL 输入协议 | 参考输入遵循独立的一小时任务临时合同,不自动进入个人资源库;生成结果仍按请求的保存方式处理。 |
storageMode 是平台保存选项,支持图片、音频、视频及文档解析的 JSON 生成/处理请求,也支持主动 multipart 上传的同名表单字段;MiniMax V2 的输出支持同一选项。上传和生成是两次独立请求,分别选择保存方式。未获允许或策略暂不可确认时,临时模式请求会被拒绝;已接受任务保留受理时的选择。输入、输出分别从各自成功入库起保留一小时。到期停止业务读取,物理文件由后台异步回收,执行中的必要引用保护仍生效。
资产响应中的 storageMode、ingestedAt 和 expiresAt 用于核对保存方式与时间;已在门户永久保存的资源没有自动到期时间。不要把旧响应中的到期时间当作永久保存后的当前状态。
空间满额时,新上传和新生成会被拒绝;已有资源仍可查看、下载、删除,原任务重放和已接受生成的交付继续完成。回收站、临时资源及尚待物理回收的文件仍占空间,后台诊断副本不重复计入个人用量。普通 Key 不能通过应用来源或隐藏产物字段绕过保存与配额。
1. 创建 H3 任务
先在服务端设置环境变量。Key 不得进入网页源码、浏览器存储、URL 或日志。
export JUSP_BASE_URL='https://api.jusuanhub.com/v1'
export JUSP_API_KEY='<API_KEY>'
export JUSP_MODEL='minimax-h3'
export JUSP_IDEMPOTENCY_KEY="$(openssl rand -hex 16)"文生视频最小请求:
jq -n --arg model "$JUSP_MODEL" '{
model:$model,
generationMode:"t2v",
prompt:"清晨的海岸,镜头缓慢推进,柔和的自然光",
resolutionTier:"768p",
orientation:"landscape",
aspectRatio:"16:9",
seconds:5
}' |
curl --fail-with-body --max-time 60 "$JUSP_BASE_URL/media/generations" \
-H "Authorization: Bearer $JUSP_API_KEY" \
-H "Idempotency-Key: $JUSP_IDEMPOTENCY_KEY" \
-H 'Content-Type: application/json' \
--data-binary @- --output create.jsonH3 四种模式缺省开启 optimizePrompt,先完成提示词准备再生成。已独立优化并采用最终文本,或希望直接使用原文时,在创建正文显式添加 "optimizePrompt": false,优化调用和费用为零。该开关只接受布尔值;省略不会让其他模型自动优化。重试与压缩按实际优化用量计费,完整上界和人工采用例子见提示词优化。
平台尚未启用自动优化能力时,H3 缺省或 optimizePrompt: true 请求返回 503 prompt_optimization_capability_unavailable。此时不会按原文自动生成;需要直接使用已确认文本时显式传 false,仍需满足正常生成审核与规格要求。默认优化示例以平台已启用该能力为前提。
创建成功通常返回 202。保存整个响应,尤其是绝对 jobUrl:
{
"jobId": "job_...",
"jobUrl": "https://api.jusuanhub.com/v1/jobs/job_...?model=minimax-h3",
"status": "queued"
}2. 查询返回的 jobUrl
不要把 jobId 拼到 Portal 域名。优先读取响应中的 URL:
JOB_URL="$(jq -er '.jobUrl' create.json)"
curl --fail-with-body --max-time 60 "$JOB_URL" \
-H "Authorization: Bearer $JUSP_API_KEY" \
--output job.json202 只代表受理,包含自动优化准备的时间。若优化技术重试一次后仍失败,查询 Job 得到 failed 和 errorCode: prompt_optimization_failed,不会回退原文继续生成;查看费用回执,不能把失败等同未产生优化费用。
queued 或 running 时按 retryAfterSeconds / refreshAfterSeconds 有界轮询;succeeded、failed、canceled 是终态。本地等待超时不会取消服务端任务,更不能换新幂等键重新创建。
自动优化的错误会区分原因:准备超时为 prompt_optimization_timeout;内容审核未通过为 content_safety_blocked;需要补充说明为 content_safety_requires_clarification;优化稿被拒绝为 prompt_optimization_candidate_rejected;审核服务暂不可用为 content_safety_unavailable。这些错误发生于 failureStage: prompt_optimization,安全相关原因的 phase 为 content_safety。技术失败继续使用 prompt_optimization_failed。响应说明视频生成尚未开始,优化费用仍按实际调用结算。
查询 HTTP 200 仅表示查询成功,必须检查正文 status、errorCode、errorMessage;有 details 时可显示受控的审核原因和操作指导。retryable: false 表示不要自动新建付费任务。恢复查询保留原失败原因。
3. 鉴权下载 contentUrl
任务成功后,直接读取返回的资源地址。省略 deliveryMode 默认返回无可见水印的 source master,通常在 Job succeeded 后立即可下载:
CONTENT_URL="$(jq -er '.outputs[0].contentUrl // .assets[0].contentUrl' job.json)"
curl --fail-with-body --location --max-time 300 "$CONTENT_URL" \
-H "Authorization: Bearer $JUSP_API_KEY" \
--output result.mp4需要带平台标识版本时才显式追加 deliveryMode=marked。该版本由独立导出任务生成,可能先返回 HTTP 202;不能把 202 JSON 保存成 MP4:
MARKED_URL="${CONTENT_URL}&deliveryMode=marked"
while :; do
STATUS="$(curl --silent --show-error --location --max-time 300 \
-H "Authorization: Bearer $JUSP_API_KEY" \
--dump-header marked.headers \
--output marked.body \
--write-out '%{http_code}' \
"$MARKED_URL")"
if [ "$STATUS" = 200 ]; then
mv marked.body result-marked.mp4
break
fi
if [ "$STATUS" != 202 ]; then
printf '带标识下载失败,HTTP %s\n' "$STATUS" >&2
cat marked.body >&2
exit 1
fi
WAIT_SECONDS="$(jq -r '.retryAfterSeconds // 2' marked.body)"
sleep "$WAIT_SECONDS"
donedeliveryMode 只接受 source 和 marked;省略等同 source。它是结果交付选项,不属于 H3 mediaSpec,不会重新调用模型或重复计费。
不要把 contentUrl 直接赋给 <video src> 或 <img src>:浏览器无法安全持有 Account API Key。Web 应用应由自己的后端下载/流式转发,或转存到应用对象存储后返回应用自己的短期签名 URL。
Java / Spring 服务端
下面使用 JDK HttpClient 和 Jackson,可直接放进 Spring Service。重点是查询和下载继续复用同一个 Authorization 头,并只向可信 API 来源发送凭据。
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
import java.time.Duration;
import java.util.Set;
import java.util.UUID;
public final class H3Example {
private static final URI BASE = URI.create("https://api.jusuanhub.com/v1");
private final String key = System.getenv("JUSP_API_KEY");
private final ObjectMapper json = new ObjectMapper();
private final HttpClient http = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10)).build();
private HttpRequest.Builder authenticated(URI uri) {
if (!uri.getScheme().equals(BASE.getScheme()) ||
!uri.getAuthority().equals(BASE.getAuthority()))
throw new IllegalArgumentException("拒绝向非 API 来源发送 Key");
return HttpRequest.newBuilder(uri)
.timeout(Duration.ofSeconds(60))
.header("Authorization", "Bearer " + key);
}
public void run() throws Exception {
var payload = json.createObjectNode()
.put("model", "minimax-h3")
.put("generationMode", "t2v")
.put("prompt", "清晨的海岸,镜头缓慢推进,柔和的自然光")
.put("resolutionTier", "768p")
.put("orientation", "landscape")
.put("aspectRatio", "16:9")
.put("seconds", 5);
var createRequest = authenticated(BASE.resolve("/v1/media/generations"))
.header("Content-Type", "application/json")
.header("Idempotency-Key", UUID.randomUUID().toString())
.POST(HttpRequest.BodyPublishers.ofString(json.writeValueAsString(payload)))
.build();
var createResponse = http.send(createRequest, HttpResponse.BodyHandlers.ofString());
if (createResponse.statusCode() / 100 != 2)
throw new IllegalStateException(createResponse.body());
JsonNode job = json.readTree(createResponse.body());
URI jobUrl = URI.create(job.path("jobUrl").asText());
var terminal = Set.of("succeeded", "failed", "canceled");
var deadline = System.nanoTime() + Duration.ofMinutes(30).toNanos();
while (!terminal.contains(job.path("status").asText())) {
if (System.nanoTime() >= deadline)
throw new IllegalStateException("本地等待结束;保留 jobUrl 稍后恢复");
Thread.sleep(Math.max(1, job.path("retryAfterSeconds").asInt(3)) * 1000L);
var response = http.send(
authenticated(jobUrl).GET().build(), HttpResponse.BodyHandlers.ofString());
if (response.statusCode() / 100 != 2)
throw new IllegalStateException(response.body());
job = json.readTree(response.body());
}
if (!job.path("status").asText().equals("succeeded"))
throw new IllegalStateException(job.toString());
// 原样 contentUrl 默认返回无可见水印的 source master。
URI contentUrl = URI.create(job.path("outputs").get(0).path("contentUrl").asText());
var download = http.send(
authenticated(contentUrl).timeout(Duration.ofMinutes(5)).GET().build(),
HttpResponse.BodyHandlers.ofFile(Path.of("result.mp4")));
if (download.statusCode() / 100 != 2)
throw new IllegalStateException("下载失败:" + download.statusCode());
}
}正式项目应把 HttpClient、ObjectMapper 和 API 配置作为单例依赖注入,并按 错误与恢复 处理 429、5xx、超时和幂等恢复。
快速排错
| 现象 | 根因和处理 |
|---|---|
api.jusuanhub.com:10443 失败 | 删除旧端口,改用标准 443;同时检查鉴权和查询参数。 |
portal.jusuanhub.com/v1/... 返回 HTML 403/405 | Portal 是网页入口,不是模型 API;改用 api.jusuanhub.com/v1。 |
| Job 或资源返回 404,但 Portal 中能看到结果 | 通常缺少 Bearer、Key 不属于原任务,或手工拼 URL 丢了 model;原样使用返回 URL。 |
| 下载得到很小的 JSON 而不是视频 | 只有显式 deliveryMode=marked 才可能返回 202;读取 retryAfterSeconds 后重试同一 URL,不能把 202 body 当作媒体文件。 |
| 需要带平台标识结果 | 在原 contentUrl 后追加 &deliveryMode=marked;默认不带可见水印。 |
| 409 | 相同幂等键对应的状态/正文冲突;按原键恢复,开始新业务动作才换键。 |
| 429 | 按 Retry-After 退避,不并发重放。 |
| 5xx 或网络超时 | 写请求结果可能未知;先用原 jobUrl / 幂等键查询,不能立即创建第二个任务。 |
H3 四种模式和素材限制见 MiniMax H3,通用任务状态机见 等待任务并下载结果。