---
title: "Search workflow tasks"
method: POST
path: "/api/workflow-tasks/search"
tags: ["workflow_tasks"]
---

# Search workflow tasks

`POST /api/workflow-tasks/search`

## Request

- Base URL: `https://beta.getsales.io/playtables/v1`
- URL: `https://beta.getsales.io/playtables/v1/api/workflow-tasks/search`
- Auth: HTTP bearer and API key in header `Team-SID`

One row per step of one record's journey, the execution ledger, and a play's acts. Person timeline: filter people_sid (open statuses = the plan, terminal = history). Manual queue: type eq manual_task, status eq pending, assignee_user_sid. Needs me: initiator eq play, status eq pending; the acts under one event: trigger_activity_sid. counts.groups is the funnel; page_size 0 = counts only. Not for message bodies (search_messages).

Contract:
- MCP tool `search_workflow_tasks`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
- Operation `search`, response envelope `search`.
- Flags: read only.

## Request body

- SearchWorkflowTasksRequest: Request body of `search_workflow_tasks`.
  - `filter` object: Field filters, ANDed: {field: {eq | ne | in | nin | gte | lte | gt | lt | is_null}}; q inside it is free text. Omit for every row.
    - `sid` object: Task sid(s), wf_tk_ prefix - also the point-lookup path (no get tool).
      - `eq` string: Workflow task sid (wf_tk_…).
      - `in` string[]
    - `initiator` object: Who bore the task (2026-10-14). Needs me = { eq: "play" } with status eq pending: the drafts and questions waiting in the Signals feed.
      - `eq` 'workflow_record' | 'play' | 'user'
      - `in` string[]
    - `play_sid` object: One play's acts (pt_pl_…); is_null:true = a journey's tasks.
      - `eq` string: Play sid (pt_pl_…).
      - `in` string[]
      - `is_null` boolean
    - `trigger_activity_sid` object: The acts under one event (cr_ac_…): what a play left waiting or did on that fact.
      - `eq` string: Activity (fact) sid (cr_ac_…).
      - `in` string[]
      - `is_null` boolean
    - `workflow_sid` object: Per-campaign execution view (wf_wf_…).
      - `eq` string: Workflow sid (wf_wf_…).
      - `in` string[]
    - `workflow_record_sid` object: One record's task history (wf_rc_…).
      - `eq` string: Workflow record sid (wf_rc_…).
      - `in` string[]
    - `people_sid` object: Person timeline (cr_pp_…); resolve names via people search first.
      - `eq` string: Person sid (cr_pp_…).
      - `in` string[]
    - `sender_profile_sid` object: Per-sender queue/load (ub_sp_…); is_null:true = orchestration-class.
      - `eq` string: Sender profile sid (ub_sp_…).
      - `in` string[]
      - `is_null` boolean
    - `step_id` object: Step drill-down - meaningful only combined with a workflow_sid filter.
      - `eq` integer
      - `in` integer[]
    - `type` object: Manual queue = { eq: "manual_task" }.
      - `eq` 'linkedin_send_connection_request' | 'linkedin_send_message' | 'linkedin_send_inmail' | 'linkedin_visit_profile' | 'linkedin_endorse_skills' | 'linkedin_withdraw_connection_request' | 'email_send' | 'wait' | 'wait_for_event' | 'condition' | 'api_call' | 'ask_ai' | 'manual_task' | 'linkedin_like_latest_post' | 'linkedin_comment_latest_post' | 'ab_test' | 'move_to_workflow' | 'add_tag' | 'remove_tag' | 'set_field' | 'change_sender' | 'run_column'
      - `ne` 'linkedin_send_connection_request' | 'linkedin_send_message' | 'linkedin_send_inmail' | 'linkedin_visit_profile' | 'linkedin_endorse_skills' | 'linkedin_withdraw_connection_request' | 'email_send' | 'wait' | 'wait_for_event' | 'condition' | 'api_call' | 'ask_ai' | 'manual_task' | 'linkedin_like_latest_post' | 'linkedin_comment_latest_post' | 'ab_test' | 'move_to_workflow' | 'add_tag' | 'remove_tag' | 'set_field' | 'change_sender' | 'run_column'
      - `in` string[]
      - `nin` string[]
    - `status` object: Open = pending | scheduled | dispatched; the rest are terminal.
      - `eq` 'pending' | 'scheduled' | 'dispatched' | 'done' | 'failed' | 'skipped' | 'skipped_reply' | 'skipped_stoplisted' | 'cancelled' | 'expired'
      - `ne` 'pending' | 'scheduled' | 'dispatched' | 'done' | 'failed' | 'skipped' | 'skipped_reply' | 'skipped_stoplisted' | 'cancelled' | 'expired'
      - `in` string[]
      - `nin` string[]
    - `assignee_user_sid` object: "My manual tasks" scope (external user sid); is_null:true = unassigned team queue.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `error_code` object: Failure triage on failed | expired rows.
      - `eq` string
      - `in` string[]
      - `is_null` boolean
    - `scheduled_at` object: "What dispatches in the next hour" - ISO 8601 bounds.
      - `gte` string
      - `lte` string
      - `gt` string
      - `lt` string
      - `is_null` boolean
    - `finished_at` object: Executed-history window; is_null:true = still open.
      - `gte` string
      - `lte` string
      - `is_null` boolean
    - `created_at` object: Planning window, ISO 8601.
      - `gte` string
      - `lte` string
      - `gt` string
      - `lt` string
    - `deleted_at` object: Default scope is { is_null: true } (live rows).
      - `gte` string
      - `lte` string
      - `is_null` boolean
  - `include` string[]: Relations to attach to every item; omit for the bare rows.
  - `sort` object: One column and its direction; omit for the default order.
    - `field` 'created_at' | 'scheduled_at' | 'finished_at', required: The column to order by.
    - `direction` 'asc' | 'desc': asc or desc; default desc.
  - `page_size` integer: 0..500, default 50; 0 = counts only, 1 = the first row.
  - `cursor` string, nullable: pagination.next_cursor of the previous page.

## Response `200`

`search` success envelope.

- SearchWorkflowTasksResponse
  - `success` true, required
  - `operation` 'search', required
  - `items` object[], required
    - `item` object, required
      - `sid` string, required: Task sid (wf_tk_…) - one row per step of a journey, kept across retries; rides gtm's rows as client_reference.
      - `team_sid` string, required: Owning team (ts_tm_…, external - gs.service.id).
      - `workflow_sid` string, nullable, required: Parent workflow (wf_wf_…), denormalized for gates and filters. null on a play's task, unless it is a question about a journey (2026-10-14).
      - `workflow_version_sid` string, nullable, required: Pinned version (wf_vr_…); (workflow_version_sid, step_id) resolves the step definition. null on a play's task.
      - `workflow_record_sid` string, nullable, required: Owning record (wf_rc_…) - the person×workflow journey this task executes one step of. On a play's task only the journey its question is about, else null.
      - `people_sid` string, required: The person (cr_pp_…), denormalized for the person timeline.
      - `step_id` integer, nullable, required: Step id within the pinned version (small int, server-assigned, unique per workflow). null on a play's task.
      - `type` 'linkedin_send_connection_request' | 'linkedin_send_message' | 'linkedin_send_inmail' | 'linkedin_visit_profile' | 'linkedin_endorse_skills' | 'linkedin_withdraw_connection_request' | 'email_send' | 'wait' | 'wait_for_event' | 'condition' | 'api_call' | 'ask_ai' | 'manual_task' | 'linkedin_like_latest_post' | 'linkedin_comment_latest_post' | 'ab_test' | 'move_to_workflow' | 'add_tag' | 'remove_tag' | 'set_field' | 'change_sender' | 'run_column', required: Step kind copied at planning: 7 send-class (Messaging) + 6 orchestration-class values.
      - `attempt` integer, required: Which attempt the row is on (>= 1; the executor's own retries stop at 3, a human retry_workflow_task may go past it). A retry re-arms the SAME row: attempt+1, the outcome before it archived in previous_attempts, the sid kept.
      - `status` 'pending' | 'scheduled' | 'dispatched' | 'done' | 'failed' | 'skipped' | 'skipped_reply' | 'skipped_stoplisted' | 'cancelled' | 'expired', required: Execution state; terminal = done | failed | skipped | skipped_reply | skipped_stoplisted | cancelled | expired. skipped = nothing to do (error_code already_invited: an invite from the sender profile is pending; already_connected: the person is a connection) and the record moved on.
      - `initiator` 'workflow_record' | 'play' | 'user', required: workflow_record = one step of one record's journey (every task until 2026-10-14); play = a play's act on a fact: a draft waiting in Signals, a scheduled send, a question about a journey; user = a person's act by hand on an event of the feed (2026-10-15, act_on_activity): a Like, a comment, a message.
      - `play_sid` string, nullable, required: The play that bore the task (pt_pl_…); null on a journey's task.
      - `trigger_activity_sid` string, nullable, required: The fact a play's or a person's task answers (cr_ac_…: a birthday, a job change, a post, a visit, any event a person acted on by hand): the join from an event to the act waiting or done under it; a play never acts on one fact twice. On a journey's task only a wait the event woke, or (2026-10-15) a Like or comment naming the post its read picked; else null.
      - `act` object, nullable, required: A play's act frozen at birth (what the task does, the post or workflow it names, a question's options); null on a journey's task.
        - `do` 'send_message' | 'add_to_workflow' | 'like' | 'comment' | 'ask', required: What the task does: a LinkedIn message (variables_snapshot.message), the person entering target_workflow_sid, a reaction on post_urn, a comment under post_urn (variables_snapshot.comment), a question (options).
        - `about` 'birthday' | 'work_anniversary' | 'job_change' | 'post' | 'website_visit' | 'event', required: The fact kind the act answers; event = a person's act by hand on a kind no play answers (an accept, a profile view, a follow).
        - `actor_sid` string: A person's act by hand (initiator user, 2026-10-15): who pressed it, the caller's actor sid.
        - `target_workflow_sid` string: add_to_workflow, and a question whose move or add names one.
        - `post_urn` string: like, comment: the post the act goes to (an activity URN).
        - `reaction` string: like: the reaction as the network names it (like, celebrate, support, love, insightful, funny), the play's own or the one the AI picked from the post.
        - `options` string[]: ask: the choices complete_workflow_task takes. remove | keep | move about a journey the play paused; add for a person in no journey.
        - `suggested` 'remove' | 'keep' | 'move' | 'add': ask: the choice the play's own Do would have made (remove for Remove from every workflow, move for Move to a workflow), shown first; absent for pause-and-ask.
      - `sender_profile_sid` string, nullable, required: Sending identity (ub_sp_…) - send-class only; pinned at planning, re-stamped at dispatch. null = orchestration-class.
      - `assignee_user_sid` string, nullable, required: manual_task only: assignee user sid (external - gs.service.id, prefix TBD); fallback = sender profile assignee; null = team queue.
      - `scheduled_at` string, nullable, required: ISO 8601 UTC - when the dispatcher may act; doubles as the manual_task due hint. null for pending-born types.
      - `timeout_at` string, nullable, required: ISO 8601 UTC - wait_for_event only: give-up clock for the timeout edge.
      - `dispatched_at` string, nullable, required: ISO 8601 UTC - stamped on scheduled → dispatched.
      - `expires_at` string, nullable, required: ISO 8601 UTC - dispatched commands only; the executor refuses to START after it (send-class: dispatch+24h, ask_ai: +1h).
      - `finished_at` string, nullable, required: ISO 8601 UTC - stamped once on any terminal status.
      - `variables_snapshot` object, nullable, required: Resolved template variables frozen at dispatch (people.* / record.<slug> / ai.* keys) - send-class + ask_ai only.
      - `result` object, nullable, required: Terminal outcome payload, keys per type (message_sid, branch_id, next_step_id, output, note, …). A failure on the sender profile's browser adds error_cause (proxy_failed, linkedin_session, …) and cause_owner (client: the team fixes it; support: we do).
      - `error_code` string, nullable, required: Machine reason token when status = failed | expired (max 64), or skipped (already_invited, already_connected). send_unconfirmed: gtm-api could not tell for a day whether the send went out, so it may have reached the person (see retry_workflow_task).
      - `error_message` string, nullable, required: Human detail of the failure (max 1024); null on a skip.
      - `previous_attempts` object[], nullable, required: The outcomes this row was re-armed past, oldest first (a retry, the executor's own or a person's, keeps the row and archives the attempt here); null until the first retry.
        - `attempt` integer, required: The attempt number it was.
        - `status` 'pending' | 'scheduled' | 'dispatched' | 'done' | 'failed' | 'skipped' | 'skipped_reply' | 'skipped_stoplisted' | 'cancelled' | 'expired', required: How it ended: failed | expired | skipped_stoplisted (the retryable outcomes).
        - `error_code` string, nullable, required: Its reason token.
        - `error_message` string, nullable, required
        - `result` object, nullable, required: Its result payload, when it had one (an api_call's http_status; a browser failure's error_cause and cause_owner).
        - `dispatched_at` string, nullable, required: ISO 8601 UTC.
        - `finished_at` string, nullable, required: ISO 8601 UTC.
      - `created_at` string, required: ISO 8601 UTC - the planning moment.
      - `updated_at` string, required: ISO 8601 UTC.
      - `deleted_at` string, nullable, required: ISO 8601 UTC - set ONLY by the owning record's cascade (no delete verb on this entity); null = live.
    - `included` object, required
      - `people` object: The person row (PeopleDomain - entities/people.md), 1:1.
      - `workflow_record` object: Owning record (WorkflowRecordDomain - entities/workflow_records.md), 1:1.
      - `workflow` object: Parent workflow (WorkflowDomain - entities/workflows.md), 1:1 - campaign name for queue cards.
      - `sender_profile` object, nullable: Sending identity (SenderProfileDomain - entities/sender_profiles.md), 1:1; null for orchestration-class tasks.
      - `eta` object, nullable: When a planned task is expected to run, computed on read: the sender profile scheduler's estimate for a scheduled send-class task (or, for a send in doubt, when gtm-api is asked again about its last attempt), and for a pending wait with a deadline when it will be decided (an accept wait after its account's connections sync past the deadline) or the pause that holds it. Null for every other task.
        - `eta_at` string, nullable, required: ISO 8601 UTC. A send: the minute the sender profile pick is expected to hand it off, laid over the send window. A wait: when it will be decided, never before the timeout pass reads it again (a sync that is overdue backs off, up to a day). Null while the account does not sync at all, or the journey is paused.
        - `position` integer, nullable, required: A send: 1-based position in its (sender profile, action type) bucket's order. A wait: null.
        - `days_ahead` integer, nullable, required: A send: whole days of the bucket's cap ahead of it. A wait: calendar days from today (UTC).
        - `waits_for` 'deadline' | 'linkedin_sync' | 'journey' | 'send_outcome': What the time waits for. A wait: linkedin_sync = an accept wait is decided on the account's first connections sync after the wait ends, which can be days later (2026-09-27). A send: send_outcome = gtm-api could not confirm whether the last attempt went out, and eta_at is the next time it is asked, not a send; it goes out again only on gtm's proof that it did not (2026-10-04).
        - `account_status` 'reconnect_required' | 'disconnected' | 'stopped', nullable: A wait only: the sender profile's LinkedIn state when the account does not sync at all (eta_at is null then).
        - `journey_status` 'paused_on_reply' | 'paused_manual' | 'paused_blocked': waits_for journey only: the pause that holds the wait.
        - `expires_at` string, nullable: ISO 8601 UTC. waits_for linkedin_sync: when the wait fails (wait_expired, the journey with it) if its account never syncs its connections, 30 days past the wait's deadline. waits_for send_outcome: when the step fails send_unconfirmed for a person if gtm-api still cannot tell, a day after the doubt began. Null for every other task.
  - `pagination` object, required
    - `next_cursor` string, nullable, required
    - `has_more` boolean, required
    - `total_count` integer, nullable, required
  - `applied_filters` object, required
  - `includes` string[], required
  - `meta` object, required
    - `trace_id` string, required: UUID v7; same 128-bit value as the X-Trace-Id header.
    - `span_id` string, required: 16 hex chars, root span of this request.
    - `timestamp` string, required: ISO 8601 UTC (Y-m-dTH:i:sZ), response time.
    - `duration_ms` integer, required: Server-side wall clock.
    - `team_sid` string, nullable: The team this call ran in (the token team, or the team_sid override). Null when unauthenticated; absent from pre-2026-08-20 backends.
    - `actor_type` string, nullable: user | agent | api_key | system. Null when unauthenticated; absent from pre-2026-08-20 backends.
  - `counts` object
    - `total_count` integer, required: Tasks matching the filter (full filter scope, not the page).
    - `groups` object, required
      - `status` union, required: Execution funnel by WorkflowTaskStatusEnum (9 values).
        - object
        - unknown[]
          - unknown
      - `type` union, required: Step-kind mix by WorkflowTaskTypeEnum (13 values).
        - object
        - unknown[]
          - unknown
      - `workflow_sid` union, required: Per-campaign task load, keyed by wf_wf_ sid.
        - object
        - unknown[]
          - unknown
      - `sender_profile_sid` union, required: Per-sender queue depth; the "null" bucket = orchestration-class.
        - object
        - unknown[]
          - unknown
      - `error_code` union, required: Failure triage ("what is breaking"), keyed by error_code or "null".
        - object
        - unknown[]
          - unknown

## Other responses

- `4XX`: MCP error envelope. `error.code` is one of validation_failed, nothing_to_update, not_found, relation_not_found, invalid_transition, limit_exceeded, payment_required, duplicate_rejected, conflict, delete_blocked, unauthorized, forbidden, rate_limited, not_implemented.
- `5XX`: MCP error envelope with `error.code` internal_error or service_unavailable.

---

[API](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables.md) - [All operations](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables/llms.txt) - [OpenAPI document](https://skmtc.dev/getsales/apis/getsales-public-contract-gs-service-playtables/revisions/aa394506515d?raw)
