# customWorkflow

This method allows you to execute a custom Linked API workflow using a raw workflow definition for complex multi-step operations.

```typescript
try {
  const workflow = await linkedapi.customWorkflow.execute({
    actionType: "st.searchCompanies",
    term: "AI startup",
    filter: {
      locations: ["San Francisco", "New York"],
      sizes: ["11-50", "51-200"]
    },
    limit: 10,
    then: {
      actionType: "st.doForCompanies",
      then: {
        actionType: "st.openCompanyPage",
        basicInfo: true,
        then: {
          actionType: "st.retrieveCompanyEmployees",
          limit: 5,
          filter: {
            position: "manager"
          },
          then: {
            actionType: "st.doForPeople",
            then: {
              actionType: "st.sendConnectionRequest",
              note: "Hi! I'd love to connect and discuss opportunities."
            }
          }
        }
      }
    }
  });

  const { data } = await linkedapi.customWorkflow.result(workflow.workflowId);

  console.log('Custom workflow executed successfully.');
  console.log('Workflow result:', data);
} catch (e) {
  // A list of all critical errors can be found here:
  // https://linkedapi.io/sdks/handling-results-and-errors/#handling-critical-errors
  if (e instanceof LinkedApiError) {
    console.error(`Critical Error - Type: ${e.type}, Message: ${e.message}`);
  } else {
    console.error('An unexpected, non-API error occurred:', e);
  }
}
```

```python
from linkedapi import LinkedApiError

try:
    workflow = linkedapi.custom_workflow.execute(
        {
            "actionType": "st.searchCompanies",
            "term": "AI startup",
            "filter": {
                "locations": ["San Francisco", "New York"],
                "sizes": ["11-50", "51-200"],
            },
            "limit": 10,
            "then": {
                "actionType": "st.doForCompanies",
                "then": {
                    "actionType": "st.openCompanyPage",
                    "basicInfo": True,
                    "then": {
                        "actionType": "st.retrieveCompanyEmployees",
                        "limit": 5,
                        "filter": {
                            "position": "manager",
                        },
                        "then": {
                            "actionType": "st.doForPeople",
                            "then": {
                                "actionType": "st.sendConnectionRequest",
                                "note": "Hi! I'd love to connect and discuss opportunities.",
                            },
                        },
                    },
                },
            },
        }
    )

    result = linkedapi.custom_workflow.result(workflow.workflow_id)
    data = result.data

    print("Custom workflow executed successfully.")
    print("Workflow result:", data)
except LinkedApiError as e:
    # A list of all critical errors can be found here:
    # https://linkedapi.io/sdks/handling-results-and-errors/#handling-critical-errors
    print(f"Critical Error - Type: {e.type}, Message: {e.message}")
except Exception as error:
    print("An unexpected, non-API error occurred:", error)
```

## Params

Pass a workflow definition object that follows our [HTTP API workflow format](/docs/building-workflows).

## Data

Completion object that matches our [HTTP API completion format](/docs/executing-workflows).

## Errors

The method has no execution errors (`errors` is always `[]`).

## Iterating over post comments

Reacting to a single comment is available directly via [`reactToComment`](/sdks/react-to-comment) and [`replyToComment`](/sdks/reply-to-comment). To react or reply to **every** comment on a post without knowing their URLs upfront, use a custom workflow: retrieve the comments with `st.retrievePostComments`, iterate over them with `st.doForComments`, and either react/reply directly or open each comment first with `st.openComment` to run several comment-scoped actions.

```typescript
const workflow = await linkedapi.customWorkflow.execute({
  actionType: "st.retrievePostComments",
  postUrl: "https://www.linkedin.com/posts/username_activity-id",
  limit: 3,
  sort: "mostRelevant",
  then: {
    actionType: "st.doForComments",
    then: {
      actionType: "st.openComment",
      then: [
        { actionType: "st.reactToComment", type: "celebrate" },
        { actionType: "st.replyToComment", text: "Great point, thanks for sharing!" }
      ]
    }
  }
});
```

```python
workflow = linkedapi.custom_workflow.execute(
    {
        "actionType": "st.retrievePostComments",
        "postUrl": "https://www.linkedin.com/posts/username_activity-id",
        "limit": 3,
        "sort": "mostRelevant",
        "then": {
            "actionType": "st.doForComments",
            "then": {
                "actionType": "st.openComment",
                "then": [
                    {"actionType": "st.reactToComment", "type": "celebrate"},
                    {"actionType": "st.replyToComment", "text": "Great point, thanks for sharing!"},
                ],
            },
        },
    }
)
```

> The `st.openComment` wrapper is optional — `st.reactToComment` and `st.replyToComment` can be nested directly under `st.doForComments`. Similarly, `st.doForPosts` accepts `st.reactToPost`, `st.commentOnPost`, `st.retrievePostComments`, and `st.retrievePostReactions` directly, so you can act on each iterated post without wrapping it in `st.openPost`.
