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

# DeepResearch Batch API

> Process multiple deep research tasks in parallel with shared configuration

The Batch API allows you to process multiple DeepResearch tasks in parallel with shared configuration and progress monitoring.

<Note>
  [Human-in-the-loop (HITL)](/guides/deepresearch-hitl) checkpoints are not available for batch requests. Use individual `deepresearch.create()` tasks for HITL support.
</Note>

<Note>
  For conceptual overview, batch lifecycle, and best practices, see the [Batch Processing Guide](/guides/deepresearch-batching). This page focuses on TypeScript SDK method reference.
</Note>

## Quick Start

```typescript theme={null}
import { Valyu } from "valyu-js";

const client = new Valyu();

// Create batch, add tasks, wait for completion
const batch = await client.batch.create({ name: "Research Batch", mode: "standard" });
await client.batch.addTasks(batch.batch_id, {
  tasks: [
    { query: "Research AI trends" },
    { query: "Analyze market data" }
  ]
});
const result = await client.batch.waitForCompletion(batch.batch_id);
console.log(`Completed: ${result.counts.completed} tasks`);
```

## Methods

### `batch.create(options?)`

Creates a new batch container. Returns a batch ID that you'll use for subsequent operations.

**Parameters:**

```typescript theme={null}
interface CreateBatchOptions {
  name?: string;                                    // Optional batch name
  mode?: "fast" | "standard" | "heavy" | "max";      // Research mode: "standard" (default), "heavy" (comprehensive), or "fast" (faster completion)
  outputFormats?: ("markdown" | "pdf" | "toon" | Record<string, any>)[];  // Output formats: ["markdown"], ["pdf"], ["toon"], or JSON schema. Cannot mix JSON schema with "markdown"/"pdf". "toon" requires JSON schema.
  search?: {                                        // Search configuration (type, sources, dates, category). See Search Configuration section for details.
    searchType?: "all" | "web" | "proprietary";     // Default: "all"
    includedSources?: string[];                     // e.g., ["web", "academic", "finance", "patent", "transportation", "politics", "legal"]
    excludedSources?: string[];                     // Array of source types to exclude
    startDate?: string;                             // YYYY-MM-DD format
    endDate?: string;                               // YYYY-MM-DD format
    category?: string;                              // Category filter (source-dependent)
  };
  webhookUrl?: string;                              // HTTPS URL for completion notification
  metadata?: Record<string, string | number | boolean>; // Custom metadata
}
```

**Response:**

```typescript theme={null}
interface CreateBatchResponse {
  success: boolean;
  batch_id?: string;                                // Use this for subsequent operations
  name?: string;                                     // Batch name
  status?: BatchStatus;
  mode?: "fast" | "standard" | "heavy";             // Research mode
  output_formats?: ("markdown" | "pdf" | "toon" | Record<string, any>)[];
  search_params?: {
    search_type?: "all" | "web" | "proprietary";
    included_sources?: string[];
  };
  counts?: BatchCounts;                              // Task counts
  cost?: number;                                     // Total cost in dollars
  created_at?: string;                               // ISO 8601 timestamp string
  completed_at?: string;                              // ISO 8601 timestamp string (if completed)
  webhook_secret?: string;                           // Secret for webhook verification (only on creation)
  error?: string;
}
```

**Example:**

```typescript theme={null}
const batch = await client.batch.create({
  name: "Q4 Research Batch",
  mode: "fast",
  outputFormats: ["markdown"],
  metadata: {
    project: "Q4-Research",
    user: "analyst-1"
  }
});

if (batch.success) {
  console.log(`Created batch: ${batch.batch_id}`);
}
```

### `batch.addTasks(batchId, options)`

Adds one or more tasks to an existing batch. You can call this multiple times to add tasks incrementally.

**Constraints:**

* **Maximum tasks per request**: 100
* **Minimum tasks per request**: 1
* Batch must be in `"open"` or `"processing"` status

**Parameters:**

```typescript theme={null}
interface AddBatchTasksOptions {
  tasks: BatchTaskInput[]; // Array of 1-100 tasks
}

interface BatchTaskInput {
  id?: string;                                      // Optional custom task identifier (for tracking)
  query: string;                                    // Research query or task description (required)
  strategy?: string;                                // Deprecated: use researchStrategy instead
  researchStrategy?: string;                        // Natural language strategy to guide the research phase
  reportFormat?: string;                            // Natural language instructions for output format (highest priority)
  urls?: string[];                                  // Array of URLs to extract content from
  metadata?: Record<string, string | number | boolean>; // Custom metadata
}
```

Tasks inherit `mode`, `outputFormats`, and `search` from the batch and cannot override them.

**Response:**

```typescript theme={null}
interface AddBatchTasksResponse {
  success: boolean;
  batch_id?: string;                                // Batch ID
  added?: number;                                    // Number of tasks successfully added
  tasks?: BatchTaskCreated[];                       // Array of created task objects
  counts?: BatchCounts;                             // Updated task counts for the batch
  error?: string;
}

interface BatchTaskCreated {
  task_id?: string;                                 // User-provided task identifier (if specified)
  deepresearch_id: string;                          // DeepResearch task ID
  status: string;                                    // Task status
}
```

**Example:**

```typescript theme={null}
    const addResult = await client.batch.addTasks(batchId, {
      tasks: [
        {
          query: "What are the latest developments in quantum computing?"
        },
        {
          query: "Analyze the impact of AI on healthcare in 2024"
        },
        {
          query: "Compare renewable energy trends across Europe",
          urls: ["https://example.com/report.pdf"]
        }
      ]
    });

    if (addResult.success) {
      console.log(`Added ${addResult.added} tasks`);
    }
```

### `batch.status(batchId)`

Gets the current status of a batch, including task counts and cost information.

**Response:**

```typescript theme={null}
interface BatchStatusResponse {
  success: boolean;
  batch?: DeepResearchBatch;
  error?: string;
}

interface DeepResearchBatch {
  batch_id: string;
  organisation_id?: string;
  api_key_id?: string;
  credit_id?: string;
  name?: string;
  status: BatchStatus;                              // "open" | "processing" | "completed" | "completed_with_errors" | "cancelled"
  mode: "fast" | "standard" | "heavy";             // Research mode
  output_formats?: ("markdown" | "pdf" | "toon" | Record<string, any>)[];
  search_params?: {
    search_type?: "all" | "web" | "proprietary";
    included_sources?: string[];
  };
  counts: BatchCounts;
  cost: number;                                     // Total cost in dollars (replaces 'usage' object)
  webhook_url?: string;
  webhook_secret?: string;                         // Only returned on batch creation
  created_at: string;                               // ISO 8601 timestamp string
  completed_at?: string;                            // ISO 8601 timestamp string (only present when batch is completed)
  metadata?: Record<string, string | number | boolean>;
}

interface BatchCounts {
  total: number;                                    // Total tasks in batch
  queued: number;                                    // Tasks waiting to start
  running: number;                                  // Tasks currently running
  completed: number;                                // Successfully completed tasks
  failed: number;                                   // Failed tasks
  cancelled: number;                                // Cancelled tasks
}
```

**Example:**

```typescript theme={null}
const status = await client.batch.status(batchId);

if (status.success && status.batch) {
  console.log(`Status: ${status.batch.status}`);
  console.log(
    `Progress: ${status.batch.counts.completed}/${status.batch.counts.total}`
  );
  console.log(`Cost: $${status.batch.cost}`);
}
```

### `batch.listTasks(batchId, options?)`

Lists all tasks in a batch with their individual statuses. Pass `includeOutput: true` to get full output, sources, images, and cost for each task.

**Parameters:**

```typescript theme={null}
interface ListBatchTasksOptions {
  status?: string;          // Filter: "completed", "failed", "cancelled", "running", "queued"
  limit?: number;           // Results per page (default: 25, max: 50)
  lastKey?: string;         // Pagination cursor from previous response
  includeOutput?: boolean;  // Include full output, sources, images, and cost (default: false)
}
```

**Response:**

```typescript theme={null}
interface ListBatchTasksResponse {
  success: boolean;
  batch_id?: string;                                // Batch ID
  tasks?: BatchTaskListItem[];
  pagination?: BatchPagination;                     // Pagination information
  error?: string;
}

interface BatchPagination {
  count: number;                                    // Number of tasks returned in this response
  last_key?: string;                                // Pagination key for fetching next page (if has_more is true)
  has_more: boolean;                                // Whether there are more tasks to fetch
}

interface BatchTaskListItem {
  task_id?: string;                                 // User-provided task identifier
  deepresearch_id: string;                          // Task ID (use with deepresearch.status())
  query: string;                                    // The research query
  status: DeepResearchStatus;                       // Task status
  created_at: string;                               // ISO 8601 timestamp string
  completed_at?: string;                            // ISO 8601 timestamp string
  // Additional fields when includeOutput is true:
  output_type?: string;                             // "markdown", "pdf", "toon", "structured"
  output?: string;                                  // Full research output
  sources?: Source[];                               // Cited sources
  images?: string[];                                // Image URLs
  pdf_url?: string;                                 // PDF download URL
  deliverables?: any;                               // Deliverable outputs
  error?: string;                                   // Error message (failed tasks)
  cost?: number;                                    // Task cost in dollars
}
```

**Example:**

```typescript theme={null}
// Lightweight listing (status only)
const tasksList = await client.batch.listTasks(batchId);

if (tasksList.success && tasksList.tasks) {
  tasksList.tasks.forEach((task, i) => {
    console.log(`${i + 1}. ${task.status}: ${task.query.substring(0, 50)}...`);
  });
}

// Get full output for completed tasks
const results = await client.batch.listTasks(batchId, {
  status: "completed",
  includeOutput: true,
});

for (const task of results.tasks) {
  console.log(`Task: ${task.task_id || task.deepresearch_id}`);
  console.log(`Query: ${task.query}`);
  console.log(`Output: ${task.output?.substring(0, 200)}...`);
  console.log(`Sources: ${task.sources?.length} cited`);
  console.log(`Cost: $${task.cost}`);
}

// Paginate through all results
let lastKey = results.pagination.last_key;
while (lastKey) {
  const nextPage = await client.batch.listTasks(batchId, {
    status: "completed",
    includeOutput: true,
    lastKey,
  });
  for (const task of nextPage.tasks) {
    console.log(`Task: ${task.deepresearch_id} - ${task.query}`);
  }
  lastKey = nextPage.pagination.last_key;
}
```

<Tip>
  By default, `includeOutput` is `false`, returning a lightweight listing with task status only. Set `includeOutput: true` when you need the full output, sources, images, and cost for each task.
</Tip>

### `batch.waitForCompletion(batchId, options?)`

Waits for a batch to complete by polling its status at regular intervals. This is useful for long-running batches where you want to be notified when all tasks finish.

**Parameters:**

```typescript theme={null}
interface BatchWaitOptions {
  pollInterval?: number;                            // Polling interval in ms (default: 10000)
  maxWaitTime?: number;                             // Maximum wait time in ms (default: 7200000 = 2 hours)
  onProgress?: (batch: DeepResearchBatch) => void; // Progress callback
}
```

**Response:**

Returns the final `DeepResearchBatch` object when the batch reaches a terminal state (`completed`, `completed_with_errors`, or `cancelled`).

**Example:**

```typescript theme={null}
try {
  const finalBatch = await client.batch.waitForCompletion(batchId, {
    pollInterval: 10000,                            // Check every 10 seconds
    maxWaitTime: 600000,                            // Wait up to 10 minutes
    onProgress: (batch) => {
      console.log(
        `Progress: ${batch.counts.completed}/${batch.counts.total} completed`
      );
      console.log(
        `Running: ${batch.counts.running}, Queued: ${batch.counts.queued}`
      );
    }
  });

  console.log("Batch completed!");
  console.log(`Final status: ${finalBatch.status}`);
} catch (error) {
  console.error(`Wait interrupted: ${error.message}`);
}
```

### `batch.cancel(batchId)`

Cancels a batch and all its pending tasks. Tasks that are already running will continue, but queued tasks will be cancelled.

**Response:**

```typescript theme={null}
interface CancelBatchResponse {
  success: boolean;
  message?: string;
  batch_id?: string;
  error?: string;
}
```

**Example:**

```typescript theme={null}
const result = await client.batch.cancel(batchId);

if (result.success) {
  console.log(`Batch ${batchId} cancelled successfully`);
} else {
  console.log(`Failed to cancel: ${result.error}`);
}
```

### `batch.list()`

Lists all batches associated with your API key.

**Response:**

```typescript theme={null}
interface ListBatchesResponse {
  success: boolean;
  batches?: DeepResearchBatch[];                    // Array of batches (direct array, no wrapper)
  error?: string;
}
```

**Example:**

```typescript theme={null}
const result = await client.batch.list();

if (result.success && result.batches) {
  console.log(`Found ${result.batches.length} batches:`);

  result.batches.forEach((batch, i) => {
    console.log(`${i + 1}. ${batch.batch_id}`);
    console.log(`   Name: ${batch.name || "Unnamed"}`);
    console.log(`   Status: ${batch.status}`);
    console.log(`   Tasks: ${batch.counts.total}`);
  });
}
```

## Complete Example

Here's a complete example that demonstrates the full batch workflow:

```typescript theme={null}
const { Valyu } = require('valyu-js');

const client = new Valyu(process.env.VALYU_API_KEY);

async function runBatchExample() {
  try {
    // 1. Create a batch
    console.log('Creating batch...');
    const batch = await client.batch.create({
      name: 'Research Questions Batch',
      mode: 'fast',
      outputFormats: ['markdown'],
      search: {
        searchType: 'all',
        includedSources: ['valyu/valyu-arxiv']
      },
      metadata: {
        project: 'Q4-Research',
        user: 'analyst-1'
      }
    });

    if (!batch.success) {
      throw new Error(`Failed to create batch: ${batch.error}`);
    }

    const batchId = batch.batch_id;
    console.log(`✓ Created batch: ${batchId}\n`);

    // 2. Add tasks to the batch
    console.log('Adding tasks...');
    const addResult = await client.batch.addTasks(batchId, {
      tasks: [
        {
          query: 'What are the latest developments in quantum computing?'
        },
        {
          query: 'Analyze the impact of AI on healthcare in 2024'
        },
        {
          query: 'Compare renewable energy trends across Europe'
        }
      ]
    });

    if (!addResult.success) {
      throw new Error(`Failed to add tasks: ${addResult.error}`);
    }
    console.log(`✓ Added ${addResult.added} tasks\n`);

    // 3. Monitor progress
    console.log('Waiting for completion...');
    const finalBatch = await client.batch.waitForCompletion(batchId, {
      pollInterval: 10000,
      maxWaitTime: 600000,
      onProgress: (batch) => {
        console.log(
          `  Progress: ${batch.counts.completed}/${batch.counts.total} completed ` +
            `(${batch.counts.running} running, ${batch.counts.queued} queued)`
        );
      }
    });

    console.log('\n✓ Batch completed!');
    console.log(`Final status: ${finalBatch.status}`);
    console.log(`Completed: ${finalBatch.counts.completed}`);
    console.log(`Failed: ${finalBatch.counts.failed}`);

    // 4. Get all results with full output
    console.log('\nFetching task results...');
    const results = await client.batch.listTasks(batchId, {
      status: 'completed',
      includeOutput: true,
    });

    for (const task of results.tasks) {
      console.log(`\nTask: ${task.query.substring(0, 50)}...`);
      console.log(`Output length: ${task.output?.length || 0} characters`);
      console.log(`Sources: ${task.sources?.length || 0} cited`);
      console.log(`Cost: $${task.cost}`);
    }

  } catch (error) {
    console.error('Error:', error.message);
  }
}

runBatchExample();
```

## Search Configuration

The `search` parameter controls which data sources are queried. See the [Batch Processing Guide](/guides/deepresearch-batching#search-parameters) for complete documentation of all search options.

```typescript theme={null}
const batch = await client.batch.create({
  name: "Academic Research",
  mode: "standard",
  search: {
    searchType: "proprietary",
    includedSources: ["academic", "finance"],
    startDate: "2024-01-01",
    endDate: "2024-12-31"
  }
});
```

<Note>
  Batch-level search parameters are inherited by all tasks and cannot be overridden per-task.
</Note>

## Integration with DeepResearch API

Individual tasks in a batch are DeepResearch tasks. You can use the standard DeepResearch methods:

```typescript theme={null}
// Get detailed task result
const result = await client.deepresearch.status(task.deepresearch_id);

// Update a running task
await client.deepresearch.update(task.deepresearch_id, "Focus on recent data");

// Cancel an individual task
await client.deepresearch.cancel(task.deepresearch_id);
```

## Limitations

<Warning>
  Batch tasks do not support: `files`, `deliverables`, `mcpServers`, or `previousReports`. Use `client.deepresearch.create()` for these features.
</Warning>

| Constraint                | Value                  |
| ------------------------- | ---------------------- |
| Maximum tasks per request | 100                    |
| Minimum tasks per request | 1                      |
| Batch status to add tasks | `open` or `processing` |

**Inherited settings** (cannot override per-task): `mode`, `outputFormats`, `search`

**Per-task overrides allowed**: `researchStrategy`, `reportFormat`, `strategy` (deprecated), `urls`, `metadata`

See the [Batch Processing Guide](/guides/deepresearch-batching#limitations) for complete details.

## See Also

<CardGroup cols={2}>
  <Card title="Batch Processing Guide" icon="book" href="/guides/deepresearch-batching">
    Complete guide with lifecycle, best practices, and examples
  </Card>

  <Card title="DeepResearch API" icon="flask" href="/sdk/typescript-sdk/deepresearch">
    Individual task API with all features
  </Card>

  <Card title="Python SDK" icon="python" href="/sdk/python-sdk/deepresearch-batch">
    Python batch methods
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/endpoint/deepresearch-batch-create">
    REST API endpoint documentation
  </Card>
</CardGroup>
