Returning.AIDocs
v1

API reference / Workflow Builder

.md

Export a workflow definition

Returns the workflow as a portable definition: its name, its trigger, and every step with its options.

Last updated 28 Oct 2026API v1

Method
GET
Path
https://api.returning.ai/v1/workflow-builder/data-workflows/{workflowId}/export
Permission
workflowBuilder
Retries
Safe to retry: nothing is written.

Authentication#

Header
Authorization: Bearer <API_KEY>
Permission
workflowBuilder

Authorization: Bearer <API_KEY> with workflowBuilder, for the community that owns the workflow. Redaction is not optional and has no parameter to turn it off, so an export can be read, kept and re-imported without the document ever holding a working credential.

FailureMeaningRecovery
401 AUTHENTICATION_REQUIREDNo key, or an unknown keySend a valid key.
403 API_KEY_PERMISSION_DENIEDNo workflowBuilderGrant the permission.
404 WORKFLOW_NOT_FOUNDUnknown id, or another community's workflowUse an id from this community.

Behaviour#

The document has the same shape an import reads, so it can be posted back to POST / as {definition} to recreate the workflow, here or in another community.

Node credentials in the document are replaced by the redaction marker and listed in redactedPaths. A credential that an import blanked and nobody has filled in yet is written the same way, so an export always shows what is still missing. The trigger's own credentials are removed entirely rather than marked: a webhook trigger's key stays behind as apiKey: {enabled: true} with no value, and an AES key arrives as enabled with an empty key and IV. Import mints or re-collects those.

Request#

Path parameters#

workflowId#stringREQUIRED
Workflow identifier: 24 hexadecimal characters, as returned in _id.

Rule^[0-9a-fA-F]{24}$

Eg65f1a2b3c4d5e6f708192a3b

Headers#

Authorization#stringREQUIRED
Community API key: Bearer <API_KEY>.

EgBearer <API_KEY>

Watch for

  • Redaction covers HTTP auth values, credential-named headers, parameters and body keys, URL query parameters with a credential name, and node-level credentials. The trigger's key material is not exported at all. A secret an author typed inside a raw body template is returned as authored, so treat an export as sensitive even though the named credentials are replaced.
  • An empty auth value is "no auth", not a redacted secret: a bearer token stored as [] stays [] and is not listed in redactedPaths.
  • Importing this document blanks the redacted node credentials, reports them in secretsToFill, and POST /{workflowId}/validate reports each one as a MISSING_SECRET warning until it is filled in. The warning does not stop a deploy, so fill them before going live.
  • The trigger's key does not travel, so an import mints a fresh webhook key for the new workflow. An AES key cannot be minted: it arrives enabled but blank, for the author to re-enter.
  • The export has no run history, no identifiers from the source community's fields or leaderboards beyond the ids the steps already stored, and no deployment state.
More examples and details

A workflow with one HTTP step whose headers and bearer token are redacted:

JSON
{
  "kind": "returningai.workflow",
  "formatVersion": 1,
  "variant": "data_workflows",
  "exportedAt": "2026-10-24T11:02:00.000Z",
  "workflow": { "name": "VIP bonus", "outgoingWebhookUrl": null },
  "trigger": {
    "name": "Trade bonus trigger",
    "type": "webhook",
    "options": { "tokenExchangeEnabled": false, "apiKey": { "enabled": true } }
  },
  "nodes": [
    {
      "ref": "node-0",
      "name": "Notify receiver",
      "type": "http",
      "order": 1,
      "continueOnFailure": false,
      "retryOnFailure": false,
      "options": {
        "method": "POST",
        "url": ["https://receiver.example.com/trade-bonus"],
        "params": {},
        "headers": { "X-Api-Key": ["__REDACTED__"] },
        "bodyType": "json",
        "body": { "member": ["{{trigger.email}}"] },
        "auth": { "type": "bearer-token", "token": ["__REDACTED__"] }
      }
    }
  ],
  "redactedPaths": ["nodes[0].options.headers.X-Api-Key", "nodes[0].options.auth.token"]
}
curl --request GET \
  --url 'https://api.returning.ai/v1/workflow-builder/data-workflows/<workflowId>/export' \
  --header 'Authorization: Bearer <API_KEY>'

Response#

HTTP 200 with the document at the top level, not wrapped in data: it is a file format, and an import reads it verbatim. redactedPaths rides alongside the document.

kind is returningai.workflow, formatVersion is 1, and variant is data_workflows. All four are required by an import.

The document carries one id space: step references and {{...}} templates are rewritten to the document's own names, trigger for the trigger and each step's ref for the steps, so the same file can be imported into any community without editing a reference. Each reference is paired with the step it named rather than with a position, so a step inserted after the trigger or a step inside a router branch keeps its meaning. An import rewires them onto the ids it mints. Step order is authored order, and ref is the local name a template or reference can use.

To prove an export, import it and compare: create a workflow with {definition}, then read the new workflow back and match step types, order and options, ignoring identifiers.

kind#string
Document kind.

Eg"returningai.workflow"

formatVersion#integer
Document format version.

Eg1

variant#string
Which workflow runtime produced the document. An import requires data_workflows.

Eg"data_workflows"

exportedAt#string
When the document was produced.

Eg"2026-10-24T11:02:00.000Z"

workflow#object
Workflow name and failure webhook.

Eg{"name": "VIP bonus", "outgoingWebhookUrl": null}

trigger#object
Trigger name, type and options, with credentials replaced.

RuleNullable

Eg{ ... }

nodes#object[]
Steps in canvas order, with credentials replaced. Step references and {{...}} templates use the document's own names: trigger and each step's ref.

Eg[ ... ]

ref#string
Local reference name.

Eg"node-0"

redactedPaths#string[]
Every location replaced by the marker.

Eg[ ... ]

{
  "kind": "returningai.workflow",
  "formatVersion": 1,
  "variant": "data_workflows",
  "exportedAt": "2026-10-24T11:02:00.000Z",
  "workflow": {
    "name": "VIP bonus",
    "outgoingWebhookUrl": null
  },
  "trigger": {
    "name": "Trade bonus trigger",
    "type": "webhook",
    "options": {
      "tokenExchangeEnabled": false,
      "apiKey": {
        "enabled": true
      }
    }
  },
  "nodes": [
    {
      "ref": "node-0",
      "name": "Notify receiver",
      "type": "http",
      "order": 1,
      "continueOnFailure": false,
      "retryOnFailure": false,
      "options": {
        "method": "POST",
        "url": ["https://receiver.example.com/trade-bonus"],
        "params": {},
        "headers": {
          "X-Api-Key": ["__REDACTED__"]
        },
        "bodyType": "json",
        "body": {
          "member": ["{{trigger.email}}"]
        },
        "auth": {
          "type": "bearer-token",
          "token": ["__REDACTED__"]
        }
      }
    }
  ],
  "redactedPaths": [
    "nodes[0].options.headers.X-Api-Key",
    "nodes[0].options.auth.token"
  ]
}

Errors#

Fix the request04

400VALIDATION_FAILEDFix the request
The id is not 24 hexadecimal characters. Use the id exactly as returned.
401AUTHENTICATION_REQUIREDFix the request
No key, or an unknown key. Send a valid key.
401API_KEY_REQUIREDFix the request
A valid admin session was used, because this API accepts community API keys only. Use a community API key.
403API_KEY_PERMISSION_DENIEDFix the request
No workflowBuilder. Grant the permission.

Fix the data01

404WORKFLOW_NOT_FOUNDFix the data
Unknown id, or another community's workflow. Use an id from this community.

Retry with backoff02

429RATE_LIMITEDRetry with backoff
The community's API rate limit was reached. Wait for the window to reset, then retry.
500INTERNAL_ERRORRetry with backoff
Unexpected failure. Retry with bounded backoff.

Retries

Safe to retry: nothing is written. The document contains exportedAt, so two exports of an unchanged workflow differ in that field only.

{
  "meta": {
    "status": "error",
    "statusCode": 400,
    "code": "VALIDATION_FAILED",
    "errors": [
      {
        "path": "params.workflowId",
        "message": "Id must be a 24 character hex string"
      }
    ],
    "requestId": "3f4d0e8b-7a6c-4f1e-9b2d-5a7c8e1f0a3b"
  },
  "message": "API request rejected error.",
  "detail": "The request body is not valid.",
  "solution": "Read error detail and try again."
}

Next step#

Create or replace the triggerPUT/v1/workflow-builder/data-workflows/{workflowId}/trigger