# Export a workflow

**GET** `/api/workflows/{id}/export`

Returns a workflow’s draft as a file another installation can import.

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

## Parameters

### Path

- `id` · Required · UUID: The workflow’s ID.

## Save it as a file

The answer is ordinary JSON, not a download. Save `data`, and import that with [Import a workflow](https://docs.gorunner.io/api/workflows/import-workflow), which also takes the whole answer.

It holds the draft: the name, description, trigger type, tags and tree. No ID, state, folder, runs or webhook token.

Connection IDs in the tree travel as they are, and won’t exist on another installation.

## Responses

- 200 OK

  The export.

- 400 `VALIDATION_ERROR`

  `id` isn’t a UUID.

- 403 `FORBIDDEN`

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

- 404 `NOT_FOUND`

  No workflow with this ID in the token’s workspace.

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) · [`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
WORKFLOW_ID="your-workflow-id"

curl "$GORUNNER/api/workflows/$WORKFLOW_ID/export" \
  -H "Authorization: Bearer $GORUNNER_TOKEN"
```

**JavaScript**

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

const res = await fetch(
  `${GORUNNER}/api/workflows/${WORKFLOW_ID}/` +
    `export`,
  {
    headers: { Authorization: `Bearer ${TOKEN}` },
  },
);
const { data } = await res.json();
```

**Python**

```python
import os, requests

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

res = requests.get(
    f"{GORUNNER}/api/workflows/{WORKFLOW_ID}/"
    f"export",
    headers={"Authorization": f"Bearer {TOKEN}"},
)
data = res.json()["data"]
```

Response · 200 OK

```json
{
  "data": {
    "gorunnerExport": "workflow",
    "version": 1,
    "exportedAt": "2026-10-25T09:00:00Z",
    "workflow": {
      "name": "Order intake",
      "description": "Sends new orders to fulfilment.",
      "triggerType": "webhook",
      "tags": [
        "orders"
      ],
      "definition": {
        "schemaVersion": 2,
        "trigger": {
          "name": "trigger",
          "displayName": "Order received",
          "type": "webhook",
          "pieceId": "webhook",
          "pieceVersion": "1.0.0",
          "actionId": "catch_webhook",
          "config": {
            "methods": [
              "POST"
            ]
          },
          "valid": true,
          "nextAction": {
            "name": "forward",
            "displayName": "Forward to fulfilment",
            "type": "PIECE",
            "pieceId": "http",
            "pieceVersion": "1.0.0",
            "actionId": "send_request",
            "config": {
              "method": "POST",
              "url": "https://example.com/fulfilment",
              "body_type": "json",
              "body_json": "{{trigger.body}}"
            },
            "valid": true
          }
        },
        "settings": {}
      }
    }
  }
}
```

**Every field**

It takes no body.

### Response · 200 OK

- `data` · object: The portable file format produced by the export route and accepted by import. Carries no ids, no status, no folder, no webhook token and no run history — only what is meaningful on another instance.
  - `gorunnerExport` · string: Format marker; the value is the literal string `workflow`, not a boolean. One of `workflow`.
  - `version` · integer: Export FORMAT version — 1. Unrelated to `definition.schemaVersion`, which is 2. One of `1`.
  - `exportedAt` · time: When the export was produced. Informational; import ignores it.
  - `workflow` · object: The portable payload inside an export envelope. Import also accepts this object on its own, without the envelope around it.
    - `name` · string: On import, an empty or absent name becomes "Imported Workflow".
    - `description` · string
    - `triggerType` · string: Overridden by whatever `definition.trigger` says, so it is effectively informational. One of `manual`, `cron`, `webhook`, `callable`, `event`, `error`, `run_finished`, `poll`.
    - `tags` · array of strings: Trimmed and deduplicated case-insensitively on import.
    - `definition` · object: The workflow definition, and the single most important shape in this API. A workflow definition: its fields are in [Workflow definition](https://docs.gorunner.io/api/workflow-definition).

Related: [Import a workflow](https://docs.gorunner.io/api/workflows/import-workflow) · [Duplicate a workflow](https://docs.gorunner.io/api/workflows/duplicate-workflow)

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