Base URL
All API requests are made to:
https://steelengine.comQuick 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"
}| Status | Meaning | What to do |
|---|---|---|
400 | Invalid request parameters | Check the details array for specific field errors. code: "INVALID_SELECTED_OUTPUT" means a selectedOutputs entry names no existing block or field |
401 | Missing or invalid API key | Verify your X-API-Key header |
402 | Usage limit exceeded | The billed account has spent its budget for the period. Check Get Usage Limits for the current spend and limit |
403 | Access denied | Check you have permission for this resource and that the key's scope covers it |
404 | Resource not found | Verify the ID exists and belongs to your workspace |
409 | Conflict | The workflow call chain is invalid, or the workflow's environment promotion binding rejected the run |
429 | Rate limit exceeded | Back off and retry; see Rate Limits for which responses carry Retry-After |
503 | Result unavailable | The 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.