> ## Documentation Index
> Fetch the complete documentation index at: https://docs.apimart.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Modelos oficiais de vídeo Grok

> Gere vídeos a partir de texto ou imagens com grok-imagine-video e grok-imagine-video-1.5, ou edite um vídeo com o modelo base.

<Info>
  Esta página cobre os modelos oficiais `grok-imagine-video` e `grok-imagine-video-1.5`. Eles são diferentes de `grok-imagine-1.5-video-ext`; não misture nomes ou parâmetros.
</Info>

<Warning>
  Nunca exponha a API Key no navegador, variáveis públicas, LocalStorage, URL ou logs. Chame a APIMart pelo backend ou BFF.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.apimart.ai/v1/videos/generations \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --header 'Idempotency-Key: 7d0141e4-a19a-4650-a717-dab777b3a330' \
    --data '{
      "model": "grok-imagine-video",
      "prompt": "A cinematic aerial shot of a coastal city at sunrise",
      "duration": 5,
      "resolution": "720p",
      "aspect_ratio": "16:9",
      "nsfw_check": true
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://api.apimart.ai/v1/videos/generations", {
    method: "POST",
    headers: {
      Authorization: "Bearer <token>",
      "Content-Type": "application/json",
      Accept: "application/json",
      "Idempotency-Key": crypto.randomUUID(),
    },
    body: JSON.stringify({
      model: "grok-imagine-video",
      prompt: "Improve motion consistency and apply cinematic color grading",
      video: { url: "https://cdn.example.com/source-video.mp4" },
    }),
  });

  console.log(response.status, await response.json());
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "code": 200,
    "data": [{
      "status": "submitted",
      "task_id": "task_01M09Y4Y101HTFFPV2QPW9DQ3W"
    }]
  }
  ```

  ```json 400 theme={null}
  {
    "error": {
      "message": "Invalid request parameters",
      "type": "invalid_request_error",
      "param": "resolution",
      "code": "invalid_request_error"
    }
  }
  ```
</ResponseExample>

## Visão geral

Todos os modos usam o mesmo endpoint assíncrono:

```http theme={null}
POST https://api.apimart.ai/v1/videos/generations
```

| Campos enviados              | Modo                             | Modelos                      |
| ---------------------------- | -------------------------------- | ---------------------------- |
| Sem `image_urls` nem `video` | Texto para vídeo                 | Ambos os modelos             |
| `image_urls`                 | Imagens de referência para vídeo | Ambos os modelos             |
| `video`                      | Edição de vídeo                  | Somente `grok-imagine-video` |

Após enviar, guarde `data[0].task_id` e consulte:

```http theme={null}
GET https://api.apimart.ai/v1/tasks/{task_id}
```

<Warning>
  Não envie `X-APIMart-Response-Version`: ele ativa resposta HTTP `202`. Esta página usa o formato assíncrono HTTP `200` anterior.
</Warning>

## Capacidades

| Capacidade                          | `grok-imagine-video` | `grok-imagine-video-1.5` |
| ----------------------------------- | :------------------: | :----------------------: |
| Texto para vídeo                    |           ✅          |             ✅            |
| Uma ou várias imagens de referência |           ✅          |             ✅            |
| Edição de vídeo                     |           ✅          |             ❌            |
| `480p`                              |           ✅          |             ✅            |
| `720p`                              |           ✅          |             ✅            |
| `1080p`                             |           ❌          |             ✅            |
| Duração: 1–15 segundos              |         1–15         |           1–15           |
| Prompt                              |        1–8000        |          1–8000          |

```text theme={null}
duration     = 8
resolution   = 480p
aspect_ratio = auto
```

O contrato público não fixa máximo de imagens. Mantenha um array não vazio de URLs válidas na ordem original; não reutilize limites de modelos de imagem.

## Cabeçalhos

<ParamField header="Authorization" type="string" required>
  `Bearer <APIMART_API_KEY>`
</ParamField>

<ParamField header="Content-Type" type="string" required>
  Use sempre `application/json`.
</ParamField>

<ParamField header="Accept" type="string">
  `application/json`
</ParamField>

<ParamField header="Idempotency-Key" type="string">
  `Idempotency-Key` é opcional e muito recomendado para solicitações pagas. Aceita 1–191 caracteres ASCII visíveis; UUID recomendado. Um retry reutiliza chave e body originais. Não troque a chave se o resultado for incerto.

  Use uma nova chave por operação lógica. Uma repetição deve reutilizar a chave e o corpo originais.
</ParamField>

## Parâmetros

### Campos comuns

<ParamField body="model" type="string" required>
  Nome oficial; edição apenas com o modelo base

  * `grok-imagine-video`
  * `grok-imagine-video-1.5`
</ParamField>

<ParamField body="prompt" type="string" required>
  Instrução não vazia, máximo 8000 Unicode

  `Array.from(prompt).length`
</ParamField>

<ParamField body="nsfw_check" type="boolean" default={false}>
  Define se a moderação de conteúdo será executada antes do envio da tarefa de vídeo.

  * `true`: Usa `omni-moderation-latest` para revisar o prompt e as imagens de entrada
  * `false` ou omitido: Não solicita moderação nem adiciona custo ou latência de revisão (padrão)
</ParamField>

### Campos de geração

<ParamField body="duration" type="integer" default={8}>
  Somente geração; inteiro 1–15, padrão 8
</ParamField>

<ParamField body="resolution" type="string" default="480p">
  Base: `480p/720p`; 1.5: `480p/720p/1080p`; padrão `480p`

  * `grok-imagine-video`: `480p`, `720p`
  * `grok-imagine-video-1.5`: `480p`, `720p`, `1080p`
</ParamField>

<ParamField body="aspect_ratio" type="string" default="auto">
  Somente geração; `auto`, `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2` ou `2:3`

  * `auto`
  * `1:1`, `16:9`, `9:16`
  * `4:3`, `3:4`, `3:2`, `2:3`
</ParamField>

<ParamField body="image_urls" type="string[]">
  Array opcional; cada item é uma URL HTTPS pública; omitir se vazio

  * Cada item deve ser uma URL HTTPS pública; URL relativa, Data URL e Base64 puro não são aceitos.
  * Não envie aliases como `image`, `images` ou `input_reference`.
  * A ordem é preservada; URLs repetidas ocupam várias entradas e podem ser cobradas mais de uma vez.
</ParamField>

### Campos de edição de vídeo

<ParamField body="video" type="object">
  Vídeo fonte `{url}` em HTTPS público; somente Base

  <Expandable title="URL">
    <ParamField body="url" type="string" required>
      HTTPS
    </ParamField>
  </Expandable>
</ParamField>

A edição requer `model`, `prompt` e `video`, com `nsfw_check` opcional. Não envie `duration`, `resolution`, `aspect_ratio` nem `image_urls`; a plataforma detecta a duração da origem.

## Tipos de solicitação TypeScript

Use uma união discriminada para impedir campos de geração na edição.

```ts theme={null}
type GrokVideoModel =
  | "grok-imagine-video"
  | "grok-imagine-video-1.5";

type GrokVideoResolution = "480p" | "720p" | "1080p";

type GrokVideoAspectRatio =
  | "auto"
  | "1:1"
  | "16:9"
  | "9:16"
  | "4:3"
  | "3:4"
  | "3:2"
  | "2:3";

interface GrokVideoGenerateRequest {
  model: GrokVideoModel;
  prompt: string;
  nsfw_check?: boolean;
  duration?: number;
  resolution?: GrokVideoResolution;
  aspect_ratio?: GrokVideoAspectRatio;
  image_urls?: string[];
}

interface GrokVideoEditRequest {
  model: "grok-imagine-video";
  prompt: string;
  nsfw_check?: boolean;
  video: { url: string };
}

type GrokVideoRequest =
  | GrokVideoGenerateRequest
  | GrokVideoEditRequest;
```

## Exemplos

<Tabs>
  <Tab title="Texto para vídeo">
    ```json theme={null}
    {"model":"grok-imagine-video","prompt":"A cinematic aerial shot at sunrise","duration":5,"resolution":"720p","aspect_ratio":"16:9"}
    ```
  </Tab>

  <Tab title="1.5 · 1080p">
    ```json theme={null}
    {"model":"grok-imagine-video-1.5","prompt":"A smooth studio product commercial","duration":5,"resolution":"1080p","aspect_ratio":"16:9"}
    ```
  </Tab>

  <Tab title="Uma ou várias imagens de referência">
    ```json theme={null}
    {
      "model":"grok-imagine-video-1.5",
      "prompt":"Use the first image as subject and the second as style",
      "duration":5,
      "resolution":"720p",
      "aspect_ratio":"16:9",
      "image_urls":[
        "https://cdn.example.com/subject.jpg",
        "https://cdn.example.com/style.jpg"
      ]
    }
    ```
  </Tab>

  <Tab title="Edição de vídeo">
    ```json theme={null}
    {
      "model":"grok-imagine-video",
      "prompt":"Improve motion consistency and apply cinematic color grading",
      "video":{"url":"https://cdn.example.com/source.mp4"}
    }
    ```
  </Tab>
</Tabs>

## Tarefas assíncronas

### Criação bem-sucedida

Uma criação bem-sucedida retorna HTTP `200`. Salve `data[0].task_id`; o envio não significa vídeo concluído. Um ID de tarefa significa enviado, não concluído.

```json theme={null}
{
  "code":200,
  "data":[{"status":"submitted","task_id":"task_01M09Y4Y101HTFFPV2QPW9DQ3W"}]
}
```

### Consultar tarefa

```http theme={null}
GET https://api.apimart.ai/v1/tasks/{task_id}
Authorization: Bearer <APIMART_API_KEY>
Accept: application/json
```

Consulte `GET /v1/tasks/{task_id}` a cada 3–5 segundos. Após recarregar, retome com o ID salvo.

| `data.status` | Significado                  | Ação                               |
| ------------- | ---------------------------- | ---------------------------------- |
| `pending`     | Na fila                      | Continuar consultando              |
| `processing`  | Gerando                      | Mostrar progresso                  |
| `completed`   | Concluída                    | Ler resultado e parar              |
| `failed`      | Falhou e foi reembolsada     | Mostrar erro e parar               |
| `unknown`     | Temporariamente desconhecida | Reduzir frequência e tentar depois |

### Resposta concluída

```json theme={null}
{
  "code":200,
  "data":{
    "id":"task_xxx",
    "status":"completed",
    "progress":100,
    "created":1787040038,
    "completed":1787040081,
    "actual_time":43,
    "estimated_time":100,
    "cost":0.072,
    "credits_cost":0.72,
    "result":{"videos":[{"url":["https://cdn.example.com/result.mp4"],"expires_at":1787126481}]}
  }
}
```

`result.videos[0].url` é um array de strings, não uma string. Valide cada valor como URL HTTPS. Recomenda-se validação em tempo de execução:

```ts theme={null}
function extractVideoURLs(payload: unknown): string[] {
  const groups = (payload as any)?.data?.result?.videos;
  if (!Array.isArray(groups)) return [];

  return groups.flatMap((group: any) =>
    Array.isArray(group?.url)
      ? group.url.filter(
          (url: unknown): url is string =>
            typeof url === "string" && /^https:///i.test(url),
        )
      : [],
  );
}
```

Use `expires_at` para expiração. Não fixe duração; peça download ou armazenamento.

### Resposta com falha

```json theme={null}
{
  "code":200,
  "data":{
    "id":"task_xxx",
    "status":"failed",
    "progress":100,
    "cost":0,
    "credits_cost":0,
    "error":{"message":"Task failed.","type":"task_failed","param":"","code":"task_failed"}
  }
}
```

<Warning>
  A consulta pode retornar HTTP `200` com `data.status=failed`. Decida por `data.status`; tarefa falha tem `cost=0`.
</Warning>

## Catálogo de preços

```http theme={null}
GET https://api.apimart.ai/api/pricing/models/all
```

Leia `GET /api/pricing/models/all` e encontre o `id` em `data.models.video`. Preços são estimativas; o valor final é `data.cost`.

### Preço do vídeo de saída

```json theme={null}
{
  "fixed_prices":{
    "unit":"usd_per_second",
    "dimension":"resolution",
    "items":[
      {"key":"480P","original_price":0.05,"after_discount":0.04},
      {"key":"720P","original_price":0.07,"after_discount":0.056}
    ]
  }
}
```

* As chaves de preço são `480P/720P/1080P`, e a solicitação usa minúsculas; normalize ao consultar.
* `default` é metadado de compatibilidade, não uma resolução selecionável.
* Use `after_discount` diretamente; não aplique o desconto novamente.

### Preço do material de entrada

```json theme={null}
{"unit":"usd_per_image","original_price":0.002,"after_discount":0.0016}
```

```json theme={null}
{"unit":"usd_per_second","original_price":0.01,"after_discount":0.008}
```

O preço de vídeo é um objeto escalar. Não exija `items`, `billing_mode` ou `max_billable_seconds`. O modelo 1.5 não tem preço de entrada de vídeo.

### Fórmulas de estimativa

```text theme={null}
Geração = preço de saída/segundo × duração + preço por imagem × quantidade
Edição = preço 720P/segundo × segundos fonte + preço de entrada × segundos fonte
```

Preços específicos e arredondamento podem alterar a estimativa. O valor final é sempre `data.cost`.

## Regras do frontend

### Troca de modelo

* Base mostra `480p/720p`; 1.5 também `1080p`.
* Ao trocar de 1.5 `1080p` para Base, voltar a `480p`.
* Edição fixa `grok-imagine-video`.

### Troca de modo

| Modo                  | Controles visíveis                                   | Campos enviados                  | Deve limpar                                   |
| --------------------- | ---------------------------------------------------- | -------------------------------- | --------------------------------------------- |
| Geração               | `prompt/duration/resolution/aspect_ratio/nsfw_check` | Campos de geração                | `image_urls/video`                            |
| Imagens de referência | Campos de geração + `image_urls`                     | Campos de geração + `image_urls` | `video`                                       |
| Edição de vídeo       | `prompt/video/nsfw_check`                            | `model/prompt/video/nsfw_check`  | `duration/resolution/aspect_ratio/image_urls` |

`nsfw_check` é opcional em todos os modos. Envie `true` com a moderação ativa; omita ou envie `false` quando desativada.

Desative o botão quando alguma condição for verdadeira:

* Texto omite `image_urls` e `video`.
* Referência envia `image_urls` e omite `video`.
* Edição limpa campos de geração.
* Desative com prompt, duração, resolução ou URL inválida, upload ativo ou envio duplicado.
* Prompt ≤8000 Unicode e duração inteira 1–15.
* Somente URL HTTPS pública; omitir `image_urls` vazio.

## Erros comuns

| HTTP / Status | Causa                                     | Tratamento                           |
| ------------- | ----------------------------------------- | ------------------------------------ |
| `400`         | Parâmetro, prompt ou enum inválido        | Mostrar mensagem e campo             |
| `401`         | Chave ausente ou inválida                 | Não repetir; verificar servidor      |
| `402`         | Saldo insuficiente                        | Solicitar recarga                    |
| `403`         | Sem permissão                             | Não repetir automaticamente          |
| `409`         | Conflito idempotente ou solicitação ativa | Manter chave e tentar depois         |
| `429`         | Limite                                    | Respeitar `Retry-After`              |
| `500/502/503` | Falha temporária                          | Retries limitados com chave original |
| `failed`      | Tarefa assíncrona falhou                  | Parar consulta; custo zero           |

## Checklist

* API Key apenas em backend ou BFF.
* Não misturar modelos oficiais com `grok-imagine-1.5-video-ext`.
* Prompt ≤8000 Unicode e duração inteira 1–15.
* Somente URL HTTPS pública; omitir `image_urls` vazio.
* Na edição, envie apenas `model/prompt/video` mais `nsfw_check` opcional e use o modelo Base.
* Ler `data[0].task_id` e final em `data.status`.
* Ler `result.videos[].url[]` e respeitar `expires_at`.
* Exibir catálogo e usar `data.cost` final.
