Meet the Lodol Developer API
Lodol runs your workflows. The Developer API lets your own software run them too. With an API key and a few lines of code, your systems can list the workflows in a workspace, start a run, follow it while it works, and stop it if they need to. The automations you built in Lodol become callable steps in the rest of your stack.
This post walks through the parts you touch first: authentication, running a workflow, and tracking an execution. Then it covers the two things that decide whether an integration holds up in production, idempotency and rate limits. The full endpoint reference lives at docs.lodol.com.
Authentication
Every request authenticates with an API key. You create keys in your workspace settings, where you name each one, grant it a set of scopes, and set an optional expiration. A key is shown once when you generate it and stored only as a hash, so copy it somewhere safe at that moment. If a key is ever exposed, revoke it from the same screen and its access ends immediately.
Scopes decide what a key can do. There are three:
| Scope | Grants |
|---|---|
workflows:read | List and read workflows |
workflows:execute | Start and stop runs |
executions:read | List and read executions |
Send the key as a bearer token on every request. Keys begin with sk_live_.
curl https://api-prod.lodol.com/api/v1/workflows \
-H "Authorization: Bearer sk_live_..."
A missing or malformed Authorization header returns 401. A valid key that lacks the scope a route requires returns 403.
The Python SDK
If you work in Python, the SDK is the quickest way to start. Install it, create a client with your key, and the resources line up with the REST API. Workflows come back as typed objects rather than raw dictionaries.
pip install lodol
from lodol import Lodol
client = Lodol(api_key="sk_live_...")
for workflow in client.workflows.list():
print(workflow.id, workflow.name)
The workspace is taken from the key, so you never pass a team or account ID. Listing workflows is a plain GET /api/v1/workflows under the hood, and every field on the returned object is a field the endpoint sends back.
Running a workflow
Runs are asynchronous. A workflow might finish in two seconds or take several minutes, so rather than hold a connection open, the API accepts the run and hands you an execution ID to follow. You start a run by its workflow ID.
execution = client.workflows.run("665f1a2b9c4d3e2f1a0b8c7d")
print(execution.id, execution.status) # 6690b3d5c1e4f2a7b8d9e0f1 queued
The same call over REST is a POST to the run endpoint. It takes no request body: the workflow runs as it is published, pulling from the sources it is already configured to use.
curl -X POST \
https://api-prod.lodol.com/api/v1/workflows/665f1a2b9c4d3e2f1a0b8c7d/run-async \
-H "Authorization: Bearer sk_live_..."
The endpoint responds with 202 Accepted and the new execution:
{
"execution_id": "6690b3d5c1e4f2a7b8d9e0f1",
"workflow_id": "665f1a2b9c4d3e2f1a0b8c7d",
"status": "queued",
"created_at": "2026-05-08T14:32:10.512000+00:00"
}
Starting a run needs the workflows:execute scope.
Tracking an execution
Once a run is going, you read its status. The SDK can block until the run reaches a terminal state and hand you the result, which is usually what you want:
result = client.executions.wait(execution.id, timeout=120)
if result.status == "success":
print(result.steps)
elif result.status == "failed":
print("run failed:", result.error)
You can also read an execution directly at any time:
curl https://api-prod.lodol.com/api/v1/executions/6690b3d5c1e4f2a7b8d9e0f1 \
-H "Authorization: Bearer sk_live_..."
An execution starts queued, moves to running, and ends in one of success, failed, or stopped. Workflows that hand off to a person sit in paused, awaiting_review, or awaiting_input until someone acts. Add ?include_step_results=true to a read to see the output of each step. To stop a run in progress, POST to /api/v1/executions/{id}/stop.
To page through past runs, call GET /api/v1/executions. It uses cursor pagination: pass the ID of the last execution you saw as after to get the next page, and set workflow_id to narrow the list to a single workflow. Pages default to 20 executions and cap at 100.
Idempotency
Networks fail in an inconvenient way. Sometimes a request reaches the server and does its work, but the response never makes it back to you. Now you cannot tell whether the run started. Retry and you might start it twice. For a workflow that pays a vendor, running twice is a real cost, not a hypothetical one.
Attach an idempotency key to a run or stop request and retries become safe. Send the same key more than once and Lodol runs the workflow a single time.
execution = client.workflows.run(
"665f1a2b9c4d3e2f1a0b8c7d",
idempotency_key="invoice-8842",
)
Over REST, the key travels in the Idempotency-Key header:
curl -X POST \
https://api-prod.lodol.com/api/v1/workflows/665f1a2b9c4d3e2f1a0b8c7d/run-async \
-H "Authorization: Bearer sk_live_..." \
-H "Idempotency-Key: invoice-8842"
The first request runs, and Lodol caches its response for 24 hours. A later request with the same key returns that stored response and adds the header X-Idempotent-Replayed: true, without starting a second run. If the original request is still in flight when the retry lands, you get a 409 with a Retry-After header, so you know to wait a moment and try again. Keys are scoped to your workspace, so you are free to reuse a natural identifier from your own data, like an invoice number or an order ID.
Rate limits and concurrency
Two limits apply, both per workspace and both set by your plan.
The first is a request rate limit, measured per minute and shared across every key in the workspace, so adding keys does not raise your ceiling. Each response reports where you stand:
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 118
X-RateLimit-Reset: 42
Go over the limit and the request returns 429 with a Retry-After value in seconds. The numbers above are illustrative; the ones you get depend on your plan.
The second limit caps how many executions run at once. Start more than your plan allows and the run endpoint returns 429 with a message naming your concurrent limit. A finished run frees its slot, so the cap is on simultaneous work rather than total volume.
When you hit either limit, the SDK raises an error carrying the wait time, which keeps a backoff loop to a few lines:
import time
from lodol import RateLimitError
try:
client.workflows.run("665f1a2b9c4d3e2f1a0b8c7d")
except RateLimitError as exc:
time.sleep(float(exc.retry_after or 1))
# then retry
Errors
Errors use standard HTTP status codes with a JSON body. The body always carries an error message, and some responses add a stable error_code you can branch on.
{
"error": "API key lacks required scope(s)"
}
| Status | Meaning |
|---|---|
400 | The request was malformed, for example a bad cursor or limit value |
401 | The API key is missing, malformed, invalid, or expired |
402 | The workspace is out of credits |
403 | The key is missing a scope the route requires |
404 | No workflow or execution with that ID exists in your workspace |
409 | A request with the same idempotency key is still being processed |
429 | A rate limit or the concurrency limit was reached |
Getting started.
Generate a key in your workspace settings, run pip install lodol, and you can list workflows and start runs from your own systems in a few minutes. The complete reference, with every endpoint, field, and query parameter, is at docs.lodol.com.

