Skip to main content
Lesson 11 of 12 · Batch API: Bulk Processing

Tracking, Status, and Cancellation

Lesson 11 of 12 Updated November 2, 2026 Developer
On this page
  1. Manage the batch lifecycle
  2. Two levels of status
  3. Check counters
  4. List your batches
  5. Retrieve results
  6. Check request metadata
  7. Cancel a batch
  8. Polling strategy
  9. Key takeaways

Updated November 2, 2026 based on xAI documentation: the batch discount is 20% on eligible text models (not 50%), examples follow the REST API and the official xai-sdk (client.batch.*; xAI’s Batch API does not match OpenAI’s format, so the OpenAI SDK does not apply), and the Responses API takes precedence over Chat Completions, a legacy endpoint at xAI. Sources: Batch API · REST Reference · Batch Pricing.

Manage the batch lifecycle

Once you submit your requests, you need to track processing progress, read statuses, and know when and how to cancel a batch. This lesson covers all available management operations.

Two levels of status

xAI tracks progress at two levels. The batch itself has no global status like “completed” or “failed”: it carries counters in its state object. Each request, however, has its own status:

Request statusMeaningAction
pendingQueuedWait
succeededProcessed, result availableRetrieve result
failedError during processingRead message, retry if useful
cancelledCanceled, for example with its batchResubmit if necessary

The batch is fully processed when its num_pending counter drops to zero. It can also be canceled or expire: after expire_time, its results are no longer accessible.

Check counters

The GET /v1/batches/{batch_id} call returns the batch and its counters:

curl "https://api.x.ai/v1/batches/$BATCH_ID" \
  -H "Authorization: Bearer $XAI_API_KEY"

The response includes:

{
  "batch_id": "batch_1934e8b5-f3dc-45f1-8329-9841b0aee9d8",
  "name": "analyse_avis_clients",
  "state": {
    "num_requests": 500,
    "num_pending": 155,
    "num_success": 342,
    "num_error": 3,
    "num_cancelled": 0
  }
}

These counters track progress in real time, without waiting for processing to finish. With the SDK, read them in client.batch.get(batch_id=...).state.

List your batches

To find a batch or check history:

curl "https://api.x.ai/v1/batches?limit=20" \
  -H "Authorization: Bearer $XAI_API_KEY"

The list is paginated by limit and pagination_token. Batches remain there until expiration. With the SDK, client.batch.list(limit=20) returns a batches list where each element carries its name, batch_id, and state. The xAI console offers the same view, in visual form.

Retrieve results

You can retrieve results at any time, even during processing:

curl "https://api.x.ai/v1/batches/$BATCH_ID/results?limit=100" \
  -H "Authorization: Bearer $XAI_API_KEY"

Each result carries the batch_request_id of its request. Failed requests appear there with their message; with the SDK, the succeeded and failed properties of each page separate them.

Check request metadata

To track the status of each request:

curl "https://api.x.ai/v1/batches/$BATCH_ID/requests?limit=50" \
  -H "Authorization: Bearer $XAI_API_KEY"

Each entry gives the request identifier, its endpoint, model, status, and creation and end dates. This is the diagnostic tool when a counter stalls, or to verify what was successfully added.

Cancel a batch

If you need to stop processing in progress:

curl -X POST "https://api.x.ai/v1/batches/$BATCH_ID:cancel" \
  -H "Authorization: Bearer $XAI_API_KEY"

Cancellation is final: pending requests won’t be processed, and you can no longer add requests to the batch. Requests already processed, however, remain available in the results. Cancel if:

  • You detected an error in your requests after submission
  • The batch is no longer needed (priority change)
  • You want to resubmit a corrected batch

With the SDK: client.batch.cancel(batch_id=...), which returns the batch and its counters at the time of cancellation.

Polling strategy

In production, wait for completion with spaced polling and a maximum delay:

import time


def attendre_batch(client, batch_id, intervalle=300, delai_max=2 * 86400):
    """Wait until all requests in the batch are processed."""
    debut = time.monotonic()
    while time.monotonic() - debut < delai_max:
        batch = client.batch.get(batch_id=batch_id)
        etat = batch.state
        if batch.cancel_by_xai_message:
            raise RuntimeError(f"Canceled by xAI: {batch.cancel_by_xai_message}")
        if etat.num_requests > 0 and etat.num_pending == 0:
            return batch
        print(f"{etat.num_success} succeeded, {etat.num_error} failed, "
              f"{etat.num_pending} pending out of {etat.num_requests}")
        time.sleep(intervalle)
    raise TimeoutError(f"Batch not finished after {delai_max} s")

An interval of a few minutes suits large batches; xAI’s documentation polls every few seconds in its examples, which cover small batches. And since results are available as they come in, nothing prevents retrieving them during the wait.

Key takeaways

  • Read the batch by its counters (num_pending, num_success, num_error…); each request has its status: pending, succeeded, failed, cancelled
  • GET /v1/batches/{id} gives progress, /results the results, /requests the request detail
  • Cancellation (POST /v1/batches/{id}:cancel) is irreversible, but keeps results already produced
  • Lists and results paginate with limit and pagination_token
  • Poll at intervals of a few minutes, with a maximum delay, and retrieve before expire_time