LoopFour

Runs API

Execute and monitor workflow runs

Runs API

Execute workflows and monitor their execution progress, including step-by-step logs.

List Runs

Retrieve all workflow runs for your company with cursor-based pagination.

GET /api/v1/runs

Query Parameters

ParameterTypeDefaultDescription
workflowIdstring-Filter by workflow ID
statusstring-Filter: pending, running, completed, failed, cancelled
limitnumber50Number of results (1-100)
cursorstring-Cursor for pagination

Response

{
  "success": true,
  "data": [
    {
      "id": "run_550e8400-e29b-41d4-a716-446655440000",
      "workflowId": "wf_xxx",
      "status": "completed",
      "triggerType": "webhook",
      "startedAt": "2024-01-15T10:30:00.000Z",
      "completedAt": "2024-01-15T10:30:05.000Z",
      "durationMs": 5000,
      "error": null,
      "createdAt": "2024-01-15T10:30:00.000Z"
    },
    {
      "id": "run_660e8400-e29b-41d4-a716-446655440001",
      "workflowId": "wf_xxx",
      "status": "failed",
      "triggerType": "api",
      "startedAt": "2024-01-15T10:25:00.000Z",
      "completedAt": "2024-01-15T10:25:02.000Z",
      "durationMs": 2000,
      "error": {
        "code": "STEP_ERROR",
        "message": "Connection timeout"
      },
      "createdAt": "2024-01-15T10:25:00.000Z"
    }
  ],
  "meta": {
    "cursor": "eyJ0cyI6MTcwNTMxMjAwMDAwMCwiaWQiOiJydW5fNjYwZTg0MDAuLi4ifQ==",
    "hasMore": true
  }
}

Example

curl -X GET "http://localhost:3000/api/v1/runs?status=failed&limit=20" \
  -H "x-api-key: YOUR_API_KEY"

Get Run

Retrieve details of a specific workflow run. If the run is still in progress, status is automatically synced from Trigger.dev.

GET /api/v1/runs/:id

Path Parameters

ParameterTypeDescription
idstringRun UUID

Response

{
  "success": true,
  "data": {
    "id": "run_550e8400-e29b-41d4-a716-446655440000",
    "workflowId": "wf_xxx",
    "status": "completed",
    "triggerType": "webhook",
    "input": {
      "type": "invoice.paid",
      "data": {
        "object": {
          "id": "in_xxx",
          "amount_paid": 9900,
          "customer_email": "customer@example.com"
        }
      }
    },
    "output": {
      "slackMessageId": "1234567890.123456",
      "hubspotContactId": "12345"
    },
    "stepResults": [
      {
        "stepId": "notify-team",
        "status": "success",
        "startedAt": "2024-01-15T10:30:01.000Z",
        "completedAt": "2024-01-15T10:30:02.000Z",
        "durationMs": 1000,
        "input": { "channel": "#finance", "text": "..." },
        "output": { "ts": "1234567890.123456" },
        "attempt": 1
      },
      {
        "stepId": "create-contact",
        "status": "success",
        "startedAt": "2024-01-15T10:30:02.000Z",
        "completedAt": "2024-01-15T10:30:04.000Z",
        "durationMs": 2000,
        "input": { "email": "customer@example.com", ... },
        "output": { "id": "12345" },
        "attempt": 1
      }
    ],
    "startedAt": "2024-01-15T10:30:00.000Z",
    "completedAt": "2024-01-15T10:30:05.000Z",
    "durationMs": 5000,
    "error": null,
    "createdAt": "2024-01-15T10:30:00.000Z"
  }
}

Step Results

Each step result includes:

FieldTypeDescription
stepIdstringStep identifier
statusstringsuccess, error, skipped
startedAtstringISO timestamp when step started
completedAtstringISO timestamp when step completed
durationMsnumberExecution time in milliseconds
inputobjectResolved input passed to the step
outputobjectOutput returned by the step
errorobjectError details if step failed
attemptnumberRetry attempt number

Get Run Logs

Retrieve execution logs for a workflow run with step-by-step details.

GET /api/v1/runs/:id/logs

Response

{
  "success": true,
  "data": {
    "runId": "run_550e8400-e29b-41d4-a716-446655440000",
    "workflowId": "wf_xxx",
    "status": "completed",
    "logs": [
      {
        "stepId": "notify-team",
        "status": "success",
        "startedAt": "2024-01-15T10:30:01.000Z",
        "completedAt": "2024-01-15T10:30:02.000Z",
        "durationMs": 1000,
        "input": {
          "channel": "#finance",
          "text": "Invoice in_xxx paid!"
        },
        "output": {
          "ts": "1234567890.123456",
          "channel": "C1234567890"
        },
        "error": null,
        "attempt": 1
      },
      {
        "stepId": "create-contact",
        "status": "success",
        "startedAt": "2024-01-15T10:30:02.000Z",
        "completedAt": "2024-01-15T10:30:04.000Z",
        "durationMs": 2000,
        "input": {
          "email": "customer@example.com",
          "properties": { "firstname": "John" }
        },
        "output": {
          "id": "12345",
          "properties": { ... }
        },
        "error": null,
        "attempt": 1
      }
    ],
    "startedAt": "2024-01-15T10:30:00.000Z",
    "completedAt": "2024-01-15T10:30:05.000Z",
    "durationMs": 5000,
    "error": null
  }
}

Failed Step Example

{
  "stepId": "sync-to-crm",
  "status": "error",
  "startedAt": "2024-01-15T10:30:02.000Z",
  "completedAt": "2024-01-15T10:30:05.000Z",
  "durationMs": 3000,
  "input": { "recordId": "123", ... },
  "output": null,
  "error": {
    "code": "STEP_ERROR",
    "message": "API rate limit exceeded"
  },
  "attempt": 3
}

Cancel Run

Cancel a running or pending workflow execution.

POST /api/v1/runs/:id/cancel

Cancellable States

StatusCancellable
pendingYes
runningYes
completedNo
failedNo
cancelledNo

Response

{
  "success": true,
  "data": {
    "id": "run_550e8400-e29b-41d4-a716-446655440000",
    "status": "cancelled",
    "message": "Run cancellation requested"
  }
}

Error Response (Invalid State)

{
  "success": false,
  "error": {
    "code": "INVALID_STATE",
    "message": "Can only cancel running or pending runs"
  }
}

Retry Run

Retry a failed workflow run from the first failed step. The original input is preserved.

POST /api/v1/runs/:id/retry

Retriable States

StatusRetriable
pendingNo
runningNo
completedNo
failedYes
timeoutYes
cancelledNo

Response (202 Accepted)

{
  "success": true,
  "data": {
    "originalRunId": "run_550e8400-e29b-41d4-a716-446655440000",
    "newRunId": "run_770e8400-e29b-41d4-a716-446655440002",
    "workflowId": "wf_xxx",
    "restartFromStepId": "sync-to-crm",
    "status": "pending",
    "createdAt": "2024-01-15T10:35:00.000Z"
  }
}

Error Response (Invalid State)

{
  "success": false,
  "error": {
    "code": "INVALID_STATE",
    "message": "Can only retry failed runs"
  }
}

Restart Run

Restart a failed or completed run from a specific step. This enables "time travel" debugging - you can re-execute from any step while preserving outputs from previous steps.

POST /api/v1/runs/:id/restart

Request Body

{
  "fromStepId": "sync-to-crm",
  "overrideInput": {
    "retryCount": 1
  }
}
FieldTypeRequiredDescription
fromStepIdstringYesStep ID to restart from (inclusive)
overrideInputobjectNoOverride/merge input fields

Restartable States

StatusRestartable
pendingNo
runningNo
completedYes
failedYes
timeoutYes
cancelledNo

Response (202 Accepted)

{
  "success": true,
  "data": {
    "originalRunId": "run_550e8400-e29b-41d4-a716-446655440000",
    "newRunId": "run_880e8400-e29b-41d4-a716-446655440003",
    "workflowId": "wf_xxx",
    "restartFromStepId": "sync-to-crm",
    "status": "pending",
    "createdAt": "2024-01-15T10:40:00.000Z"
  }
}

How It Works

  1. Creates new run linked to the original via restartedFromRunId
  2. Preserves step outputs from steps before the restart point
  3. Executes from specified step with hydrated context
  4. Supports input override to test with modified data

Example: Debug a Failed Step

# Get the failed run to see which step failed
curl -X GET "http://localhost:3000/api/v1/runs/run_xxx" \
  -H "x-api-key: YOUR_API_KEY"
 
# Restart from the failed step with corrected input
curl -X POST "http://localhost:3000/api/v1/runs/run_xxx/restart" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fromStepId": "sync-to-crm",
    "overrideInput": {
      "apiEndpoint": "https://api.salesforce.com/v2"
    }
  }'

Error Response (Invalid Step)

{
  "success": false,
  "error": {
    "code": "INVALID_STEP",
    "message": "Step not found: invalid-step-id"
  }
}

Run Statuses

StatusDescription
pendingQueued for execution, waiting to start
runningCurrently executing steps
completedAll steps completed successfully
failedExecution stopped due to an error
cancelledManually cancelled by user
suspendedWaiting for external input (e.g., approval)

Trigger Types

TypeDescription
apiTriggered via API call
webhookTriggered by webhook event
scheduleTriggered by schedule
manualTriggered manually (e.g., via UI)

Polling for Completion

To wait for a run to complete, poll the GET endpoint:

async function waitForCompletion(runId, timeoutMs = 60000) {
  const startTime = Date.now();
 
  while (Date.now() - startTime < timeoutMs) {
    const response = await fetch(
      `http://localhost:3000/api/v1/runs/${runId}`,
      { headers: { 'x-api-key': API_KEY } }
    );
 
    const { data } = await response.json();
 
    if (data.status === 'completed') {
      return data.output;
    }
 
    if (data.status === 'failed') {
      throw new Error(data.error?.message || 'Workflow failed');
    }
 
    if (data.status === 'cancelled') {
      throw new Error('Workflow was cancelled');
    }
 
    // Wait 1 second before polling again
    await new Promise(resolve => setTimeout(resolve, 1000));
  }
 
  throw new Error('Timeout waiting for workflow completion');
}

Error Responses

Run Not Found (404)

{
  "success": false,
  "error": {
    "code": "NOT_FOUND",
    "message": "Run not found"
  }
}

Invalid State (400)

{
  "success": false,
  "error": {
    "code": "INVALID_STATE",
    "message": "Can only cancel running or pending runs"
  }
}