Getting Started

Base URL, first API call, response format, error handling, and pagination

Base URL

All API requests are made to:

https://steelengine.com

Quick Start

Get your API key

Go to the SteelEngine platform and navigate to Settings, then go to API Keys and click Create. See Authentication for details on key types.

Find your workflow ID

Open a workflow in the SteelEngine editor. The workflow ID is the last UUID in the URL:

https://steelengine.com/{orgSlug}/{workspaceSlug}/w/{workflowId}

The first segment after the host is your organization's slug, the second is your workspace's slug, and {workflowId} is the workflow's UUID. See Organizations and Workspaces for the slug rules.

You can also use the List Workflows endpoint to get all workflow IDs in a workspace.

Deploy your workflow

A workflow must be deployed before it can be executed via the API. Click the Deploy button in the editor toolbar, or use the dashboard to manage deployments.

Make your first request

The top-level fields of the request body are the workflow's input. Name them after the input fields defined on the workflow's Start block:

curl -X POST https://steelengine.com/api/workflows/{workflowId}/execute \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -d '{"message": "Hello"}'

You can also wrap the fields in a top-level input object. {"input": {"message": "Hello"}} reaches the workflow the same way. Send a plain string, number, or array as input. The fields stream, selectedOutputs, useDraftState, includeFileBase64, base64MaxBytes, and stopAfterBlockId are execution controls. SteelEngine never passes them to the workflow. See Execute Workflow for what each one does.

Sync vs Async Execution

By default, workflow executions are synchronous — the API blocks until the workflow completes and returns the result directly.

For long-running workflows, use asynchronous execution by sending the X-Execution-Mode: async header:

curl -X POST https://steelengine.com/api/workflows/{workflowId}/execute \
  -H "Content-Type: application/json" \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "X-Execution-Mode: async" \
  -d '{"message": "Hello"}'

This returns immediately (HTTP 202) with a jobId:

{
  "success": true,
  "async": true,
  "jobId": "exec_def456",
  "executionId": "exec_def456",
  "message": "Workflow execution queued",
  "statusUrl": "https://steelengine.com/api/jobs/exec_def456"
}

The jobId is the execution ID. Poll the Get Job Status endpoint until the status is completed, failed, or cancelled:

curl https://steelengine.com/api/jobs/{jobId} \
  -H "X-API-Key: YOUR_API_KEY"

Job status transitions follow: pending → processing → completed, failed, or cancelled. A run that is waiting for human input reports paused and is not finished. The output field is present once the run has a result.

On SteelEngine Cloud a run's execution record expires 7 days after it finishes. After that the endpoint answers from run history: the same status and times, metadata.source: "run-history", and the run-history copy of the output, which is size-capped and has secrets removed. Once run history is deleted, 30 days after the run finishes, the endpoint returns 404.

Async requests cannot carry the execution controls useDraftState, selectedOutputs, stopAfterBlockId, includeFileBase64, or base64MaxBytes. If they are present, the API returns 400.

A synchronous request can also return HTTP 202. This happens when the run was admitted but its result did not arrive in time. The body is then a pending receipt: {"success": true, "pending": true, "executionId": "...", "statusUrl": "..."}. The run is still going. Poll statusUrl. Sending the request again would start a second run.

You can also receive block outputs as they are produced. Set stream: true in the body. List the outputs in selectedOutputs as blockName.field, for example agent1.content. Send the X-SteelEngine-Stream-Version: 2 header. The response is a Server-Sent Events stream. See the TypeScript SDK for the frame format and a reader.

Response Format

A successful synchronous execution returns the execution result, marked with the X-SteelEngine-Response-Type: execution header:

{
  "success": true,
  "executionId": "exec_def456",
  "output": {
    "result": "Hello, world!"
  },
  "metadata": {
    "startTime": "2025-01-01T00:00:00.000Z",
    "endTime": "2025-01-01T00:00:01.250Z",
    "duration": 1250
  }
}

status is included when the engine reports one (success, failed, cancelled, or paused). A failed execution returns the same shape with success: false, an error message, and HTTP 500.

If the workflow ends in a Response block, the API returns the body, status code, and headers that block authored instead, and sets X-SteelEngine-Response-Type: response. Every execution response also carries the execution ID in the X-Execution-Id header.

Execution responses do not include rate limit or usage information. The /api/v1 workflows, logs, and audit logs endpoints attach a limits object with workflowExecutionRateLimit and usage. For everything else, call Get Usage Limits.

Error Handling

The API uses standard HTTP status codes. Error responses include a human-readable error message:

{
  "error": "Workflow not found"
}
StatusMeaningWhat to do
400Invalid request parametersCheck the details array for specific field errors. code: "INVALID_SELECTED_OUTPUT" means a selectedOutputs entry names no existing block or field
401Missing or invalid API keyVerify your X-API-Key header
402Usage limit exceededThe billed account has spent its budget for the period. Check Get Usage Limits for the current spend and limit
403Access deniedCheck you have permission for this resource and that the key's scope covers it
404Resource not foundVerify the ID exists and belongs to your workspace
409ConflictThe workflow call chain is invalid, or the workflow's environment promotion binding rejected the run
429Rate limit exceededBack off and retry; see Rate Limits for which responses carry Retry-After
503Result unavailableThe run was admitted but its result could not be recovered (code: "RESULT_UNAVAILABLE"). Poll the statusUrl in the body instead of resubmitting

Use the Get Usage Limits endpoint to check your current rate limit status and billing usage at any time.

Rate Limits

Rate limits depend on your subscription plan. Self-hosted deployments with billing disabled use the enterprise limits for every account: 600 sync, 5000 async, and 500 API endpoint requests per minute by default, with the sync and async limits overridable through RATE_LIMIT_ENTERPRISE_SYNC and RATE_LIMIT_ENTERPRISE_ASYNC. Your account has a sync bucket and an async bucket, both reported by Get Usage Limits as requestsPerMinute, maxBurst, remaining, and resetAt. The execute endpoint currently counts every API execution against the sync bucket, including requests sent with X-Execution-Mode: async.

When you are rate limited, the execute endpoint returns 429 with {"error": "Rate limit exceeded. Please try again later."}. This response has no Retry-After header. Back off and check resetAt from Get Usage Limits before you retry. A 429 that carries Retry-After: 5 means the server admission gate is at capacity, not that your bucket is empty.

The /api/v1 workflows, logs, and audit logs endpoints have their own per-key request limit. They report it in the X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Their 429 responses include Retry-After.

Pagination

List endpoints (workflows, logs, audit logs) use cursor-based pagination:

# First page
curl "https://steelengine.com/api/v1/logs?limit=20" \
  -H "X-API-Key: YOUR_API_KEY"

# Next page — use the nextCursor from the previous response
curl "https://steelengine.com/api/v1/logs?limit=20&cursor=abc123" \
  -H "X-API-Key: YOUR_API_KEY"

The response includes a nextCursor field. When nextCursor is absent or null, you have reached the last page.

On this page