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 "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.
Bearer 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 more03 / 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.
# 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."
}'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.
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"
}]
}'{
"data": {
"channel": "linkedin",
"received": 1,
"created": 1,
"updated": 0,
"failed": 0,
"companiesCreated": 1,
"results": [
{ "index": 0, "ok": true, "created": true, "contactId": "...", "companyId": "...", "companyCreated": true }
]
}
}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.
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" }
]
}'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.
/api/v1/outreach/jobsOutreach /jobs
outreach:read/api/v1/outreach/budgetOutreach /budget
outreach:manage/api/v1/outreach/jobs/leaseOutreach /jobs/lease
outreach:work/api/v1/outreach/jobs/{jobId}/heartbeatOutreach /jobs/{jobId}/heartbeat
outreach:work/api/v1/outreach/jobs/{jobId}/checkpointOutreach /jobs/{jobId}/checkpoint
outreach:work/api/v1/outreach/jobs/{jobId}/completeOutreach /jobs/{jobId}/complete
outreach:work/api/v1/outreach/jobs/{jobId}/failOutreach /jobs/{jobId}/fail
outreach:work/api/v1/outreach/jobs/{jobId}/retryOutreach /jobs/{jobId}/retry
outreach:manage/api/v1/outreach/eventsOutreach /events
outreach:events/api/v1/outreach/campaigns/{campaignId}/metricsOutreach /campaigns/{campaignId}/metrics
outreach:read/api/v1/outreach/metrics/reconcileOutreach /metrics/reconcile
outreach:manage/api/v1/outreach/jobs/nextOutreach /jobs/lease
outreach:work/api/v1/outreach/jobs/enqueueEnqueue a bounded explicit cohort
outreach:manage/api/v1/outreach/campaigns/{campaignId}/jobsEnqueue a bounded explicit cohort
outreach:manage/api/v1/outreach/research/{researchId}Read bounded immutable research
outreach:read/api/v1/outreach/publications/{publicationId}Read canonical publication status
outreach:read/api/v1/contactsList contacts with cursor pagination and filters
contacts:read/api/v1/contactsCreate a contact
contacts:write/api/v1/contact-fieldsList custom contact columns for agent qualification
contacts:read/api/v1/contact-fieldsCreate a custom column on the Contacts page
contacts:write/api/v1/contacts/{contactId}Retrieve one contact
contacts:read/api/v1/contacts/{contactId}Update one contact
contacts:write/api/v1/contacts/bulkCreate or upsert up to 100 contacts
contacts:write/api/v1/contacts/lookupPlan LinkedIn skips, refreshes, and creates for up to 100 identities
contacts:read/api/v1/imports/apifyImport profiles, upsert their companies, and link both records
contacts:write + companies:write/api/v1/lead-scrapes/campaignsList Catchment-managed lead-scrape campaigns
contacts:read + contacts:write/api/v1/lead-scrapes/campaignsRegister or reprioritize lead-scrape campaigns
contacts:write + companies:write/api/v1/lead-scrapes/nextLease the next unique page for a lead-scrape campaign
contacts:write + companies:write/api/v1/lead-scrapes/{runId}/completeComplete or fail a leased lead-scrape page
contacts:write + companies:write/api/v1/companiesList companies
companies:read/api/v1/companiesCreate a company
companies:write/api/v1/companies/{companyId}Retrieve one company
companies:read/api/v1/companies/{companyId}Update one company
companies:write/api/v1/companies/{companyId}/relationshipsRead linked contacts and deals
companies:read/api/v1/companies/{companyId}/relationshipsLink contacts and deals
companies:write/api/v1/dealsList deals
deals:read/api/v1/dealsCreate a deal
deals:write/api/v1/deals/{dealId}Retrieve one deal
deals:read/api/v1/deals/{dealId}Update one deal
deals:write/api/v1/deals/{dealId}/stageMove a deal to another stage
deals:write/api/v1/tasksList tasks
tasks:read/api/v1/tasksCreate a task
tasks:write/api/v1/tasks/{taskId}Retrieve one task
tasks:read/api/v1/tasks/{taskId}Update one task
tasks:write/api/v1/activitiesList CRM activities
activities:read/api/v1/activitiesLog a CRM activity
activities:write/api/v1/pipelinesList pipelines and their stages
deals:read/api/v1/searchSearch contacts, companies, and deals
Any read scope/api/v1/webhooksList webhook subscriptions
webhooks:read/api/v1/webhooksCreate a webhook subscription
webhooks:write/api/v1/webhooks/{webhookId}Delete a webhook subscription
webhooks:write/api/v1/discovery/sourcesList connected discovery sources with consent basis and health
discovery:read/api/v1/discovery/sourcesConnect a source and record its legal basis for capture
discovery:write/api/v1/discovery/sources/{sourceId}Read one connected source
discovery:read/api/v1/discovery/sources/{sourceId}Remove a source and stop capture
discovery:write/api/v1/discovery/sources/{sourceId}/actionsConfigure, authorize, pause, resume, refresh or re-scope a source
discovery:write/api/v1/discovery/ingestIngest captured signals from a connector run
discovery:write/api/v1/discovery/opportunitiesList ranked opportunities
discovery:read/api/v1/discovery/opportunitiesRun detection over persisted signals
discovery:write/api/v1/discovery/opportunities/{opportunityId}/decisionAccept, approve, act on, snooze or dismiss an opportunity
discovery:write/api/v1/discovery/opportunities/{opportunityId}/handoffHand an approved opportunity to an execution agent
discovery:write/api/v1/discovery/outcomesRecord an outcome so the ranker can learn from it
discovery:write/api/v1/discovery/metricsDiscovery funnel metrics
discovery:read/api/v1/discovery/privacyExport retained data for a subject
discovery:read/api/v1/discovery/privacyErase or restrict a subject's retained data
discovery:write/api/v1/discovery/demand-radar/{resource}List settings, sources, candidates, gaps, communities, threads or watches
discovery:read/api/v1/discovery/demand-radar/{resource}Create or correct up to 100 Demand Radar records in one write
discovery:write/api/v1/discovery/demand-radar/{resource}/{recordId}Read one Demand Radar record
discovery:read/api/v1/discovery/demand-radar/{resource}/{recordId}Correct part of a record; the merged result is re-validated
discovery:write/api/v1/discovery/demand-radar/{resource}/{recordId}Retract a Demand Radar record
discovery:write/api/v1/outreach/statusRead redacted Outreach health and budget configuration
outreach:read/api/v1/outreach/campaignsPage workspace Outreach campaigns
outreach:read/api/v1/outreach/campaignsCreate a draft campaign with paid execution disabled
outreach:manage/api/v1/outreach/campaigns/{campaignId}Read one campaign
outreach:read/api/v1/outreach/campaigns/{campaignId}Update allowlisted campaign settings with expected revision
outreach:manage/api/v1/outreach/source-campaignsPage acquisition source campaigns without contact write capability
outreach:read/api/v1/outreach/campaigns/{campaignId}/enrollEnroll at most 100 contacts transactionally
outreach:manage/api/v1/outreach/campaigns/{campaignId}/leadsPage campaign leads using one indexed filter
outreach:read/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}Read bounded research, drafts, outcomes and publication
outreach:read/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}/draftsPage immutable draft history
outreach:read/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}/eventsPage lead outcome history
outreach:read/api/v1/outreach/campaigns/{campaignId}/leads/{leadId}/commandsRecord an idempotent command with its action-specific capability
outreach:manage + outreach:review/api/v1/outreach/publications/{publicationId}/attachAttach a fixed Keypiece /start snapshot to an approved intent
outreach:review/api/v1/outreach/candidatesPage eligible indexed contact candidates using one bounded filter
outreach:read/api/v1/outreach/maintenanceRun one resumable dry-run or write candidate backfill chunk
outreach:manage/api/v1/api-keysList API keys without their secrets
Admin session/api/v1/api-keysCreate an API key; secret returned once
Admin session/api/v1/api-keysRevoke an API key
Admin session06 / 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.
limitintegerPage size. Default 25; maximum 100.
cursorstringOpaque continuation token from the previous response.
fieldsstringComma-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.