# MiniMax H3 Max Turbo — Scenepond API

Model ID: `minimax/h3-max-turbo/image-to-video`

Model developer: MiniMax

Purpose: Image to video

Source page: https://open.scenepond.ai/en/models/minimax/h3-max-turbo/image-to-video#api

Reviewed: 2026-10-11

Base URL: `https://open.scenepond.ai/v1`

Authenticate every request with Authorization: Bearer and your Scenepond API key. Keep the key on your server.

## Scenepond asynchronous tasks

`POST /v1/tasks`

### Minimum request

#### cURL

```bash
curl --fail-with-body -X POST "https://open.scenepond.ai/v1/tasks" \
  -H "Authorization: Bearer $SCENEPOND_API_KEY" \
  -H "Content-Type: application/json" \
  --data-binary @- <<'JSON'
{
  "model": "minimax/h3-max-turbo/image-to-video",
  "parameters": {
    "prompt": "A quiet lakeside at sunrise",
    "image_urls": [
      "https://example.com/reference.png"
    ]
  }
}
JSON
```

#### Python

```python
import os
import json
from urllib.parse import quote
from urllib.request import Request, urlopen

payload = json.loads("{\n  \"model\": \"minimax/h3-max-turbo/image-to-video\",\n  \"parameters\": {\n    \"prompt\": \"A quiet lakeside at sunrise\",\n    \"image_urls\": [\n      \"https://example.com/reference.png\"\n    ]\n  }\n}")

request = Request(
    "https://open.scenepond.ai/v1/tasks",
    headers={
        "Authorization": "Bearer " + os.environ["SCENEPOND_API_KEY"],
        "Content-Type": "application/json",
    },
    data=json.dumps(payload).encode("utf-8"),
    method="POST",
)
with urlopen(request) as response:
    result = json.load(response)
print(json.dumps(result, indent=2))
```

#### JavaScript

```javascript
const response = await fetch("https://open.scenepond.ai/v1/tasks", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.SCENEPOND_API_KEY}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
  "model": "minimax/h3-max-turbo/image-to-video",
  "parameters": {
    "prompt": "A quiet lakeside at sunrise",
    "image_urls": [
      "https://example.com/reference.png"
    ]
  }
})
});
if (!response.ok) throw new Error(`API error: ${response.status} ${await response.text()}`);
const result = await response.json();
console.log(result);
```

### Request parameters

- `model` — **Required**; `string`. Use this exact public model ID.
  - Constraints: `const = "minimax/h3-max-turbo/image-to-video"`

- `parameters` — **Required**; `object`. Generation parameters for this model.

### Fields in parameters

These fields apply when parameters is supplied. A required child does not make its optional parent required.

- `parameters.target_audio_url` — **Optional**; `string`. Accessible HTTP(S) audio URL for reference audio.
  - Constraints: `minLength = 1`; `pattern = "\\S"`

- `parameters.enable_safety_checker` — **Optional**; `boolean`. Whether the provider safety checker is enabled. Provider policy may reject attempts to disable it.
  - Default: `true`

- `parameters.duration` — **Optional**; `number`. Requested video duration in seconds.
  - Default: `5`
  - Constraints: `minimum = 5`; `maximum = 15`

- `parameters.resolution` — **Optional**; `string`. Output resolution. Values are case-sensitive and specific to this model.
  - Default: `"768P"`
  - Constraints: `enum = ["480P","768P","1080P"]`

- `parameters.prompt` — **Required**; `string`. Describe the subject, scene, and desired generation.
  - Constraints: `maxLength = 50000`; `minLength = 1`

- `parameters.sync_mode` — **Optional**; `boolean`. Only false is supported. This gateway submits asynchronous tasks.
  - Default: `false`
  - Constraints: `enum = [false]`

- `parameters.prompt_expansion_mode` — **Optional**; `string`. Provider prompt expansion strategy.
  - Default: `"balanced"`

- `parameters.seed` — **Optional**; `integer`. Integer seed for controlling generation randomness.

- `parameters.image_urls` — **Required**; `string[]`. Reference image URLs, in first-frame then last-frame order.


### Illustrative responses

Response examples show the structure only. IDs, URLs, and values are placeholders.

#### Submission response

```json
{
  "task_id": "task_EXAMPLE",
  "model": "minimax/h3-max-turbo/image-to-video",
  "status": "queued",
  "progress": 0,
  "created_at": 1700000000,
  "finished_at": 0,
  "error": null,
  "links": {
    "self": "/v1/tasks/task_EXAMPLE",
    "artifacts": "/v1/tasks/task_EXAMPLE/artifacts"
  }
}
```

#### Completed task status

```json
{
  "task_id": "task_EXAMPLE",
  "model": "minimax/h3-max-turbo/image-to-video",
  "status": "succeeded",
  "progress": 100,
  "created_at": 1700000000,
  "finished_at": 1700000060,
  "error": null,
  "links": {
    "self": "/v1/tasks/task_EXAMPLE",
    "artifacts": "/v1/tasks/task_EXAMPLE/artifacts"
  }
}
```

#### Artifact listing

```json
{
  "task_id": "task_EXAMPLE",
  "artifacts": [
    {
      "key": "video",
      "type": "video",
      "mime_type": "video/mp4",
      "content_url": "https://open.scenepond.ai/v1/tasks/task_EXAMPLE/artifacts/video/content",
      "expires_at": 1701209660
    }
  ]
}
```

#### Expired artifact response (API key authentication)

```json
{
  "error": {
    "message": "Artifact content has expired or is no longer available",
    "type": "artifact_expired",
    "code": "artifact_expired"
  }
}
```

### Follow-up requests

#### 2. Check task status

Poll every few seconds until succeeded or failed.

`GET /v1/tasks/{task_id}`

##### cURL

```bash
curl --fail-with-body -X GET "https://open.scenepond.ai/v1/tasks/$SCENEPOND_TASK_ID" \
  -H "Authorization: Bearer $SCENEPOND_API_KEY"
```

##### Python

```python
import os
import json
from urllib.parse import quote
from urllib.request import Request, urlopen

request = Request(
    "https://open.scenepond.ai/v1/tasks/" + quote(os.environ["SCENEPOND_TASK_ID"], safe="") + "",
    headers={
        "Authorization": "Bearer " + os.environ["SCENEPOND_API_KEY"],
        "Content-Type": "application/json",
    },
    method="GET",
)
with urlopen(request) as response:
    result = json.load(response)
print(json.dumps(result, indent=2))
```

##### JavaScript

```javascript
if (!process.env.SCENEPOND_TASK_ID) throw new Error("Set SCENEPOND_TASK_ID first");
const response = await fetch("https://open.scenepond.ai/v1/tasks/" + encodeURIComponent(process.env.SCENEPOND_TASK_ID) + "", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.SCENEPOND_API_KEY}`,
    "Content-Type": "application/json"
  }
});
if (!response.ok) throw new Error(`API error: ${response.status} ${await response.text()}`);
const result = await response.json();
console.log(result);
```

#### 3. Get the results

After succeeded, list artifacts and download each content_url with the same API key.

`GET /v1/tasks/{task_id}/artifacts`

##### cURL

```bash
curl --fail-with-body -X GET "https://open.scenepond.ai/v1/tasks/$SCENEPOND_TASK_ID/artifacts" \
  -H "Authorization: Bearer $SCENEPOND_API_KEY"
```

##### Python

```python
import os
import json
from urllib.parse import quote
from urllib.request import Request, urlopen

request = Request(
    "https://open.scenepond.ai/v1/tasks/" + quote(os.environ["SCENEPOND_TASK_ID"], safe="") + "/artifacts",
    headers={
        "Authorization": "Bearer " + os.environ["SCENEPOND_API_KEY"],
        "Content-Type": "application/json",
    },
    method="GET",
)
with urlopen(request) as response:
    result = json.load(response)
print(json.dumps(result, indent=2))
```

##### JavaScript

```javascript
if (!process.env.SCENEPOND_TASK_ID) throw new Error("Set SCENEPOND_TASK_ID first");
const response = await fetch("https://open.scenepond.ai/v1/tasks/" + encodeURIComponent(process.env.SCENEPOND_TASK_ID) + "/artifacts", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.SCENEPOND_API_KEY}`,
    "Content-Type": "application/json"
  }
});
if (!response.ok) throw new Error(`API error: ${response.status} ${await response.text()}`);
const result = await response.json();
console.log(result);
```

#### 4. Download before expiry

Set SCENEPOND_TASK_ID to task_id and SCENEPOND_ARTIFACT_KEY to artifacts[].key. Download the binary file before expires_at. The content endpoint supports GET, HEAD, and Range requests; saving content_url alone does not save the media.

`GET /v1/tasks/{task_id}/artifacts/{artifact_key}/content`

##### cURL

```bash
curl --fail-with-body --output output.bin -X GET "https://open.scenepond.ai/v1/tasks/$SCENEPOND_TASK_ID/artifacts/$SCENEPOND_ARTIFACT_KEY/content" \
  -H "Authorization: Bearer $SCENEPOND_API_KEY"
```

##### Python

```python
import os
import json
from urllib.parse import quote
from urllib.request import Request, urlopen

request = Request(
    "https://open.scenepond.ai/v1/tasks/" + quote(os.environ["SCENEPOND_TASK_ID"], safe="") + "/artifacts/" + quote(os.environ["SCENEPOND_ARTIFACT_KEY"], safe="") + "/content",
    headers={
        "Authorization": "Bearer " + os.environ["SCENEPOND_API_KEY"],
        "Content-Type": "application/json",
    },
    method="GET",
)
with urlopen(request) as response:
    with open("output.bin", "wb") as output:
        output.write(response.read())
print("Saved output.bin")
```

##### JavaScript

```javascript
import { writeFile } from "node:fs/promises";
if (!process.env.SCENEPOND_TASK_ID) throw new Error("Set SCENEPOND_TASK_ID first");
if (!process.env.SCENEPOND_ARTIFACT_KEY) throw new Error("Set SCENEPOND_ARTIFACT_KEY first");
const response = await fetch("https://open.scenepond.ai/v1/tasks/" + encodeURIComponent(process.env.SCENEPOND_TASK_ID) + "/artifacts/" + encodeURIComponent(process.env.SCENEPOND_ARTIFACT_KEY) + "/content", {
  method: "GET",
  headers: {
    "Authorization": `Bearer ${process.env.SCENEPOND_API_KEY}`,
    "Content-Type": "application/json"
  }
});
if (!response.ok) throw new Error(`API error: ${response.status} ${await response.text()}`);
await writeFile("output.bin", Buffer.from(await response.arrayBuffer()));
console.log("Saved output.bin");
```

### Request notes

- Images and videos use the same task API. Select a model; channel selection is automatic.
- Authenticate every request with Authorization: Bearer and your Scenepond API key. Keep the key on your server.
- Submit once, save task_id, then poll until succeeded or failed. Download results from the artifacts endpoint.
- Creation returns the task ID after acceptance. Some tasks may already be complete when the ID is returned.
- Accepted submissions return HTTP 202 with Location: /v1/tasks/{task_id}.
- Generated artifacts are stored for 14 days. Download them before expires_at; expired artifacts cannot be recovered.
- Do not automatically resubmit a timed-out POST. It may already have created a billable task.
- Parameters and limits vary by model. Only the fields listed for this model are accepted.
- Generated images and videos are stored for 14 days. Download and save them before expiry.
- Each stored artifact includes expires_at, its expiry time as a Unix timestamp in seconds. Use that value for each file; do not calculate expiry from the task creation time.
- Some older results may omit expires_at. This does not mean unlimited storage; download them as soon as possible.
- After expiry, content requests authenticated with an API key (without an access query parameter) return HTTP 410 with code artifact_expired. Private access links may return 404 for unavailable content. Expired files cannot be downloaded or recovered.
- Keep content_url private. Saving a link does not preserve the file; download the actual bytes to your own storage before expires_at.
