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

# TypeScript SDK

> TypeScript client library for CatchAll API

TypeScript SDK provides access to the CatchAll API from TypeScript or JavaScript
applications with full type safety and modern async/await patterns.

## Installation

<Tabs>
  <Tab title="npm">
    ```bash theme={null}
    npm install newscatcher-catchall-sdk
    ```
  </Tab>

  <Tab title="yarn">
    ```bash theme={null}
    yarn add newscatcher-catchall-sdk
    ```
  </Tab>

  <Tab title="pnpm">
    ```bash theme={null}
    pnpm add newscatcher-catchall-sdk
    ```
  </Tab>
</Tabs>

## Quickstart

Get started with CatchAll in three steps:

<Steps>
  <Step title="Initialize the client">
    ```typescript theme={null}
    import { CatchAllApiClient } from "newscatcher-catchall-sdk";

    const client = new CatchAllApiClient({ apiKey: "YOUR_API_KEY" });
    ```
  </Step>

  <Step title="Create a job">
    ```typescript theme={null}
    const job = await client.jobs.createJob({
      query: "AI company acquisitions",
      limit: 10,
    });
    const jobId = job.job_id;
    ```
  </Step>

  <Step title="Wait and retrieve results">
    ```typescript theme={null}
    const POLL_INTERVAL_MS = 60000;

    // Poll for completion
    while (true) {
      const status = await client.jobs.getJobStatus({ job_id: jobId });
      if (status.status === "completed") {
        break;
      }
      await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
    }

    // Get results
    const results = await client.jobs.getJobResults({ job_id: jobId });
    console.log(`Found ${results.valid_records} valid records`);
    ```
  </Step>
</Steps>

<Note>
  Jobs process asynchronously and typically complete in 10-15 minutes. See the
  [Quickstart](/web-search-api/get-started/quickstart) for a complete walkthrough.
</Note>

## Working with jobs

<Tabs>
  <Tab title="Get suggestions">
    Get suggested validators, enrichments, and date ranges before creating a job:

    ```typescript theme={null}
    import { CatchAllApiClient } from "newscatcher-catchall-sdk";

    const client = new CatchAllApiClient({ apiKey: "YOUR_API_KEY" });

    const suggestions = await client.jobs.initialize({
      query: "AI company acquisitions",
      context: "Focus on deal size and acquiring company details"
    });

    console.log(JSON.stringify(suggestions, null, 2));
    ```

    <Expandable title="suggestions response">
      ```json theme={null}
      {
        "validators": [
          {
            "name": "is_acquisition_event",
            "description": "true if article describes a completed or announced acquisition",
            "type": "boolean"
          },
          {
            "name": "involves_ai_company",
            "description": "true if acquiring or acquired company is in AI sector",
            "type": "boolean"
          }
        ],
        "enrichments": [
          {
            "name": "acquirer_company",
            "description": "Extract the acquiring company name",
            "type": "company"
          },
          {
            "name": "acquired_company",
            "description": "Extract the acquired company name",
            "type": "company"
          },
          {
            "name": "deal_value",
            "description": "Extract acquisition price if mentioned",
            "type": "number"
          },
          {
            "name": "announcement_date",
            "description": "Extract date of announcement",
            "type": "date"
          },
          {
            "name": "acquirer_details",
            "description": "Extract details about the acquiring company",
            "type": "text"
          }
        ],
        "start_date": "2026-02-01T14:12:57.292205+00:00",
        "end_date": "2026-02-06T14:12:57.292205+00:00",
        "date_modification_message": [
          "No dates were provided; using a default window of 5 days (2026-02-01 to 2026-02-06)."
        ]
      }
      ```
    </Expandable>

    <Tip>
      To learn more, see the [Initialize endpoint](/web-search-api/api-reference/jobs/initialize-job).
    </Tip>
  </Tab>

  <Tab title="Create and track">
    Submit a query and track its progress:

    ```typescript theme={null}
    const POLL_INTERVAL_MS = 60000;

    // Create job with custom validators and enrichments
    const job = await client.jobs.createJob({
      query: "AI company acquisitions",
      context: "Focus on deal size and acquiring company details",
      limit: 10,
      validators: [
        {
          name: "is_acquisition_event",
          description: "true if article describes a completed or announced acquisition",
          type: "boolean"
        }
      ],
      enrichments: [
        {
          name: "acquirer_company",
          description: "Extract the acquiring company name",
          type: "company"
        },
        {
          name: "acquired_company",
          description: "Extract the acquired company name",
          type: "company"
        },
        {
          name: "deal_value",
          description: "Extract acquisition price if mentioned",
          type: "number"
        }
      ]
    });
    console.log(`Job created: ${job.job_id}`);

    // Monitor progress
    const jobId = job.job_id;
    while (true) {
      const status = await client.jobs.getJobStatus({ job_id: jobId });

      if (status.status === "completed") {
        break;
      }

      const currentStep = status.steps.find((s) => !s.completed);
      if (currentStep) {
        console.log(`Step ${currentStep.order}/7: ${currentStep.status}`);
      }

      await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
    }

    // Retrieve results
    const results = await client.jobs.getJobResults({ job_id: jobId });
    console.log(`\nFound ${results.valid_records} valid records`);
    for (const record of results.all_records) {
      console.log(`  ${record.record_title}`);
    }
    ```

    <Note>
      Validators and enrichments are optional. If not provided, the system
      generates them automatically based on your query.
    </Note>
  </Tab>

  <Tab title="Continue jobs">
    Extend processing limits for completed jobs:

    ```typescript theme={null}
    const POLL_INTERVAL_MS = 60000;

    // Continue job to process more records
    const continued = await client.jobs.continueJob({
      job_id: jobId,
      new_limit: 50,
    });
    console.log(
      `Continued: ${continued.previous_limit} -> ${continued.new_limit} records`
    );

    // Wait for completion
    while (true) {
      const status = await client.jobs.getJobStatus({ job_id: jobId });
      if (status.status === "completed") {
        break;
      }
      await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
    }

    // Get final results
    const finalResults = await client.jobs.getJobResults({ job_id: jobId });
    console.log(`Total: ${finalResults.valid_records} valid records`);
    ```

    <Tip>
      Use `limit` parameter when creating jobs to start with fewer records for quick testing.
      Continue the job if you need more records after reviewing initial results.
    </Tip>
  </Tab>

  <Tab title="Early results">
    Retrieve partial results during the enriching stage:

    ```typescript theme={null}
    const POLL_INTERVAL_MS = 60000;

    while (true) {
      const status = await client.jobs.getJobStatus({ job_id: jobId });

      if (status.status === "enriching" || status.status === "completed") {
        const results = await client.jobs.getJobResults({ job_id: jobId });
        
        if (results.valid_records > 0) {
          console.log(
            `Progress: ${results.progress_validated}/${results.candidate_records} validated, ${results.valid_records} valid`
          );
        }

        if (status.status === "completed") {
          break;
        }
      }

      await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
    }
    ```
  </Tab>

  <Tab title="List jobs">
    Retrieve all jobs created by your account:

    ```typescript theme={null}
    const jobs = await client.jobs.getUserJobs();

    for (const job of jobs) {
      console.log(`Job ${job.job_id}: ${job.query} (${job.status})`);
    }
    ```
  </Tab>
</Tabs>

<Accordion title="Complete example with all features">
  ```typescript theme={null}
  import { CatchAllApiClient, CatchAllApiError } from "newscatcher-catchall-sdk";

  const POLL_INTERVAL_MS = 60000;

  const client = new CatchAllApiClient({ apiKey: "YOUR_API_KEY" });

  try {
    // Create job with custom enrichments
    const job = await client.jobs.createJob({
      query: "AI company acquisitions",
      context: "Focus on deal size and acquiring company details",
      limit: 10,
      enrichments: [
        {
          name: "acquirer_company",
          description: "Extract the acquiring company name",
          type: "company"
        },
        {
          name: "deal_value",
          description: "Extract acquisition price if mentioned",
          type: "number"
        }
      ]
    });
    const jobId = job.job_id;
    console.log(`Job created: ${jobId}`);

    // Poll with early results access
    while (true) {
      const status = await client.jobs.getJobStatus({ job_id: jobId });

      if (status.status === "enriching" || status.status === "completed") {
        const results = await client.jobs.getJobResults({ job_id: jobId });
        if (results.valid_records > 0) {
          console.log(`Progress: ${results.valid_records} valid records`);
        }

        if (status.status === "completed") {
          break;
        }
      }

      await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
    }

    // Continue if needed
    let results = await client.jobs.getJobResults({ job_id: jobId });
    if (results.valid_records >= 10) {
      await client.jobs.continueJob({
        job_id: jobId,
        new_limit: 50,
      });

      while (true) {
        const status = await client.jobs.getJobStatus({ job_id: jobId });
        if (status.status === "completed") {
          break;
        }
        await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
      }

      results = await client.jobs.getJobResults({ job_id: jobId });
    }

    // Display results
    console.log(`\nFinal: ${results.valid_records} valid records`);
    for (const record of results.all_records) {
      console.log(`  ${record.record_title}`);
    }
  } catch (err) {
    if (err instanceof CatchAllApiError) {
      console.error(`Status: ${err.statusCode}`);
      console.error(`Error: ${err.message}`);
    }
  }
  ```
</Accordion>

## Working with monitors

Automate recurring queries with scheduled execution.

<Tabs>
  <Tab title="Create monitor">
    Create a monitor from a completed job:

    ```typescript theme={null}
    const monitor = await client.monitors.createMonitor({
      reference_job_id: jobId,
      schedule: "every day at 12 PM UTC",
      webhook_ids: ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
    });
    console.log(`Monitor created: ${monitor.monitor_id}`);
    ```

    <Note>
      Monitors require a minimum 24-hour interval between executions. Learn more in the
      [Monitors documentation](/web-search-api/concepts/monitors).
    </Note>
  </Tab>

  <Tab title="Update monitor">
    Update webhook configuration for an existing monitor:

    ```typescript theme={null}
    const updated = await client.monitors.updateMonitor({
      monitor_id: monitor.monitor_id,
      webhook_ids: ["b2c3d4e5-f6a7-8901-bcde-f12345678901"],
      limit: 100,
    });
    console.log(`Monitor updated: ${updated.status}`);
    ```
  </Tab>

  <Tab title="Pause/Resume">
    Control monitor execution:

    ```typescript theme={null}
    // Pause monitor
    await client.monitors.disableMonitor({ monitor_id: monitor.monitor_id });
    console.log("Monitor paused");

    // Resume monitor
    await client.monitors.enableMonitor({ monitor_id: monitor.monitor_id });
    console.log("Monitor resumed");
    ```
  </Tab>

  <Tab title="List monitors">
    Retrieve all monitors for your account:

    ```typescript theme={null}
    const monitors = await client.monitors.listMonitors();

    console.log(`Total monitors: ${monitors.total_monitors}`);
    for (const m of monitors.monitors) {
      const status = m.enabled ? "active" : "paused";
      console.log(`${m.monitor_id}: ${status}`);
    }
    ```
  </Tab>

  <Tab title="Retrieve results">
    Access aggregated results from all monitor executions:

    ```typescript theme={null}
    // List execution history
    const jobs = await client.monitors.listMonitorJobs({
      monitor_id: monitor.monitor_id,
      sort: "desc",
    });
    console.log(`Monitor executed ${jobs.total_jobs} jobs`);

    // Get all collected records
    const results = await client.monitors.pullMonitorResults({
      monitor_id: monitor.monitor_id,
    });
    console.log(`Total records: ${results.records}`);

    for (const record of results.all_records) {
      console.log(`  ${record.record_title}`);
      console.log(`  Added: ${record.added_on}`);
    }
    ```
  </Tab>
</Tabs>

<Accordion title="Complete monitor example">
  ```typescript theme={null}
  import { CatchAllApiClient, CatchAllApiError } from "newscatcher-catchall-sdk";

  const client = new CatchAllApiClient({ apiKey: "YOUR_API_KEY" });

  try {
    // Create monitor from completed job
    const jobId = "af7a26d6-cf0b-458c-a6ed-4b6318c74da3";

    const monitor = await client.monitors.createMonitor({
      reference_job_id: jobId,
      schedule: "every day at 12 PM UTC",
      webhook_ids: ["a1b2c3d4-e5f6-7890-abcd-ef1234567890"],
    });
    const monitorId = monitor.monitor_id;
    console.log(`Monitor created: ${monitorId}`);

    // Update webhook
    await client.monitors.updateMonitor({
      monitor_id: monitorId,
      webhook_ids: ["b2c3d4e5-f6a7-8901-bcde-f12345678901"],
      limit: 100,
    });

    // List all monitors
    const allMonitors = await client.monitors.listMonitors();
    for (const m of allMonitors.monitors) {
      const status = m.enabled ? "active" : "paused";
      console.log(`${m.monitor_id}: ${status}`);
    }

    // Control execution
    await client.monitors.disableMonitor({ monitor_id: monitorId });
    await client.monitors.enableMonitor({ monitor_id: monitorId });

    // List execution history
    const jobs = await client.monitors.listMonitorJobs({
      monitor_id: monitorId,
      sort: "desc",
    });
    console.log(`\nMonitor executed ${jobs.total_jobs} jobs`);
    for (const job of jobs.jobs) {
      console.log(`  Job ${job.job_id}: ${job.start_date} to ${job.end_date}`);
    }

    // Get aggregated results
    const results = await client.monitors.pullMonitorResults({
      monitor_id: monitorId,
    });
    console.log(`\nCollected ${results.records} total records`);
    for (const record of results.all_records) {
      console.log(`  ${record.record_title}`);
    }
  } catch (err) {
    if (err instanceof CatchAllApiError) {
      console.error(`Status: ${err.statusCode}`);
      console.error(`Error: ${err.message}`);
    }
  }
  ```
</Accordion>

## Company watchlist

Company watchlist lets you track specific companies across jobs. Create entities,
group them into a dataset, then connect the dataset to any job to get per-company
relevance scores in results.

<Tabs>
  <Tab title="Create entity">
    ```typescript theme={null}
    import { CatchAllApiClient } from "newscatcher-catchall-sdk";

    const client = new CatchAllApiClient({ apiKey: "YOUR_API_KEY" });

    const entity = await client.entities.createEntity({
      name: "NewsCatcher",
      entity_type: "company",
      description: "AI-powered news data provider",
      additional_attributes: {
        company_attributes: {
          domain: "newscatcherapi.com",
          alternative_names: ["NC", "NewsCatcher API"],
          key_persons: ["Artem Bugara", "Maksym Sugonyaka"],
        },
      },
    });
    const entityId = entity.id;
    ```
  </Tab>

  <Tab title="Create dataset from CSV">
    Upload a CSV to create a dataset and entities in one step:

    ```typescript theme={null}
    import { createReadStream } from "fs";

    const dataset = await client.datasets.createDatasetFromCsv({
      file: createReadStream("companies.csv"),
      name: "My Portfolio",
    });
    const datasetId = dataset.dataset_id;
    ```

    CSV format:

    ```csv theme={null}
    name,description,domain,alternative_names,key_persons
    NewsCatcher,"AI-powered news data provider",newscatcherapi.com,"NC;NewsCatcher API","Artem Bugara;Maksym Sugonyaka"
    OpenAI,"Artificial intelligence research company",openai.com,"Open AI","Sam Altman"
    ```
  </Tab>

  <Tab title="Submit connected job">
    Wait for the dataset to reach `ready` status, then submit a job:

    ```typescript theme={null}
    const POLL_INTERVAL_MS = 5000;

    // Poll until ready
    while (true) {
      const status = await client.datasets.getDataset({ dataset_id: datasetId });
      if (status.latest_status === "ready") break;
      await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
    }

    // Submit connected job
    const job = await client.jobs.createJob({
      query: "AI chip partnerships",
      connected_dataset_ids: [datasetId],
    });
    ```
  </Tab>

  <Tab title="Read results">
    Each record includes a `connected_entities` array with relevance scores:

    ```typescript theme={null}
    const results = await client.jobs.getJobResults({ job_id: job.job_id });

    for (const record of results.all_records) {
      console.log(record.record_title);
      for (const entity of record.connected_entities ?? []) {
        console.log(`  ${entity.name}: score ${entity.ed_score}/10`);
        console.log(`  ${entity.relation}`);
      }
    }
    ```
  </Tab>
</Tabs>

<Tip>
  For a full step-by-step walkthrough including batch entity creation and the
  JSON API path, see [Company Watchlist](/web-search-api/concepts/company-search).
</Tip>

## Type safety

The SDK exports all request and response types for full TypeScript support:

```typescript theme={null}
import { CatchAllApi } from "newscatcher-catchall-sdk";

const request: CatchAllApi.SubmitRequestDto = {
  query: "AI company acquisitions",
  context: "Focus on deal size and acquiring company details",
  limit: 10,
};

const job = await client.jobs.createJob(request);
```

## Error handling

Handle API errors with structured exception handling:

```typescript theme={null}
import { CatchAllApiError } from "newscatcher-catchall-sdk";

try {
  await client.jobs.createJob({
    query: "AI company acquisitions",
  });
} catch (err) {
  if (err instanceof CatchAllApiError) {
    console.log(`Status: ${err.statusCode}`);
    console.log(`Error: ${err.message}`);
  }
}
```

## Advanced usage

### Pagination

Retrieve large result sets page by page:

```typescript theme={null}
let page = 1;
while (true) {
  const results = await client.jobs.getJobResults({
    job_id: jobId,
    page: page,
    page_size: 100,
  });

  console.log(`Page ${results.page}/${results.total_pages}`);

  for (const record of results.all_records) {
    console.log(`  ${record.record_title}`);
  }

  if (results.page >= results.total_pages) {
    break;
  }
  page++;
}
```

### Timeouts

Configure custom timeouts at the request level:

```typescript theme={null}
const response = await client.jobs.createJob(
  {
    query: "AI company acquisitions",
  },
  {
    timeoutInSeconds: 30,
  }
);
```

### Retries

Configure automatic retry behavior for failed requests:

```typescript theme={null}
const response = await client.jobs.createJob(
  {
    query: "AI company acquisitions",
  },
  {
    maxRetries: 3,
  }
);
```

### Aborting requests

Cancel requests using an abort signal:

```typescript theme={null}
const controller = new AbortController();

const response = await client.jobs.createJob(
  {
    query: "AI company acquisitions",
  },
  {
    abortSignal: controller.signal,
  }
);

// Cancel the request
controller.abort();
```

## Runtime compatibility

The SDK works in the following runtimes:

* Node.js 18+
* Vercel
* Cloudflare Workers
* Deno v1.25+
* Bun 1.0+
* React Native

## Resources

* [GitHub Repository](https://github.com/Newscatcher/newscatcher-catchall-typescript)
* [NPM Package](https://www.npmjs.com/package/newscatcher-catchall-sdk)
* [API Reference](/web-search-api/api-reference/jobs/create-job)
* [Quickstart Guide](/web-search-api/get-started/quickstart)
