# Preview an import

**POST** `/api/workflows/import/preview`

Shows what a workflow exported from another automation tool would become, without making anything.

Needs [an API token](https://docs.gorunner.io/api/authentication#scopes) with the **Read** permission for workflows (`workflow:read`).

## Parameters

### Body

The exported file, as the other tool wrote it. Up to 5 MiB.

## Why two installations can differ

The preview maps only to apps this installation can run. The same file can map further elsewhere.

A GoRunner export needs no preview: send it to [Import a workflow](https://docs.gorunner.io/api/workflows/import-workflow), which explains the report’s fields.

## Responses

- 200 OK

  The report, with `format` `external` (detected from the file). For a file that is not an export it reads, `format` is empty, `report` is `null` and `message` says why.

- 403 `FORBIDDEN`

  The token lacks the **Read** permission for workflows.

- 422 `VALIDATION_ERROR`

  The file names its format but can’t be read.

- 500 `INTERNAL_ERROR`

  Something failed on GoRunner’s side. Try again.

- 503 `PIECES_UNAVAILABLE`

  GoRunner couldn’t check which apps this workspace may use. Nothing changed. Try again.

Any call can also answer: [`401 UNAUTHORIZED`](https://docs.gorunner.io/errors#UNAUTHORIZED) · [`401 TOKEN_ENDED`](https://docs.gorunner.io/errors#TOKEN_ENDED) · [`403 TOKEN_SURFACE_OFF`](https://docs.gorunner.io/errors#TOKEN_SURFACE_OFF) · [`403 FEATURE_OFF`](https://docs.gorunner.io/errors#FEATURE_OFF) · [`403 EMBED_NOT_ALLOWED`](https://docs.gorunner.io/errors#EMBED_NOT_ALLOWED) · [`403 EMBED_NOT_AVAILABLE`](https://docs.gorunner.io/errors#EMBED_NOT_AVAILABLE) · [`403 ACCOUNT_SUSPENDED`](https://docs.gorunner.io/errors#ACCOUNT_SUSPENDED) · [`413 PAYLOAD_TOO_LARGE`](https://docs.gorunner.io/errors#PAYLOAD_TOO_LARGE) · [`415 INVALID_CONTENT_TYPE`](https://docs.gorunner.io/errors#INVALID_CONTENT_TYPE) · [`429 RATE_LIMITED`](https://docs.gorunner.io/errors#RATE_LIMITED) · [`503 BUSY`](https://docs.gorunner.io/errors#BUSY) · [`503 PAUSED`](https://docs.gorunner.io/errors#PAUSED) · [`503 SERVICE_UNAVAILABLE`](https://docs.gorunner.io/errors#SERVICE_UNAVAILABLE). See [Errors](https://docs.gorunner.io/api/errors#by-status).

Request

**curl**

```bash
GORUNNER="https://api.gorunner.io"
GORUNNER_TOKEN="grt_…"  # needs Read for workflows

curl -X POST "$GORUNNER/api/workflows/import/preview" \
  -H "Authorization: Bearer $GORUNNER_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Order intake",
    "nodes": [
      {
        "name": "Webhook",
        "type": "webhook",
        "parameters": {
          "path": "orders"
        }
      }
    ],
    "connections": {}
  }'
```

**JavaScript**

```js
const GORUNNER = "https://api.gorunner.io";
const TOKEN = process.env.GORUNNER_TOKEN;

const res = await fetch(
  `${GORUNNER}/api/workflows/import/preview`,
  {
    method: "POST",
    headers: {
        Authorization: `Bearer ${TOKEN}`,
        "Content-Type": "application/json",
      },
    body: JSON.stringify({
        name: "Order intake",
        nodes: [
          {
            name: "Webhook",
            type: "webhook",
            parameters: { path: "orders" },
          },
        ],
        connections: {},
      }),
  },
);
const { data } = await res.json();
```

**Python**

```python
import os, requests

GORUNNER = "https://api.gorunner.io"
TOKEN = os.environ["GORUNNER_TOKEN"]

res = requests.post(
    f"{GORUNNER}/api/workflows/import/preview",
    headers={"Authorization": f"Bearer {TOKEN}"},
    json={
      "name": "Order intake",
      "nodes": [
        {
          "name": "Webhook",
          "type": "webhook",
          "parameters": {"path": "orders"},
        },
      ],
      "connections": {},
    },
)
data = res.json()["data"]
```

Response · 200 OK, shortened

```json
{
  "data": {
    "format": "external",
    "report": {
      "format": "external",
      "name": "Order intake",
      "nodes": [
        {
          "sourceName": "Slack",
          "sourceType": "slack",
          "outcome": "mapped",
          "pieceId": "slack",
          "stepName": "slack",
          "ready": false,
          "note": "Choose a connection and check the fields.",
          "leftovers": 2
        }
      ],
      "mappedCount": 1,
      "substitutedCount": 0,
      "parkedCount": 0,
      "needsAttention": 1,
      "stepsWithLeftovers": 1
    }
  }
}
```

**Every field**

Body: object.

The exported file, verbatim, as the other tool wrote it.

### Response · 200 OK

- `data` · object
  - `format` · string: Detected from the file: `external` for another automation tool’s export, empty when the file is not an export this importer reads. One of `external`,.
  - `report` · object or null: Null when `format` is empty. One of: `format` and `name` and `nodes` and `mappedCount` and `substitutedCount` and `parkedCount` and `needsAttention` and `stepsWithLeftovers` and `warnings`, or null.
    - `format` · string: Detected from the file: always `external` (another automation tool’s export). One of `external`.
    - `name` · string: The name the source file gave the workflow.
    - `nodes` · array of objects
      - `sourceName` · string: What the source file called it, so a person can find it there.
      - `sourceType` · string: The source node’s own short type, without the source tool’s package prefix, e.g. `slack` or `httpRequest`.
      - `outcome` · string: `mapped` — an app here does that job. `substituted` — no app for it, but a generic one does the same work. `parked` — nothing here does it, so the step is an invalid No Op carrying the original settings. One of `mapped`, `substituted`, `parked`.
      - `pieceId` · string: The GoRunner app it became. `no-op` on a parked step.
      - `stepName` · string: Its name here — what an expression referencing it says.
      - `ready` · boolean: Whether the step runs as imported. False asks for a visit: a connector can be MAPPED and still need its fields, because a foreign node’s settings rarely mean the same thing here.
      - `note` · string: The honest sentence for this row.
      - `leftovers` · integer: How many of the source’s own settings are still on this node because there was no field for them. Present even when `ready` is true — a step can run and still be unfinished.
    - `mappedCount` · integer
    - `substitutedCount` · integer
    - `parkedCount` · integer
    - `needsAttention` · integer: How many steps cannot run as imported — the number that decides whether this is a draft to finish or a draft to publish.
    - `stepsWithLeftovers` · integer: How many nodes still hold settings the translation could not place, whether or not they can run. NOT the same question as needsAttention: a step can run exactly as imported and still be carrying settings the original had, so a flow can be fully valid and still have translation left in it.
    - `warnings` · array of strings: File-level things the reader should know: a shape that had to be flattened (the source ran a fan-out in parallel, this product runs one chain), nodes nothing reached, comments left behind, expressions that need rewriting.
  - `message` · string: Present only when the file is neither format.

Related: [Import a workflow](https://docs.gorunner.io/api/workflows/import-workflow) · [Import from n8n or Activepieces](https://docs.gorunner.io/build/import-workflows)

Source: https://docs.gorunner.io/api/workflows/preview-workflow-import
