Reference · 13 operations
Actions: lists and find
Last updated from API version 2026-10-06 at (live spec, refreshed hourly). openapi.json
Find
Resolve a LinkedIn profile URL to its provider id.
/api/v1/actions/find/provider_id- Scope
- read
- Credits
- See the catalog entry
- Idempotency-Key
- optional
- Class
- read
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, records
- Max targets
- 100
- Dry run
- Supported
Read class, free. Looks each target's LinkedIn URL up through one
LinkedIn account of this workspace: the key's bound identity, else
identityId (a session defaults to the signed-in member's own
identity). Never another workspace's account; no profile-view
notification is sent. Targets: a contact (its LinkedIn URL), contacts,
or up to 100 inline records with linkedinUrl. One target runs
inline (200 {data: {action, result}}); dryRun: true (or
Owlbound-Dry-Run: true) returns the plan and calls nothing. More
than one target (or mode: "async") creates an async run:
202 {data: {action}} with Location: /api/v1/actions/{id}; the
targets run in batches of 25 and their outcomes are on
GET /actions/{id}/targets and GET /events. A deployment without
the async runner answers 503 ACTIONS_ASYNC_UNAVAILABLE and creates
nothing. A dry run stores its plan for
15 minutes; a real call with that planId (or Owlbound-Plan) runs
only if the targets, skip set, input, approval outcome and credit
maximum still match, else 409 PLAN_STALE with the new plan in
error.details.plan. A plan runs once (409 PLAN_ALREADY_APPLIED)
and only for the key, session or agent run that made it. 4xx answers
are stored under the Idempotency-Key: apply a new planId with a new
Idempotency-Key. After a key rotation the old key keeps its plans
during the grace period; the new key gets 404 for them.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
FindProviderIdRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputFindProviderIdInput0
No options; the LinkedIn URL comes from each target.
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose LinkedIn account runs the lookup. A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own.
Responses
200The finished action and its result, or the dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202An async run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/find/provider_id" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"target": {
"kind": "contact",
"contactId": "<contactId>"
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Find a person's LinkedIn profile URL.
/api/v1/actions/find/linkedin_url- Scope
- enrich
- Credits
- 20 credits per target
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, records
- Max targets
- 1,000
- Dry run
- Supported
- Writes back
- contact
Spend class. Runs a waterfall per target and stops at the first URL
whose confidence is at least input.minConfidence (default
medium): internal (this workspace's own contacts, free), then
apollo and zoominfo with the workspace's own connected keys
(BYOK, free), then linkedin_search, a name search on the identity's
own LinkedIn account (20 credits, enrichment.linkedin_url.find,
charged only when it finds the URL). Override the order with
input.providers. Confidence: high for the contact's own URL or an
email match, medium for a name with the company, low for a name
alone. Nothing found is free. Targets: a contact, contacts, or up to
100 inline records with firstName and lastName (and company,
domain) or email; a contact that already has a LinkedIn URL is
answered from it, free. A found URL is written onto a contact target
per output.contact (default fillEmpty). The LinkedIn search spends
one of the account's 150 daily LinkedIn lookups; without an identity
with an active LinkedIn account it is skipped. One target runs inline
(200 {data: {action, result}}, one target's price held then settled
at what it was charged); more (or mode: "async") create an async
run (202), billed per batch of 25. dryRun: true returns the plan
with the credit maximum and calls nothing.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
FindLinkedInUrlRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputFindLinkedInUrlInput0
- outputFindLinkedInUrlOutput0
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose LinkedIn account runs the
linkedin_searchstep. A bound key uses its identity (another is403 IDENTITY_NOT_ALLOWED); a session defaults to the member's own. Without a usable identity the search step is skipped.
Responses
200The finished action and its result, or the dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202An async run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 402 Not enough credits (INSUFFICIENT_CREDITS). With an Idempotency-Key this
result is stored and replayed: after adding credits, retry with a new
Idempotency-Key.
· 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/find/linkedin_url" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"target": {
"kind": "contact",
"contactId": "<contactId>"
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Resolve a Sales Navigator profile URL to its public LinkedIn URL.
/api/v1/actions/find/public_url- Scope
- read
- Credits
- See the catalog entry
- Idempotency-Key
- optional
- Class
- read
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, records
- Max targets
- 100
- Dry run
- Supported
Read class, free. Reads each Sales Navigator profile through one
LinkedIn account of this workspace (the key's bound identity, else
identityId; a session defaults to the member's own), never another
workspace's, with no profile-view notification. Each lookup spends
one of the account's 150 daily LinkedIn lookups; a URL that is
already public is answered as is, free. Targets: a contact (its
stored Sales Navigator URL), contacts, or up to 100 inline records
with salesNavUrl. One target runs inline; more create an async run
(202). dryRun: true returns the plan and calls nothing.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
FindPublicUrlRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputFindPublicUrlInput0
No options; the Sales Navigator URL comes from each target.
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose LinkedIn account runs the lookup. A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own.
Responses
200The finished action and its result, or the dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202An async run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/find/public_url" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"target": {
"kind": "contact",
"contactId": "<contactId>"
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Find LinkedIn company ids for a company name.
/api/v1/actions/find/company_ids- Scope
- read
- Credits
- See the catalog entry
- Idempotency-Key
- optional
- Class
- read
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- records
- Max targets
- 100
- Dry run
- Supported
Read class, free. Looks each query up in LinkedIn's company search
through one LinkedIn account of this workspace (the key's bound
identity, else identityId; a session defaults to the member's own).
The result is up to 25 companies {id, name, logoUrl} (ids for the
companyIds filter of actions.lists.linkedin_search); no match is
a success with no companies. Targets: up to 100 inline records with
query (1 to 100 characters). One target runs inline; more create an
async run (202). dryRun: true returns the plan and calls nothing.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
FindCompanyIdsRequest
- 0
- inputFindCompanyIdsInput0
No options; the query comes from each record.
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose LinkedIn account runs the search. A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own.
Responses
200The finished action and its result, or the dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202An async run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/find/company_ids" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"target": {
"kind": "records",
"records": [
{
"query": "<query>"
}
]
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Lists
A list of people from LinkedIn search criteria.
/api/v1/actions/lists/linkedin_search- Scope
- enrich
- Credits
- 12 credits per call + 3 credits per record (quantity from input.maxResults)
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Writes back
- contact
- Max duration
- 7200 s
Searches LinkedIn (Sales Navigator by default, or classic) on the
identity's own LinkedIn account (the key's bound identity, else
identityId); nobody is contacted. A paused search is
503 LINKEDIN_SEARCH_DEGRADED.
Spend class, async only (202 {data: {action}}, Location: /api/v1/actions/{id}); target none (the list makes its own
targets: one per provider page, run in order). Price
audience.scrape.start: 12 per list plus 3 per person written,
charged per page once the page is written (a person already written
by an earlier page of the same list is not charged again; a page
that writes nobody is free), held per batch of pages, never above
maxCredits (pages that would pass it are skipped RUN_CAPPED) or
the key's daily credit cap (CAP_EXCEEDED). dryRun: true counts
the search once with the provider (reused for 15 minutes, also by
the call that applies the plan) and returns the pages and the
credit estimate; nothing is held or written. The people land in the
list's items (read by the list-to-table writer) and, for an
audience, in its contacts. Cancel stops at the next page.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsLinkedInSearchRequest
- 0
At least
keywordsor one filter. - targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/linkedin_search" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"keywords": "<keywords>",
"locationIds": [
"<locationIds>"
],
"industryIds": [
"<industryIds>"
]
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Scrape a saved audience (ICP) into its contacts.
/api/v1/actions/lists/icp- Scope
- enrich
- Credits
- 12 credits per call + 3 credits per record (quantity from input.maxPages)
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Writes back
- contact
- Max duration
- 7200 s
Runs the audience's search (its Sales Navigator URL, or its criteria
compiled to one) and imports the people into the workspace's
contacts as members of the audience, as the app's scrape does.
An audience being scraped is 409 LIST_BUSY; a first scrape of an
audience over 1,000 people is 422 ICP_TOO_BROAD; company
audiences are 422 LIST_SOURCE_UNSUPPORTED. maxPages pages of 25
(10 for saved lead lists).
Spend class, async only (202 {data: {action}}, Location: /api/v1/actions/{id}); target none (the list makes its own
targets: one per provider page, run in order). Price
audience.scrape.start: 12 per list plus 3 per person written,
charged per page once the page is written (a person already written
by an earlier page of the same list is not charged again; a page
that writes nobody is free), held per batch of pages, never above
maxCredits (pages that would pass it are skipped RUN_CAPPED) or
the key's daily credit cap (CAP_EXCEEDED). dryRun: true counts
the search once with the provider (reused for 15 minutes, also by
the call that applies the plan) and returns the pages and the
credit estimate; nothing is held or written. The people land in the
list's items (read by the list-to-table writer) and, for an
audience, in its contacts. Cancel stops at the next page.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsIcpRequest
- 0
- targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/icp" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"icpProfileId": "<icpProfileId>"
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
A list of companies from a LinkedIn company search.
/api/v1/actions/lists/companies- Scope
- enrich
- Credits
- 12 credits per call + 3 credits per record (quantity from input.maxResults)
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Max duration
- 7200 s
A list of companies from a LinkedIn company search (Sales Navigator
by default, or classic) on the identity's own LinkedIn account (the
key's bound identity, else identityId); it spends the account's
daily search budget (429 LINKEDIN_SEARCH_LIMIT). At least
keywords or one filter. The companies land in the list's items
and, with output.table, in a table with company columns (name,
LinkedIn URL, industry, location, employees, followers,
description, logo, LinkedIn provider id); output.companies: true
also finds or creates each company in the workspace's companies
(by LinkedIn URL, empty fields filled, nothing overwritten) and
links its row. A company list never writes contacts
(output.contacts is 400).
Spend class, async only (202 {data: {action}}, Location: /api/v1/actions/{id}); target none (the list makes its own
targets: one per page of 25, run in order). Price
audience.scrape.start: 12 per list plus 3 per record written,
charged per page once the page is written (a record already written
by an earlier page of the same list is not charged again; a page
that writes nothing is free), held per batch of pages, never above
maxCredits (pages that would pass it are skipped RUN_CAPPED) or
the key's daily credit cap (CAP_EXCEEDED). Cancel stops at the
next page.
dryRun: true counts the search once with the provider (reused for
15 minutes, also by the call that applies the plan) and returns the
pages and the credit estimate; nothing is held or written.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsCompaniesRequest
- 0
At least
keywordsor one filter. - targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/companies" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"keywords": "<keywords>",
"locationIds": [
"<locationIds>"
],
"industryIds": [
"<industryIds>"
]
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
actions.lists.company_employees
A list of one company's employees.
/api/v1/actions/lists/company_employees- Scope
- enrich
- Credits
- 12 credits per call + 3 credits per record (quantity from input.limit)
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Writes back
- contact
- Max duration
- 7200 s
Everyone at one company (our data provider's employee search, no title
filter), up to limit (at most 100) people.
The company is input.company: exactly one of its LinkedIn
numeric linkedinId, its domain or its LinkedIn company url
(looked up once and reused for 15 minutes; no match is
404 NOT_FOUND). Runs on our data provider, no LinkedIn account: on
the workspace's own data provider key when it has one (free),
else on Owlbound's, where uncached company lookups and searches
are limited per workspace and day (429 PROVIDER_DAILY_LIMIT) and
a wallet with no credits gets no lookup (a dry run returns the
estimate without the count, warning COUNT_UNKNOWN; a real call is
402). The search runs once for every person asked for, never
more than maxCredits pays for (on page 1, which may wait up to a
few minutes for it), so the wallet must hold the whole estimate
before the list starts: otherwise 402 INSUFFICIENT_CREDITS
(details.required, details.available), and a dry-run warning. The people land in the list's items and,
with output.table, in a table (the people columns);
output.contacts pushes them when the list finishes.
Spend class, async only (202 {data: {action}}, Location: /api/v1/actions/{id}); target none (the list makes its own
targets: one per page of 25, run in order). Price
audience.scrape.start: 12 per list plus 3 per record written,
charged per page once the page is written (a record already written
by an earlier page of the same list is not charged again; a page
that writes nothing is free), held per batch of pages, never above
maxCredits (pages that would pass it are skipped RUN_CAPPED) or
the key's daily credit cap (CAP_EXCEEDED). Cancel stops at the
next page.
dryRun: true returns the pages and the estimate from the
company's size (the lookup only; no search runs); nothing is held
or written.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsCompanyEmployeesRequest
- 0
- targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/company_employees" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"company": {
"linkedinId": "<linkedinId>",
"domain": "<domain>",
"url": "https://example.com"
}
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
A list of one company's decision makers.
/api/v1/actions/lists/decision_makers- Scope
- enrich
- Credits
- 12 credits per call + 3 credits per record (quantity from input.limit)
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Writes back
- contact
- Max duration
- 7200 s
The decision makers of one company: our data provider's employee search
filtered by titleKeywords (default Founder, Chief, President, Vice
President, VP, Director, Head, Owner, Partner, Manager), up to
limit (at most 50) people.
The company is input.company: exactly one of its LinkedIn
numeric linkedinId, its domain or its LinkedIn company url
(looked up once and reused for 15 minutes; no match is
404 NOT_FOUND). Runs on our data provider, no LinkedIn account: on
the workspace's own data provider key when it has one (free),
else on Owlbound's, where uncached company lookups and searches
are limited per workspace and day (429 PROVIDER_DAILY_LIMIT) and
a wallet with no credits gets no lookup (a dry run returns the
estimate without the count, warning COUNT_UNKNOWN; a real call is
402). The search runs once for every person asked for, never
more than maxCredits pays for (on page 1, which may wait up to a
few minutes for it), so the wallet must hold the whole estimate
before the list starts: otherwise 402 INSUFFICIENT_CREDITS
(details.required, details.available), and a dry-run warning. The people land in the list's items and,
with output.table, in a table (the people columns);
output.contacts pushes them when the list finishes.
Spend class, async only (202 {data: {action}}, Location: /api/v1/actions/{id}); target none (the list makes its own
targets: one per page of 25, run in order). Price
audience.scrape.start: 12 per list plus 3 per record written,
charged per page once the page is written (a record already written
by an earlier page of the same list is not charged again; a page
that writes nothing is free), held per batch of pages, never above
maxCredits (pages that would pass it are skipped RUN_CAPPED) or
the key's daily credit cap (CAP_EXCEEDED). Cancel stops at the
next page.
dryRun: true returns the pages and the estimate from the
company's size (the lookup only; no search runs); nothing is held
or written.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsDecisionMakersRequest
- 0
- targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/decision_makers" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"company": {
"linkedinId": "<linkedinId>",
"domain": "<domain>",
"url": "https://example.com"
}
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
A list of the people who engaged with a LinkedIn post.
/api/v1/actions/lists/post_engagers- Scope
- enrich
- Credits
- 12 credits per call + 3 credits per record (quantity from input.maxResults)
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Writes back
- contact
- Max duration
- 7200 s
The people who commented on or reacted to one LinkedIn post (a
post URL or urn:li: id, or userPostId, one of the workspace's
published posts), at most 100 comments and 100 reactions as the
app reads them; only people with a profile URL, each once. Read on
the identity's own LinkedIn account (the key's bound identity, else
identityId); the count and every page spend the account's daily
search budget (429 LINKEDIN_SEARCH_LIMIT). The people land in the
list's items and, with output.table, in a table (the people
columns); output.contacts pushes them when the list finishes.
Spend class, async only (202 {data: {action}}, Location: /api/v1/actions/{id}); target none (one target per page of 25,
run in order). Price audience.scrape.start: 12 per list plus 3
per person written, charged per page once the page is written (a
person an earlier page wrote is not charged again; a page that
writes nobody is free), never above maxCredits or the key's daily
credit cap. dryRun: true reads the post's comment and reaction
counts once (reused for 15 minutes) and returns the pages and the
credit estimate; nothing is held or written. Cancel stops at the
next page.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsPostEngagersRequest
- 0
Exactly one of
postUrloruserPostId. - targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/post_engagers" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"postUrl": "https://example.com",
"userPostId": "<userPostId>",
"kinds": [
"comments",
"reactions"
]
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
actions.lists.website_visitors
A list of the companies that visited the website.
/api/v1/actions/lists/website_visitors- Scope
- read
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- read
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Max duration
- 7200 s
The companies Snitcher identified on the workspace's website since
since (an ISO date within the last 90 days; default 30 days
ago), with their visits, most visits first, those with at least
minVisits, at most maxResults (read from the workspace's most
recent 2,000 sessions). Needs Snitcher set up (else 422 LIST_SOURCE_UNSUPPORTED). Read class, free: the visits are the
workspace's own data; nothing is held or charged. Async only
(202 {data: {action}}); one target per page of 25. The companies
land in the list's items and, with output.table, in a table
(name, LinkedIn URL, industry, location, employees, logo, LinkedIn
provider id, domain, visits), each row linked to the workspace's
company; never contacts. dryRun: true returns the companies'
count and the pages.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsWebsiteVisitorsRequest
- 0
- targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/website_visitors" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"since": "2026-10-24T09:00:00Z",
"minVisits": 1,
"maxResults": 100
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Build a list from any list source.
/api/v1/actions/lists/create- Scope
- enrich
- Credits
- 12 credits per call + 3 credits per record (quantity from input.source.maxResults)
- Idempotency-Key
- required
- Class
- spend
- Approval floor
- none
- Runs
- Async
- Targets
- none
- Max targets
- 100
- Dry run
- Supported
- Writes back
- contact
- Max duration
- 7200 s
The umbrella of actions.lists.*: input.source.kind names the
operation (sales_nav, linkedin_search, icp, companies,
company_employees, decision_makers, post_engagers,
website_visitors) and the rest of
source is its input. Both spellings create the same action (its
kind is the source's operation).
Spend class, async only (202 {data: {action}}, Location: /api/v1/actions/{id}); target none (the list makes its own
targets: one per provider page, run in order). Price
audience.scrape.start: 12 per list plus 3 per person written,
charged per page once the page is written (a person already written
by an earlier page of the same list is not charged again; a page
that writes nobody is free), held per batch of pages, never above
maxCredits (pages that would pass it are skipped RUN_CAPPED) or
the key's daily credit cap (CAP_EXCEEDED). dryRun: true counts
the search once with the provider (reused for 15 minutes, also by
the call that applies the plan) and returns the pages and the
credit estimate; nothing is held or written. The people land in the
list's items (read by the list-to-table writer) and, for an
audience, in its contacts. Cancel stops at the next page.
Parameters
- Idempotency-Keyheaderstring
1 to 255 printable ASCII characters, scoped to the API key (a rotated key shares its predecessor's keys) and kept 24 h. Accepted on every POST, PATCH and DELETE (ignored on GET); required from v1 keys where the operation says
x-owlbound-idempotent: required(missing:400 VALIDATION_ERROR,param: Idempotency-Key). Same key and body after completion: the stored response is replayed withIdempotent-Replayed: true. Results over 64 KB are not stored; their replay is409 IDEMPOTENCY_RESULT_UNAVAILABLEwithdetails.originalRequestId(check state with a GET). Same key while the first request runs:409 IDEMPOTENCY_IN_PROGRESSwithRetry-After. Same key, other body or operation:422 IDEMPOTENCY_KEY_REUSED. A request that ended 5xx may be retried with the same key. 4xx results are stored and replayed too: a402 INSUFFICIENT_CREDITSreplays even after a top-up, so use a new Idempotency-Key after adding credits.min length 1max length 255 - Owlbound-Dry-Runheaderboolean
true: same as body fielddryRun: true(action operations). - Owlbound-Planheaderstring
A
planIdfrom a dry run: same as the body fieldplanId(action operations). A different bodyplanIdis400.pattern ^plan_[0-9a-f]{48}$
Request body (required) · application/json
ListsCreateRequest
- 0
- targetActionTargetNone0
Lists make their own targets (one per provider page).
- dryRunboolean0
Same as the
Owlbound-Dry-Runheader. - planIdstring
Apply this dry run's plan (same as
Owlbound-Plan). Not withdryRun: true.pattern ^plan_[0-9a-f]{48}$ - modestring
auto(default) runs inline when the operation is sync, one target would run and the class is not send;syncforces inline (422 ACTION_NOT_SYNCwhen it cannot);asyncforces a run.autosyncasync - notifyActionNotify0
Events for this action.
targetEvents: truealso writes oneaction.target.completed/action.target.failedevent per target (feed and webhooks); without it only action-level events are written, to keep the volume down.webhookis accepted and has no effect (webhook endpoints subscribe by event type). - identityIdstring | null0
The identity whose connected LinkedIn account runs the search (sources read through your LinkedIn account only). A bound key uses its identity (another is
403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED); a session defaults to the member's own. - maxCreditsnumber
Caps the list's credits (default and ceiling the plan's estimatedMax).
min 0 - outputListOutput0
Where the people land besides the list's items.
tablewrites one row per person into a table of this workspace (not available yet for some workspaces:409 TABLE_STORE_UNSUPPORTED):{tableId}uses its columns that match (key, else name, with a type that takes the value; the plan lists the fields left unmapped),{create: {name}}makes a table with every list column (first name, last name, title, company, location, LinkedIn URL, Sales Navigator URL, profile picture, LinkedIn provider id). Rows are matched by the person (a re-run fills empty cells, never duplicates).contacts: truepushes the rows to contacts (the table push, fill empty fields) when the list finishes; it needstableand the push rule (owner, admin or leader), checked again when the list finishes. Anyoutputneeds thewritescope as well asenrich(403 INSUFFICIENT_SCOPE). The push outcome (pushed, refused and failed rows, last error code) is on the action'sresult.contactsPush. Company lists (lists.companies) write company columns instead (name, LinkedIn URL, industry, location, employees, followers, description, logo, LinkedIn provider id), never contacts; theircompanies: truefinds or creates each company in the workspace's companies (by LinkedIn URL, empty fields filled) and links its table row (writescope; allowed without a table). Website-visitor lists write company columns plus domain and visits, each row linked to the workspace's company; never contacts. - schedulestring | null0
Refreshing lists are not available yet (
422 SCHEDULE_UNAVAILABLE).
Responses
200The dry-run plan.Show schema
ActionRunResponse
- dataone ofrequired0
+ Show child fields− Hide child fields
One of
with action
- 0
One action run. Read it again with
GET /api/v1/actions/{id}. - resultanyrequired0
The target's result, or null when it was skipped or failed.
with plan
- 0
What a real call would do, from every check up to the first side effect. Nothing is reserved, sent, written or charged. The plan is stored for 15 minutes: send its
planIdwith the real call to run exactly what was reviewed (409 PLAN_STALEwith a new plan if anything bound changed or it expired).
- 0
Metadata on every success response.
202The list run was created (queued); poll it or read the event feed.Show schema
ActionResponse
- dataobjectrequired0
+ Show child fields− Hide child fields
- 0
One action run. Read it again with
GET /api/v1/actions/{id}.
- 0
Metadata on every success response.
Errors
400 The request is invalid (VALIDATION_ERROR, CURSOR_MISMATCH, UNSUPPORTED_FILTER) · 401 Missing, invalid, expired or revoked key · 403 Missing scope, suspended workspace or unavailable identity · 404 Unknown resource or route. A resource in another workspace is also 404 · 409 IDEMPOTENCY_IN_PROGRESS (the first request with this key is still
running; `Retry-After` is the lease left, at most 60 s) or
IDEMPOTENCY_RESULT_UNAVAILABLE (the original result was too large to
store; `details.originalRequestId`).
· 422 IDEMPOTENCY_KEY_REUSED (the key was used with another body or operation), or an action that cannot run · 429 Rate limit reached · 500 Unexpected error · 503 The backend is unreachable; retry after `Retry-After`. Every error is {error: {type, code, message, requestId, docUrl}}; see error codes.
curl -X POST "https://app.owlbound.ai/api/v1/actions/lists/create" \
-H "Authorization: Bearer $OWLBOUND_API_KEY" \
-H "Owlbound-Version: 2026-10-06" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"input": {
"source": {
"url": "https://example.com",
"kind": "sales_nav"
}
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Models on this page
Shared objects the operations above link to. Clients must ignore fields they do not know.
ActionTargetContactobject
- kind"contact"required0
- contactIdstringrequired0
ActionTargetContactsobject
- kind"contacts"required0
- contactIdsarray of stringrequired
Deduplicated, order kept.
min items 1max items 1000
ActionTargetLinkedInRecordsobject
- kind"records"required0
- min items 1max items 100
LinkedInUrlRecordobject
- linkedinUrlstringrequiredmax length 500
FindProviderIdInputobject
No options; the LinkedIn URL comes from each target.
ActionNotifyobject
Events for this action. targetEvents: true also writes one
action.target.completed / action.target.failed event per target
(feed and webhooks); without it only action-level events are written,
to keep the volume down. webhook is accepted and has no effect
(webhook endpoints subscribe by event type).
- targetEventsbooleandefault false
- webhookboolean0
Actionobject
One action run. Read it again with GET /api/v1/actions/{id}.
- idstringrequired0
- kindstringrequired0
The operation id.
- classstringrequired
Safety class: decides scope, approval, caps and enforcement.
readwritespendexternal_writesend - statusstringrequiredpending_approvalqueuedrunningsucceededfailedrejectedcanceledexpiredpartial
- identityIdstring | nullrequired0
- 0
- costobjectrequired0
+ Show child fields− Hide child fields
- estimatednumberrequired0
- chargednumberrequired0
- reservationIdstring | nullrequired0
- 0
- targetobjectrequired0
+ Show child fields− Hide child fields
- kindstringrequired0
- tableIdstring0
- viewIdstring0
- columnIdstring0
The send column this action runs (tables.rows.push target column).
- outputobject | nullrequired0
- resultanyrequired0
The single target's result (sync), or null; bulk results are per target.
- 0
- 0
Who started the action.
agentis an LLM-driven caller (the in-app agent, MCP) acting for the key or member inonBehalfOf. - createdAtnumberrequired0
- updatedAtnumberrequired0
ActionApprovalobject
- modestringrequirednonealwaysover_threshold
- urlstring | nullrequired0
- decidedBystring | nullrequired0
- decidedAtnumber | nullrequired0
- expiresAtnumber | nullrequired0
ActionCountsobject
- totalintegerrequired0
- queuedintegerrequired0
- scheduledintegerrequired0
- runningintegerrequired0
- succeededintegerrequired0
- skippedintegerrequired0
- failedintegerrequired0
- canceledintegerrequired0
ActionErrorobject
- codestringrequired0
- messagestringrequired0
ActionActorobject
Who started the action. agent is an LLM-driven caller (the in-app
agent, MCP) acting for the key or member in onBehalfOf.
- kindstringrequiredapiKeysessionagentjob
- idstringrequired0
API key id, user id, agent run id or job id.
- onBehalfOfobject0
Agent only.
+ Show child fields− Hide child fields
- kindstringrequiredapiKeysession
- idstringrequired0
Planobject
What a real call would do, from every check up to the first side
effect. Nothing is reserved, sent, written or charged. The plan is
stored for 15 minutes: send its planId with the real call to run
exactly what was reviewed (409 PLAN_STALE with a new plan if
anything bound changed or it expired).
- operationIdstringrequired0
- classstringrequired
Safety class: decides scope, approval, caps and enforcement.
readwritespendexternal_writesend - identityIdstring | nullrequired0
- targetsobjectrequired0
+ Show child fields− Hide child fields
- totalintegerrequired0
- wouldRunintegerrequired0
- wouldSkiparray of objectrequired0
+ Show child fields− Hide child fields
- reasonstringrequired0
- countintegerrequired0
- samplearray of stringrequired0
- creditsobjectrequired0
+ Show child fields− Hide child fields
- estimatedMinnumberrequired0
- estimatedMaxnumberrequired0
- availablenumberrequired0
- capRemainingnumber | nullrequired0
- quotaobject | nullrequired0
LinkedIn sends: the daily budget the action spends (an estimate: warm-up, health and the identity's other sends move it; the send gate decides at send time).
bucketis the daily limit's key,identityRemainingTodaywhat the identity's account has left today,keyRemainingTodaythe key's, user's or agent's daily sends left (null: uncapped),wouldDeferthe targets that would wait for a later day,firstSlotAt/lastSlotAtwhen the first and last of them would go (ms; null past 7 days). Null for other operations.+ Show child fields− Hide child fields
- bucketstringrequired0
- identityRemainingTodaynumberrequired0
- keyRemainingTodaynumber | nullrequired0
- wouldDefernumberrequired0
- firstSlotAtnumber | nullrequired0
- lastSlotAtnumber | nullrequired0
- approvalobjectrequired0
+ Show child fields− Hide child fields
- requiredbooleanrequired0
- reasonstring | nullrequiredkey_modeoperation_floorover_thresholdagentrequestedidentity_owner
- writesobjectrequired0
- previewarray of anyrequired0
The first targets that would run (at most 5).
- planIdstringrequired
Valid until
expiresAt, for the principal that made the dry run only.pattern ^plan_[0-9a-f]{48}$ - expiresAtnumberrequired0
When the plan expires (epoch milliseconds).
ResponseMetaobject
Metadata on every success response.
- requestIdstringrequired0
- 0
- pagePageMeta0
Cursor pagination.
hasMoreis the only end signal; pages may be short. - dryRunboolean0
True only on a dry-run response (action operations).
CreditsMetaobject
- usednumberrequired0
Credits charged by this request. Reads are free.
- balancenumber0
- estimatednumber0
Dry run only (action operations).
- availablenumber0
Dry run only (action operations).
- reservationIdstring | null0
Async operations only; the job settles this reservation.
PageMetaobject
Cursor pagination. hasMore is the only end signal; pages may be short.
- nextCursorstring | nullrequired0
- hasMorebooleanrequired0
- limitintegerrequiredmin 1max 200
ActionTargetPersonRecordsobject
- kind"records"required0
- min items 1max items 100
PersonRecordobject
A person to find; needs firstName and lastName, or email.
- firstNamestringmax length 200
- lastNamestringmax length 200
- companystringmax length 200
- domainstring
The company's domain (used to match the workspace's own contacts).
max length 200 - emailstringmax length 320
FindLinkedInUrlInputobject
- providersarray of LinkedInUrlProvider
The waterfall, in order (default
internal,apollo,zoominfo,linkedin_search). Apollo and ZoomInfo run only with the workspace's own connected keys.internalapollozoominfolinkedin_searchmin items 1max items 4 - minConfidencestringlowmediumhigh
FindLinkedInUrlOutputobject
- contactstring
Write the found URL onto a contact target:
fillEmpty(default) only when it has none,overwritealways,skipnever.skipfillEmptyoverwrite
FindPublicUrlInputobject
No options; the Sales Navigator URL comes from each target.
ActionTargetCompanyQueryRecordsobject
- kind"records"required0
- min items 1max items 100
CompanyQueryRecordobject
- querystringrequiredmin length 1max length 100
FindCompanyIdsInputobject
No options; the query comes from each record.
ActionTargetNoneobject
Lists make their own targets (one per provider page).
- kind"none"required0
ListOutputobject
Where the people land besides the list's items. table
writes one row per person into a table of this workspace (not available
yet for some workspaces: 409 TABLE_STORE_UNSUPPORTED):
{tableId} uses its columns that match (key, else name, with a
type that takes the value; the plan lists the fields left
unmapped), {create: {name}} makes a table with every list column
(first name, last name, title, company, location, LinkedIn URL,
Sales Navigator URL, profile picture, LinkedIn provider id). Rows
are matched by the person (a re-run fills empty cells, never
duplicates). contacts: true pushes the rows to contacts (the
table push, fill empty fields) when the list finishes; it needs
table and the push rule (owner, admin or leader), checked again
when the list finishes. Any output needs the write scope as well
as enrich (403 INSUFFICIENT_SCOPE). The push outcome (pushed,
refused and failed rows, last error code) is on the action's
result.contactsPush. Company lists (lists.companies)
write company columns instead (name, LinkedIn URL, industry,
location, employees, followers, description, logo, LinkedIn
provider id), never contacts; their companies: true finds or
creates each company in the workspace's companies (by LinkedIn
URL, empty fields filled) and links its table row (write scope;
allowed without a table). Website-visitor lists write
company columns plus domain and visits, each row linked to the
workspace's company; never contacts.
- tableone of0
+ Show child fields− Hide child fields
One of
with tableId
- tableIdstringrequired0
with create
- createobjectrequired0
+ Show child fields− Hide child fields
- namestringrequiredmin length 1max length 200
- contactsboolean0
- companiesboolean0
ListsLinkedInSearchInputobject
At least keywords or one filter.
- keywordsstring0
- locationIdsarray of string0
- industryIdsarray of string0
- seniorityLevelsarray of string0
- companyHeadcountarray of object0
+ Show child fields− Hide child fields
- minnumberrequired0
- maxnumber0
- companyTypesarray of string0
- roleKeywordsarray of string0
- excludeRoleKeywordsarray of string0
- companyIdsarray of string0
- excludeCompanyIdsarray of string0
- apistringclassicsales_navigatordefault "sales_navigator"
- maxResultsinteger
People to fetch at most.
default 100min 1max 1000
ListsIcpInputobject
- icpProfileIdstringrequired0
- maxPagesintegerdefault 4min 1max 40
ListsCompaniesInputobject
At least keywords or one filter.
- keywordsstring0
- locationIdsarray of string0
- industryIdsarray of string0
- companyHeadcountarray of object0
+ Show child fields− Hide child fields
- minnumberrequired0
- maxnumber0
- apistringclassicsales_navigatordefault "sales_navigator"
- maxResultsinteger
People to fetch at most.
default 100min 1max 1000
ListsCompanyEmployeesInputobject
- 0
Exactly one of the company's LinkedIn numeric id, its domain (
example.com) or its LinkedIn company URL (https://www.linkedin.com/company/<slug>/). - limitintegerdefault 100min 1max 100
ListsCompanyRefobject
Exactly one of the company's LinkedIn numeric id, its domain
(example.com) or its LinkedIn company URL
(https://www.linkedin.com/company/<slug>/).
- linkedinIdstringpattern ^[1-9][0-9]{0,19}$
- domainstringmax length 253
- urlstringmax length 2000
ListsDecisionMakersInputobject
- 0
Exactly one of the company's LinkedIn numeric id, its domain (
example.com) or its LinkedIn company URL (https://www.linkedin.com/company/<slug>/). - titleKeywordsarray of stringmax items 30
- limitintegerdefault 50min 1max 50
ListsPostEngagersInputobject
Exactly one of postUrl or userPostId.
- postUrlstring
A LinkedIn post URL or its
urn:li:activity|ugcPost|share:id.max length 2000 - userPostIdstring0
One of the workspace's posts published through Owlbound.
- kindsarray of stringcommentsreactionsdefault ["comments","reactions"]
- maxResultsintegerdefault 200min 1max 200
ListsWebsiteVisitorsInputobject
- sincestring
Visits since this time (within the last 90 days; default 30 days ago).
format: date-time - minVisitsintegerdefault 1min 1max 1000
- maxResultsintegerdefault 100min 1max 1000
ListsCreateInputobject
- sourceone ofrequired0
kindplus the input ofactions.lists.<kind>(sales_nav: ListsSalesNavInput,linkedin_search: ListsLinkedInSearchInput,icp: ListsIcpInput,companies: ListsCompaniesInput,company_employees: ListsCompanyEmployeesInput,decision_makers: ListsDecisionMakersInput,post_engagers: ListsPostEngagersInput,website_visitors: ListsWebsiteVisitorsInput).+ Show child fields− Hide child fields
One of
kind: "sales_nav"
- urlstringrequired
A Sales Navigator people search or saved lead list URL.
max length 4000 - maxResultsinteger
People to fetch at most.
default 100min 1max 1000 - kind"sales_nav"required0
kind: "linkedin_search"
- kind"linkedin_search"required0
kind: "icp"
- kind"icp"required0
kind: "companies"
- kind"companies"required0
kind: "company_employees"
- kind"company_employees"required0
kind: "decision_makers"
- kind"decision_makers"required0
kind: "post_engagers"
- kind"post_engagers"required0
kind: "website_visitors"
- kind"website_visitors"required0