Create and read Tasks

The create request, attaching files, the read response, and what each status means.

Create a Task

bash
curl -sS https://tycoon.us/api/public/tasks \
  -H "Authorization: Bearer $TYCOON_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: organic-growth-2026-08-01" \
  -d '{
    "prompt": "Improve organic growth through durable, evidence-backed work.",
    "title": "Organic-growth outcome",
    "workspace_id": "<bound-growth-workspace-id>",
    "budget_usd": 250,
    "working_guidance": "Prefer reversible SEO experiments and concise weekly updates.",
    "playbook_id": "<existing-company-skill-id>",
    "outcome": {
      "target": "Increase qualified organic clicks by 305% from the measured baseline.",
      "deadline_at": "2026-11-01T00:00:00.000Z",
      "metric_id": "<existing-workspace-metric-id>"
    }
  }'

First response (201):

json
{
  "task": {
    "id": "cm...",
    "title": "Competitor research",
    "status": "queued",
    "created_at": "2026-08-01T12:00:00.000Z"
  },
  "workspace": {
    "id": "cm...",
    "name": "Growth",
    "slug": "growth",
    "task_bound": false
  },
  "idempotent_replay": false
}

prompt is required and limited to 20,000 characters. title (200 characters), workspace_id, and budget_usd (at most 100,000) are optional. Omitting workspace_id creates an isolated task-bound workspace; specifying it requires either the API key's controller workspace or a currently valid explicit binding. Omitting budget_usd means no per-Task ceiling; it does not make workspace usage free.

The response's workspace is the immutable execution home for that Task. A later request may use a different or newly created workspace, but no API call can migrate an existing Task. The key controller workspace remains the payer for every one of those Tasks and their direct child contributions.

The optional durable-outcome fields — outcome, working_guidance, and playbook_id — are described under Long-running outcomes.

skill is the more explicit Skill input. Send either skill.id (an existing Company Skill in the execution workspace) or a Markdown-only skill.upload:

json
"skill": {
  "upload": {
    "name": "SEO experiment method",
    "description": "Customer-supplied operating method for this one Task.",
    "markdown": "# Method\n1. Establish the baseline...",
    "tags": ["seo", "experiment"]
  }
}

Tycoon creates an Tycoon Agent-private Skill in that Task's execution workspace and pins its first revision to the Task. The upload has no file, connector, secret, workspace-sharing, or standing Skill-management authority. playbook_id and skill are mutually exclusive.

Add runtime to an ordinary-key request using the runtime catalog receipt above. Add callback to receive events only for this Task, or cadence to create an existing Routine-backed follow-up for this long-horizon outcome:

json
{
  "callback": {
    "url": "https://customer.example/hooks/organic-growth",
    "events": ["task.check_in", "task.requires_action", "task.done"],
    "secret": "a-customer-secret-with-at-least-16-characters"
  },
  "cadence": {
    "cron": "0 9 * * 1",
    "timezone": "America/Los_Angeles",
    "title": "Weekly organic-growth follow-up"
  }
}

The callback secret is accepted for delivery signing but never returned or included in a Task projection. cadence uses a five-field cron expression and the existing Routine owner; it is not a public scheduler or a second Task lifecycle. A published-method customer may supply a callback, but cannot pick a cadence.

Attach files the work must read

A Task often depends on something the customer already has: a brief, a spreadsheet, a design, a transcript, last quarter's report. Send the bytes first, then create the Task that references them.

Bytes never travel through the create request. POST /uploads returns a signed URL you PUT the file to directly, so an attachment is bounded by the 200 MB object-storage limit rather than by the platform's 32 MiB inbound request limit. The hash you claim is not trusted: finalize re-reads the stored object and verifies size and sha256 before the file exists as far as the API is concerned.

bash
# 1. Ask where to put it. sha256 is the hex digest of the file's bytes.
curl -sS https://tycoon.us/api/public/uploads \
  -H "Authorization: Bearer $TYCOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"q3-brief.pdf","mime_type":"application/pdf","byte_size":184320,"sha256":"<hex>"}'
# → {"status":"upload","uploadUrl":"https://…","headers":{…},"expiresAt":"…"}
#   {"status":"exists","asset":{…}}      already stored — skip to step 3
#   {"status":"needs-finalize"}          bytes are there, finalize them

# 2. PUT the bytes with EXACTLY the headers you were given.
curl -sS -X PUT "$UPLOAD_URL" -H "Content-Type: application/pdf" --data-binary @q3-brief.pdf

# 3. Register it. Returns the asset id you reference when creating the Task.
curl -sS https://tycoon.us/api/public/uploads/finalize \
  -H "Authorization: Bearer $TYCOON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"q3-brief.pdf","mime_type":"application/pdf","byte_size":184320,"sha256":"<hex>"}'
# → 201 {"asset":{"id":"cxxx","name":"q3-brief.pdf", …}}

Then reference the ids on create, up to 20 per Task:

json
{
  "prompt": "Turn the attached brief into a launch plan.",
  "attachments": [{ "asset_id": "cxxx" }]
}

Both upload endpoints use the tasks:write scope — an attachment exists to feed a Task, and no separate grant stands between a key and its own input.

What the worker sees. The Task's brief lists every attachment by id, name, size and type, and names the commands that open them. A Task created with a file it cannot read must say so in its result rather than quietly producing an outcome that ignored the customer's input.

Which workspace the file lands in. The asset is created in the key's own workspace. When the Task executes somewhere else — the isolated task-bound workspace a create without workspace_id mints, or a bound workspace — the same stored object is registered in that workspace too, so the worker can read it. The bytes are stored once; only the reference is duplicated.

Errors. 404 attachment_not_found — the id does not exist, or belongs to a workspace this key does not control; the two are deliberately indistinguishable. 409 blob_missing | size_mismatch | hash_mismatch — finalize verified the stored object and it did not match what you declared.

Read status, result, and usage

bash
curl -sS https://tycoon.us/api/public/tasks/cm... \
  -H "Authorization: Bearer $TYCOON_API_KEY"
json
{
  "task": {
    "id": "cm...",
    "reference": "acme-42",
    "title": "Competitor research",
    "status": "completed",
    "created_at": "2026-08-01T12:00:00.000Z",
    "started_at": "2026-08-01T12:00:03.000Z",
    "completed_at": "2026-08-01T12:04:21.000Z",
    "updated_at": "2026-08-01T12:04:21.000Z"
  },
  "outcome": {
    "updated_at": "2026-08-01T12:04:21.000Z",
    "summary": "The experiment is live and the next weekly observation is scheduled.",
    "judgment": "unmet",
    "trajectory": "on-track",
    "remaining_gap": "The target lift is not yet proven.",
    "next": {
      "kind": "wait",
      "label": "Observe the weekly Metric sample",
      "at": "2026-08-08T12:00:00.000Z",
      "wait_for": "routine observation"
    },
    "measure": {
      "title": "Qualified organic clicks",
      "unit": "clicks",
      "current_value": 125,
      "baseline_value": 100,
      "baseline_at": "2026-08-01T12:00:00.000Z",
      "target_value": null,
      "last_synced_at": "2026-08-01T12:00:00.000Z"
    },
    "cadences": [{
      "purpose": "measurement",
      "status": "active",
      "cadence": "weekly",
      "next_run_at": "2026-08-08T12:00:00.000Z",
      "health": "healthy"
    }]
  },
  "playbook": {
    "id": "<existing-company-skill-id>",
    "revision": "<pinned-skill-revision-id>",
    "name": "Growth operating method"
  },
  "result": {
    "text": "...",
    "created_at": "2026-08-01T12:04:20.000Z"
  },
  "required_actions": [],
  "usage": {
    "input_tokens": 12340,
    "output_tokens": 1870,
    "cached_input_tokens": 4200,
    "cost_usd_micros": "482000",
    "cost_usd": 0.482,
    "ledger_entries": 3,
    "wallet_debit_applied": true,
    "budget_usd_micros": "25000000"
  },
  "poll_after_ms": null
}

Statuses are queued, running, requires_action, waiting, completed, or canceled. Before a terminal state, honor poll_after_ms. If required_actions is non-empty, read its id, action_version, safe items, and api_resolvable flag, then follow Resolve a required action from your backend.

The response deliberately omits workspace memory, system prompts, model reasoning, agent/pod/run identities, child execution traces, and raw Task metadata. Usage includes the API root and any direct child Tasks Tycoon Agent used to complete it, so delegated work is not silently under-counted.

For a completed Success-Brief Task, result.text is the accepted result summary from the exact current Task.currentAcceptedEvaluationId, projected through the same communication snapshot used by Tasks and Tycoon Agent. Plain and historical Tasks fall back to the durable close Comment selected by TaskResult.closeCommentId. A later Comment, stale evaluation, or invalid/cross-Task pointer cannot silently replace the published result.

Pause, resume, or cancel a Task

Use the canonical lifecycle control adapter when the customer needs to stop or resume work. It requires tasks:write and an Idempotency-Key.

bash
curl -sS -X POST https://tycoon.us/api/public/tasks/cm.../control \
  -H "Authorization: Bearer $TYCOON_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: organic-growth-pause-1" \
  -d '{"action":"pause"}'

Actions are pause, resume, and cancel. Pause/resume use the existing archive/restore fence; cancel uses the existing Task end owner, terminal notification, timing, and dependent-Task wake path. There is no API-only Task status. A same-body replay returns the same accepted response with idempotent_replay: true.

Next steps

這篇文章對你有幫助嗎?