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

> ## Agent Instructions
> Setting up Context.dev for a user? Follow https://docs.context.dev/agent-quickstart.md. MCP clients sign in with OAuth and need no API key; application code reads CONTEXT_DEV_API_KEY.

# Status and results

> Poll a batch until it finishes, read its records as paginated JSON or gzipped NDJSON files within 7 days, and find earlier batches.

A batch is done when its status is `completed`, `cancelled`, or `failed`. Then you can page through its records as JSON or download them as files. Result files are deleted 7 days after the batch finishes.

## Check status

`GET /v1/batch/{batch_id}` returns the batch. Poll every 10 to 30 seconds while `status` is `queued`, `running`, or `cancelling`, or let a [webhook](/webhooks) tell you when it's done. A finished batch (trimmed):

```json theme={null}
{
  "id": "batch_9f2c8a",
  "status": "completed",
  "progress": { "succeeded": 1998, "failed": 2, "pending": 0 },
  "page_errors": [{ "code": "NOT_FOUND", "count": 2 }],
  "failure": null,
  "timing": {
    "created_at": "2026-09-26T12:00:00.000Z",
    "started_at": "2026-09-26T12:00:02.000Z",
    "completed_at": "2026-09-26T12:09:41.000Z"
  },
  "results": {
    "expires_at": "2026-09-27T12:10:05.000Z",
    "files": [{ "url": "https://storage.googleapis.com/…", "items": 50, "bytes": 184320 }]
  }
}
```

| Field                                   | Meaning                                                                                                                                                                     |
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `progress.succeeded`, `progress.failed` | Pages attempted so far, by outcome.                                                                                                                                         |
| `progress.pending`                      | Accepted pages not attempted yet. It's `0` once a batch is `completed`. A cancelled or failed batch keeps the pages it never reached here, and they have no result records. |
| `page_errors`                           | Failed pages grouped by `error_code`, largest group first.                                                                                                                  |
| `failure`                               | Why the batch itself stopped: `enqueue_failed` (its work couldn't be queued) or `stalled` (no progress for an hour, even after two automatic requeues). `null` otherwise.   |
| `results`                               | Download links. `null` until the batch is final.                                                                                                                            |

A crawl can finish below its `maxUrls` when it runs out of pages in scope.

## Read results

`GET /v1/batch/{batch_id}/results` pages through a finished batch's records as JSON. It returns `409 BATCH_NOT_COMPLETED` until the batch is final.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import ContextDev from "context.dev";

  const client = new ContextDev({ apiKey: process.env.CONTEXT_DEV_API_KEY });

  const page = await client.batch.getResults("batch_9f2c8a", { limit: 100 });
  console.log(page.data.length, page.has_more, page.next_cursor);
  ```

  ```python Python theme={null}
  import os
  from context.dev import ContextDev

  client = ContextDev(api_key=os.environ["CONTEXT_DEV_API_KEY"])

  page = client.batch.get_results("batch_9f2c8a", limit=100)
  print(len(page.data), page.has_more, page.next_cursor)
  ```

  ```ruby Ruby theme={null}
  require "cgi/core"
  require "context_dev"

  client = ContextDev::Client.new(api_key: ENV.fetch("CONTEXT_DEV_API_KEY"))

  page = client.batch.get_results("batch_9f2c8a", limit: 100)
  puts page.data.length, page.has_more, page.next_cursor.inspect
  ```

  ```go Go theme={null}
  package main

  import (
  	"context"
  	"fmt"
  	"os"

  	contextdev "github.com/context-dot-dev/context-go-sdk/v2"
  	"github.com/context-dot-dev/context-go-sdk/v2/option"
  )

  func main() {
  	client := contextdev.NewClient(option.WithAPIKey(os.Getenv("CONTEXT_DEV_API_KEY")))

  	page, err := client.Batch.GetResults(context.Background(), "batch_9f2c8a", contextdev.BatchGetResultsParams{
  		Limit: contextdev.Int(100),
  	})
  	if err != nil {
  		panic(err)
  	}
  	fmt.Println(len(page.Data), page.HasMore, page.NextCursor)
  }
  ```

  ```php PHP theme={null}
  <?php
  require __DIR__.'/vendor/autoload.php';

  use ContextDev\Client;

  $client = new Client(apiKey: getenv('CONTEXT_DEV_API_KEY'));

  $page = $client->batch->getResults("batch_9f2c8a", limit: 100);
  echo count($page->data), PHP_EOL;
  var_dump($page->hasMore, $page->nextCursor);
  ```

  ```bash cURL theme={null}
  curl -G https://api.context.dev/v1/batch/batch_9f2c8a/results \
    -H "Authorization: Bearer $CONTEXT_DEV_API_KEY" \
    --data-urlencode "limit=100"
  ```
</CodeGroup>

```json theme={null}
{
  "data": [
    {
      "url": "https://example.com/about",
      "itemId": "about",
      "status": "ok",
      "http_status": 200,
      "final_url": "https://example.com/about",
      "markdown": "# About us\n\n…",
      "metadata": { "title": "About us", "sourceUrl": "https://example.com/about", "finalUrl": "https://example.com/about" },
      "cache_metadata": { "status": "miss", "age_ms": 0 }
    },
    {
      "url": "https://example.com/careers",
      "itemId": "careers",
      "status": "error",
      "error_code": "NOT_FOUND",
      "message": "Page returned 404"
    }
  ],
  "has_more": false,
  "next_cursor": null
}
```

* `limit` is 1–100 and defaults to 25. A page can close early to stay under about 8 MB, so keep requesting with `cursor` set to `next_cursor` while `has_more` is `true`. An unknown cursor returns `400`.
* Records aren't in submission order. Match them with `itemId`; `meta` comes back too.
* A successful record has `status: "ok"`, `final_url`, `metadata`, `cache_metadata`, and `markdown` or `html`. Markdown batches with `includeHTML` return both. `ocr_pages` appears when OCR recovered PDF pages.
* A failed record has `status: "error"`, `error_code`, and `message`:

| `error_code`           | Meaning                                                                            |
| ---------------------- | ---------------------------------------------------------------------------------- |
| `NOT_FOUND`            | The page returned 404.                                                             |
| `WEBSITE_BLOCKED`      | The site served a bot challenge or an access wall.                                 |
| `WEBSITE_ACCESS_ERROR` | No content could be fetched, or a crawl redirect left the crawl's scope.           |
| `REQUEST_TIMEOUT`      | The page didn't finish within 60 seconds. Timed-out pages get one automatic retry. |
| `UNSUPPORTED_CONTENT`  | The content type can't be scraped.                                                 |
| `PDF_SKIPPED`          | A PDF page with `pdf.shouldParse: false`.                                          |
| `PDF_IMAGES_ONLY`      | A scanned PDF with no text layer. Resubmit it with `pdf.ocr: true`.                |
| `INTERNAL_ERROR`       | Context.dev couldn't process the page.                                             |

## Download files

For large batches, download the files in `results.files` instead of paging. Each file is gzipped NDJSON, one record per line, with up to 50 records, so a 25,000-URL batch has about 500 files. File order carries no meaning.

Each link expires 24 hours after the call that returned it (`results.expires_at`). Retrieve the batch again for new links. The `data.batch.results` links in a `batch.*` webhook expire 24 hours after the event, and a replay resends those same links.

Result files are deleted 7 days after the batch finishes. After that, the links stop working and `/results` can't return the records, so copy what you need within 7 days.

## List batches

`GET /v1/batch/list` returns your batches, newest first. It returns 25 per page by default and up to 100 with `limit`. Filter with these parameters:

| Parameter     | Notes                                                              |
| ------------- | ------------------------------------------------------------------ |
| `status`      | One status, such as `completed`.                                   |
| `q`           | Up to 200 characters. Searches batch IDs, crawl sources, and tags. |
| `search_type` | `prefix` (default) or `exact`.                                     |
| `tags`        | Comma-separated. Matches batches with any of the tags.             |

Page with `cursor` set to `next_cursor`. A search with `q` or `tags` can return `503 SEARCH_UNAVAILABLE`; retry it, or list without them.

## Related

* [Submit a batch](/batches/submit): `itemId`, `meta`, and page options.
* [Cancel, limits, and errors](/batches/limits-and-errors): delete old batches and handle errors.
* [List batch results reference](/api-reference/batches/results) and [Retrieve a batch reference](/api-reference/batches/retrieve)
