Loopfour

API quickstart

Create an API key, create a workflow through the API, start a run and read its result, in one short walkthrough with working requests.

This walkthrough creates a small workflow through the API, makes it live, runs it with your own input and reads the result. The workflow takes a list of invoice lines and reshapes each one into the fields a later step would need.

Before you start

  • An API key with workflows:write, workflows:execute and runs:read (or workflows:read). A key created under Settings > API keys in Studio has all three. See Authentication and API keys.
  • curl, or any HTTP client.

Set the key once in your shell:

export LOOPFOUR_API_KEY="wfk_live_..."

Create the workflow

Send the workflow definition to POST /workflows. It has an API trigger and one Transform step.

curl -X POST https://workflow.loopfour.ai/api/v1/workflows \
  -H "x-api-key: $LOOPFOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Reshape invoice lines",
    "description": "Maps raw invoice lines to number, amount and customer",
    "trigger": { "type": "api" },
    "inputSchema": {
      "type": "object",
      "required": ["lines"],
      "properties": { "lines": { "type": "array" } }
    },
    "steps": [
      {
        "id": "map_lines",
        "type": "transform",
        "name": "Map invoice lines",
        "config": {
          "operation": "map",
          "data": "{{input.lines}}",
          "mapping": {
            "invoiceNumber": "number",
            "amount": "total",
            "customer": "customer.name"
          }
        }
      }
    ]
  }'

The API answers 201 (abridged below). Keep data.id: it is the workflow id, used as $WORKFLOW_ID in the next steps. A new workflow is a draft at version label v0.1.

{
  "success": true,
  "data": {
    "id": "8d0c4a52-0000-4000-8000-000000000001",
    "name": "Reshape invoice lines",
    "status": "draft",
    "version": 1,
    "versionLabel": "v0.1",
    "trigger": { "type": "api" },
    "steps": [ ... ]
  }
}

Activate it

A run can start only when the workflow is active. Activation is the same action as Deploy in Studio.

curl -X POST https://workflow.loopfour.ai/api/v1/workflows/$WORKFLOW_ID/activate \
  -H "x-api-key: $LOOPFOUR_API_KEY"
{
  "success": true,
  "data": { "id": "8d0c4a52-...", "status": "active", "version": 2, "versionLabel": "v1.0" }
}

Activation checks the steps first. A definition with a broken step is refused with 400 and the reason.

Start a run

Post the run input to POST /workflows/:id/run. Everything under input is available to steps as {{input.<path>}}.

curl -X POST https://workflow.loopfour.ai/api/v1/workflows/$WORKFLOW_ID/run \
  -H "x-api-key: $LOOPFOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input": {
      "lines": [
        { "number": "INV-1001", "total": 1200, "customer": { "name": "Acme Ltd" } },
        { "number": "INV-1002", "total": 450, "customer": { "name": "Birch & Co" } }
      ]
    },
    "idempotencyKey": "reshape-2026-11-12"
  }'

The API answers 202 straight away, and the run continues in the background. Keep data.run_id as $RUN_ID.

{
  "success": true,
  "data": {
    "run_id": "c51e7f10-0000-4000-8000-000000000002",
    "status": "pending",
    "workflow_id": "8d0c4a52-...",
    "mode": "async"
  }
}

Sending the same idempotencyKey again for this workflow returns the existing run (200) instead of starting a second one.

Read the run

curl https://workflow.loopfour.ai/api/v1/runs/$RUN_ID \
  -H "x-api-key: $LOOPFOUR_API_KEY"

When status is completed, output holds the output of the last step, and stepResults holds one entry per step (abridged here):

{
  "success": true,
  "data": {
    "id": "c51e7f10-...",
    "workflowId": "8d0c4a52-...",
    "status": "completed",
    "triggerType": "api",
    "output": [
      { "invoiceNumber": "INV-1001", "amount": 1200, "customer": "Acme Ltd" },
      { "invoiceNumber": "INV-1002", "amount": 450, "customer": "Birch & Co" }
    ],
    "stepResults": [
      { "stepId": "map_lines", "status": "success", "durationMs": 12, "attempt": 1 }
    ],
    "startedAt": "2026-11-12T10:00:00.000Z",
    "completedAt": "2026-11-12T10:00:01.000Z",
    "error": null
  }
}

Poll until status is completed, failed or cancelled. A run with an Approval step waits in waiting_approval until someone decides.

Wait for the result in one call

For short workflows you can ask the run endpoint to wait. Add "mode": "sync" and, optionally, maxExecutionTimeMs (1,000 to 300,000; default 30,000).

curl -X POST https://workflow.loopfour.ai/api/v1/workflows/$WORKFLOW_ID/run \
  -H "x-api-key: $LOOPFOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "input": { "lines": [] }, "mode": "sync", "maxExecutionTimeMs": 60000 }'

A finished run returns 200 with output and duration_ms. If the wait runs out first, you get 202 with timed_out: true and the run_id to poll, unless you set "onTimeout": "throw_error", which returns 408 with code SYNC_TIMEOUT.

What to try next

On this page