---
title: "Retry workflow task"
method: POST
path: "/api/workflow-tasks/{sid}/retry"
tags: ["workflow_tasks"]
---

# Retry workflow task

`POST /api/workflow-tasks/{sid}/retry`

## Request

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

Run a stopped step again for one person: a failed, expired or skipped_stoplisted task is re-armed (the same row, attempt+1) and the record is back active on that step. The cap of 3 does not apply. A send_unconfirmed failure is asked of gtm-api first; resend_unverified true is a person's word it never arrived. 409 invalid_transition on done, skipped, cancelled or skipped_reply (resume the record), an open task, a record that moved on. Not for a whole journey from the top.

Contract:
- MCP tool `retry_workflow_task`, registry package `mcp.playtables/workflow_tasks`, mount `playtables.journeys`.
- Operation `action`, response envelope `action`.
- Flags: dangerous: the MCP layer gates it behind a preview/commit token, and the effect cannot be undone through this API.

## Path parameters

- `sid` string, required: Workflow task sid (wf_tk_…).

## Request body

- RetryWorkflowTaskRequest: Request body of `retry_workflow_task`.
  - `reason` string: Why the step runs again - rides the workflow-records.resumed event payload when the record is revived (not on the row).
  - `resend_unverified` boolean, nullable: For a send that failed send_unconfirmed (gtm-api could not tell whether it went out): true only after a person looked where it would show (the thread, Sent, the invitations, the post) and vouches it never arrived, since a second send may reach them twice.

## Response `200`

`action` success envelope.

- RetryWorkflowTaskResponse
  - `success` true, required
  - `operation` 'action', required
  - `action` string, required: kebab-case verb; matches the route segment.
  - `item` object, nullable, 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.
  - `result` object, required
    - `updated_workflow_record` object, nullable, required: The owning record AFTER the revival (WorkflowRecordDomain - entities/workflow_records.md): failed → active on this step, error cleared; a live, paused or gate-blocked (paused_blocked) record keeps its status. null for a play's task, which stands alone (re-armed and due now).
  - `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.

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