星海智算开发文档
模型 API

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.json

H3 四种模式缺省开启 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.json

202 只代表受理,包含自动优化准备的时间。若优化技术重试一次后仍失败,查询 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"
done

deliveryMode 只接受 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/405Portal 是网页入口,不是模型 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,通用任务状态机见 等待任务并下载结果。

本页目录