Quickstart: start a run with the API
This guide starts a run of the ready-made Hello Lantfly actor (lantfly~hello), waits for it, and reads its
results. The same three calls work for any actor.
You need a Lantfly account with a verified email. If you do not have one yet, follow the first two steps of the Console quickstart.
1. Create an API token
- In the Console, open Settings → API & integrations.
- In the token form, enter a Name (for example
quickstart) and, if you like, Expires in (days). - Leave Read-only off: starting a run is a write. You can also limit the token to some actors or to some permissions; see API tokens.
- Click Create token and copy the token. It is shown once. Lantfly keeps only a hash of it, so if you lose it you create a new one.
Keep it in an environment variable:
export LANTFLY_TOKEN="paste-your-token-here"
Every request sends it in the Authorization header:
Authorization: Bearer $LANTFLY_TOKEN
A token acts for your account and can start paid runs. Keep it out of source control and front-end code. Revoke it in Settings → API & integrations if it leaks.
2. Start a run and wait for it
POST /api/v3/actors/:actor/runs starts a run. The actor can be named by its ID or its slug (lantfly~hello).
The body has the input for the actor and optional options. wait_for_finish (0 to 60 seconds) keeps the request
open until the run finishes or the time is up.
- curl
- Node
- Python
curl -s -X POST "https://lantfly.com/api/v3/actors/lantfly~hello/runs" \
-H "Authorization: Bearer $LANTFLY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"input": { "message": "Hello from the API", "count": 5 },
"options": { "memory_mb": 256, "timeout_secs": 120 },
"wait_for_finish": 60
}'
const API = 'https://lantfly.com/api/v3';
const headers = {
Authorization: `Bearer ${process.env.LANTFLY_TOKEN}`,
'Content-Type': 'application/json',
};
const res = await fetch(`${API}/actors/lantfly~hello/runs`, {
method: 'POST',
headers,
body: JSON.stringify({
input: { message: 'Hello from the API', count: 5 },
options: { memory_mb: 256, timeout_secs: 120 },
wait_for_finish: 60,
}),
});
const body = await res.json();
if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message}`);
const run = body.data;
console.log(run.id, run.status, run.default_dataset_id);
import os
import requests
API = "https://lantfly.com/api/v3"
headers = {"Authorization": f"Bearer {os.environ['LANTFLY_TOKEN']}"}
res = requests.post(
f"{API}/actors/lantfly~hello/runs",
headers=headers,
json={
"input": {"message": "Hello from the API", "count": 5},
"options": {"memory_mb": 256, "timeout_secs": 120},
"wait_for_finish": 60,
},
timeout=90,
)
body = res.json()
if not res.ok:
raise RuntimeError(f"{body['error']['code']}: {body['error']['message']}")
run = body["data"]
print(run["id"], run["status"], run["default_dataset_id"])
The answer is 201 Created with the run in data:
{
"data": {
"id": "9b1f6c1e-6a4e-4b7f-9d3a-2f0c5d7e8a11",
"actor_id": "…",
"status": "SUCCEEDED",
"origin": "API",
"default_dataset_id": "…",
"default_key_value_store_id": "…",
"default_request_queue_id": "…",
"stats": { "run_time_secs": 4.2, "compute_units": 0.0003, "result_count": 5 },
"usage_total_usd": 0.0001,
"started_at": "2026-11-03T08:00:01.123Z",
"finished_at": "2026-11-03T08:00:05.321Z"
}
}
If the run is still READY or RUNNING when wait_for_finish runs out, the answer comes back anyway with the current
status. Poll GET /api/v3/runs/:run until the status is one of SUCCEEDED, FAILED, TIMED-OUT or ABORTED:
- curl
- Node
- Python
curl -s "https://lantfly.com/api/v3/runs/$RUN_ID" \
-H "Authorization: Bearer $LANTFLY_TOKEN"
const finished = ['SUCCEEDED', 'FAILED', 'TIMED-OUT', 'ABORTED'];
let current = run;
while (!finished.includes(current.status)) {
await new Promise((r) => setTimeout(r, 5000));
const res = await fetch(`${API}/runs/${current.id}`, { headers });
current = (await res.json()).data;
}
console.log('Finished with', current.status);
import time
finished = {"SUCCEEDED", "FAILED", "TIMED-OUT", "ABORTED"}
while run["status"] not in finished:
time.sleep(5)
run = requests.get(f"{API}/runs/{run['id']}", headers=headers, timeout=30).json()["data"]
print("Finished with", run["status"])
For long runs, skip polling: pass webhooks when you start the run, or set up a webhook,
and Lantfly calls your URL when the run ends.
3. Fetch the dataset items
The results are in the run's default dataset. GET /api/v3/datasets/:dataset/items returns them as JSON by default,
with offset and limit for paging. Add format=csv (or jsonl, xlsx, html, xml, rss) for a file.
- curl
- Node
- Python
curl -s "https://lantfly.com/api/v3/datasets/$DATASET_ID/items?limit=100" \
-H "Authorization: Bearer $LANTFLY_TOKEN"
# The same items as a CSV file
curl -s "https://lantfly.com/api/v3/datasets/$DATASET_ID/items?format=csv" \
-H "Authorization: Bearer $LANTFLY_TOKEN" -o results.csv
const items = await fetch(
`${API}/datasets/${current.default_dataset_id}/items?limit=100`,
{ headers },
).then((r) => r.json());
console.log(items.meta.total, 'items');
for (const item of items.data) console.log(item);
items = requests.get(
f"{API}/datasets/{run['default_dataset_id']}/items",
headers=headers,
params={"limit": 100},
timeout=30,
).json()
print(items["meta"]["total"], "items")
for item in items["data"]:
print(item)
{
"data": [
{ "index": 1, "message": "Hello from the API", "at": "2026-11-03T08:00:02.000Z" },
{ "index": 2, "message": "Hello from the API", "at": "2026-11-03T08:00:02.010Z" }
],
"meta": { "total": 5, "offset": 0, "limit": 100, "count": 5, "desc": false }
}
When a run is refused
Errors always have the shape { "error": { "code": "…", "message": "…" } }. The ones you are most likely to meet when
starting runs:
| Status | code | What to do |
|---|---|---|
401 | unauthenticated | The token is missing, wrong or revoked. |
403 | email_not_verified | Verify the email of the account owner. |
402 | not_enough_usage_to_run_paid_actor | Your plan usage and credit are used up. Buy credit or change plan in Billing. |
422 | validation_failed | The input does not match the actor's input schema; error.fields says which field. |
429 | concurrent_runs_limit_exceeded | Too many runs are waiting or running for your plan. Wait for some to finish. |
See Errors for the full list.
Next steps
- Runs: statuses, logs, abort, resurrect and limits.
- Datasets: formats, fields, pagination and public links.
- Idempotency: retry
POSTrequests safely withIdempotency-Key. - API reference