> ## Documentation Index
> Fetch the complete documentation index at: https://docs.firsttouch.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> For API operations, fetch https://gateway.firsttouch.ai/api/public/openapi.json for the complete input/output schemas, internal references, and x-mcp-annotations. Endpoint Markdown intentionally omits generated schema fragments. Select /api/public/tools/<tool_name> using the exact underscore-separated name. Send requests to https://gateway.firsttouch.ai; the canonical document currently omits servers. Start at https://docs.firsttouch.com/api-reference/agent-start.md.

# Execution And Recovery

> Interpret accepted actions, pending tasks, pagination, and failures without duplicating work.

An HTTP `200` response means the API returned an operation result. Read that result to determine whether work was accepted, remains pending, was blocked, or has completed. Creating an action is not evidence that an email or LinkedIn message was sent.

## Keep The Write Receipt

[`add_dynamic_action`](/api-reference/operations/firsttouch-tools/add-dynamic-action) creates one action step per call. Its description identifies `enrollmentId` and `nodeId` together as the write receipt.

* Save the returned `enrollmentId`, `nodeId`, and `flowPlanId` along with any `uiLinks` and `nextSteps`.
* If `nodeAppended=true`, the step was appended. Do not repeat the same creation call because `taskIds` is empty or enrollment details have not caught up.
* Check `taskIdsPending` and `taskMaterializationStatus` for task creation that is still pending. Use the returned guidance and inspect the enrollment or task list as appropriate.
* Report the observed state, such as an appended action awaiting task creation or approval. Report a send as completed only when execution evidence supports it.

These fields are documented specifically for Dynamic Actions. Do not assume other operations return the same receipt or status fields. The current Dynamic Action output schema is unspecified; its operation description supplies the receipt guidance.

To cancel an MCP Dynamic Actions enrollment, use `remove_dynamic_action_prospect` with the exact returned `enrollmentId`. Do not use normal Flow Plan cancellation or structural mutation tools for this shared system flow.

## Review Approval Tasks

Use `list_user_tasks` to find tasks and `preview_task` to inspect the exact content. If the user requested changes, use `edit_task_action` and preview the resulting content before approval. Call `complete_task` or `skip_task` only for the action the user authorized.

For Dynamic Actions, set `action.isHumanApprovalRequired=true` when the user requests approval. Email, LinkedIn send, InMail, and call actions otherwise default to no human approval. Creating an approval task and completing that task are separate actions.

## Handle Missing Metadata

Check both field presence and `null` before using response metadata. Current MCP audience responses can omit `sync`, `salesNavigatorImportStatus`, or an unassigned `linkedFlowId`; LinkedIn queue rows can omit unavailable provider fields. These omissions are a known mismatch with required nullable properties in the published output schemas. Keep the mismatch visible in validation logs, and do not fill missing values with invented IDs, success states, or approval decisions.

For LinkedIn queue rows, inspect `request.isAwaitingRequirement` and the returned requirement details before interpreting provider status. A row waiting on prerequisites is not evidence that a provider request was sent.

## Handle Ambiguous Failures

There is no universal retry rule for all FirstTouch operations. After a timeout, cancellation, or server error on a write, check available resource state before deciding whether to repeat it. Do not assume that the absence of a response means the write did not happen.

| Situation                                             | Next step                                                                                                                                       |
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Dynamic Action returned `nodeAppended=true`           | Keep the receipt and inspect the existing enrollment or tasks; do not append the same step again.                                               |
| LinkedIn Unibox reply timed out or failed ambiguously | Re-fetch the conversation and ask the user whether to retry. Never retry `send_linkedin_unibox_message` automatically.                          |
| LinkedIn Unibox returned a blocked result             | Explain the block; do not report the message as sent.                                                                                           |
| `400` or `409`                                        | Inspect validation or state-conflict details and correct the request or resolve the conflict before another attempt.                            |
| `401` or `403`                                        | Correct authentication, team access, permissions, or feature eligibility. Repeating the same request will not fix those conditions.             |
| `429`, `499`, `500`, or a network timeout             | Inspect any returned guidance and whether the operation could have changed state. Apply its specific recovery rules before considering a retry. |

When escalating an error, retain the operation name, HTTP status, timestamp, and error body with secrets removed. Include `traceId` if the response supplies it; do not require that field to exist in every failure response. Never include API keys or raw authorization headers.

## Continue Discovery Without Repeating A Search

[`discover_contacts`](/api-reference/operations/firsttouch-tools/discover-contacts) is charged. Its description recommends a `pageSize` of `1` for a general preview and permits up to 10 rows per call. It reserves `pageSize` credits and charges one credit per returned profile row.

After a preview or page, pass the returned **`nextPage` value as the next request's `nextToken`** and request only the additional rows needed. Do not restart the same search without the continuation token. Other list operations use their own pagination fields; for example, `list_audiences` accepts a `cursor`. Read each operation's schema instead of assuming one pagination convention applies everywhere.

## Recover A Background Import

`start_contact_discovery_audience_import` starts asynchronous work. Preserve its returned import identifier and use `get_contact_discovery_audience_import_status` to inspect that import instead of starting it again merely because it is unfinished.

The status operation omits saved prospect IDs by default. Set `includeProspectIds=true` when recovering partial results after a failed import. Inspect saved results before deciding whether more work is needed, so contacts and credit spend are not duplicated.

The current import response schemas do not define a complete state enum or polling interval. Use returned status and guidance; do not code against guessed state names or promise a fixed completion time.

## Diagnose Missing Outreach

Use the enrollment, task, and queue operations together. Email queue results cover actions submitted to the email sending service; absence from that queue alone does not establish that an action was never created. Check approval, sender setup, required recipient data, and the flow step before retrying creation.

Use each queue's exact field names; the two responses use different casing:

| Result         | Field                                             | Meaning                                                                     |
| -------------- | ------------------------------------------------- | --------------------------------------------------------------------------- |
| LinkedIn queue | `queue.items[].request.enrollmentId`              | Enrollment to inspect with `get_flow_enrollment`.                           |
| LinkedIn queue | `queue.items[].request.requestGate`               | A scheduler, working-hours, limit, or provider gate on an existing request. |
| LinkedIn queue | `queue.items[].request.estimatedExecutionTimeUtc` | Current execution estimate, when supplied.                                  |
| Email queue    | `queue.items[].enrollment_id`                     | Enrollment to inspect with `get_flow_enrollment`.                           |
| Email queue    | `queue.items[].estimated_execution_time_utc`      | Current send estimate; it is not an inbox-delivery guarantee.               |

Follow returned working-hours and scheduling information. A successfully created action can wait for the sender's next working window. Preserve the existing receipt and check that action again instead of creating a replacement.

See the [operation catalog](/api-reference/operation-catalog) for the exact inspection and queue methods, or the [MCP use cases](/WebApp/Mcp/use-cases) for workflow examples.
