Skip to content
Get started
Guides

Tasks

Run, stream, and continue tasks against a Handinger worker.

A task is one run of a worker. Each task has a chronological list of turns — one per user message and the agent’s reply. Tasks store the full conversation, attached files, sources, and usage metrics, so you can return to them later or hand them off across services.

This guide covers running new tasks, continuing existing ones, streaming live output, and the supporting operations (retrieve, archive).

The minimum required parameters are workerId (the template to run) and input (the user message). The call blocks until the worker finishes and returns a Worker object reflecting the final state.

import Handinger from '@ramensoft/handinger';
const client = new Handinger({
apiKey: process.env['HANDINGER_API_KEY'], // This is the default and can be omitted
});
const worker = await client.tasks.create({
input: "What's the weather today in Barcelona?",
workerId: 'wrk_vk81XUHKHG-qr4',
});
console.log(worker.id);

The budget parameter controls how aggressively the worker spends to complete the task. Higher budgets unlock more tool calls and longer reasoning, but cost more credits.

BudgetWhen to use it
lowQuick lookups and classification — typically a single tool call.
standardDefault. Balanced research with a handful of tool calls.
highMulti-step research, comparison, or extraction across many sources.
unlimitedLong-running, exhaustive jobs. Use with care — there is no spend cap.

Pass budget: 'high' (or the level you want) alongside workerId and input in the call shown above.

Reuse a prior taskId to add a follow-up turn instead of starting a new task. The worker keeps full conversation history, any attached files, and the cached state of external tools.

There is no separate “continue” endpoint — POST /api/tasks is the single entry point. Adding taskId to the request above is what tells Handinger to append a turn rather than start a fresh task.

You can also send a taskId for a task that does not exist yet — Handinger will create the task with that id. This is the recommended pattern when you want to correlate Handinger tasks with rows in your own database without a second round-trip. Generate a ULID (or any unique string) on your side, insert your own row, and pass the same id as taskId when you call tasks.create.

For long-running tasks, prefer streaming so your UI can render token-by-token. The API returns Server-Sent Events when either:

  • You send stream: true in the request body, or
  • You set the Accept header to text/event-stream.

Each event is a structured chunk of the agent’s output (text deltas, tool calls, source citations, file outputs, and a final done marker). Each SDK exposes the stream idiomatically (async iterators in TypeScript and Python, channels in Go, etc.) — see the SDK reference for the exact iteration pattern.

Send the request as multipart/form-data to attach files. Up to 5 files per request, 10 MB per file, and 30 MB total. The bytes are bootstrapped into the worker’s workspace before the task starts and remain available for follow-up turns.

Each SDK accepts file inputs in its native form (e.g. ReadStream in TypeScript, file objects in Python, io.Reader in Go); the SDK switches the request to multipart/form-data automatically when files are present.

GET /api/tasks/{taskId} returns the task metadata plus every turn the worker has recorded — useful for backfilling history into your own UI, or for asynchronously collecting the result of a fire-and-forget task.

import Handinger from '@ramensoft/handinger';
const client = new Handinger({
apiKey: process.env['HANDINGER_API_KEY'], // This is the default and can be omitted
});
const taskWithTurns = await client.tasks.retrieve('tsk_01HZY31W2SZJ8MJ2FQTR3M1K9D');
console.log(taskWithTurns.task);

DELETE /api/tasks/{taskId} archives a task so it stops appearing in GET /api/tasks listings. Turns and files are retained for audit purposes — archiving is a soft delete that hides the task from default views. Only the worker creator can archive a task.

import Handinger from '@ramensoft/handinger';
const client = new Handinger({
apiKey: process.env['HANDINGER_API_KEY'], // This is the default and can be omitted
});
const deleteTaskResponse = await client.tasks.delete('tsk_01HZY31W2SZJ8MJ2FQTR3M1K9D');
console.log(deleteTaskResponse.archived);

Every task carries a status and a triggeredBy value:

FieldValuesNotes
statuspending, running, completed, error, abortedNon-streaming responses only return after the task is completed, error, or aborted.
triggeredByapi, ui, email, scheduleAPI key calls are logged as api; web dashboard usage is ui. Use this to filter audit logs.

402 Payment Required Your organization is out of billing credits. Top up in the dashboard or downgrade the task budget.

403 Forbidden on a taskId from another worker A task belongs to exactly one worker. Make sure the workerId you send matches the worker the original task was created against, or omit taskId to start fresh.

The stream stops without a done event Most likely a network proxy is buffering the SSE response. Pass Cache-Control: no-cache and disable HTTP/1.1 keep-alive buffering on your proxy. Use curl -N for raw debugging.