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 / 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

36 operations across the current v1 API.

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/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/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