# MiniMax H3

VIDEOFeaturedminimax-h3

**MiniMax H3** (Hailuo-03) is the next-generation open-weight multimodal video model from [MiniMax](https://www.minimaxi.com/), producing 2K clips at 24 FPS with native stereo audio generated in the same pass. It supports text-to-video and image-to-video with optional first-to-last frame control, durations from 5 to 15 seconds, and six aspect ratios from 21:9 to 9:16\. It is the image-to-video pick for a subject that has to act on beats, such as head turns, reactions, and gestures, and it lands each beat the prompt asks for. Ideal for cinematic storytelling, social content, and any workflow that needs sound locked to motion without a separate audio pass.

Best for

Image-to-video where a subject acts on beats: head turns, reactions, gestures, 2K video with native stereo audio, First-and-last-frame controlled transitions, Cinematic 5–15s clips across six aspect ratios

POST

/v2/workspaces/{workspace\_id}/base-models/minimax-h3/inferences

```bash
curl --request POST \
  --url https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
  "prompt": "a knight standing in a snowy forest",
  "aspect_ratio": "LANDSCAPE_16_9_768p",
  "duration_seconds": 5,
  "guidance_file_first_frame": [
    {
      "url": "<file_url>"
    }
  ],
  "guidance_file_last_frame": [
    {
      "url": "<file_url>"
    }
  ]
}'
```

```python
import requests


url = "https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences"


payload = {
    "prompt": "a knight standing in a snowy forest",
    "aspect_ratio": "LANDSCAPE_16_9_768p",
    "duration_seconds": 5,
    "guidance_file_first_frame": [{ "url": "<file_url>" }],
    "guidance_file_last_frame": [{ "url": "<file_url>" }]
}
headers = {
    "Authorization": "Bearer <token>",
    "Content-Type": "application/json"
}


response = requests.post(url, json=payload, headers=headers)


print(response.json())
```

```js
const url = 'https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences';
const options = {
  method: 'POST',
  headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
  body: '{"prompt":"a knight standing in a snowy forest","aspect_ratio":"LANDSCAPE_16_9_768p","duration_seconds":5,"guidance_file_first_frame":[{"url":"<file_url>"}],"guidance_file_last_frame":[{"url":"<file_url>"}]}'
};


try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main


import (
  "fmt"
  "strings"
  "net/http"
  "io"
)


func main() {


  url := "https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences"


  payload := strings.NewReader("{\n  \"prompt\": \"a knight standing in a snowy forest\",\n  \"aspect_ratio\": \"LANDSCAPE_16_9_768p\",\n  \"duration_seconds\": 5,\n  \"guidance_file_first_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ],\n  \"guidance_file_last_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ]\n}")


  req, _ := http.NewRequest("POST", url, payload)


  req.Header.Add("Authorization", "Bearer <token>")
  req.Header.Add("Content-Type", "application/json")


  res, _ := http.DefaultClient.Do(req)


  defer res.Body.Close()
  body, _ := io.ReadAll(res.Body)


  fmt.Println(res)
  fmt.Println(string(body))


}
```

```php
<?php


$curl = curl_init();


curl_setopt_array($curl, [
  CURLOPT_URL => "https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => "",
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => json_encode([
    'prompt' => 'a knight standing in a snowy forest',
    'aspect_ratio' => 'LANDSCAPE_16_9_768p',
    'duration_seconds' => 5,
    'guidance_file_first_frame' => [
        [
                'url' => '<file_url>'
        ]
    ],
    'guidance_file_last_frame' => [
        [
                'url' => '<file_url>'
        ]
    ]
  ]),
  CURLOPT_HTTPHEADER => [
    "Authorization: Bearer <token>",
    "Content-Type: application/json"
  ],
]);


$response = curl_exec($curl);
$err = curl_error($curl);


curl_close($curl);


if ($err) {
  echo "cURL Error #:" . $err;
} else {
  echo $response;
}
```

```java
OkHttpClient client = new OkHttpClient();


MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "{\n  \"prompt\": \"a knight standing in a snowy forest\",\n  \"aspect_ratio\": \"LANDSCAPE_16_9_768p\",\n  \"duration_seconds\": 5,\n  \"guidance_file_first_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ],\n  \"guidance_file_last_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ]\n}");
Request request = new Request.Builder()
  .url("https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences")
  .post(body)
  .addHeader("Authorization", "Bearer <token>")
  .addHeader("Content-Type", "application/json")
  .build();


Response response = client.newCall(request).execute();
```

```ruby
require 'uri'
require 'net/http'


url = URI("https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences")


http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true


request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n  \"prompt\": \"a knight standing in a snowy forest\",\n  \"aspect_ratio\": \"LANDSCAPE_16_9_768p\",\n  \"duration_seconds\": 5,\n  \"guidance_file_first_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ],\n  \"guidance_file_last_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ]\n}"


response = http.request(request)
puts response.read_body
```

```csharp
var client = new RestClient("https://api.app.layer.ai/api/v2/workspaces/:workspace_id/base-models/minimax-h3/inferences");
var request = new RestRequest("", Method.Post);
request.AddHeader("Authorization", "Bearer <token>");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\n  \"prompt\": \"a knight standing in a snowy forest\",\n  \"aspect_ratio\": \"LANDSCAPE_16_9_768p\",\n  \"duration_seconds\": 5,\n  \"guidance_file_first_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ],\n  \"guidance_file_last_frame\": [\n    {\n      \"url\": \"<file_url>\"\n    }\n  ]\n}", ParameterType.RequestBody);
var response = client.Execute(request);
```

* Layer API

## Authorizations

* **[bearerAuth](/docs/v2/rest-api#bearerauth)**
* **[oauth2](/docs/v2/rest-api#oauth2)**

## Parameters

### Path Parameters

**workspace\_id**

required

_Workspace Id_

Id of the workspace that owns the resource.

string format: uuid

Id of the workspace that owns the resource.

### Query Parameters

**session\_name**

_Session Name_

Organize this run under a named session. A new session is created if none matches.

string

nullable

Organize this run under a named session. A new session is created if none matches.

### Header Parameters

**Idempotency-Key**

string

<= 255 characters

Opaque key making a retry of this request return the first result. A 2xx response is replayed for 24 hours with `Idempotent-Replayed: true`. A 4xx releases the key. A 5xx, or a request still running, holds the key for 120 seconds, during which a retry gets 409; after that a retry executes again. The key covers the method, path, query, and byte-identical body it was first used with; reusing it for a different request is rejected with 422\. Protection is best effort: if the key store is unavailable, or a record is lost early, a retry can execute again even after an earlier 409\. See the Idempotency section of the API description.

## Request Bodyrequired

_MiniMax H3_object

**prompt**

required

_Prompt_

Describe what to generate, or the change to make.

string

<= 50000 characters

**color\_palette**

_Colors_

Colors the output should use. This model doesn’t take a palette natively, so the colors are added to the prompt.

object

**colors**

_Colors_

Array<object>

<= 16 items

_PaletteColor_

One named color of a palette.

object

**name**

required

_Name_

string

\>= 1 characters <= 64 characters

**hex**

required

_Hex_

string

/^#(?:\[0-9A-Fa-f\]{6}|\[0-9A-Fa-f\]{3})$/

**role**

_Role_

string

nullable <= 64 characters

**reference\_set\_id**

_Reference Set Id_

string format: uuid

nullable

**aspect\_ratio**

_Aspect ratio_

The shape and size of the output.

string

default: LANDSCAPE\_16\_9\_768p

Allowed values: LANDSCAPE\_21\_9\_768p LANDSCAPE\_16\_9\_768p LANDSCAPE\_4\_3\_768p SQUARE\_768p PORTRAIT\_3\_4\_768p PORTRAIT\_9\_16\_768p LANDSCAPE\_21\_9\_1440p LANDSCAPE\_16\_9\_1440p LANDSCAPE\_4\_3\_1440p SQUARE\_1440p PORTRAIT\_3\_4\_1440p PORTRAIT\_9\_16\_1440p LANDSCAPE\_21\_9\_2160p LANDSCAPE\_16\_9\_2160p LANDSCAPE\_4\_3\_2160p SQUARE\_2160p PORTRAIT\_3\_4\_2160p PORTRAIT\_9\_16\_2160p

**prompt\_enhancement**

_Prompt enhancement_

Let the model rewrite the prompt before generating.

_Advanced field._

string

default: AUTO

Allowed values: AUTO OFF FAST STANDARD QUALITY

**seed**

_Seed_

The starting point for the model’s randomness. The same seed and settings give the same result.

_Advanced field._

integer

nullable

**duration\_seconds**

_Duration_

Length of the generated clip, in seconds.

integer

default: 5

**guidance\_file\_first\_frame**

_First frame_

The frame the video starts on

Array<object>

_InferenceFormFileRef_

A single guidance/reference file supplied to a `reference_image_list` field.

The slot’s guidance `type` is fixed by the field it’s attached to; the caller supplies the file (its URL, or the id of a file it can read) and, where the model supports per-file weighting, a weight.

object

**url**

required

_Url_

The file’s URL, or the id of a file in this workspace or a public file.

string

**weight**

_Weight_

number

nullable

**guidance\_file\_last\_frame**

_Last frame_

The frame the video ends on

Array<object>

_InferenceFormFileRef_

A single guidance/reference file supplied to a `reference_image_list` field.

The slot’s guidance `type` is fixed by the field it’s attached to; the caller supplies the file (its URL, or the id of a file it can read) and, where the model supports per-file weighting, a weight.

object

**url**

required

_Url_

The file’s URL, or the id of a file in this workspace or a public file.

string

**weight**

_Weight_

number

nullable

**prompt\_language**

_Prompt language_

The language the prompt is written in, so it reaches the model as you meant it.

_Advanced field._

string

nullable

##### Example

```json
{
  "prompt": "a knight standing in a snowy forest",
  "aspect_ratio": "LANDSCAPE_16_9_768p",
  "duration_seconds": 5,
  "guidance_file_first_frame": [
    {
      "url": "<file_url>"
    }
  ],
  "guidance_file_last_frame": [
    {
      "url": "<file_url>"
    }
  ]
}
```

## Responses

### 202

Successful Response

_ExecuteForgeOutput_object

**inference\_id**

required

_Inference Id_

Unique identifier for this forge run.

string format: uuid

**status**

required

_InferenceStatus_

Current status: IN\_PROGRESS.

string

Allowed values: in\_progress complete failed cancelled deleted

**estimated\_price\_creative\_units**

_Estimated Price Creative Units_

Estimated price in Creative Units.

number

nullable

**poll\_interval\_seconds**

required

_Poll Interval Seconds_

Suggested polling interval in seconds.

integer

**created\_at**

required

_Created At_

Timestamp of when the run was created.

string format: date-time

**session\_id**

_Session Id_

Session ID the run was added to, if a session was specified.

string format: uuid

nullable

**normalized\_parameters**

Any of:

**NormalizedInferenceParameters**

_NormalizedInferenceParameters_

Inference parameters after model-specific normalization.

These reflect the actual values used for generation, including model defaults applied for any parameters not explicitly set.

object

**width**

_Width_

Resolved output width in pixels.

integer

nullable

**height**

_Height_

Resolved output height in pixels.

integer

nullable

**batch\_size**

_Batch Size_

Number of outputs to generate.

integer

nullable

**num\_inference\_steps**

_Num Inference Steps_

Resolved number of diffusion steps.

integer

nullable

**guidance\_scale**

_Guidance Scale_

Resolved guidance scale.

number

nullable

**duration\_seconds**

_Duration Seconds_

Resolved output length in seconds — video duration or audio clip length.

number

nullable

**fps**

_Fps_

Resolved FPS.

integer

nullable

**null**

null

##### Example

```json
{
  "status": "in_progress"
}
```

### 401

Unauthenticated — missing or invalid Bearer token.

object

**type**

required

string

**title**

required

string

**status**

required

integer

**detail**

required

string

**error\_code**

required

Machine-readable error code: the last path segment of `type`.

string

##### Example

```json
{
  "type": "https://api.layer.ai/errors/ERROR_CODE",
  "title": "Error Title",
  "status": 400,
  "detail": "Human-readable description.",
  "error_code": "ERROR_CODE"
}
```

### 403

Forbidden — insufficient permissions, or the access token lacks the scope the operation requires.

object

**type**

required

string

**title**

required

string

**status**

required

integer

**detail**

required

string

**error\_code**

required

Machine-readable error code: the last path segment of `type`.

string

##### Example

```json
{
  "type": "https://api.layer.ai/errors/ERROR_CODE",
  "title": "Error Title",
  "status": 400,
  "detail": "Human-readable description.",
  "error_code": "ERROR_CODE"
}
```

### 404

Resource not found.

object

**type**

required

string

**title**

required

string

**status**

required

integer

**detail**

required

string

**error\_code**

required

Machine-readable error code: the last path segment of `type`.

string

##### Example

```json
{
  "type": "https://api.layer.ai/errors/ERROR_CODE",
  "title": "Error Title",
  "status": 400,
  "detail": "Human-readable description.",
  "error_code": "ERROR_CODE"
}
```

### 409

The outcome of the request with this `Idempotency-Key` is not known yet: it is still running, or it failed without a stored response. Retry after the number of seconds in `Retry-After`.

object

**type**

required

string

**title**

required

string

**status**

required

integer

**detail**

required

string

**error\_code**

required

Machine-readable error code: the last path segment of `type`.

string

##### Example

```json
{
  "type": "https://api.layer.ai/errors/ERROR_CODE",
  "title": "Error Title",
  "status": 400,
  "detail": "Human-readable description.",
  "error_code": "ERROR_CODE"
}
```

### 422

Invalid input parameters, or an `Idempotency-Key` reused for a different request.

object

**type**

required

string

**title**

required

string

**status**

required

integer

**detail**

required

string

**error\_code**

required

Machine-readable error code: the last path segment of `type`.

string

##### Example

```json
{
  "type": "https://api.layer.ai/errors/ERROR_CODE",
  "title": "Error Title",
  "status": 400,
  "detail": "Human-readable description.",
  "error_code": "ERROR_CODE"
}
```

### 429

Rate limited — retry after the number of seconds in `Retry-After`.

object

**type**

required

string

**title**

required

string

**status**

required

integer

**detail**

required

string

**error\_code**

required

Machine-readable error code: the last path segment of `type`.

string

##### Example

```json
{
  "type": "https://api.layer.ai/errors/ERROR_CODE",
  "title": "Error Title",
  "status": 400,
  "detail": "Human-readable description.",
  "error_code": "ERROR_CODE"
}
```

### 500

Internal server error.

object

**type**

required

string

**title**

required

string

**status**

required

integer

**detail**

required

string

**error\_code**

required

Machine-readable error code: the last path segment of `type`.

string

##### Example

```json
{
  "type": "https://api.layer.ai/errors/ERROR_CODE",
  "title": "Error Title",
  "status": 400,
  "detail": "Human-readable description.",
  "error_code": "ERROR_CODE"
}
```
