Catchment DOCS
Checking session…

CATCHMENT API / V1

Move signals into
your CRM.

One workspace-scoped API for captured profiles, companies, deals, follow-ups, and the systems around them.

OpenAPI JSON ↗

01 / QUICKSTART

Your first request

Create an API key in Integrations, store it as a secret, then send it as a Bearer token. Keys are tied to one workspace, so you never pass a workspace ID to regular API endpoints.

cURL
curl "https://your-catchment-host/api/v1/contacts?limit=25" \
  -H "Authorization: Bearer $CATCHMENT_API_KEY"

02 / AUTHENTICATION

Keys have explicit scopes

Use the smallest set of read and write scopes your integration needs. Full access is available for trusted systems and expands to every current scope; future scopes are not silently added.

AuthorizationBearer ck_live_••••••••••••

The raw key is visible only once. Catchment stores a hash, and revoked or expired keys stop authenticating immediately.

contacts:readcontacts:writecompanies:readdeals:writewebhooks:write+ 7 more

03 / AGENT QUALIFICATION

Let agents shape and qualify the contact table

A key with contacts:read can discover the workspace's contact columns. A key with contacts:write can create text, number, boolean, date, or select columns, then update a contact's lifecycle stage, custom values, and remarks. New definitions appear on the Contacts page automatically.

Qualification workflow
# 1. Create or discover a qualification column
curl -X POST "https://your-catchment-host/api/v1/contact-fields" \
  -H "Authorization: Bearer $CATCHMENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: qualification-field-v1" \
  -d '{"label":"Agent qualification","type":"select","options":["Qualified","Review","Disqualified"]}'

# 2. Qualify a lead and leave team-visible remarks
curl -X PATCH "https://your-catchment-host/api/v1/contacts/$CONTACT_ID" \
  -H "Authorization: Bearer $CATCHMENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: qualify-$CONTACT_ID-v1" \
  -d '{
    "lifecycleStage":"marketing_qualified",
    "customFields":{"agent-qualification":"Qualified"},
    "notes":"Strong ICP match: owns the buying process; follow up this week."
  }'
Discover before writing.

Call GET /api/v1/contact-fields and use the returned field id as the key in customFields. Remarks use the first-class notes property and are shown inline in the Contacts table.

03 / APIFY INGESTION

Post captured profiles directly

Send 1–100 dataset items with a key that has both contacts:write and companies:write. LinkedIn profile fields become contact columns; the current employer is upserted into Companies and linked to the contact. The full source item and run provenance are retained.

Request
curl -X POST "https://your-catchment-host/api/v1/imports/apify" \
  -H "Authorization: Bearer $CATCHMENT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: apify-run-abc123" \
  -d '{
    "channel": "linkedin",
    "actorRunId": "abc123",
    "datasetId": "dataset_xyz",
    "items": [{
      "firstName": "Ada",
      "lastName": "Lovelace",
      "headline": "Founder",
      "linkedinUrl": "https://linkedin.com/in/ada",
      "companyName": "Analytical Engines"
    }]
  }'
Response · 200
{
  "data": {
    "channel": "linkedin",
    "received": 1,
    "created": 1,
    "updated": 0,
    "failed": 0,
    "companiesCreated": 1,
    "results": [
      { "index": 0, "ok": true, "created": true, "contactId": "...", "companyId": "...", "companyCreated": true }
    ]
  }
}
Make retries safe.

Set Idempotency-Key to the Apify run ID. Replaying the completed run returns the same mutation outcome instead of creating duplicate contacts or companies.

04 / LINKEDIN LOOKUP

Check before you run an actor

Normalize up to 100 LinkedIn IDs or profile URLs, preserve input order, and learn whether each contact should be created, refreshed, or skipped. Use staleAfter to match your enrichment policy.

Request
curl -X POST "https://your-catchment-host/api/v1/contacts/lookup" \
  -H "Authorization: Bearer $CATCHMENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "linkedin",
    "staleAfter": "P30D",
    "identities": [
      { "linkedinUrl": "https://linkedin.com/in/ada/?trk=public" },
      { "linkedinId": "member-123" }
    ]
  }'
Identity is deterministic.

Tracking parameters, mobile hosts, case, duplicate slashes, and trailing slashes normalize to one profile identity. Display names are never authoritative company identities.

05 / API REFERENCE

All endpoints

88 operations across the current v1 API.

GET/api/v1/outreach/jobs

Outreach /jobs

outreach:read
POST/api/v1/outreach/budget

Outreach /budget

outreach:manage
POST/api/v1/outreach/jobs/lease

Outreach /jobs/lease

outreach:work
POST/api/v1/outreach/jobs/{jobId}/heartbeat

Outreach /jobs/{jobId}/heartbeat

outreach:work
POST/api/v1/outreach/jobs/{jobId}/checkpoint

Outreach /jobs/{jobId}/checkpoint

outreach:work
POST/api/v1/outreach/jobs/{jobId}/complete

Outreach /jobs/{jobId}/complete

outreach:work
POST/api/v1/outreach/jobs/{jobId}/fail

Outreach /jobs/{jobId}/fail

outreach:work
POST/api/v1/outreach/jobs/{jobId}/retry

Outreach /jobs/{jobId}/retry

outreach:manage
POST/api/v1/outreach/events

Outreach /events

outreach:events
GET/api/v1/outreach/campaigns/{campaignId}/metrics

Outreach /campaigns/{campaignId}/metrics

outreach:read
POST/api/v1/outreach/metrics/reconcile

Outreach /metrics/reconcile

outreach:manage
POST/api/v1/outreach/jobs/next

Outreach /jobs/lease

outreach:work
POST/api/v1/outreach/jobs/enqueue

Enqueue a bounded explicit cohort

outreach:manage
POST/api/v1/outreach/campaigns/{campaignId}/jobs

Enqueue a bounded explicit cohort

outreach:manage
GET/api/v1/outreach/research/{researchId}

Read bounded immutable research

outreach:read
GET/api/v1/outreach/publications/{publicationId}

Read canonical publication status

outreach:read
GET/api/v1/contacts

List contacts with cursor pagination and filters

contacts:read
POST/api/v1/contacts

Create a contact

contacts:write
GET/api/v1/contact-fields

List custom contact columns for agent qualification

contacts:read
POST/api/v1/contact-fields

Create a custom column on the Contacts page

contacts:write
GET/api/v1/contacts/{contactId}

Retrieve one contact

contacts:read
PATCH/api/v1/contacts/{contactId}

Update one contact

contacts:write
POST/api/v1/contacts/bulk

Create or upsert up to 100 contacts

contacts:write
POST/api/v1/contacts/lookup

Plan LinkedIn skips, refreshes, and creates for up to 100 identities

contacts:read
POST/api/v1/imports/apify

Import profiles, upsert their companies, and link both records

contacts:write + companies:write
GET/api/v1/lead-scrapes/campaigns

List Catchment-managed lead-scrape campaigns

contacts:read + contacts:write
POST/api/v1/lead-scrapes/campaigns

Register or reprioritize lead-scrape campaigns

contacts:write + companies:write
POST/api/v1/lead-scrapes/next

Lease the next unique page for a lead-scrape campaign

contacts:write + companies:write
POST/api/v1/lead-scrapes/{runId}/complete

Complete or fail a leased lead-scrape page

contacts:write + companies:write
GET/api/v1/companies

List companies

companies:read
POST/api/v1/companies

Create a company

companies:write
GET/api/v1/companies/{companyId}

Retrieve one company

companies:read
PATCH/api/v1/companies/{companyId}

Update one company

companies:write
GET/api/v1/companies/{companyId}/relationships

Read linked contacts and deals

companies:read
PATCH/api/v1/companies/{companyId}/relationships

Link contacts and deals

companies:write
GET/api/v1/deals

List deals

deals:read
POST/api/v1/deals

Create a deal

deals:write
GET/api/v1/deals/{dealId}

Retrieve one deal

deals:read
PATCH/api/v1/deals/{dealId}

Update one deal

deals:write
POST/api/v1/deals/{dealId}/stage

Move a deal to another stage

deals:write
GET/api/v1/tasks

List tasks

tasks:read
POST/api/v1/tasks

Create a task

tasks:write
GET/api/v1/tasks/{taskId}

Retrieve one task

tasks:read
PATCH/api/v1/tasks/{taskId}

Update one task

tasks:write
GET/api/v1/activities

List CRM activities

activities:read
POST/api/v1/activities

Log a CRM activity

activities:write
GET/api/v1/pipelines

List pipelines and their stages

deals:read
GET/api/v1/search

Search contacts, companies, and deals

Any read scope
GET/api/v1/webhooks

List webhook subscriptions

webhooks:read
POST/api/v1/webhooks

Create a webhook subscription

webhooks:write
DELETE/api/v1/webhooks/{webhookId}

Delete a webhook subscription

webhooks:write
GET/api/v1/discovery/sources

List connected discovery sources with consent basis and health

discovery:read
POST/api/v1/discovery/sources

Connect a source and record its legal basis for capture

discovery:write
GET/api/v1/discovery/sources/{sourceId}

Read one connected source

discovery:read
DELETE/api/v1/discovery/sources/{sourceId}

Remove a source and stop capture

discovery:write
POST/api/v1/discovery/sources/{sourceId}/actions

Configure, authorize, pause, resume, refresh or re-scope a source

discovery:write
POST/api/v1/discovery/ingest

Ingest captured signals from a connector run

discovery:write
GET/api/v1/discovery/opportunities

List ranked opportunities

discovery:read
POST/api/v1/discovery/opportunities

Run detection over persisted signals

discovery:write
POST/api/v1/discovery/opportunities/{opportunityId}/decision

Accept, approve, act on, snooze or dismiss an opportunity

discovery:write
POST/api/v1/discovery/opportunities/{opportunityId}/handoff

Hand an approved opportunity to an execution agent

discovery:write
POST/api/v1/discovery/outcomes

Record an outcome so the ranker can learn from it

discovery:write
GET/api/v1/discovery/metrics

Discovery funnel metrics

discovery:read
GET/api/v1/discovery/privacy

Export retained data for a subject

discovery:read
POST/api/v1/discovery/privacy

Erase or restrict a subject's retained data

discovery:write
GET/api/v1/discovery/demand-radar/{resource}

List settings, sources, candidates, gaps, communities, threads or watches

discovery:read
POST/api/v1/discovery/demand-radar/{resource}

Create or correct up to 100 Demand Radar records in one write

discovery:write
GET/api/v1/discovery/demand-radar/{resource}/{recordId}

Read one Demand Radar record

discovery:read
PATCH/api/v1/discovery/demand-radar/{resource}/{recordId}

Correct part of a record; the merged result is re-validated

discovery:write
DELETE/api/v1/discovery/demand-radar/{resource}/{recordId}

Retract a Demand Radar record

discovery:write
GET/api/v1/outreach/status

Read redacted Outreach health and budget configuration

outreach:read
GET/api/v1/outreach/campaigns

Page workspace Outreach campaigns

outreach:read
POST/api/v1/outreach/campaigns

Create a draft campaign with paid execution disabled

outreach:manage
GET/api/v1/outreach/campaigns/{campaignId}

Read one campaign

outreach:read
PATCH/api/v1/outreach/campaigns/{campaignId}

Update allowlisted campaign settings with expected revision

outreach:manage
GET/api/v1/outreach/source-campaigns

Page acquisition source campaigns without contact write capability

outreach:read
POST/api/v1/outreach/campaigns/{campaignId}/enroll

Enroll at most 100 contacts transactionally

outreach:manage
GET/api/v1/outreach/campaigns/{campaignId}/leads

Page campaign leads using one indexed filter

outreach:read
GET/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}

Read bounded research, drafts, outcomes and publication

outreach:read
GET/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}/drafts

Page immutable draft history

outreach:read
GET/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}/events

Page lead outcome history

outreach:read
POST/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}/commands

Record an idempotent command with its action-specific capability

outreach:manage + outreach:review
POST/api/v1/outreach/publications/{publicationId}/attach

Attach a fixed Keypiece /start snapshot to an approved intent

outreach:review
GET/api/v1/outreach/candidates

Page eligible indexed contact candidates using one bounded filter

outreach:read
POST/api/v1/outreach/maintenance

Run one resumable dry-run or write candidate backfill chunk

outreach:manage
GET/api/v1/api-keys

List API keys without their secrets

Admin session
POST/api/v1/api-keys

Create an API key; secret returned once

Admin session
DELETE/api/v1/api-keys

Revoke an API key

Admin session

06 / PAGINATION

Predictable list requests

List endpoints accept limit (1–100), an opaque cursor, direction, and endpoint-specific filters. Use the returned meta.nextCursor without modifying it.

limitinteger

Page size. Default 25; maximum 100.

cursorstring

Opaque continuation token from the previous response.

fieldsstring

Comma-separated sparse fieldset where supported.

07 / SAFETY & ERRORS

Automation stays inspectable

Every API error is JSON and includes a request ID in both the response body and X-Request-Id header. Invalid, revoked, and expired keys return 401; an authenticated key without the required scope returns 403. Keep the request ID when reporting an unexpected failure.

High-impact agent operations can require an approval header. Bulk contact mutations require X-Catchment-Approval: bulk-contact-mutation; closing a deal uses a deal-specific approval value.

400/422Invalid request
401Invalid or inactive key
403Insufficient scope
409Conflict or in-flight retry
429Rate limited
500Server error