Reference · 7 operations
Actions: contacts
Last updated from API version 2026-10-06 at (live spec, refreshed hourly). openapi.json
Add tags to contacts.
/api/v1/actions/contacts/tag- Scope
- write
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- write
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, rows
- Max targets
- 500
- Dry run
- Supported
- Writes back
- contact
Adds input.tags (1 to 20, at most 100 characters each) to each contact's
tags; tags it already has are kept once.
Write class: workspace data only, free, no approval. One contact runs
inline (200 {data: {action, result}}), more (or mode: "async") create
an async run (202). A contact with nothing to change is skipped
UNCHANGED; a table row without a linked contact NO_CONTACT.
dryRun: true returns who would change and writes 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
ContactsTagRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputobjectrequired0
+ Show child fields− Hide child fields
- tagsarray of stringrequiredmin items 1max items 20
- 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).
Responses
200The finished action and its result (one target), 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/contacts/tag" \
-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>"
},
"input": {
"tags": [
"<tags>"
]
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Remove tags from contacts.
/api/v1/actions/contacts/untag- Scope
- write
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- write
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, rows
- Max targets
- 500
- Dry run
- Supported
- Writes back
- contact
Removes input.tags from each contact's tags.
Write class: workspace data only, free, no approval. One contact runs
inline (200 {data: {action, result}}), more (or mode: "async") create
an async run (202). A contact with nothing to change is skipped
UNCHANGED; a table row without a linked contact NO_CONTACT.
dryRun: true returns who would change and writes 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
ContactsTagRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputobjectrequired0
+ Show child fields− Hide child fields
- tagsarray of stringrequiredmin items 1max items 20
- 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).
Responses
200The finished action and its result (one target), 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/contacts/untag" \
-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>"
},
"input": {
"tags": [
"<tags>"
]
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Set contacts' status.
/api/v1/actions/contacts/set_status- Scope
- write
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- write
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, rows
- Max targets
- 500
- Dry run
- Supported
- Writes back
- contact
Sets input.status (new, ready, incomplete, contacted, replied,
converted, lost) on each contact.
Write class: workspace data only, free, no approval. One contact runs
inline (200 {data: {action, result}}), more (or mode: "async") create
an async run (202). A contact with nothing to change is skipped
UNCHANGED; a table row without a linked contact NO_CONTACT.
dryRun: true returns who would change and writes 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
ContactsSetStatusRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputobjectrequired0
+ Show child fields− Hide child fields
- statusstringrequirednewreadyincompletecontactedrepliedconvertedlost
- 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).
Responses
200The finished action and its result (one target), 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/contacts/set_status" \
-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>"
},
"input": {
"status": "new"
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Assign contacts to an owner identity.
/api/v1/actions/contacts/assign_owner- Scope
- write
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- write
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, rows
- Max targets
- 500
- Dry run
- Supported
- Writes back
- contact
Sets each contact's owner to input.ownerIdentityId, an identity of this
workspace (another workspace's is 404), active and of a member of
the workspace (else 403 IDENTITY_UNAVAILABLE).
Write class: workspace data only, free, no approval. One contact runs
inline (200 {data: {action, result}}), more (or mode: "async") create
an async run (202). A contact with nothing to change is skipped
UNCHANGED; a table row without a linked contact NO_CONTACT.
dryRun: true returns who would change and writes 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
ContactsAssignOwnerRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputobjectrequired0
+ Show child fields− Hide child fields
- ownerIdentityIdstringrequired0
An identity of this workspace.
- 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).
Responses
200The finished action and its result (one target), 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/contacts/assign_owner" \
-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>"
},
"input": {
"ownerIdentityId": "<ownerIdentityId>"
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Set contact fields (fill empty by default).
/api/v1/actions/contacts/set_fields- Scope
- write
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- write
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, rows
- Max targets
- 500
- Dry run
- Supported
- Writes back
- contact
Writes input.fields (firstName, lastName, title, headline, company,
companyDomain, email, phone, linkedInUrl, location, industry, notes) on
each contact: only fields that are empty unless input.onConflict: overwrite; an empty value never clears a field. LinkedIn URLs are
normalized; a new LinkedIn URL clears the ids derived from the old
profile (provider member id, Sales Navigator URL). Re-planned against
the contact right before the write.
Write class: workspace data only, free, no approval. One contact runs
inline (200 {data: {action, result}}), more (or mode: "async") create
an async run (202). A contact with nothing to change is skipped
UNCHANGED; a table row without a linked contact NO_CONTACT.
dryRun: true returns who would change and writes 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
ContactsSetFieldsRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputobjectrequired0
+ Show child fields− Hide child fields
- fieldsobjectrequired0
+ Show child fields− Hide child fields
- firstNamestringmax length 2000
- lastNamestringmax length 2000
- titlestringmax length 2000
- headlinestringmax length 2000
- companystringmax length 2000
- companyDomainstringmax length 2000
- emailstringmax length 2000
- phonestringmax length 2000
- linkedInUrlstringmax length 2000
- locationstringmax length 2000
- industrystringmax length 2000
- notesstringmax length 2000
- onConflictstring
fillEmpty(default): only empty fields are written.fillEmptyoverwrite
- 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).
Responses
200The finished action and its result (one target), 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/contacts/set_fields" \
-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>"
},
"input": {
"fields": {
"firstName": "<firstName>",
"lastName": "<lastName>",
"title": "<title>"
}
},
"dryRun": true
}'The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.
Link contacts to an audience (ICP).
/api/v1/actions/contacts/link_icp- Scope
- write
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- write
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, rows
- Max targets
- 500
- Dry run
- Supported
- Writes back
- contact
Sets each contact's audience to input.icpProfileId, an audience of
this workspace (another workspace's is 404).
Write class: workspace data only, free, no approval. One contact runs
inline (200 {data: {action, result}}), more (or mode: "async") create
an async run (202). A contact with nothing to change is skipped
UNCHANGED; a table row without a linked contact NO_CONTACT.
dryRun: true returns who would change and writes 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
ContactsLinkIcpRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputobjectrequired0
+ Show child fields− Hide child fields
- icpProfileIdstringrequired0
An audience (ICP profile) of this workspace.
- 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).
Responses
200The finished action and its result (one target), 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/contacts/link_icp" \
-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>"
},
"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.
Archive contacts (soft).
/api/v1/actions/contacts/archive- Scope
- write
- Credits
- See the catalog entry
- Idempotency-Key
- required
- Class
- write
- Approval floor
- none
- Runs
- Inline for one target, else async
- Targets
- contact, contacts, rows
- Max targets
- 500
- Dry run
- Supported
- Writes back
- contact
Archives each contact the way the app does (isArchived; it is then
suppressed from outreach). Nothing is deleted.
Write class: workspace data only, free, no approval. One contact runs
inline (200 {data: {action, result}}), more (or mode: "async") create
an async run (202). A contact with nothing to change is skipped
UNCHANGED; a table row without a linked contact NO_CONTACT.
dryRun: true returns who would change and writes 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
ContactsArchiveRequest
- targetone ofrequired0
+ Show child fields− Hide child fields
- inputobject0
- 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).
Responses
200The finished action and its result (one target), 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/contacts/archive" \
-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.
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
ActionTargetRowsobject
Rows of one table; each row's linked contact is the subject. A row
without a linked contact is skipped NO_CONTACT (push it to
contacts first); two rows of one contact act once
(DUPLICATE_TARGET). Not available yet for some workspaces: the
call answers 409 TABLE_STORE_UNSUPPORTED.
- kind"rows"required0
- tableIdstringrequired0
- rowIdsarray of stringrequired
Deduplicated, order kept.
min items 1max items 1000
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