Skip to content
Get API Key

Get started

Quickstart

Make a key and a worker, give the worker a task, and read the result, in about five minutes.

Updated
View as Markdown

This guide gives a worker its first task from your own code. You make a key, make a worker, give it a task, follow it until the worker stops, and read what it wrote.

Each step shows curl, TypeScript and Python. Pick one and the page keeps it picked. The TypeScript and Python steps build one small program, so add each step's code to the same file.

Before you start

  • A Little Worker account. Sign up free at thelittleworker.com.
  • For curl: curl, and jq to read JSON in step 5.
  • For TypeScript: Node 22.18 or later, which runs a .ts file as it is. Save the program as quickstart.ts and run node quickstart.ts.
  • For Python: Python 3 and the requests library (pip install requests). Save the program as quickstart.py and run python3 quickstart.py.

Step 1: Make a key

Sign in at app.thelittleworker.com, open Settings, then API Keys, and choose Create Key. Name it after your program, leave Can allow actions off, and choose Create. Copy the key: it is shown once.

Keep it in your shell, where the examples read it:

Shell
export LITTLE_WORKER_API_KEY="lw_key_..."

A key acts as you, in your workspace, so anyone who has it can give your workers tasks. Keep it out of your code, and remove it in Settings when a program no longer needs it.

Step 2: Make a worker

A worker is who does the work. Give it a name and, in system, how it should work, in plain words. A worker you already have works too: GET /workers lists them.

curl https://core.thelittleworker.com/api/v1/workers \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{
    "name": "Copywriter",
    "system": "You write short, clear copy for a small shop. Answer with a numbered list."
  }'

The answer is the new worker. Its id is how every other call names it. A worker has more fields than this, such as its tools and its model; shortened, the answer is:

JSON
{
  "type": "worker",
  "id": "worker_bf5ff997fca044b38dc1cc9ea5b60100",
  "version": 1,
  "name": "Copywriter",
  "description": null,
  "system": "You write short, clear copy for a small shop. Answer with a numbered list.",
  "quality": "standard",
  "model_source": "quality",
  "status": "active",
  "archived_at": null,
  "created_at": "2026-10-25T22:06:53.046Z",
  "updated_at": "2026-10-25T22:06:53.046Z"
}

Left without a model, a worker uses the model its Quality picks. With curl, keep the id for the next steps:

Shell
export WORKER_ID="worker_bf5ff997fca044b38dc1cc9ea5b60100"

Step 3: Give it a task

A task is one piece of work by one worker. Say what you want in a user.message, the way you would say it to a person: what to do, and what done looks like. Sent in initial_events, the message starts the work as soon as the task is made.

curl https://core.thelittleworker.com/api/v1/tasks \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{
    "worker": "'"$WORKER_ID"'",
    "title": "Subject lines",
    "initial_events": [
      {
        "type": "user.message",
        "content": [{ "type": "text", "text": "Write three subject lines for an email that says the shop now opens at 7 am." }]
      }
    ]
  }'

The answer is 200 and the task. Its status is running. state says the same in the words the app shows: not_started for a moment, until the worker picks it up, and then working. Shortened, it is:

JSON
{
  "type": "task",
  "id": "task_01M5TTRJKWYAK3XHFX432K5MBV",
  "worker": {
    "type": "worker",
    "id": "worker_bf5ff997fca044b38dc1cc9ea5b60100",
    "version": 1,
    "name": "Copywriter"
  },
  "chat_id": "chat_d0605ba7bcba441384d781ea56d8bf04",
  "created_by": "person",
  "title": "Subject lines",
  "ask": "Write three subject lines for an email that says the shop now opens at 7 am.",
  "status": "running",
  "state": { "status": "not_started", "needs": null, "waiting_reason": null },
  "stop_reason": null,
  "result_summary": null,
  "sent_back_count": 0,
  "budget": {
    "type": "limit",
    "max_list_cost": { "amount": "500", "currency": "USD" }
  },
  "created_at": "2026-10-25T22:06:59.561Z",
  "updated_at": "2026-10-25T22:06:59.561Z"
}

Every task has a budget, the most its work may cost at list price. Left out, it is $5.00. A task made without initial_events waits as idle, and nothing runs until you send it a message (step 5 shows how).

The task is also in the app, in a new chat with the worker, so a person can follow it there too. With curl, keep its id:

Shell
export TASK_ID="task_01M5TTRJKWYAK3XHFX432K5MBV"

Step 4: Follow the work

The task is running until the worker stops, and then it is idle. The plainest way to know when it stops is to read the task every few seconds:

curl https://core.thelittleworker.com/api/v1/tasks/$TASK_ID \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19"

A task that is rescheduling is held by a plan or spending cap, and goes on by itself when there is room.

To see each step as it happens, follow the task's events instead. The answer stays open and sends each event as it comes, as Server-Sent Events. after=0 starts from the first event; without it, the stream sends only what happens after it opens.

Shell
curl -N "https://core.thelittleworker.com/api/v1/tasks/$TASK_ID/events/stream?after=0" \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19"
Text
id: 1
event: user.message
data: {"type":"user.message","sequence":"1","content":[{"type":"text","text":"Write three subject lines..."}],...}

id: 2
event: task.status_running
data: {"type":"task.status_running","sequence":"2",...}

id: 10
event: worker.message
data: {"type":"worker.message","sequence":"10","content":[{"type":"text","text":"1. Open at 7 am, starting Monday..."}],"sources":[],...}

id: 11
event: task.status_idle
data: {"type":"task.status_idle","sequence":"11","run_id":"run_488241351b7a4b528b8bf6df21c7b7a8","stop_reason":{"type":"end_turn"},"stop_details":null,...}

Other events come in between, such as worker.tool_use when the worker uses a tool and task.usage right before each stop. task.status_idle means the worker stopped, and its stop_reason says why: end_turn when its turn is over. The stream stays open after it, so stop curl with Ctrl+C. If the connection drops, connect again with the last id you saw in a Last-Event-ID header, and the stream sends only what came after it.

Step 5: Read the result

When state.status is done, result_summary holds one line about the result. The worker's full answer is its last worker.message event, as content blocks:

curl -s -g "https://core.thelittleworker.com/api/v1/tasks/$TASK_ID/events?types[]=worker.message&order=desc&limit=1" \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  | jq -r '.data[0].content[] | select(.type == "text") | .text'

types[] keeps only the events of that type, and order=desc lists the newest first. Without them, events come oldest first, up to 100 a page: follow next_page until it is null.

If the task is needs_you instead, state.needs says what it waits for:

state.needs What to do
allow The worker waits to take an action that asks first, and stop_reason is requires_action. Allow or deny it in the app. A key made with Can allow actions may answer too, with a user.approval event.
answer Read the worker's question, its last worker.message, and send your answer as a user.message event.
help The work failed, or it stopped at a limit, such as the task's budget. stop_reason says which. Read its last events, then send a message or give a new task.
look The worker's own check still found the work short. Accept it as it is with a user.accept event, or send it back.

A message goes to the task's events. A message to a task that is done opens it again, the same as sending it back.

Shell
curl https://core.thelittleworker.com/api/v1/tasks/$TASK_ID/events \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{ "events": [{ "type": "user.message", "content": [{ "type": "text", "text": "The shop is called Field Day." }] }] }'

Step 6: Send it back if it is not right

Finished work is done by itself: there is nothing to accept. If the result is not what you wanted, send it back with what to change, and the worker works on it again:

curl https://core.thelittleworker.com/api/v1/tasks/$TASK_ID/events \
  -H "x-api-key: $LITTLE_WORKER_API_KEY" \
  -H "Little-Worker-Version: 2026-10-19" \
  -H "content-type: application/json" \
  -d '{ "events": [{ "type": "user.send_back", "reason": "Make each one shorter than 40 characters." }] }'

The answer is 200, with one entry in data for the event you sent. Its task is running again, with state.status working and sent_back_count 1, and its run_id names the new stretch of work. Follow it as in step 4.

Next steps

  • Tasks reference: every field of a task, and the routes to list, read, change and take back tasks.
  • Overview: the main ideas, headers, errors and limits in one place.

Type a few words, like “give a task” or “errors”.