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

# Job Batches

> Process multiple KYB/KYC cases in batches

The Job Batch feature allows you to process multiple KYB or KYC cases simultaneously by uploading a CSV file or using our standard API endpoints. This guide covers how to create, monitor, and manage job batches.

## What is a Job Batch?

A job batch is a collection of related jobs that are processed together. Each batch has:

* A unique batch ID
* A batch name (typically derived from the uploaded CSV filename)
* An agent key it's associated with
* Creation timestamp

```mermaid theme={null}
graph TD
    A[Upload CSV] --> B[Create Batch]
    B --> C[Process Jobs]
    C --> D[Monitor Progress]
    D --> E[Download Reports]
    E --> F[Export Results]

    style A fill:#f9d71c,stroke:#333,stroke-width:2px
    style B fill:#91c2e8,stroke:#333,stroke-width:2px
    style C fill:#91c2e8,stroke:#333,stroke-width:2px
    style D fill:#91c2e8,stroke:#333,stroke-width:2px
    style E fill:#91c2e8,stroke:#333,stroke-width:2px
    style F fill:#f9d71c,stroke:#333,stroke-width:2px
```

## Creating a Batch

### Using CSV Upload

The simplest way to create a batch is by uploading a CSV file containing multiple cases.

<CodeGroup>
  ```bash theme={null}
  curl -X POST 'https://api.parcha.ai/api/v1/enqueueFromCSV' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -F 'file=@/path/to/cases.csv' \
  -F 'agent_id=your-agent-key'
  ```

  ```python theme={null}
  import requests
  import os

  def create_batch_from_csv(api_key: str, agent_key: str, csv_path: str):
      url = "https://api.parcha.ai/api/v1/enqueueFromCSV"
      
      with open(csv_path, 'rb') as f:
          files = {'file': f}
          data = {'agent_id': agent_key}
          headers = {'Authorization': f'Bearer {api_key}'}
          
          response = requests.post(url, 
                                 headers=headers,
                                 data=data, 
                                 files=files)
          return response.json()

  # Example usage
  result = create_batch_from_csv(
      api_key='YOUR_API_KEY',
      agent_key='your-agent-key',
      csv_path='cases.csv'
  )
  print(f"Batch created with {len(result['jobs'])} jobs")
  ```

  ```typescript theme={null}
  import axios from 'axios';
  import FormData from 'form-data';
  import fs from 'fs';

  async function createBatchFromCSV(
    apiKey: string, 
    agentKey: string, 
    csvPath: string
  ) {
    const form = new FormData();
    form.append('file', fs.createReadStream(csvPath));
    form.append('agent_id', agentKey);

    const response = await axios.post(
      'https://api.parcha.ai/api/v1/enqueueFromCSV',
      form,
      {
        headers: {
          ...form.getHeaders(),
          'Authorization': `Bearer ${apiKey}`
        }
      }
    );

    return response.data;
  }

  // Example usage
  createBatchFromCSV(
    'YOUR_API_KEY',
    'your-agent-key',
    'cases.csv'
  )
  .then(result => {
    console.log(`Batch created with ${result.jobs.length} jobs`);
  })
  .catch(console.error);
  ```
</CodeGroup>

Example Response:

```json theme={null}
{
 "status": "ok",
 "jobs": [
   {
     "id": "f4cba9af-d976-414e-ad2f-c585696840bd", 
     "status": "QUEUED",
     "agent_id": "your-agent-key"
   },
   {
     "case_id": "john-doe-123",
     "job_id": "a1b2c3d4e5f6414ead2fc585696840bd",
     "started_at": "2024-12-10 17:40:30", 
     "status": "complete",
     "recommendation": "Review",
     "checks": {
       "Source of Wealth Check": "Failed",
       "Adverse Media and OSInt Check": "Failed"
     },
     "pdf_url": "https://storage.example.com/reports/a1b2c3d4e5f6414ead2fc585696840bd.pdf?signed=abc123"
   }
 ]
}
```

The CSV format should match your agent type:

<CodeGroup>
  ```csv KYB Example theme={null}
  business_name,website,industry,description
  Acme Corp,www.acme.com,Technology,Leading provider of cloud solutions
  Beta Inc,www.beta.com,Finance,Investment management firm
  ```

  ```csv KYC Example theme={null}
  first_name,last_name,date_of_birth,country_of_nationality
  John,Doe,1980-01-01,US
  Jane,Smith,1985-05-15,UK
  ```
</CodeGroup>

## Listing Batches

To get a list of all batches for an agent:

<CodeGroup>
  ```bash cURL theme={null}
  curl 'https://api.parcha.ai/api/v1/getJobBatches?agent_key=your-agent-key&include_signed_urls=true' \
  -H 'Authorization: Bearer YOUR_API_KEY'
  ```

  ```python Python theme={null}
  import requests

  def get_batches(api_key: str, agent_key: str, include_urls: bool = True):
      url = f"https://api.parcha.ai/api/v1/getJobBatches"
      
      params = {
          'agent_key': agent_key,
          'include_signed_urls': include_urls  # Returns secure URLs for CSV files
      }
      
      headers = {'Authorization': f'Bearer {api_key}'}
      
      response = requests.get(url, headers=headers, params=params)
      return response.json()

  # Example usage
  batches = get_batches('YOUR_API_KEY', 'your-agent-key')
  for batch in batches:
      print(f"Batch: {batch['batch_name']}")
      print(f"Created: {batch['created_at']}")
      print(f"CSV URL: {batch.get('csv_signed_url', 'No URL available')}")
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';

  async function getBatches(
    apiKey: string, 
    agentKey: string, 
    includeUrls: boolean = true  // Returns secure URLs for CSV files
  ) {
    const response = await axios.get(
      'https://api.parcha.ai/api/v1/getJobBatches',
      {
        params: {
          agent_key: agentKey,
          include_signed_urls: includeUrls
        },
        headers: {
          'Authorization': `Bearer ${apiKey}`
        }
      }
    );
    
    return response.data;
  }
  ```
</CodeGroup>

### Parameters:

* `include_signed_urls`: When set to true, returns secure signed URLs for accessing the original CSV files. These URLs are valid for 1 hour.

Example Response:

```json theme={null}
[
    {
        "updated_at": "2024-01-10T17:40:29.883017",
        "agent_key": "your-agent-key",
        "created_at": "2024-01-10T17:40:29.883011",
        "id": "7fe54d2f-cd87-4d52-9734-d97e893d554a",
        "batch_name": "example_batch.csv [2024-01-10 17:40 UTC]",
        "csv_signed_url": "https://storage.example.com/signed-url-to-csv"
    },
    {
        "updated_at": "2024-01-10T16:53:54.888520",
        "agent_key": "your-agent-key",
        "created_at": "2024-01-10T16:53:54.888513",
        "id": "1a967c94-ddcf-4a23-9953-a3f13ab6af69",
        "batch_name": "another_batch.csv [2024-01-10 16:53 UTC]",
        "csv_signed_url": "https://storage.example.com/signed-url-to-csv"
    }
]
```

## ## Getting Batch Jobs

To retrieve all jobs in a specific batch:

<CodeGroup>
  ```bash cURL theme={null}
  curl 'https://api.parcha.ai/api/v1/getBatchJobs?batch_id=your-batch-id&fetch_pdf_from_gcs=true' \
  -H 'Authorization: Bearer YOUR_API_KEY'
  ```

  ```python Python theme={null}
  import requests

  def get_batch_jobs(
      api_key: str, 
      batch_id: str, 
      fetch_pdf: bool = True  # Include secure PDF URLs in response
  ):
      url = f"https://api.parcha.ai/api/v1/getBatchJobs"
      
      params = {
          'batch_id': batch_id,
          'fetch_pdf_from_gcs': fetch_pdf
      }
      
      headers = {'Authorization': f'Bearer {api_key}'}
      
      response = requests.get(url, headers=headers, params=params)
      return response.json()
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';

  async function getBatchJobs(
    apiKey: string, 
    batchId: string,
    fetchPdf: boolean = true  // Include secure PDF URLs in response
  ) {
    const response = await axios.get(
      'https://api.parcha.ai/api/v1/getBatchJobs',
      {
        params: {
          batch_id: batchId,
          fetch_pdf_from_gcs: fetchPdf
        },
        headers: {
          'Authorization': `Bearer ${apiKey}`
        }
      }
    );
    
    return response.data;
  }
  ```
</CodeGroup>

### Parameters:

* `fetch_pdf_from_gcs`: When set to true, includes secure signed URLs for accessing the PDF reports. These URLs are valid for 1 hour.

Example Response:

```json theme={null}
[
    {
        "case_id": "CASE-001",
        "job_id": "f4cba9afd976414ead2fc585696840bd",
        "started_at": "2024-01-10 17:40:30",
        "status": "complete",
        "recommendation": "Review",
        "checks": {
            "Source of Wealth Check": "Failed",
            "Adverse Media Check": "Failed"
        },
        "pdf_url": "https://storage.example.com/signed-url-to-pdf"
    },
    {
        "case_id": "CASE-002",
        "job_id": "a1b2c3d4e5f6414ead2fc585696840bd",
        "started_at": "2024-01-10 17:41:30",
        "status": "complete",
        "recommendation": "Approve",
        "checks": {
            "Source of Wealth Check": "Passed",
            "Adverse Media Check": "Passed"
        },
        "pdf_url": "https://storage.example.com/signed-url-to-pdf"
    }
]
```

## Downloading Reports

If a job doesn't have a PDF report URL or you need to regenerate it:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST 'https://api.parcha.ai/api/v1/downloadReport' \
  -H 'Authorization: Bearer YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "case_id": "your-case-id",
    "agent_key": "your-agent-key",
    "force_refresh_report": false
  }' \
  --output "case_report.pdf"
  ```

  ```python Python theme={null}
  import requests

  def download_report(
      api_key: str, 
      case_id: str,
      agent_key: str,
      force_refresh: bool = False  # Set to True to regenerate PDF
  ):
      url = "https://api.parcha.ai/api/v1/downloadReport"
      
      data = {
          "case_id": case_id,
          "agent_key": agent_key,
          "force_refresh_report": force_refresh
      }
      
      headers = {'Authorization': f'Bearer {api_key}'}
      
      response = requests.post(
          url, 
          headers=headers,
          json=data
      )
      
      if response.headers['content-type'] == 'application/pdf':
          # Save PDF
          with open(f"{case_id}_report.pdf", 'wb') as f:
              f.write(response.content)
          return f"Report saved as {case_id}_report.pdf"
      else:
          return response.json()
  ```

  ```typescript TypeScript theme={null}
  import axios from 'axios';
  import fs from 'fs';

  async function downloadReport(
    apiKey: string,
    caseId: string,
    agentKey: string,
    forceRefresh: boolean = false  // Set to True to regenerate PDF
  ) {
    const response = await axios.post(
      'https://api.parcha.ai/api/v1/downloadReport',
      {
        case_id: caseId,
        agent_key: agentKey,
        force_refresh_report: forceRefresh
      },
      {
        headers: {
          'Authorization': `Bearer ${apiKey}`
        },
        responseType: 'arraybuffer'
      }
    );

    if (response.headers['content-type'] === 'application/pdf') {
      const fileName = `${caseId}_report.pdf`;
      fs.writeFileSync(fileName, response.data);
      return `Report saved as ${fileName}`;
    } else {
      const data = JSON.parse(
        Buffer.from(response.data).toString('utf8')
      );
      return data;
    }
  }
  ```
</CodeGroup>

### Parameters:

* `force_refresh_report`: When set to true, forces regeneration of the PDF report. This is useful if:
  * The downloaded PDF is blank or corrupted
  * The job was previously in a queued or in-progress state
  * You need a fresh copy of the report
* Note: Generated PDF URLs expire after 1 hour

Example Request Body:

```json theme={null}
{
    "agent_key": "your-agent-key",
    "case_id": "CASE-001"
}
```

Response: Returns a PDF file with the report content.

## Batch Processing Flow

1. **Create Batch**
   * Upload CSV file or use API endpoints
   * System generates batch ID and processes jobs

2. **Monitor Progress**
   * Use `getJobBatches` to list all batches
   * Use `getBatchJobs` to check individual job statuses

3. **Access Reports**
   * Download PDF reports using provided GCS URLs
   * Generate missing reports using `downloadReport` endpoint

4. **Export Results**
   * Use CSV export functionality for batch results
   * Access individual job results through API
