# Handling results and errors

When you initiate any workflow, the execute() method immediately returns workflow tracking details. You can then use the result() method with this ID to get the workflow results when it's complete.

When you initiate any workflow, the `execute()` method immediately returns workflow tracking details:

- `workflowId` – unique workflow identifier.
- `workflowStatus` – initial workflow status, either `pending` or `running`.
- `message` – human-readable queue or duration message, when available.

You can then use the `result()` method with this ID to get the workflow results when it's complete.

```typescript
const workflow = await linkedapi.checkConnectionStatus.execute({
  personUrl: "https://www.linkedin.com/in/john-doe"
});

const result = await linkedapi.checkConnectionStatus.result(workflow.workflowId);
```

```python
from linkedapi import CheckConnectionStatusParams

workflow = linkedapi.check_connection_status.execute(
    CheckConnectionStatusParams(person_url="https://www.linkedin.com/in/john-doe")
)

result = linkedapi.check_connection_status.result(workflow.workflow_id)
```

The structure of the object returned by `result()` depends on whether you use a [predefined workflow](/sdks/predefined-vs-custom-workflows) or a [custom workflow](/sdks/predefined-vs-custom-workflows).

## For predefined workflows

When using a standard, predefined method, `result()` returns a convenient object with two key fields:

- `data` – typed object containing the successful result of the workflow.
- `errors` – array of non-critical **workflow execution errors**, that may have occurred during the run, but did not stop the entire workflow. Each error object contains `type` and `message` fields.

```typescript
const workflow = await linkedapi.checkConnectionStatus.execute({
  personUrl: "https://www.linkedin.com/in/john-doe"
});
const result = await linkedapi.checkConnectionStatus.result(workflow.workflowId);

const data = result.data;
const errors = result.errors;
```

```python
from linkedapi import CheckConnectionStatusParams

workflow = linkedapi.check_connection_status.execute(
    CheckConnectionStatusParams(person_url="https://www.linkedin.com/in/john-doe")
)
result = linkedapi.check_connection_status.result(workflow.workflow_id)

data = result.data
errors = result.errors
```

> For each predefined method, the specific structure of its `data` object and a list of possible `errors` are detailed on the corresponding page in the side navigation menu.

## For custom workflows

When using `customWorkflow`, the `result()` method returns the raw **completion object**. This object contains the full execution context of the workflow, and you are responsible for parsing it according to the specification on the [building workflows](/docs/building-workflows) page.

```typescript
const workflow = await linkedapi.customWorkflow.execute({
  "actionType": "st.openPersonPage",
  "personUrl": "https://www.linkedin.com/in/john-doe",
  "basicInfo": true,
  "then": {
    "actionType": "st.checkConnectionStatus",
  }
});

const workflowCompletion = await linkedapi.customWorkflow.result(workflow.workflowId);
```

```python
workflow = linkedapi.custom_workflow.execute(
    {
        "actionType": "st.openPersonPage",
        "personUrl": "https://www.linkedin.com/in/john-doe",
        "basicInfo": True,
        "then": {
            "actionType": "st.checkConnectionStatus",
        },
    }
)

workflow_completion = linkedapi.custom_workflow.result(workflow.workflow_id)
```

## Checking status without waiting

Use `status()` when you want to check a workflow once without waiting for it to finish. If the workflow is still `pending` or `running`, the SDK returns its current `workflowStatus` and, when provided, `message`. The message can change between polling requests, for example when a workflow moves from `pending` to `running`.

```typescript
const workflowId = "YOUR_WORKFLOW_ID";
const status = await linkedapi.checkConnectionStatus.status(workflowId);

if ('workflowStatus' in status) {
  showProgress(status.workflowStatus, status.message);
}
```

```python
from linkedapi import WorkflowInProgressResponse

workflow_id = "YOUR_WORKFLOW_ID"
status = linkedapi.check_connection_status.status(workflow_id)

if isinstance(status, WorkflowInProgressResponse):
    show_progress(status.workflow_status, status.message)
```

## Receiving results via webhooks

Instead of polling `result()` or `status()`, you can register a webhook and let Linked API notify your endpoint when a workflow completes – and when a connected account changes status. This is the better fit for long-running workflows and for reacting to account events (like a reconnection becoming required) that no single `result()` call would surface.

Each delivery is an HTTP `POST` with a typed event in its body. Parse the raw request body with `parseWebhookEvent` / `parse_webhook_event`, then branch on the event's `type`:

```typescript
import { parseWebhookEvent } from '@linkedapi/node';

const event = parseWebhookEvent(rawRequestBody);

if (event.type === 'workflow.completed') {
  console.log(event.data.workflowId, event.data.status, event.data.result);
}
```

```python
from linkedapi import parse_webhook_event

event = parse_webhook_event(raw_request_body)

if event.type == "workflow.completed":
    print(event.data.workflow_id, event.data.status, event.data.result)
```

`workflow.completed` carries the full workflow result in `fat` payload mode; in `thin` mode fetch it with `result()` using `data.workflowId`. Deliveries are at-least-once, so deduplicate on the event `id`.

See [Webhook Events](/docs/webhooks) for the full event model, and [Webhooks](/sdks/webhooks) to register and manage one with the SDK.

## Handling critical errors

Separate from the non-critical `errors` array [returned by pre-defined workflows](/sdks/handling-results-and-errors), the SDK can throw **critical errors**. These are exceptions that immediately stop execution and indicate a fundamental problem with the request or your account.

These exceptions, always of the type `LinkedApiError`, can be thrown when calling `execute()` to initiate a workflow or when calling `result()` to get the results. You must handle them using a `try...catch` block to inspect the error's `type` field and determine the cause.

```typescript
try {
  const workflow = await linkedapi.checkConnectionStatus.execute({
    personUrl: "https://www.linkedin.com/in/john-doe"
  });

  const { data, errors } = await linkedapi.checkConnectionStatus.result(workflow.workflowId);

  // 1. Handling non-critical execution errors
  if (errors && errors.length > 0) {
    console.warn('Workflow completed with execution errors:', errors);
  }

  // Handling the successful result
  if (data) {
    console.log('Connection Status:', data.connectionStatus);
  }

} catch (e) {
  // 2. Handling critical errors (exceptions)
  if (e instanceof LinkedApiError) {
    if (e.type === LINKED_API_ERROR.invalidLinkedApiToken) {
      console.error('Authentication failed. Please check your API token.');

    } else if (e.type === LINKED_API_ERROR.subscriptionRequired) {
      console.error('Invalid parameters in request:', e.message);

    } else {
      // Handle other types of critical API errors
      console.error(`A different API error occurred: ${e.type}`);
    }
  } else {
    // Handle other unexpected errors (e.g., network issues)
    console.error('An unexpected, non-API error occurred:', e);
  }
}
```

```python
from linkedapi import CheckConnectionStatusParams, LinkedApiError

try:
    workflow = linkedapi.check_connection_status.execute(
        CheckConnectionStatusParams(person_url="https://www.linkedin.com/in/john-doe")
    )

    result = linkedapi.check_connection_status.result(workflow.workflow_id)
    data = result.data
    errors = result.errors

    # 1. Handling non-critical execution errors
    if errors:
        print("Workflow completed with execution errors:", errors)

    # Handling the successful result
    if data:
        print("Connection Status:", data.connection_status)

except LinkedApiError as e:
    # 2. Handling critical errors (exceptions)
    if e.type == "invalidLinkedApiToken":
        print("Authentication failed. Please check your API token.")
    elif e.type == "subscriptionRequired":
        print("Invalid parameters in request:", e.message)
    else:
        print(f"A different API error occurred: {e.type}")
except Exception as error:
    # Handle other unexpected errors (e.g., network issues)
    print("An unexpected, non-API error occurred:", error)
```

**Here are all possible critical errors:**

- `invalidLinkedApiToken` – the provided `linked-api-token` is invalid.
- `invalidIdentificationToken` – the provided `identification-token` is invalid.
- `subscriptionRequired` – no purchased subscription seats available for this LinkedIn account.
- `plusPlanRequired` – to execute this workflow you need the [Plus plan](/pricing).
- `invalidWorkflow` (only for custom workflows) – workflow configuration is not valid due to violated [action constraints](/docs/actions-overview) or invalid [action parameters](/docs/actions-overview): {validation_details}.
- `invalidRequestPayload` – invalid request body/parameters: {validation_details}.
- `tooManyRequests` – too many requests have been made in the last minute.
- `linkedinAccountSignedOut` – your LinkedIn account has been signed out in our cloud browser. This occasionally happens as LinkedIn may sign out accounts after an extended period. You'll need to visit [our platform](https://app.linkedapi.io/) and reconnect your account.
- `languageNotSupported` – your LinkedIn account uses a language other than English, which is currently the only supported option. If you encounter this issue, please contact our support. We prioritize adding new languages based on user requests, so your feedback is important.
