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

# Procesamiento por lotes

> Envía grandes volúmenes de solicitudes de forma asíncrona usando la API Batch. Procesa completaciones de chat, embeddings y generación de imágenes en masa con una ventana de finalización de 24 horas.

La API Batch te permite enviar grupos de solicitudes como un solo trabajo que se procesa de forma asíncrona.
Esto es útil cuando necesitas ejecutar muchas solicitudes y no requieres resultados inmediatos — por ejemplo, realizar evaluaciones, generar embeddings para un gran conjunto de datos o clasificar contenido en masa.

Las solicitudes por lotes se ejecutan dentro de una **ventana de finalización de 24 horas** y tienen límites de velocidad separados y más altos que las llamadas síncronas a la API.

## Endpoints compatibles

| Endpoint                 | Descripción                         |
| ------------------------ | ----------------------------------- |
| `/v1/chat/completions`   | Solicitudes de completación de chat |
| `/v1/embeddings`         | Generación de embeddings            |
| `/v1/images/generations` | Generación de imágenes              |

Todas las solicitudes en un solo lote deben dirigirse al mismo endpoint.

## Ciclo de vida

Un lote pasa por estos estados:

```
validating → in_progress → finalizing → completed
     ↓            ↓
   failed     cancelling → cancelled
```

| Estado        | Descripción                                                                                              |
| ------------- | -------------------------------------------------------------------------------------------------------- |
| `validating`  | El archivo de entrada está siendo verificado por errores de formato y contenido.                         |
| `failed`      | La validación falló — el archivo de entrada contiene errores. Consulta `batch.errors` para más detalles. |
| `in_progress` | Las solicitudes están siendo procesadas.                                                                 |
| `finalizing`  | Todas las solicitudes han sido procesadas y se están generando los archivos de salida.                   |
| `completed`   | El lote finalizó. Descarga los resultados desde `output_file_id`.                                        |
| `cancelling`  | Se solicitó una cancelación. Las solicitudes en curso están finalizando.                                 |
| `cancelled`   | El lote fue cancelado. Puede haber resultados parciales disponibles.                                     |
| `expired`     | El lote no se completó dentro de la ventana de 24 horas.                                                 |

## Paso 1 — Prepara el archivo de entrada

Crea un archivo JSONL donde cada línea sea una solicitud. Cada línea tiene cuatro campos:

| Campo       | Tipo   | Descripción                                                                                                              |
| ----------- | ------ | ------------------------------------------------------------------------------------------------------------------------ |
| `custom_id` | string | Tu identificador para esta solicitud. Se usa para emparejar la entrada con la salida. Debe ser único dentro del archivo. |
| `method`    | string | `"POST"` — el único método soportado.                                                                                    |
| `url`       | string | La ruta del endpoint — debe coincidir con el `endpoint` que declares al crear el lote.                                   |
| `body`      | object | El cuerpo de la solicitud — los mismos parámetros que enviarías al endpoint síncrono.                                    |

```jsonl theme={null}
{"custom_id": "request-1", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "meetkai:functionary-es-mini", "messages": [{"role": "user", "content": "Summarize the benefits of batch processing in one sentence."}], "max_tokens": 100}}
{"custom_id": "request-2", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "meetkai:functionary-es-mini", "messages": [{"role": "user", "content": "What is the capital of France?"}], "max_tokens": 100}}
{"custom_id": "request-3", "method": "POST", "url": "/v1/chat/completions", "body": {"model": "meetkai:functionary-es-mini", "messages": [{"role": "user", "content": "Explain embeddings in one paragraph."}], "max_tokens": 100}}
```

Un solo lote puede contener hasta **10,000 solicitudes**.

## Paso 2 — Sube el archivo de entrada

Sube el archivo JSONL usando la API de Archivos con `purpose: "batch"`.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm files upload \
    --file ./batch_input.jsonl \
    --purpose batch \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts MKA1 SDK theme={null}
  import { SDK } from '@meetkai/mka1';

  const mka1 = new SDK({
    bearerAuth: `Bearer ${YOUR_API_KEY}`,
  });

  const file = await mka1.llm.files.upload({
    file: new File([jsonlContent], 'batch_input.jsonl', { type: 'application/jsonl' }),
    purpose: 'batch',
  });

  console.log(file.id);     // "file_abc123"
  console.log(file.status); // "processed"
  ```

  ```ts OpenAI SDK theme={null}
  import OpenAI from 'openai';

  const openai = new OpenAI({
    apiKey: '<mka1-api-key>',
    baseURL: 'https://apigw.mka1.com/api/v1/llm/',
    defaultHeaders: { 'X-On-Behalf-Of': '<end-user-id>' },
  });

  const file = await openai.files.create({
    file: new File([jsonlContent], 'batch_input.jsonl', { type: 'application/jsonl' }),
    purpose: 'batch',
  });

  console.log(file.id);     // "file_abc123"
  console.log(file.status); // "processed"
  ```

  ```csharp C# SDK theme={null}
  using System.Text;
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;
  using MeetKai.MKA1.Types.Requests;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var file = await sdk.Llm.Files.UploadAsync(new UploadFileRequestBody()
  {
      File = new UploadFileFile()
      {
          FileName = "batch_input.jsonl",
          Content = Encoding.UTF8.GetBytes(jsonlContent),
      },
      Purpose = UploadFilePurpose.Batch,
  });

  Console.WriteLine(file.File!.Id);     // "file_abc123"
  ```

  ```python Python SDK theme={null}
  from mka1 import SDK

  sdk = SDK(bearer_auth="Bearer YOUR_API_KEY")

  file = sdk.llm.files.upload(
      file={"file_name": "batch_input.jsonl", "content": open("batch_input.jsonl", "rb")},
      purpose="batch",
  )

  print(file.id)      # "file_abc123"
  print(file.status)  # "processed"
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/files \
    --request POST \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --form 'file=@batch_input.jsonl;type=application/jsonl' \
    --form 'purpose=batch'
  ```
</CodeGroup>

## Paso 3 — Crea el lote

Pasa el ID del archivo subido, el endpoint de destino y la ventana de finalización.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm batches create --body '{
    "input_file_id": "file_abc123",
    "endpoint": "/v1/chat/completions",
    "completion_window": "24h"
  }'
  ```

  ```ts MKA1 SDK theme={null}
  const batch = await mka1.llm.batches.create({
    inputFileId: file.id,
    endpoint: '/v1/chat/completions',
    completionWindow: '24h',
  });

  console.log(batch.id);            // "batch_abc123"
  console.log(batch.status);        // "validating" or "in_progress"
  console.log(batch.requestCounts); // { total: 3, completed: 0, failed: 0 }
  ```

  ```ts OpenAI SDK theme={null}
  const batch = await openai.batches.create({
    input_file_id: file.id,
    endpoint: '/v1/chat/completions',
    completion_window: '24h',
  });

  console.log(batch.id);              // "batch_abc123"
  console.log(batch.status);          // "validating" or "in_progress"
  console.log(batch.request_counts);  // { total: 3, completed: 0, failed: 0 }
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var batch = await sdk.Llm.Batches.CreateAsync(new CreateBatchRequest()
  {
      InputFileId = file.File!.Id,
      Endpoint = BatchEndpoint.RootV1ChatCompletions,
  });

  Console.WriteLine(batch.BatchObject!.Id);            // "batch_abc123"
  Console.WriteLine(batch.BatchObject!.Status);        // "validating" or "in_progress"
  Console.WriteLine(batch.BatchObject!.RequestCounts); // { Total: 3, Completed: 0, Failed: 0 }
  ```

  ```python Python SDK theme={null}
  batch = sdk.llm.batches.create(
      input_file_id=file.id,
      endpoint="/v1/chat/completions",
  )

  print(batch.id)              # "batch_abc123"
  print(batch.status)          # "validating" or "in_progress"
  print(batch.request_counts)  # { total: 3, completed: 0, failed: 0 }
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/batches \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "input_file_id": "file_abc123",
      "endpoint": "/v1/chat/completions",
      "completion_window": "24h"
    }'
  ```
</CodeGroup>

También puedes adjuntar metadatos para tu propio seguimiento:

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm batches create --body '{
    "input_file_id": "file_abc123",
    "endpoint": "/v1/chat/completions",
    "completion_window": "24h",
    "metadata": {
      "description": "nightly evaluation run",
      "run_id": "eval-2026-03-31"
    }
  }'
  ```

  ```ts MKA1 SDK theme={null}
  const batch = await mka1.llm.batches.create({
    inputFileId: file.id,
    endpoint: '/v1/chat/completions',
    completionWindow: '24h',
    metadata: {
      description: 'nightly evaluation run',
      run_id: 'eval-2026-03-31',
    },
  });
  ```

  ```ts OpenAI SDK theme={null}
  const batch = await openai.batches.create({
    input_file_id: file.id,
    endpoint: '/v1/chat/completions',
    completion_window: '24h',
    metadata: {
      description: 'nightly evaluation run',
      run_id: 'eval-2026-03-31',
    },
  });
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var batch = await sdk.Llm.Batches.CreateAsync(new CreateBatchRequest()
  {
      InputFileId = file.File!.Id,
      Endpoint = BatchEndpoint.RootV1ChatCompletions,
      Metadata = new Dictionary<string, string>
      {
          { "description", "nightly evaluation run" },
          { "run_id", "eval-2026-03-31" },
      },
  });
  ```

  ```python Python SDK theme={null}
  batch = sdk.llm.batches.create(
      input_file_id=file.id,
      endpoint="/v1/chat/completions",
      metadata={
          "description": "nightly evaluation run",
          "run_id": "eval-2026-03-31",
      },
  )
  ```
</CodeGroup>

## Paso 4 — Consulta el estado del lote

Consulta el lote hasta que alcance un estado terminal.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm batches get --batch-id batch_abc123
  ```

  ```ts MKA1 SDK theme={null}
  const batch = await mka1.llm.batches.get({ batchId: 'batch_abc123' });

  console.log(batch.status);                // "completed"
  console.log(batch.requestCounts.completed); // 3
  console.log(batch.requestCounts.failed);    // 0
  console.log(batch.outputFileId);           // "file_xyz789"
  ```

  ```ts OpenAI SDK theme={null}
  const batch = await openai.batches.retrieve('batch_abc123');

  console.log(batch.status);                  // "completed"
  console.log(batch.request_counts.completed); // 3
  console.log(batch.request_counts.failed);    // 0
  console.log(batch.output_file_id);           // "file_xyz789"
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var batch = await sdk.Llm.Batches.GetAsync("batch_abc123");

  Console.WriteLine(batch.BatchObject!.Status);                // "completed"
  Console.WriteLine(batch.BatchObject!.RequestCounts);         // { Total: 3, Completed: 3, Failed: 0 }
  Console.WriteLine(batch.BatchObject!.OutputFileId);          // "file_xyz789"
  ```

  ```python Python SDK theme={null}
  batch = sdk.llm.batches.get(batch_id="batch_abc123")

  print(batch.status)                  # "completed"
  print(batch.request_counts.completed)  # 3
  print(batch.request_counts.failed)     # 0
  print(batch.output_file_id)           # "file_xyz789"
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/batches/batch_abc123 \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

Aquí tienes un ayudante para hacer polling y esperar a que el lote termine:

<CodeGroup>
  ```bash CLI theme={null}
  # Consulta un lote hasta que alcance un estado terminal usando --jq y un bucle de shell.
  BATCH_ID=batch_abc123
  while :; do
    STATUS=$(mka1 llm batches get --batch-id "$BATCH_ID" --jq '.status' --output-format json)
    echo "status: $STATUS"
    case "$STATUS" in
      completed|failed|cancelled|expired) break ;;
    esac
    sleep 2
  done
  ```

  ```ts MKA1 SDK theme={null}
  async function waitForBatch(batchId: string, timeoutMs = 120_000) {
    const terminal = ['completed', 'failed', 'cancelled', 'expired'];
    const start = Date.now();

    while (Date.now() - start < timeoutMs) {
      const batch = await mka1.llm.batches.get({ batchId });
      if (terminal.includes(batch.status)) return batch;
      await new Promise((r) => setTimeout(r, 2000));
    }

    throw new Error(`Batch ${batchId} did not complete within ${timeoutMs}ms`);
  }

  const completed = await waitForBatch(batch.id);
  ```

  ```ts OpenAI SDK theme={null}
  async function waitForBatch(batchId: string, timeoutMs = 120_000) {
    const terminal = ['completed', 'failed', 'cancelled', 'expired'];
    const start = Date.now();

    while (Date.now() - start < timeoutMs) {
      const batch = await openai.batches.retrieve(batchId);
      if (terminal.includes(batch.status)) return batch;
      await new Promise((r) => setTimeout(r, 2000));
    }

    throw new Error(`Batch ${batchId} did not complete within ${timeoutMs}ms`);
  }

  const completed = await waitForBatch(batch.id);
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  async Task<BatchObject> WaitForBatch(SDK sdk, string batchId, int timeoutMs = 300_000)
  {
      var terminal = new HashSet<BatchObjectStatus>
      {
          BatchObjectStatus.Completed,
          BatchObjectStatus.Failed,
          BatchObjectStatus.Cancelled,
          BatchObjectStatus.Expired,
      };
      var start = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();

      while (DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() - start < timeoutMs)
      {
          var batch = await sdk.Llm.Batches.GetAsync(batchId);
          if (terminal.Contains(batch.BatchObject!.Status))
              return batch.BatchObject;
          await Task.Delay(2000);
      }

      throw new TimeoutException($"Batch {batchId} did not complete within {timeoutMs}ms");
  }

  var completed = await WaitForBatch(sdk, batch.BatchObject!.Id);
  Console.WriteLine(completed.Status); // BatchObjectStatus.Completed
  ```

  ```python Python SDK theme={null}
  import time

  def wait_for_batch(sdk, batch_id, timeout_ms=120_000):
      terminal = {"completed", "failed", "cancelled", "expired"}
      start = time.time() * 1000

      while (time.time() * 1000) - start < timeout_ms:
          batch = sdk.llm.batches.get(batch_id=batch_id)
          if batch.status in terminal:
              return batch
          time.sleep(2)

      raise TimeoutError(f"Batch {batch_id} did not complete within {timeout_ms}ms")

  completed = wait_for_batch(sdk, batch.id)
  ```
</CodeGroup>

## Paso 5 — Descarga los resultados

Una vez que el lote esté `completed`, descarga el archivo de salida. Es un archivo JSONL donde cada línea contiene el `custom_id` que proporcionaste, la respuesta y cualquier error.

<CodeGroup>
  ```bash CLI theme={null}
  # Descarga el archivo de salida JSONL
  mka1 llm files content \
    --file-id file_xyz789 \
    --output-file ./batch_output.jsonl

  # Inspecciona los resultados en línea con jq
  mka1 llm files content --file-id file_xyz789 \
    --jq '"\(.custom_id): status=\(.response.status_code)"'
  ```

  ```ts MKA1 SDK theme={null}
  const stream = await mka1.llm.files.content({ fileId: completed.outputFileId! });
  const reader = stream.getReader();
  const chunks: Uint8Array[] = [];
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    chunks.push(value);
  }
  const text = new TextDecoder().decode(Buffer.concat(chunks));

  const results = text
    .split('\n')
    .filter((line) => line.trim())
    .map((line) => JSON.parse(line));

  for (const result of results) {
    console.log(`${result.custom_id}: status=${result.response.status_code}`);
    console.log(`  body:`, result.response.body);
  }
  ```

  ```ts OpenAI SDK theme={null}
  const content = await openai.files.content(completed.output_file_id!);
  const text = await content.text();

  const results = text
    .split('\n')
    .filter((line) => line.trim())
    .map((line) => JSON.parse(line));

  for (const result of results) {
    console.log(`${result.custom_id}: status=${result.response.status_code}`);
    console.log(`  body:`, result.response.body);
  }
  ```

  ```csharp C# SDK theme={null}
  using System.Text;
  using MeetKai.MKA1;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var content = await sdk.Llm.Files.ContentAsync(completed.OutputFileId!);

  var bytes = content.TwoHundredTextPlainBytes
      ?? content.TwoHundredApplicationJsonlBytes
      ?? content.TwoHundredApplicationJsonBytes;
  var text = Encoding.UTF8.GetString(bytes!);

  Console.WriteLine(text); // JSONL con una línea por solicitud
  ```

  ```python Python SDK theme={null}
  import json

  content = sdk.llm.files.content(file_id=completed.output_file_id)
  text = content.decode("utf-8")

  results = [json.loads(line) for line in text.strip().split("\n") if line.strip()]

  for result in results:
      print(f"{result['custom_id']}: status={result['response']['status_code']}")
      print(f"  body: {result['response']['body']}")
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/files/file_xyz789/content \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

Cada línea en el archivo de salida tiene esta estructura:

```json theme={null}
{
  "id": "response_abc123",
  "custom_id": "request-1",
  "response": {
    "status_code": 200,
    "request_id": "req_abc123",
    "body": { "...": "same shape as the synchronous endpoint response" }
  },
  "error": null
}
```

Si una solicitud falló, `response` es `null` y `error` contiene los detalles:

```json theme={null}
{
  "id": "response_def456",
  "custom_id": "request-2",
  "response": null,
  "error": {
    "code": "processing_error",
    "message": "The request could not be processed."
  }
}
```

Si alguna solicitud falló, el lote también proporciona un `error_file_id` que contiene solo las entradas fallidas.

## Cancelar un lote

Cancela un lote que aún está en progreso. Las solicitudes que ya se hayan completado permanecen en la salida.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm batches cancel --batch-id batch_abc123
  ```

  ```ts MKA1 SDK theme={null}
  const cancelled = await mka1.llm.batches.cancel({ batchId: 'batch_abc123' });
  console.log(cancelled.status); // "cancelling"
  ```

  ```ts OpenAI SDK theme={null}
  const cancelled = await openai.batches.cancel('batch_abc123');
  console.log(cancelled.status); // "cancelling"
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var cancelled = await sdk.Llm.Batches.CancelAsync("batch_abc123");
  Console.WriteLine(cancelled.BatchObject!.Status); // "cancelling"
  ```

  ```python Python SDK theme={null}
  cancelled = sdk.llm.batches.cancel(batch_id="batch_abc123")
  print(cancelled.status)  # "cancelling"
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/batches/batch_abc123/cancel \
    --request POST \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

El lote pasa a `cancelling` mientras terminan las solicitudes en curso, y luego a `cancelled`.

## Listar lotes

Recupera todos los lotes de la cuenta actual, del más reciente al más antiguo. Soporta paginación.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm batches list --limit 20
  ```

  ```ts MKA1 SDK theme={null}
  const page = await mka1.llm.batches.list({ limit: 20 });

  for (const batch of page.data) {
    console.log(`${batch.id}: ${batch.status} (${batch.requestCounts?.completed}/${batch.requestCounts?.total})`);
  }
  ```

  ```ts OpenAI SDK theme={null}
  const page = await openai.batches.list({ limit: 20 });

  for (const batch of page.data) {
    console.log(`${batch.id}: ${batch.status} (${batch.request_counts?.completed}/${batch.request_counts?.total})`);
  }
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var page = await sdk.Llm.Batches.ListAsync(limit: 20);

  foreach (var batch in page.ListBatchesResponseValue!.Data!)
  {
      Console.WriteLine($"{batch.Id}: {batch.Status} ({batch.RequestCounts?.Completed}/{batch.RequestCounts?.Total})");
  }
  ```

  ```python Python SDK theme={null}
  page = sdk.llm.batches.list(limit=20)

  for batch in page.data:
      print(f"{batch.id}: {batch.status} ({batch.request_counts.completed}/{batch.request_counts.total})")
  ```

  ```bash bash theme={null}
  curl 'https://apigw.mka1.com/api/v1/llm/batches?limit=20' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

Usa el parámetro `after` con un ID de lote para paginar los resultados.

## Ejemplo: embeddings por lote

El mismo flujo funciona para embeddings. Cambia el `url` en cada línea del JSONL y el `endpoint` al crear el lote.

```jsonl theme={null}
{"custom_id": "embed-1", "method": "POST", "url": "/v1/embeddings", "body": {"model": "meetkai:functionary-es-mini", "input": "The quick brown fox"}}
{"custom_id": "embed-2", "method": "POST", "url": "/v1/embeddings", "body": {"model": "meetkai:functionary-es-mini", "input": "jumps over the lazy dog"}}
```

<CodeGroup>
  ```bash CLI theme={null}
  # Sube el archivo JSONL de embeddings
  FILE_ID=$(mka1 llm files upload \
    --file ./embed_batch.jsonl \
    --purpose batch \
    --jq '.id' --output-format json | tr -d '"')

  # Crea el lote contra el endpoint de embeddings
  mka1 llm batches create --body "{
    \"input_file_id\": \"$FILE_ID\",
    \"endpoint\": \"/v1/embeddings\",
    \"completion_window\": \"24h\"
  }"

  # Haz polling y descarga los resultados — ver Pasos 4 y 5
  ```

  ```ts MKA1 SDK theme={null}
  const file = await mka1.llm.files.upload({
    file: new File([jsonlContent], 'embed_batch.jsonl', { type: 'application/jsonl' }),
    purpose: 'batch',
  });

  const batch = await mka1.llm.batches.create({
    inputFileId: file.id,
    endpoint: '/v1/embeddings',
    completionWindow: '24h',
  });

  const completed = await waitForBatch(batch.id);
  const stream = await mka1.llm.files.content({ fileId: completed.outputFileId! });
  // ... lee el stream como se muestra en el Paso 5
  ```

  ```ts OpenAI SDK theme={null}
  const file = await openai.files.create({
    file: new File([jsonlContent], 'embed_batch.jsonl', { type: 'application/jsonl' }),
    purpose: 'batch',
  });

  const batch = await openai.batches.create({
    input_file_id: file.id,
    endpoint: '/v1/embeddings',
    completion_window: '24h',
  });

  const completed = await waitForBatch(batch.id);
  const content = await openai.files.content(completed.output_file_id!);
  const results = (await content.text()).split('\n').filter(Boolean).map(JSON.parse);

  for (const r of results) {
    console.log(`${r.custom_id}: ${r.response.body.data[0].embedding.length} dimensions`);
  }
  ```

  ```csharp C# SDK theme={null}
  using System.Text;
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;
  using MeetKai.MKA1.Types.Requests;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var file = await sdk.Llm.Files.UploadAsync(new UploadFileRequestBody()
  {
      File = new UploadFileFile()
      {
          FileName = "embed_batch.jsonl",
          Content = Encoding.UTF8.GetBytes(jsonlContent),
      },
      Purpose = UploadFilePurpose.Batch,
  });

  var batch = await sdk.Llm.Batches.CreateAsync(new CreateBatchRequest()
  {
      InputFileId = file.File!.Id,
      Endpoint = BatchEndpoint.RootV1Embeddings,
  });

  var completed = await WaitForBatch(sdk, batch.BatchObject!.Id);
  // Descarga y analiza los resultados como se muestra en el Paso 5
  ```

  ```python Python SDK theme={null}
  file = sdk.llm.files.upload(
      file={"file_name": "embed_batch.jsonl", "content": open("embed_batch.jsonl", "rb")},
      purpose="batch",
  )

  batch = sdk.llm.batches.create(
      input_file_id=file.id,
      endpoint="/v1/embeddings",
  )

  completed = wait_for_batch(sdk, batch.id)
  # Descarga y analiza los resultados como se muestra en el Paso 5
  ```
</CodeGroup>

## Errores de validación

Si el archivo de entrada tiene problemas de formato, el lote pasa a `failed` inmediatamente.
Causas comunes:

* **JSON inválido** — una línea no es un JSON válido.
* **Campos faltantes** — falta `custom_id`, `method`, `url` o `body` en una línea.
* **Método incorrecto** — `method` debe ser `"POST"`.
* **URL no coincide** — el `url` de una línea no coincide con el `endpoint` declarado al crear el lote.
* **`custom_id` duplicado** — cada `custom_id` debe ser único dentro del archivo.

Consulta `batch.errors.data` para ver los mensajes de error específicos y los números de línea.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm batches get --batch-id batch_abc123 \
    --jq '.errors.data[] | "Line \(.line): [\(.code)] \(.message)"'
  ```

  ```ts MKA1 SDK theme={null}
  const batch = await mka1.llm.batches.get({ batchId: 'batch_abc123' });

  if (batch.status === 'failed' && batch.errors) {
    for (const err of batch.errors.data ?? []) {
      console.log(`Line ${err.line}: [${err.code}] ${err.message}`);
    }
  }
  ```

  ```ts OpenAI SDK theme={null}
  const batch = await openai.batches.retrieve('batch_abc123');

  if (batch.status === 'failed' && batch.errors) {
    for (const err of batch.errors.data ?? []) {
      console.log(`Line ${err.line}: [${err.code}] ${err.message}`);
    }
  }
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;

  var sdk = new SDK(bearerAuth: "Bearer YOUR_API_KEY");

  var batch = await sdk.Llm.Batches.GetAsync("batch_abc123");

  if (batch.BatchObject!.Status == BatchObjectStatus.Failed && batch.BatchObject.Errors != null)
  {
      foreach (var err in batch.BatchObject.Errors.Data ?? new List<BatchObjectErrorsData>())
      {
          Console.WriteLine($"Line {err.Line}: [{err.Code}] {err.Message}");
      }
  }
  ```

  ```python Python SDK theme={null}
  batch = sdk.llm.batches.get(batch_id="batch_abc123")

  if batch.status == "failed" and batch.errors:
      for err in batch.errors.data or []:
          print(f"Line {err.line}: [{err.code}] {err.message}")
  ```
</CodeGroup>

## Ver también

* [Generar una respuesta](/es/docs/generate-a-response) para el patrón síncrono de completaciones de chat.
* [Archivos y almacenes vectoriales](/es/docs/files-and-vector-stores) para la API de Archivos utilizada para subir entradas por lote.
