Skip to main content
This guide builds a Company Watchlist end to end: upload your list of companies, run a connected job to confirm the matching, then schedule a monitor that re-runs it and delivers per-company events to your app. Each step links to its reference if you need to go deeper. Use this when you track a fixed set of companies — a fund’s portfolio, a competitor set, an account list — and want recurring coverage scored per company, instead of running broad topic queries.

Before you begin

  • Get a CatchAll API key from platform.newscatcherapi.com.
  • Have your company list ready as a CSV with name and domain columns (see the format in Step 1).
  • Set up a publicly accessible HTTPS endpoint that returns a 2xx and accepts a JSON POST, or use webhook.site for testing.
  • Optionally, install the CatchAll SDK for your language:
# cURL is included on most systems. Check with:
curl --version

Build the monitor

1

Build the watchlist

A dataset is a named collection of company entities — your portfolio. The fastest way to create one is to upload a CSV: it creates the entities and the dataset in a single request. The name and domain columns are required; everything else is optional. Use semicolons to separate multiple values.
companies.csv
name,description,domain,alternative_names,key_persons
Apollo Global Management,"US-based alternative asset manager headquartered in New York City, founded 1990, NYSE: APO.",apollo.com,"Apollo","Marc Rowan"
Stripe,"Online payments platform headquartered in San Francisco and Dublin.",stripe.com,"","Patrick Collison;John Collison"
Databricks,"Data and AI platform company headquartered in San Francisco, founded 2013.",databricks.com,"",""
curl -X POST "https://catchall.newscatcherapi.com/catchAll/datasets/upload" \
  -H "x-api-key: YOUR_API_KEY" \
  -F "file=@companies.csv" \
  -F "name=Q2 Portfolio"
The description is the signal that tells two companies with the same name apart. A specific, factual description (“US-based alternative asset manager, NYSE: APO”) beats a vague one (“global leader in solutions”). See Company Watchlist for how to write descriptions that disambiguate, plus the JSON and batch alternatives to CSV upload.
2

Wait for the dataset to be ready

Entities are enriched after upload. Poll the dataset until latest_status reaches ready — don’t submit a job before this completes.
curl "https://catchall.newscatcherapi.com/catchAll/datasets/YOUR_DATASET_ID" \
  -H "x-api-key: YOUR_API_KEY"
3

Test a connected job

Run the watchlist once before scheduling it. Submit a standard job with connected_dataset_ids to activate company search mode. To collect all news about your companies rather than a single topic, set fetch_all_watchlist_news: true; to track a specific theme, pass a real query instead. Keep the job_id — you reference it when creating the monitor.
curl -X POST "https://catchall.newscatcherapi.com/catchAll/submit" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "all news",
    "connected_dataset_ids": ["YOUR_DATASET_ID"],
    "fetch_all_watchlist_news": true
  }'
Each record carries a connected_entities array — one entry per matched company, with an ed_score from 1 to 10 and a one-line relation explaining the match.
To return only events where a tracked company is the primary actor (the company that raised funding, was acquired, announced layoffs), add "ed_association_type": "event_associated". See Company Watchlist.
4

Create a webhook

A webhook is created once at the organization level, then attached to any number of jobs or monitors. Save the returned webhook.id.
curl -X POST "https://catchall.newscatcherapi.com/catchAll/webhooks" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Portfolio news feed",
    "url": "https://your-app.com/catchall/webhook",
    "type": "generic",
    "delivery_mode": "full"
  }'
CatchAll also supports slack and teams webhook types if you’d rather deliver portfolio updates straight to a channel. See Set up webhooks.
5

Schedule the monitor

A monitor re-runs the connected job on a schedule, deduplicates against previous runs, and delivers each run to the webhooks in webhook_ids. A monitor created from a watchlist job keeps the connection — every run scores the same portfolio.
curl -X POST "https://catchall.newscatcherapi.com/catchAll/monitors/create" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "reference_job_id": "YOUR_JOB_ID",
    "schedule": "every day at 9 AM UTC",
    "webhook_ids": ["YOUR_WEBHOOK_ID"]
  }'
The reference job’s end_date must be within the last 7 days, and the default minimum schedule interval is 24 hours (more frequent intervals depend on your plan). See Configure monitors.
6

Handle the delivery

After each scheduled run, CatchAll sends a POST to your webhook URL. Return a 2xx within 5 seconds and process asynchronously. For a connected watchlist, each record carries the same connected_entities array you saw when testing — so you can route each event to the right company.The payload:
{
  "monitor_id": "3fec5b07-8786-46d7-9486-d43ff67eccd4",
  "latest_job_id": "295b95d8-6041-4f4b-b132-9f009fc6af70",
  "records_count": 1,
  "records": [
    {
      "record_id": "6417909601438475967",
      "record_title": "Stripe acquires payments startup Lemon for $1.1B",
      "enrichment": {
        "enrichment_confidence": "high",
        "event_type": "acquisition",
        "deal_value": "$1.1 billion"
      },
      "citations": [
        { "title": "Stripe buys Lemon", "link": "https://example.com/stripe-lemon", "published_date": "2026-06-17 09:01:00" }
      ],
      "connected_entities": [
        {
          "entity_id": "854198fa-f702-49db-a381-0427fa87f173",
          "name": "Stripe",
          "type": "company",
          "ed_score": 9,
          "association_type": "event_associated",
          "relation": "Stripe is the acquiring company in the announced deal"
        }
      ]
    }
  ]
}
A minimal receiver routes each record by matched company:
from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route("/catchall/webhook", methods=["POST"])
def handle_webhook():
    payload = request.json
    # Return 200 immediately, then process asynchronously
    for r in payload.get("records", []):
        for e in r.get("connected_entities", []):
            print(f"[{e['name']}] {r['record_title']} (score {e['ed_score']}/10)")
    return jsonify({"status": "received"}), 200
Prefer no code? Point the webhook url at an n8n, Make, or Zapier webhook trigger and map each connected_entities entry into a Slack message, a spreadsheet row, or a CRM record on the matching company.

Keep the watchlist current

Portfolios change. Update the dataset without rebuilding the monitor — the next scheduled run picks up the new roster automatically: See the Datasets API reference for the full set of dataset operations.

See also

  • Company Watchlist: entities, datasets, association types, and per-company scoring in depth
  • Monitors: how scheduling, deduplication, and rolling date windows work
  • Build an event feed: the same pipeline for a topic query instead of a watchlist
  • Set up webhooks: webhook types, auth, testing, and delivery history
  • Configure monitors: schedules, robust webhook handling, updating a monitor