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 / 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
36 operations across the current v1 API.
/api/v1/contactsList contacts with cursor pagination and filters
contacts:read/api/v1/contactsCreate a contact
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/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.