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

# Camadas e edição de regiões do Grok Imagine 2.0 Ext

> Use segment para obter camadas de objetos e máscaras precisas e edite polígonos, caixas ou objetos detectados com region_edit.

<Info>
  `segment` e `region_edit` usam o endpoint assíncrono de imagens existente. Salve o `task_id` retornado e consulte [Obter status da tarefa](/pt/api-reference/tasks/status); a solicitação de criação não retorna diretamente as camadas ou imagens finais.
</Info>

<Warning>
  Nunca exponha uma API Key no bundle do navegador, LocalStorage, URL ou logs do frontend. Chame a APIMart pelo backend ou BFF.
</Warning>

<RequestExample>
  ```bash cURL theme={null}
  curl --request POST \
    --url https://api.apimart.ai/v1/images/generations \
    --header 'Authorization: Bearer <token>' \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --header 'Idempotency-Key: 6baf0940-25d6-4ec2-9131-925250840fa7' \
    --data '{
      "model": "grok-imagine-2.0-ext",
      "operation": "segment",
      "source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
      "include_mask_rle": true,
      "cached_only": false
    }'
  ```
</RequestExample>

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

## Visão geral das operações

| Finalidade                                                              | Entrada principal             | Resultado concluído                | Cobrança                     |
| ----------------------------------------------------------------------- | ----------------------------- | ---------------------------------- | ---------------------------- |
| `segment`: Detectar objetos e obter camadas, caixas e máscaras precisas | `source_task_id`              | `image_id`, `image_url`, `objects` | Grátis                       |
| `region_edit`: Editar um polígono, retângulo ou objeto detectado        | `image_id`, `prompt`, seleção | Nova URL e `image_id`              | Cobrado por tarefa concluída |

```text theme={null}
task_id → segment(source_task_id) → image_id + mask_rle
        → selection_regions → region_edit → new task_id + image_id
```

<Note>
  `source_task_id` e `image_id` não são intercambiáveis. `segment` recebe o ID da tarefa de origem; `region_edit` recebe o ID do ativo de imagem. Para segmentar uma imagem editada, use o ID da tarefa `region_edit` concluída como novo `source_task_id`.
</Note>

## Cabeçalhos da solicitação

Use `Authorization: Bearer <APIMART_API_KEY>`, `Content-Type: application/json` e `Accept: application/json`.

`Idempotency-Key` é opcional e fortemente recomendado para solicitações `region_edit` pagas. Aceita de 1 a 191 caracteres ASCII visíveis; recomenda-se UUID. Use uma nova chave por operação lógica. Uma repetição de rede da mesma solicitação deve reutilizar a chave e o body originais. Se o resultado for indeterminado, não repita automaticamente com outra chave.

## Fluxo de tarefa assíncrona

Uma criação bem-sucedida retorna HTTP `200` e `data[0].task_id`. Consulte `GET /v1/tasks/{task_id}?language=pt` a cada 2 segundos, aumentando até 5 segundos, com limite total de 10 minutos. Interrompa a consulta anterior quando a imagem de origem mudar.

<Warning>
  A consulta pode retornar HTTP `200` enquanto `data.status` é `failed`. Determine sempre o resultado por `data.status` e mostre `data.error` quando existir.
</Warning>

## `segment`

### Parâmetros da solicitação

| Campo              | Tipo    | Obrigatório | Padrão  | Descrição                                                                      |
| ------------------ | ------- | :---------: | ------- | ------------------------------------------------------------------------------ |
| `model`            | string  |      ✅      | —       | Fixo em `grok-imagine-2.0-ext`                                                 |
| `operation`        | string  |      ✅      | —       | Fixo em `segment`                                                              |
| `source_task_id`   | string  |      ✅      | —       | Tarefa Grok concluída, de uma única imagem e pertencente ao usuário atual      |
| `include_mask_rle` | boolean |      —      | `true`  | Retornar COCO compressed RLE; manter `true` para edição precisa                |
| `cache_only`       | boolean |      —      | `false` | Consultar apenas o cache de segmentação; não chamar o upstream em caso de miss |
| `cached_only`      | boolean |      —      | `false` | Dica de cache para o upstream, sem garantia local                              |
| `refresh`          | boolean |      —      | `false` | Ignorar o cache; não usar no fluxo normal                                      |

`segment` não precisa de `prompt`. Não envie `image_id`, `image_index`, `billing_model_name`, `n`, `size` ou `response_format`. `cache_only=true` e `refresh=true` são mutuamente exclusivos.

### Exemplos de solicitação

<Tabs>
  <Tab title="Obter camadas">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "segment",
      "source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
      "include_mask_rle": true,
      "cached_only": false
    }
    ```
  </Tab>

  <Tab title="Consultar cache">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "segment",
      "source_task_id": "<COMPLETED_SINGLE_IMAGE_TASK_ID>",
      "include_mask_rle": true,
      "cache_only": true
    }
    ```
  </Tab>
</Tabs>

Um cache miss ainda é uma tarefa bem-sucedida. Use `cache_status` ou `from_cache`; não deduza um hit por `cached`.

### Resposta concluída

Em `segment`, `data.result` contém diretamente o resultado da segmentação e não fica dentro de `images`.

```json theme={null}
{
  "code": 200,
  "data": {
    "id": "task_...",
    "status": "completed",
    "progress": 100,
    "cost": 0,
    "credits_cost": 0,
    "result": {
      "source_task_id": "task_...",
      "image_id": "6b78a7c3-5f9e-4a3d-a928-9e9b42113a3f",
      "image_url": "https://.../source.jpg",
      "from_cache": true,
      "cache_status": "hit",
      "objects": [{
        "index": 0,
        "name": "red sports car",
        "box_xyxy": [38.1, 689.8, 945.8, 1065.4],
        "score": 0.9765625,
        "mask_size": [1792, 1008],
        "mask_url": "",
        "mask_rle": { "size": [1792, 1008], "counts": "..." }
      }]
    }
  }
}
```

| Campo                 | Descrição                                                   |
| --------------------- | ----------------------------------------------------------- |
| `result.image_id`     | ID do ativo usado por `region_edit`                         |
| `result.image_url`    | URL HTTP(S) alinhada ao `image_id`                          |
| `objects[].index`     | Índice original do servidor; preserve para `object_indices` |
| `objects[].box_xyxy`  | Caixa de pixels da máscara `[x1,y1,x2,y2]`                  |
| `objects[].score`     | Confiança da detecção; pode ser `null`                      |
| `objects[].mask_size` | Sempre `[height,width]`; não fixe dimensões                 |
| `objects[].mask_rle`  | COCO compressed RLE para contornos precisos                 |
| `objects[].mask_url`  | URL opcional da máscara; pode estar vazia                   |

Um objeto sem `mask_rle` ou `mask_url` válido só permite edição aproximada por caixa.

## Decodificar `mask_rle`

`mask_rle.counts` é uma string de contagens compactadas COCO, não Base64 nem zlib. Ela é expandida por colunas; o primeiro trecho é fundo e depois alterna primeiro plano e fundo.

O TypeScript abaixo converte para uma máscara binária por linhas adequada ao navegador:

```ts theme={null}
export interface CocoRLE {
  size: [height: number, width: number];
  counts: string;
}

export interface BinaryMask {
  width: number;
  height: number;
  data: Uint8Array; // data[y * width + x]
}

function decodeCompressedCounts(counts: string): number[] {
  const runs: number[] = [];
  let cursor = 0;
  while (cursor < counts.length) {
    let value = 0;
    let shift = 0;
    let more = true;
    while (more) {
      if (cursor >= counts.length) throw new Error("Truncated COCO RLE counts");
      const current = counts.charCodeAt(cursor++) - 48;
      value |= (current & 0x1f) << shift;
      more = (current & 0x20) !== 0;
      shift += 5;
      if (!more && (current & 0x10) !== 0) value |= -1 << shift;
    }
    if (runs.length > 2) value += runs[runs.length - 2] ?? 0;
    if (value < 0) throw new Error(\`Invalid COCO RLE run: \${value}\`);
    runs.push(value);
  }
  return runs;
}

export function decodeCocoRLE(rle: CocoRLE): BinaryMask {
  const [height, width] = rle.size;
  if (!Number.isInteger(height) || !Number.isInteger(width) || height <= 0 || width <= 0) {
    throw new Error(\`Invalid mask size: \${JSON.stringify(rle.size)}\`);
  }
  const pixelCount = width * height;
  if (!Number.isSafeInteger(pixelCount) || pixelCount > 32_000_000) {
    throw new Error(\`Mask exceeds the frontend safety limit: \${pixelCount}\`);
  }
  if (!rle.counts) throw new Error("Missing COCO RLE counts");

  const data = new Uint8Array(pixelCount);
  const runs = decodeCompressedCounts(rle.counts);
  let position = 0;
  let foreground = false;
  for (const run of runs) {
    if (position + run > data.length) throw new Error("COCO RLE exceeds mask_size");
    if (foreground) {
      for (let offset = 0; offset < run; offset++) {
        const index = position + offset;
        const y = index % height;
        const x = (index - y) / height;
        data[y * width + x] = 1;
      }
    }
    position += run;
    foreground = !foreground;
  }
  if (position !== data.length) throw new Error("COCO RLE does not cover the mask");
  return { width, height, data };
}
```

Decodifique máscaras grandes em um Web Worker. Não envie valores completos de `mask_rle.counts` para logs, análises, URLs ou relatórios de erro.

### Converter máscaras em seleções precisas

```ts theme={null}
interface SelectionBoundary { points: number[] }
interface SelectionRegion { outer: SelectionBoundary; holes?: SelectionBoundary[] }
```

Trace componentes conectados e furos, simplifique os contornos e normalize cada ponto em `0–1`. Cada anel precisa de pelo menos 3 pontos distintos, área diferente de zero e não pode se cruzar. Mantenha no máximo 16 regiões maiores por camada e 400 pontos por anel.

<Warning>
  `mask_size` é `[height,width]` e usa coordenadas da máscara original, não dimensões CSS. Com `object-fit: contain`, desconte as margens, escale pela área realmente desenhada e limite o resultado a `0–1`.
</Warning>

A leitura de pixels da imagem ou de `mask_url` requer CORS. Defina `crossOrigin = "anonymous"` antes de `src` ou obtenha um Blob. Decodificar `mask_rle` diretamente evita essa dependência.

## Editar uma região: `region_edit`

### Parâmetros da solicitação

| Campo               | Tipo         | Obrigatório | Descrição                                                                                                 |
| ------------------- | ------------ | :---------: | --------------------------------------------------------------------------------------------------------- |
| `model`             | string       |      ✅      | Fixo em `grok-imagine-2.0-ext`                                                                            |
| `operation`         | string       |      ✅      | `region_edit`                                                                                             |
| `image_id`          | string       |      ✅      | ID do ativo de origem; primeiro use o `image_id` de `segment` e depois o resultado de edição mais recente |
| `prompt`            | string       |      ✅      | Instrução não vazia descrevendo a alteração                                                               |
| `selection_regions` | array        |      \*     | Polígonos normalizados em `0–1` com `outer` e `holes` opcionais; recomendado                              |
| `boxes`             | number\[]\[] |      \*     | Retângulos `[x1,y1,x2,y2]`; caixas em pixels exigem `mask_size`                                           |
| `object_indices`    | integer\[]   |      \*     | Valores originais de `objects[].index`; apenas aproximação por caixa                                      |
| `mask_size`         | integer\[]   |      \*     | Obrigatório para caixas em pixels; `[height,width]` com inteiros positivos                                |

Pelo menos um entre `selection_regions`, `boxes` ou `object_indices` deve conter dados. A API aceita combinações, mas o frontend deve usar um método por solicitação.

<Warning>
  Não envie `billing_model_name`, `size`, `aspect_ratio`, `source_aspect_ratio`, `source_size` ou `image_urls`. Omita `n` ou use `1`; omita `claim_asset` ou use `false`; omita `response_format` ou use `url`. Base64 e `stream=true` não são aceitos.
</Warning>

### Métodos de seleção

| Método              | Origem da seleção            | Precisão                 | Uso recomendado                        |
| ------------------- | ---------------------------- | ------------------------ | -------------------------------------- |
| `selection_regions` | Polígonos do frontend        | Precisa, incluindo furos | Edição de camada ou pincel em produção |
| `boxes`             | Retângulos do frontend       | Aproximação por caixa    | Ferramenta de caixa ou MVP             |
| `object_indices`    | Índices originais de segment | Aproximação por caixa    | Teste rápido de integração             |

<Tabs>
  <Tab title="Polígono preciso">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the selected car to bright red and preserve the rest",
      "selection_regions": [{
        "outer": { "points": [0.12, 0.20, 0.48, 0.20, 0.48, 0.61, 0.12, 0.61] },
        "holes": [{ "points": [0.30, 0.35, 0.38, 0.35, 0.38, 0.45, 0.30, 0.45] }]
      }]
    }
    ```

    `points` pode ser uma lista plana ou pares aninhados. Cada valor deve ser finito e estar em `0–1`; cada anel exige pelo menos 3 pares.
  </Tab>

  <Tab title="Caixa normalizada">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the car inside the box to bright red",
      "boxes": [[0.04, 0.385, 0.938, 0.594]]
    }
    ```
  </Tab>

  <Tab title="Caixa em pixels">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the car inside the box to bright red",
      "boxes": [[40, 689.6, 945.9, 1064.4]],
      "mask_size": [1792, 1008]
    }
    ```
  </Tab>

  <Tab title="Índice do objeto">
    ```json theme={null}
    {
      "model": "grok-imagine-2.0-ext",
      "operation": "region_edit",
      "image_id": "<SOURCE_IMAGE_ID>",
      "prompt": "Change the selected car to bright red",
      "object_indices": [0]
    }
    ```

    Os índices devem vir da resposta segment do mesmo `image_id`. Não os substitua por índices de uma lista filtrada, ordenada ou agrupada no frontend.
  </Tab>
</Tabs>

### Resposta concluída

```json theme={null}
{
  "code": 200,
  "data": {
    "id": "task_...",
    "status": "completed",
    "progress": 100,
    "cost": 0.016,
    "credits_cost": 0.16,
    "result": {
      "images": [{
        "url": ["https://.../result.jpg"],
        "image_ids": ["<NEW_IMAGE_ID>"],
        "items": [{
          "url": "https://.../result.jpg",
          "image_id": "<NEW_IMAGE_ID>",
          "source_image_id": "<SOURCE_IMAGE_ID>",
          "role": "region_edit"
        }],
        "expires_at": 1787040000
      }]
    }
  }
}
```

Prefira `result.images[0].items[0]`. Em respostas antigas, associe `url[0]` a `image_ids[0]` somente quando os arrays tiverem o mesmo tamanho. Continue apenas após obter uma URL HTTP(S) e um novo `image_id`.

Use `expires_at` como referência de expiração; não fixe um número de horas. Baixe ou armazene ativos necessários a longo prazo.

## Edição contínua

Após concluir uma edição, atualize juntos a URL exibida, o ID do ativo atual e o ID da tarefa de origem, e limpe camadas e consultas antigas.

* Segmentar novamente: usar o ID desta tarefa `region_edit` como `source_task_id`
* Editar novamente: usar o novo `image_id` retornado
* Nunca envie `image_id` para `segment` nem continue editando o ID da imagem anterior.

## Tratamento de erros

| HTTP / status                   | Causa comum                                                                                   | Tratamento                                                                          |
| ------------------------------- | --------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| 400 origem ou operação inválida | Operação incorreta, tarefa de origem inutilizável ou `image_id/image_index` enviado a segment | Validar a operação e usar uma tarefa concluída de uma única imagem do usuário atual |
| 400 seleção inválida            | Prompt vazio, seleção ausente ou polígono, caixa ou índice inválido                           | Validar prompt e seleção antes de enviar                                            |
| 400 opção não aceita            | `claim_asset`, `n`, formato, tamanho ou streaming inválido                                    | Remover campos não aceitos e usar saída URL                                         |
| 401 / 403                       | Chave inválida ou sem permissão do modelo                                                     | Verificar a chave do servidor e o acesso da conta                                   |
| 402                             | Saldo insuficiente                                                                            | Solicitar recarga antes de tentar novamente                                         |
| 409                             | Solicitação idempotente em andamento, alterada ou indeterminada                               | Seguir a resposta e não trocar a chave automaticamente                              |
| 429 / 5xx                       | Limite ou falha temporária                                                                    | Respeitar `Retry-After` e aplicar backoff limitado                                  |
| failed / task\_failed           | Falha na execução assíncrona                                                                  | Interromper a consulta e mostrar `data.error.message`                               |

## Cobrança

* `segment` é gratuito e termina com `cost=0` e `credits_cost=0`, mas exige autenticação e tarefa de origem válida.
* `region_edit` é pago. Use `cost` e `credits_cost` da tarefa concluída; não fixe preços no frontend.
* Nunca envie o campo interno `billing_model_name`.

## Checklist do frontend

* Manter a API Key somente no backend ou BFF.
* Enviar apenas `source_task_id` para `segment`; não enviar `image_id` ou `image_index`.
* Usar o `image_id` de segment em `region_edit` e fornecer ao menos um método de seleção.
* Usar `selection_regions` para edição precisa; `object_indices` é apenas aproximação por caixa.
* Sempre interpretar `mask_size` como `[height,width]` e compensar escala e margens.
* Reutilizar a chave idempotente original no mesmo retry e validar a URL e o novo `image_id`.
