Browse the docs

Reference · 15 operations

Actions: LinkedIn

Last updated from API version 2026-10-06 at (live spec, refreshed hourly). openapi.json

actions.linkedin.connect

Send a LinkedIn invitation to each contact.

post/api/v1/actions/linkedin/connect
Scope
act
Credits
7 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. One LinkedIn invitation per contact, with an optional note (at most 300 characters once filled). A contact already connected to the identity is skipped ALREADY_CONNECTED, one with an invitation pending INVITE_PENDING. Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. {{firstName}}, {{lastName}}, {{company}}, {{title}}, {{headline}}, {{industry}} are filled from the stored contact, as sequences fill them; a target missing a field is skipped MISSING_TEMPLATE_VARIABLES, one over LinkedIn's limit TOO_LONG. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's rendered content frozen; a person approves it in the app, then it runs. Right before each send the content is rendered again from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). A person this identity already sent the same kind of touch to within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED): Owlbound checks its own send log on the identity's LinkedIn accounts (sequences, plays, forms, the inbox and the API all write it, before and after each request), succeeded API actions, and for messages and InMail the person's synced LinkedIn conversations (outbound messages, including ones sent on LinkedIn itself). Invitations sent outside Owlbound are seen only through the connection state. The check runs again right before the request, once the account is free. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. Never sent twice: a send whose outcome is unknown (timeout, provider 5xx) is checked against LinkedIn (sent invitations, the chat) and otherwise fails OUTCOME_UNKNOWN for a person to check; it is never retried. 7 credits (sequence.linkedin.connect) per invitation sent; skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInConnectRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobject
    0
    + Show child fields
    • notestring

      The invitation note (template); at most 300 characters once filled. No note: a plain invitation.

      max length 600
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (the rendered content of the first targets).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/connect" \
  -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.

actions.linkedin.dm

Send a LinkedIn message to each contact.

post/api/v1/actions/linkedin/dm
Scope
act
Credits
6 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. One LinkedIn message per contact (at most 8,000 characters once filled). Needs a connection with the identity (NOT_CONNECTED otherwise). Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. {{firstName}}, {{lastName}}, {{company}}, {{title}}, {{headline}}, {{industry}} are filled from the stored contact, as sequences fill them; a target missing a field is skipped MISSING_TEMPLATE_VARIABLES, one over LinkedIn's limit TOO_LONG. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's rendered content frozen; a person approves it in the app, then it runs. Right before each send the content is rendered again from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). A person this identity already sent the same kind of touch to within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED): Owlbound checks its own send log on the identity's LinkedIn accounts (sequences, plays, forms, the inbox and the API all write it, before and after each request), succeeded API actions, and for messages and InMail the person's synced LinkedIn conversations (outbound messages, including ones sent on LinkedIn itself). Invitations sent outside Owlbound are seen only through the connection state. The check runs again right before the request, once the account is free. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. Never sent twice: a send whose outcome is unknown (timeout, provider 5xx) is checked against LinkedIn (sent invitations, the chat) and otherwise fails OUTCOME_UNKNOWN for a person to check; it is never retried. 6 credits (sequence.linkedin.send) per message sent.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInDmRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobjectrequired
    0
    + Show child fields
    • messagestringrequired

      The message (template); at most 8,000 characters once filled.

      min length 1max length 16000
    • conversationIdstring

      Reply in this LinkedIn conversation of the contact (one target; the conversation must be on the identity's account, else 422 CONVERSATION_ACCOUNT_MISMATCH). The reply answers the person's latest message there, frozen at approval (a newer message is CONTENT_CHANGED); each of their messages is answered at most once, and never when anything was sent to them after it. No message from them: skipped NO_MESSAGE_TO_ANSWER. No connection needed.

      0
    • attachmentsarray of object

      Files sent with the message (JPEG, PNG, GIF, WebP, PDF; about 500 KB in all), frozen at approval.

      min items 1max items 3
      + Show child fields
      • filenamestringrequired
        max length 200
      • contentTypestringrequired
        image/jpegimage/pngimage/gifimage/webpapplication/pdf
      • contentstringrequired

        Base64.

        0
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (the rendered content of the first targets).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/dm" \
  -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": {
    "message": "<message>"
  },
  "dryRun": true
}'

The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.

actions.linkedin.inmail

Send a LinkedIn InMail to each contact.

post/api/v1/actions/linkedin/inmail
Scope
act
Credits
38 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. One LinkedIn InMail per contact: subject (at most 200 characters) and message (at most 1,900) once filled. The account needs InMail (Sales Navigator, Recruiter or Premium) and credits (NO_INMAIL_CREDITS otherwise). Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. {{firstName}}, {{lastName}}, {{company}}, {{title}}, {{headline}}, {{industry}} are filled from the stored contact, as sequences fill them; a target missing a field is skipped MISSING_TEMPLATE_VARIABLES, one over LinkedIn's limit TOO_LONG. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's rendered content frozen; a person approves it in the app, then it runs. Right before each send the content is rendered again from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). A person this identity already sent the same kind of touch to within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED): Owlbound checks its own send log on the identity's LinkedIn accounts (sequences, plays, forms, the inbox and the API all write it, before and after each request), succeeded API actions, and for messages and InMail the person's synced LinkedIn conversations (outbound messages, including ones sent on LinkedIn itself). Invitations sent outside Owlbound are seen only through the connection state. The check runs again right before the request, once the account is free. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. Never sent twice: a send whose outcome is unknown (timeout, provider 5xx) is checked against LinkedIn (sent invitations, the chat) and otherwise fails OUTCOME_UNKNOWN for a person to check; it is never retried. 38 credits (sequence.inmail.send, the catalog price) per InMail sent.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInInmailRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobjectrequired
    0
    + Show child fields
    • subjectstringrequired

      The InMail subject (template); at most 200 characters once filled.

      min length 1max length 400
    • messagestringrequired

      The InMail body (template); at most 1,900 characters once filled.

      min length 1max length 3800
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (the rendered content of the first targets).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/inmail" \
  -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": {
    "subject": "<subject>",
    "message": "<message>"
  },
  "dryRun": true
}'

The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.

actions.linkedin.view_profile

View each contact's LinkedIn profile.

post/api/v1/actions/linkedin/view_profile
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. Opens each contact's LinkedIn profile from the identity's account: with notify (default true) the person sees "viewed your profile"; notify: false views it without the notification (still counted against the account's daily profile views). Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.view) per profile viewed; skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInViewProfileRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobject
    0
    + Show child fields
    • notifyboolean

      Default true: the person sees that the identity viewed their profile. False: no notification.

      0
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/view_profile" \
  -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.

actions.linkedin.follow

Follow each contact on LinkedIn.

post/api/v1/actions/linkedin/follow
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. The identity follows each contact's profile (counted against the account's 50 follows a day, shared with sequences). Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.engage) per follow; skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInFollowRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobject
    0
    + Show child fields
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/follow" \
  -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.

actions.linkedin.unfollow

Unfollow each contact on LinkedIn.

post/api/v1/actions/linkedin/unfollow
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. The identity stops following each contact's profile (counted against the account's follow limit, like a follow). Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.engage) per unfollow; skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInFollowRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobject
    0
    + Show child fields
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/unfollow" \
  -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.

actions.linkedin.like

Like a post of each contact.

post/api/v1/actions/linkedin/like
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. Likes input.postUrl (then the request targets exactly the post's author, one contact) or, without it, each contact's latest post (none: skipped NO_POSTS). Never twice per post: a post this identity already liked within 30 days is skipped. Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.engage) per like; skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInLikeRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobject
    0
    + Show child fields
    • postUrlstring

      The post (URL or URN). With it the request targets exactly one contact, the author. Without it: each contact's latest post.

      max length 2000
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/like" \
  -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.

actions.linkedin.comment

Comment on a post of each contact.

post/api/v1/actions/linkedin/comment
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. Comments input.comment (a template filled from the stored contact: {{firstName}}, {{company}}, ...; at most 1,250 characters once filled) on input.postUrl (then exactly one target, the post's author) or, without it, on each contact's latest post (none: skipped NO_POSTS). Never twice per post. Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.engage) per comment; skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInCommentRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobjectrequired
    0
    + Show child fields
    • postUrlstring

      The post (URL or URN). With it the request targets exactly one contact, the author. Without it: each contact's latest post.

      max length 2000
    • commentstringrequired

      The comment (template); at most 1,250 characters once filled.

      min length 1max length 2500
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/comment" \
  -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": {
    "comment": "<comment>"
  },
  "dryRun": true
}'

The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.

actions.linkedin.repost

Repost a contact's post.

post/api/v1/actions/linkedin/repost
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows
Max targets
1
Dry run
Supported

Send. The identity reposts input.postSocialId (the post's URN or URL), with an optional comment (template, at most 3,000 characters once filled). One target: the post's author. Never twice per post. Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.engage) per repost (10 a day per workspace); skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInRepostRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobjectrequired
    0
    + Show child fields
    • postSocialIdstringrequired

      The post to repost (its URN, e.g. urn:li:activity:123, or URL).

      min length 1max length 2000
    • commentstring

      Optional text above the repost (template); at most 3,000 characters once filled.

      max length 6000
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/repost" \
  -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": {
    "postSocialId": "<postSocialId>"
  },
  "dryRun": true
}'

The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.

actions.linkedin.reply_comment

Reply to a contact's comment on a post.

post/api/v1/actions/linkedin/reply_comment
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows
Max targets
1
Dry run
Supported

Send. A threaded reply input.text (template, at most 1,250 characters once filled) to comment commentId on post postExternalId. One target: the comment's author. Never twice per comment. Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.engage) per reply; skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInReplyCommentRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobjectrequired
    0
    + Show child fields
    • postExternalIdstringrequired

      The post the comment is on (its id or URN).

      min length 1max length 500
    • commentIdstringrequired

      The comment to reply to.

      min length 1max length 500
    • textstringrequired

      The reply (template); at most 1,250 characters once filled.

      min length 1max length 2500
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/reply_comment" \
  -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": {
    "postExternalId": "<postExternalId>",
    "commentId": "<commentId>",
    "text": "<text>"
  },
  "dryRun": true
}'

The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.

actions.linkedin.endorse

Endorse a skill of each contact.

post/api/v1/actions/linkedin/endorse
Scope
act
Credits
2 credits per target
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. Endorses input.skillName on each contact's profile. LinkedIn lets only first-degree connections endorse: a contact not connected to the identity is skipped NOT_CONNECTED; a skill the profile does not list fails PROVIDER_REFUSED (free). Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. 2 credits (sequence.linkedin.engage) per endorsement (20 a day per workspace); skips and failures are free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInEndorseRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobjectrequired
    0
    + Show child fields
    • skillNamestringrequired

      The skill to endorse, as the profile lists it.

      min length 1max length 100
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/endorse" \
  -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": {
    "skillName": "<skillName>"
  },
  "dryRun": true
}'

The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.

actions.linkedin.withdraw

Withdraw the pending invitation to each contact.

post/api/v1/actions/linkedin/withdraw
Scope
act
Credits
See the catalog entry
Idempotency-Key
required
Class
send
Approval floor
optional
Runs
Async
Targets
contact, contacts, rows, view
Max targets
1,000
Dry run
Supported

Send. Withdraws the identity's pending LinkedIn invitation to each contact, found in the account's sent invitations before anything is claimed (none: skipped NO_PENDING_INVITE); the contact's connection status becomes withdrawn. Withdrawing only lowers contact, so a suppressed, excluded or unsubscribed contact's invitation is still withdrawn. Counted against the account's 20 withdrawals a day. Sent from the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), to each target contact's stored LinkedIn profile. Always async and reviewed by default: the action is created pending_approval (the workspace default; the dashboard agent and MCP always) with every target's content frozen; a person approves it in the app, then it runs. Right before each send the content is rebuilt from the contact: a contact changed since the approval is skipped CONTENT_CHANGED. Every send passes the send gate: the key is re-checked (API_KEY_REVOKED); suppressed, excluded or unsubscribed contacts are skipped, and so is a contact an active sequence is working on (IN_SEQUENCE). Never twice: a person this identity already gave the same touch within 30 days is skipped (ALREADY_SENT, ALREADY_CONTACTED), whatever sent it (sequences, plays, the app, the API: Owlbound's send log on the identity's LinkedIn accounts, written before and after each request, and succeeded API actions), checked again right before the request. The account's daily limits, warm-up and health apply as for sequences; a send that must wait is scheduled (RATE_LIMITED, WARMING_UP, IDENTITY_BUSY, ...) and runs later. A send whose outcome is unknown (timeout, provider 5xx) fails OUTCOME_UNKNOWN for a person to check; it is never retried. Free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInFollowRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobject
    0
    + Show child fields
    • requestApprovalboolean

      Ask a person even when the key's approval mode would not.

      0
  • identityIdstring | null

    The identity whose LinkedIn account sends. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (what each of the first targets would get).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created: pending_approval until a person approves it in the app (reviewed by default), then queued and run.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/withdraw" \
  -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.

actions.linkedin.post_create

Publish a post on the identity's LinkedIn feed.

post/api/v1/actions/linkedin/post_create
Scope
act
Credits
See the catalog entry
Idempotency-Key
required
Class
send
Approval floor
required
Runs
Async
Targets
none
Max targets
1
Dry run
Supported

Send. One post (input.content, at most 3,000 characters; up to 2 mediaUrls, https, fetched with the SSRF guard) on the identity's own LinkedIn feed (the key's bound identity, else identityId; a session defaults to the member's own). Target none: the action has one target, the post. Always reviewed: the action is created pending_approval whatever the key's approval mode (a public post always waits for a person); the text, media and time are frozen at approval, and a post changed since is never published (CONTENT_CHANGED). Published at most once: a request that may have gone out (timeout, provider 5xx) ends OUTCOME_UNKNOWN and is never repeated. With scheduledAt (an ISO date in the next 5 days) the post waits scheduled and goes out then, through the same checks; approved after that time, it is skipped SCHEDULE_PASSED (never published late). The media files are read when the action is created and their bytes frozen too: a file changed behind its URL is never posted (CONTENT_CHANGED); media that cannot be read (not an image, video or PDF of at most 20 MB, 25 MB for all of a post's media) is 400. Counted against the workspace's own posts (10 a day) and the key's daily sends; the account's health applies. Free.

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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInPostCreateRequest

  • targetActionTargetNonerequired

    Lists make their own targets (one per provider page).

    0
  • inputobjectrequired
    0
    + Show child fields
    • contentstringrequired

      The post's text (published as written: no template).

      min length 1max length 3000
    • mediaUrlsarray of string

      Images, a video or a PDF to attach (https URLs, fetched with the SSRF guard).

      max items 2
    • scheduledAtstring

      Publish at this time (within the next 5 days) instead of when approved.

      format: date-time
  • identityIdstring | null

    The identity whose LinkedIn account posts. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The dry-run plan (the post as it would be published).
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
The action was created pending_approval; once a person approves it in the app, the post is published (or waits for scheduledAt).
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/post_create" \
  -H "Authorization: Bearer $OWLBOUND_API_KEY" \
  -H "Owlbound-Version: 2026-10-06" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
  "target": {
    "kind": "none"
  },
  "input": {
    "content": "<content>"
  },
  "dryRun": true
}'

The example is a dry run: it returns a plan and runs, writes and charges nothing. See dry runs and plans.

actions.linkedin.check_connection

Check each contact's connection with the identity.

post/api/v1/actions/linkedin/check_connection
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, rows, view
Max targets
100
Dry run
Supported

Whether each contact is a first-degree connection of the identity (the account's relations list, cached up to 6 hours) and, when not, whether an invitation from it is pending (the account's sent invitations). Result {connected, status} with status connected, pending or not_connected. No profile is opened. Read class, free, never reviewed: nothing is sent or written and nobody is notified. Read through the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), never another workspace's. Targets: a contact with a LinkedIn URL, contacts or table rows. One target runs inline (200 {data: {action, result}}); more (or mode: "async") create an async run (202); dryRun: true returns the plan and reads 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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInCheckConnectionRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobject
    0
  • identityIdstring | null

    The identity whose LinkedIn account reads. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The finished action and its result, or the dry-run plan.
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
An async run was created (queued); poll it or read the event feed.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/check_connection" \
  -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.

actions.linkedin.check_reply

Check whether each contact replied on LinkedIn.

post/api/v1/actions/linkedin/check_reply
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, rows, view
Max targets
100
Dry run
Supported

Whether each contact wrote to the identity on LinkedIn since input.since (an ISO date in the past): the synced inbox first (inbound messages of the contact's LinkedIn conversations on the identity's account), then the chat's last messages on LinkedIn when the inbox has nothing yet. Result {replied, repliedAt, source}. Read class, free, never reviewed: nothing is sent or written and nobody is notified. Read through the identity's own LinkedIn account (the key's bound identity, else identityId; a session defaults to the member's own), never another workspace's. Targets: a contact with a LinkedIn URL, contacts or table rows. One target runs inline (200 {data: {action, result}}); more (or mode: "async") create an async run (202); dryRun: true returns the plan and reads 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 with Idempotent-Replayed: true. Results over 64 KB are not stored; their replay is 409 IDEMPOTENCY_RESULT_UNAVAILABLE with details.originalRequestId (check state with a GET). Same key while the first request runs: 409 IDEMPOTENCY_IN_PROGRESS with Retry-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: a 402 INSUFFICIENT_CREDITS replays 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 field dryRun: true (action operations).

  • Owlbound-Planheaderstring

    A planId from a dry run: same as the body field planId (action operations). A different body planId is 400.

    pattern ^plan_[0-9a-f]{48}$

Request body (required) · application/json

LinkedInCheckReplyRequest

  • targetone ofrequired
    0
    + Show child fields
  • inputobjectrequired
    0
    + Show child fields
    • sincestringrequired

      Look for replies after this time (ISO 8601, in the past).

      format: date-time
  • identityIdstring | null

    The identity whose LinkedIn account reads. A bound key uses its identity (another is 403 IDENTITY_NOT_ALLOWED); an unbound key must name one (422 IDENTITY_REQUIRED).

    0
  • dryRunboolean

    Same as the Owlbound-Dry-Run header.

    0
  • planIdstring

    Apply this dry run's plan (same as Owlbound-Plan). Not with dryRun: 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; sync forces inline (422 ACTION_NOT_SYNC when it cannot); async forces a run.

    autosyncasync
  • 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).

    0

Responses

200
The finished action and its result, or the dry-run plan.
Show schema

ActionRunResponse

  • dataone ofrequired
    0
    + Show child fields

    One of

    with action

    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
    • resultanyrequired

      The target's result, or null when it was skipped or failed.

      0

    with plan

    • planPlanrequired

      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).

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0
202
An async run was created (queued); poll it or read the event feed.
Show schema

ActionResponse

  • dataobjectrequired
    0
    + Show child fields
    • actionActionrequired

      One action run. Read it again with GET /api/v1/actions/{id}.

      0
  • metaResponseMetarequired

    Metadata on every success response.

    0

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/linkedin/check_reply" \
  -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": {
    "since": "2026-10-24T09:00:00Z"
  },
  "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"required
    0
  • contactIdstringrequired
    0
ActionTargetContactsobject
  • kind"contacts"required
    0
  • 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"required
    0
  • tableIdstringrequired
    0
  • rowIdsarray of stringrequired

    Deduplicated, order kept.

    min items 1max items 1000
ActionTargetViewobject

A saved view of one table (viewId, its filter) and / or a filter (the tables filter language), resolved once when the action is created into the rows it matches then (later rows are not added: use an action column for that). At most the operation's maxTargets rows (422 LIMIT_EXCEEDED beyond: narrow it); no match is 400. Then exactly as rows: each row's linked contact. Not available yet for some workspaces: the call answers 409 TABLE_STORE_UNSUPPORTED.

  • kind"view"required
    0
  • tableIdstringrequired
    0
  • viewIdstring
    0
  • filterany

    A tables filter ({column, op, value}, {and: [...]}, {or: [...]}), combined with the view's.

    0
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).

  • targetEventsboolean
    default false
  • webhookboolean
    0
Actionobject

One action run. Read it again with GET /api/v1/actions/{id}.

  • idstringrequired
    0
  • kindstringrequired

    The operation id.

    0
  • classstringrequired

    Safety class: decides scope, approval, caps and enforcement.

    readwritespendexternal_writesend
  • statusstringrequired
    pending_approvalqueuedrunningsucceededfailedrejectedcanceledexpiredpartial
  • identityIdstring | nullrequired
    0
  • approvalActionApproval | nullrequired
    0
  • costobjectrequired
    0
    + Show child fields
    • estimatednumberrequired
      0
    • chargednumberrequired
      0
    • reservationIdstring | nullrequired
      0
  • countsActionCountsrequired
    0
  • targetobjectrequired
    0
    + Show child fields
    • kindstringrequired
      0
    • tableIdstring
      0
    • viewIdstring
      0
    • columnIdstring

      The send column this action runs (tables.rows.push target column).

      0
  • outputobject | nullrequired
    0
  • resultanyrequired

    The single target's result (sync), or null; bulk results are per target.

    0
  • errorActionErrorrequired
    0
  • actorActionActorrequired

    Who started the action. agent is an LLM-driven caller (the in-app agent, MCP) acting for the key or member in onBehalfOf.

    0
  • createdAtnumberrequired
    0
  • updatedAtnumberrequired
    0
ActionApprovalobject
  • modestringrequired
    nonealwaysover_threshold
  • urlstring | nullrequired
    0
  • decidedBystring | nullrequired
    0
  • decidedAtnumber | nullrequired
    0
  • expiresAtnumber | nullrequired
    0
ActionCountsobject
  • totalintegerrequired
    0
  • queuedintegerrequired
    0
  • scheduledintegerrequired
    0
  • runningintegerrequired
    0
  • succeededintegerrequired
    0
  • skippedintegerrequired
    0
  • failedintegerrequired
    0
  • canceledintegerrequired
    0
ActionErrorobject
  • codestringrequired
    0
  • messagestringrequired
    0
ActionActorobject

Who started the action. agent is an LLM-driven caller (the in-app agent, MCP) acting for the key or member in onBehalfOf.

  • kindstringrequired
    apiKeysessionagentjob
  • idstringrequired

    API key id, user id, agent run id or job id.

    0
  • onBehalfOfobject

    Agent only.

    0
    + Show child fields
    • kindstringrequired
      apiKeysession
    • idstringrequired
      0
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).

  • operationIdstringrequired
    0
  • classstringrequired

    Safety class: decides scope, approval, caps and enforcement.

    readwritespendexternal_writesend
  • identityIdstring | nullrequired
    0
  • targetsobjectrequired
    0
    + Show child fields
    • totalintegerrequired
      0
    • wouldRunintegerrequired
      0
    • wouldSkiparray of objectrequired
      0
      + Show child fields
      • reasonstringrequired
        0
      • countintegerrequired
        0
      • samplearray of stringrequired
        0
  • creditsobjectrequired
    0
    + Show child fields
    • estimatedMinnumberrequired
      0
    • estimatedMaxnumberrequired
      0
    • availablenumberrequired
      0
    • capRemainingnumber | nullrequired
      0
  • quotaobject | nullrequired

    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). bucket is the daily limit's key, identityRemainingToday what the identity's account has left today, keyRemainingToday the key's, user's or agent's daily sends left (null: uncapped), wouldDefer the targets that would wait for a later day, firstSlotAt / lastSlotAt when the first and last of them would go (ms; null past 7 days). Null for other operations.

    0
    + Show child fields
    • bucketstringrequired
      0
    • identityRemainingTodaynumberrequired
      0
    • keyRemainingTodaynumber | nullrequired
      0
    • wouldDefernumberrequired
      0
    • firstSlotAtnumber | nullrequired
      0
    • lastSlotAtnumber | nullrequired
      0
  • approvalobjectrequired
    0
    + Show child fields
    • requiredbooleanrequired
      0
    • reasonstring | nullrequired
      key_modeoperation_floorover_thresholdagentrequestedidentity_owner
  • writesobjectrequired
    0
  • previewarray of anyrequired

    The first targets that would run (at most 5).

    0
  • planIdstringrequired

    Valid until expiresAt, for the principal that made the dry run only.

    pattern ^plan_[0-9a-f]{48}$
  • expiresAtnumberrequired

    When the plan expires (epoch milliseconds).

    0
ResponseMetaobject

Metadata on every success response.

  • requestIdstringrequired
    0
  • creditsCreditsMetarequired
    0
  • Cursor pagination. hasMore is the only end signal; pages may be short.

    0
  • dryRunboolean

    True only on a dry-run response (action operations).

    0
CreditsMetaobject
  • usednumberrequired

    Credits charged by this request. Reads are free.

    0
  • balancenumber
    0
  • estimatednumber

    Dry run only (action operations).

    0
  • availablenumber

    Dry run only (action operations).

    0
  • reservationIdstring | null

    Async operations only; the job settles this reservation.

    0
PageMetaobject

Cursor pagination. hasMore is the only end signal; pages may be short.

  • nextCursorstring | nullrequired
    0
  • hasMorebooleanrequired
    0
  • limitintegerrequired
    min 1max 200
ActionTargetNoneobject

Lists make their own targets (one per provider page).

  • kind"none"required
    0

← All operations