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

# Capas y edición de regiones de Grok Imagine 2.0 Ext

> Usa segment para obtener capas de objetos y máscaras precisas, y edita polígonos, cuadros u objetos detectados con region_edit.

<Info>
  `segment` y `region_edit` usan el endpoint asíncrono de imágenes existente. Guarda el `task_id` devuelto y consulta [Obtener estado de la tarea](/es/api-reference/tasks/status); la solicitud de creación no devuelve las capas ni imágenes finales.
</Info>

<Warning>
  Nunca expongas una API Key en el paquete del navegador, LocalStorage, una URL o los registros del frontend. Llama a APIMart desde tu backend o 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>

## Resumen de operaciones

| Finalidad                                                                | Entrada principal               | Resultado final                    | Facturación                   |
| ------------------------------------------------------------------------ | ------------------------------- | ---------------------------------- | ----------------------------- |
| `segment`: Detectar objetos y obtener capas, cuadros y máscaras precisas | `source_task_id`                | `image_id`, `image_url`, `objects` | Gratis                        |
| `region_edit`: Editar un polígono, rectángulo u objeto detectado         | `image_id`, `prompt`, selección | URL nueva e `image_id`             | Se cobra por tarea completada |

```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` no son intercambiables. `segment` recibe el ID de la tarea de origen y `region_edit` el ID del recurso de imagen. Para segmentar una imagen editada, usa el ID de la tarea `region_edit` completada como nuevo `source_task_id`.
</Note>

## Encabezados de solicitud

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

`Idempotency-Key` es opcional y se recomienda especialmente para solicitudes `region_edit` de pago. Admite entre 1 y 191 caracteres ASCII visibles; se recomienda un UUID. Usa una clave nueva por operación lógica. Un reintento de red de la misma solicitud debe reutilizar la clave original y el mismo cuerpo. Si el resultado es indeterminado, no reintentes automáticamente con otra clave.

## Flujo de tarea asíncrona

Una creación correcta devuelve HTTP `200` y `data[0].task_id`. Consulta `GET /v1/tasks/{task_id}?language=es` cada 2 segundos, aumenta hasta un máximo de 5 segundos y limita el total a 10 minutos. Detén el sondeo anterior al cambiar la imagen de origen.

<Warning>
  La consulta puede devolver HTTP `200` aunque `data.status` sea `failed`. Determina siempre el resultado mediante `data.status` y muestra `data.error` cuando exista.
</Warning>

## `segment`

### Parámetros de solicitud

| Campo              | Tipo    | Obligatorio | Predeterminado | Descripción                                                            |
| ------------------ | ------- | :---------: | -------------- | ---------------------------------------------------------------------- |
| `model`            | string  |      ✅      | —              | Fijo: `grok-imagine-2.0-ext`                                           |
| `operation`        | string  |      ✅      | —              | Fijo: `segment`                                                        |
| `source_task_id`   | string  |      ✅      | —              | Tarea Grok completada, de una sola imagen y del usuario actual         |
| `include_mask_rle` | boolean |      —      | `true`         | Devuelve COCO compressed RLE; mantenlo en `true` para edición precisa  |
| `cache_only`       | boolean |      —      | `false`        | Solo consulta la caché de segmentación; no llama al proveedor si falla |
| `cached_only`      | boolean |      —      | `false`        | Sugerencia de caché al proveedor; no garantiza caché local             |
| `refresh`          | boolean |      —      | `false`        | Omite la caché; no usar en el flujo normal                             |

`segment` no necesita `prompt`. No envíes `image_id`, `image_index`, `billing_model_name`, `n`, `size` ni `response_format`. `cache_only=true` y `refresh=true` son incompatibles.

### Ejemplos de solicitud

<Tabs>
  <Tab title="Obtener capas">
    ```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 caché">
    ```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>

Una falta de caché sigue siendo una tarea correcta. Usa `cache_status` (`hit` o `miss`) o `from_cache`; no deduzcas el acierto mediante `cached`.

### Respuesta completada

En `segment`, `data.result` contiene directamente la segmentación y no está 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                 | Descripción                                                    |
| --------------------- | -------------------------------------------------------------- |
| `result.image_id`     | ID del recurso usado por `region_edit`                         |
| `result.image_url`    | URL HTTP(S) alineada con `image_id`                            |
| `objects[].index`     | Índice original del servidor; consérvalo para `object_indices` |
| `objects[].box_xyxy`  | Cuadro de píxeles de máscara `[x1,y1,x2,y2]`                   |
| `objects[].score`     | Confianza de detección; puede ser `null`                       |
| `objects[].mask_size` | Siempre `[height,width]`; no fijes dimensiones                 |
| `objects[].mask_rle`  | COCO compressed RLE para contornos precisos                    |
| `objects[].mask_url`  | URL opcional de máscara; puede estar vacía                     |

Un objeto sin `mask_rle` ni `mask_url` válido solo admite edición aproximada por cuadro.

## Decodificar `mask_rle`

`mask_rle.counts` es una cadena de conteos comprimidos COCO, no Base64 ni zlib. Se expande por columnas; el primer tramo es fondo y luego alterna primer plano y fondo.

El siguiente TypeScript lo convierte en una máscara binaria por filas adecuada para el 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 };
}
```

Decodifica máscaras grandes en un Web Worker. No envíes valores completos de `mask_rle.counts` a registros, analítica, URLs ni informes de errores.

### Convertir máscaras en selecciones precisas

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

Traza componentes conectados y huecos, simplifica los contornos y normaliza cada punto a `0–1`. Cada anillo requiere al menos 3 puntos distintos, área no nula y no debe autointersecarse. Conserva como máximo las 16 regiones mayores por capa y 400 puntos por anillo.

<Warning>
  `mask_size` es `[height,width]` y usa coordenadas de la máscara original, no del tamaño CSS. Con `object-fit: contain`, resta los márgenes, escala según el área dibujada y limita el resultado a `0–1`.
</Warning>

Leer píxeles de la imagen o de `mask_url` requiere CORS. Define `crossOrigin = "anonymous"` antes de `src` o recupera un Blob. Decodificar `mask_rle` directamente evita esta dependencia.

## Editar una región: `region_edit`

### Parámetros de solicitud

| Campo               | Tipo         | Obligatorio | Descripción                                                                                                  |
| ------------------- | ------------ | :---------: | ------------------------------------------------------------------------------------------------------------ |
| `model`             | string       |      ✅      | Fijo: `grok-imagine-2.0-ext`                                                                                 |
| `operation`         | string       |      ✅      | `region_edit`                                                                                                |
| `image_id`          | string       |      ✅      | ID del recurso de origen; primero usa `image_id` de `segment` y después el resultado de edición más reciente |
| `prompt`            | string       |      ✅      | Instrucción no vacía que describe el cambio                                                                  |
| `selection_regions` | array        |      \*     | Polígonos normalizados a `0–1` con `outer` y `holes` opcionales; recomendado                                 |
| `boxes`             | number\[]\[] |      \*     | Rectángulos `[x1,y1,x2,y2]`; los cuadros en píxeles requieren `mask_size`                                    |
| `object_indices`    | integer\[]   |      \*     | Valores originales de `objects[].index`; solo edición aproximada por cuadro                                  |
| `mask_size`         | integer\[]   |      \*     | Obligatorio para cuadros en píxeles; `[height,width]` con enteros positivos                                  |

Al menos uno de `selection_regions`, `boxes` u `object_indices` debe contener datos. La API permite combinarlos, pero el frontend debería usar un solo método por solicitud.

<Warning>
  No envíes `billing_model_name`, `size`, `aspect_ratio`, `source_aspect_ratio`, `source_size` ni `image_urls`. Omite `n` o usa `1`; omite `claim_asset` o usa `false`; omite `response_format` o usa `url`. No se admiten Base64 ni `stream=true`.
</Warning>

### Métodos de selección

| Método              | Origen de selección           | Precisión                | Uso recomendado                         |
| ------------------- | ----------------------------- | ------------------------ | --------------------------------------- |
| `selection_regions` | Polígonos del frontend        | Exacta, con huecos       | Edición de capas o pincel en producción |
| `boxes`             | Rectángulos del frontend      | Aproximación rectangular | Herramienta de cuadro o MVP             |
| `object_indices`    | Índices originales de segment | Aproximación rectangular | Prueba rápida de integración            |

<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` puede ser plano o pares anidados. Cada valor debe ser finito y estar entre `0–1`; cada anillo necesita al menos 3 pares.
  </Tab>

  <Tab title="Cuadro normalizado">
    ```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="Cuadro en píxeles">
    ```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 de 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]
    }
    ```

    Los índices deben proceder de la respuesta segment del mismo `image_id`. No los sustituyas por índices de una lista filtrada, ordenada o agrupada en el frontend.
  </Tab>
</Tabs>

### Respuesta completada

```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
      }]
    }
  }
}
```

Prioriza `result.images[0].items[0]`. En respuestas antiguas, empareja `url[0]` con `image_ids[0]` solo si ambas matrices tienen la misma longitud. Continúa únicamente tras obtener una URL HTTP(S) y un `image_id` nuevo.

Usa `expires_at` como referencia de caducidad; no fijes un número de horas. Descarga o guarda los recursos necesarios a largo plazo.

## Edición continua

Al completar una edición, actualiza a la vez la URL visible, el ID del recurso y el ID de la tarea de origen, y limpia las capas y el sondeo anteriores.

* Volver a segmentar: usa el ID de esta tarea `region_edit` como `source_task_id`
* Volver a editar: usa el nuevo `image_id` devuelto
* Nunca envíes `image_id` a `segment` ni sigas editando el ID de la imagen anterior.

## Gestión de errores

| HTTP / estado                     | Causa habitual                                                                                 | Tratamiento                                                                          |
| --------------------------------- | ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------ |
| 400 origen u operación no válidos | Operación incorrecta, tarea de origen no utilizable o `image_id/image_index` enviado a segment | Validar la operación y usar una tarea de una imagen completada por el usuario actual |
| 400 selección no válida           | Prompt vacío, selección ausente o polígono, cuadro o índice inválido                           | Validar prompt y selección antes de enviar                                           |
| 400 opción no admitida            | `claim_asset`, `n`, formato, tamaño o streaming no válido                                      | Eliminar campos no admitidos y usar salida URL                                       |
| 401 / 403                         | Clave no válida o sin permiso del modelo                                                       | Revisar la clave del servidor y el acceso de la cuenta                               |
| 402                               | Saldo insuficiente                                                                             | Solicitar recarga antes de reintentar                                                |
| 409                               | Solicitud idempotente en curso, modificada o indeterminada                                     | Seguir la respuesta y no cambiar la clave automáticamente                            |
| 429 / 5xx                         | Límite o fallo temporal                                                                        | Respetar `Retry-After` y aplicar retroceso limitado                                  |
| failed / task\_failed             | Falló la ejecución asíncrona                                                                   | Detener el sondeo y mostrar `data.error.message`                                     |

## Facturación

* `segment` es gratuito y termina con `cost=0` y `credits_cost=0`, pero requiere autenticación y una tarea de origen válida.
* `region_edit` es de pago. Usa `cost` y `credits_cost` de la tarea completada; no fijes precios en el frontend.
* Nunca envíes el campo interno `billing_model_name`.

## Lista de comprobación del frontend

* Mantener la API Key solo en el backend o BFF.
* Enviar solo `source_task_id` a `segment`; no enviar `image_id` ni `image_index`.
* Usar el `image_id` de segment para `region_edit` y aportar al menos un método de selección.
* Usar `selection_regions` para edición precisa; `object_indices` solo aproxima un cuadro.
* Interpretar siempre `mask_size` como `[height,width]` y compensar escala y márgenes.
* Reutilizar la clave idempotente original en el mismo reintento y validar tanto la URL como el nuevo `image_id`.
