> ## Agent Instructions > Autumn AI (autumn.ai) is a people and company intelligence API, a separate company from useautumn.com (billing software); no billing-product routes exist here. > Base URL https://api.autumn.ai. Auth on every request: `X-API-Key: ` or `Authorization: Bearer `. Plain HTTP + JSON. Schemas: https://www.autumn.ai/docs/openapi.json. Every docs page is Markdown at its URL plus `.md`. # Get credits Source: https://www.autumn.ai/docs/api-reference/credits/get-credits https://api.autumn.ai/openapi.json get /credits Credit balance. # Get a named output Source: https://www.autumn.ai/docs/api-reference/outputs/get-a-named-output https://api.autumn.ai/openapi.json get /task/{task_id}/outputs/{output_id} Rows from one named output. Page with limit and cursor: the body carries _next_cursor while rows remain. # Get task output Source: https://www.autumn.ai/docs/api-reference/outputs/get-task-output https://api.autumn.ai/openapi.json get /task/{task_id}/output Rows from the active output. Partial rows are readable during a run. Page with limit and cursor: the body carries _next_cursor while rows remain. # List task outputs Source: https://www.autumn.ai/docs/api-reference/outputs/list-task-outputs https://api.autumn.ai/openapi.json get /task/{task_id}/outputs The named output artifacts of a task. # Continue a task Source: https://www.autumn.ai/docs/api-reference/tasks/continue-a-task https://api.autumn.ai/openapi.json post /task/{task_id}/continue Send a message to the task. Queued (202) unless wait is true (200). # Continue a task and stream Source: https://www.autumn.ai/docs/api-reference/tasks/continue-a-task-and-stream https://api.autumn.ai/openapi.json post /task/{task_id}/continue/stream Send a message to the task and stream the turn. # Execute a task Source: https://www.autumn.ai/docs/api-reference/tasks/execute-a-task https://api.autumn.ai/openapi.json post /task/{task_id}/execute Produce output from the current spec. Queued (202) unless wait is true (200). # Execute a task and stream Source: https://www.autumn.ai/docs/api-reference/tasks/execute-a-task-and-stream https://api.autumn.ai/openapi.json post /task/{task_id}/execute/stream Produce output and stream the turn. # Get task metaprompt Source: https://www.autumn.ai/docs/api-reference/tasks/get-task-metaprompt https://api.autumn.ai/openapi.json get /task/metaprompt The task spec schema, output kinds, and metaprompt for caller-side agents. # Get task state Source: https://www.autumn.ai/docs/api-reference/tasks/get-task-state https://api.autumn.ai/openapi.json get /task/{task_id}/state Whether a turn is running and what is queued. This is the status_url on every task. # Get task status Source: https://www.autumn.ai/docs/api-reference/tasks/get-task-status https://api.autumn.ai/openapi.json get /task/{task_id} Status, spec and the last 100 events. Poll only without a stream; GET /task/{task_id}/state is cheaper. # Get task workflow Source: https://www.autumn.ai/docs/api-reference/tasks/get-task-workflow https://api.autumn.ai/openapi.json get /task/workflow The task workflow and route map. # List tasks Source: https://www.autumn.ai/docs/api-reference/tasks/list-tasks https://api.autumn.ai/openapi.json get /task Recent tasks, newest first. # Start a task Source: https://www.autumn.ai/docs/api-reference/tasks/start-a-task https://api.autumn.ai/openapi.json post /task Start a task from a prompt. Returns at once: store task_id, then stream or poll. Pass task_id to send the prompt to an existing task. # Start a task and stream Source: https://www.autumn.ai/docs/api-reference/tasks/start-a-task-and-stream https://api.autumn.ai/openapi.json post /task/stream Start a task from a prompt and stream the turn. # Start from a task spec Source: https://www.autumn.ai/docs/api-reference/tasks/start-from-a-task-spec https://api.autumn.ai/openapi.json post /task/start Start from a task.json spec with no planning turn. Without task, same as POST /task. # Start from a task spec and stream Source: https://www.autumn.ai/docs/api-reference/tasks/start-from-a-task-spec-and-stream https://api.autumn.ai/openapi.json post /task/start/stream Start from a task spec and stream the turn. # Stop a task Source: https://www.autumn.ai/docs/api-reference/tasks/stop-a-task https://api.autumn.ai/openapi.json post /task/{task_id}/stop Stop the turn, drop queued messages, return the task to plan. Outputs stay readable. # Stream task events Source: https://www.autumn.ai/docs/api-reference/tasks/stream-task-events https://api.autumn.ai/openapi.json get /task/{task_id}/stream Live events for a task. Resume with Last-Event-ID or after. # Create a draft task Source: https://www.autumn.ai/docs/api-reference/uploads/create-a-draft-task https://api.autumn.ai/openapi.json post /tasks/draft An empty task to attach uploads to. Start it with POST /task and its task_id. # Presign a file upload Source: https://www.autumn.ai/docs/api-reference/uploads/presign-a-file-upload https://api.autumn.ai/openapi.json post /upload-url Presign a .csv, .txt, .md or .markdown upload. PUT the bytes to upload_url with no auth headers, then POST /validate-upload. # Validate an uploaded file Source: https://www.autumn.ai/docs/api-reference/uploads/validate-an-uploaded-file https://api.autumn.ai/openapi.json post /validate-upload Validate an upload and return the filename for input_files. CSV becomes JSONL: delimiter detected, duplicate and blank headers renamed, extra cells kept as column_N, a user _row_id column becomes _row_id_2. # API overview Source: https://www.autumn.ai/docs/api-routes Base URL, authentication, request fields, and the full route map for the Task API. The Task API is the canonical HTTP surface for Autumn. Every task is backed by one sandbox and one agent. ```txt theme={"theme":{"light":"github-light","dark":"github-dark"}} https://api.autumn.ai ``` ## Authentication Pass your API key as either header: ```http theme={"theme":{"light":"github-light","dark":"github-dark"}} X-API-Key: YOUR_AUTUMN_API_KEY ``` ```http theme={"theme":{"light":"github-light","dark":"github-dark"}} Authorization: Bearer YOUR_AUTUMN_API_KEY ``` Create a key in Autumn settings under **API**. Use the full key you copied when creating it; the shortened key shown later in settings is for display only. Keep it in an environment variable rather than in source. ## Request fields | Field | Routes | Meaning | | ------------- | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `prompt` | `/task`, `/task/start` | Natural-language instruction. On `/task/start`, this is appended to `task.brief`. | | `task` | `/task/start` | `task.json`-style spec with `brief`, one optional `output`, inputs, and rules. The agent picks its own skills; any you send are ignored. | | `clarify` | `/task`, `/task/start` | Defaults to `false`. `false` still plans, but does not stop for a question. | | `output` | `/task`, `/task/start` | Optional output hint. Use `kind: "research"`, `"person"`, or `"company"` when your app already knows the desired shape. | | `input_files` | both | Task-local filenames or storage paths already available to Autumn. | | `version` | `/task`, `/task/start` | Model tier: `ranger` (default) or `scout`. Set at start only. | Keep `clarify: false` for automations. [Human in the loop](/docs/guides/human-in-the-loop) covers when the blocking question is worth it. ## Start from a prompt Use this when your app has natural language and wants Autumn to infer the task shape. ```bash Request theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Find 20 AI infrastructure startups hiring founding engineers.", "output": { "id": "ai-infra-startups", "kind": "research", "path": "outputs/ai-infra-startups.jsonl", "target_count": 20 }, "clarify": false }' ``` ```json Response theme={"theme":{"light":"github-light","dark":"github-dark"}} { "task_id": "8fab6f34", "status": "execute", "phase": "execute", "stream_url": "/task/8fab6f34/stream", "output_url": "/task/8fab6f34/output" } ``` ## Start from a task spec Use this when your app already knows the task shape. `prompt` is optional and is appended to the task brief before the agent starts. ```bash Request theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/start" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "task": { "brief": "Find 20 AI infrastructure startups hiring founding engineers.", "output": { "id": "ai-infra-startups", "kind": "research", "path": "outputs/ai-infra-startups.jsonl", "target_count": 20, "schema": { "title": { "type": "str" }, "notes": { "type": "str" }, "source_url": { "type": "url" }, "sources": { "type": "list[url]" } }, "schema_order": ["title", "notes", "source_url", "sources"] } }, "prompt": "Prioritize current founding engineer or early engineer roles.", "clarify": false }' ``` ```json Response theme={"theme":{"light":"github-light","dark":"github-dark"}} { "task_id": "8fab6f34", "status": "execute", "phase": "execute", "stream_url": "/task/8fab6f34/stream", "output_url": "/task/8fab6f34/output" } ``` With `clarify: true`, Autumn initializes the task in plan mode and can ask before execution. See [The task model](/docs/concepts/tasks) for how the two start modes differ. Use `GET /task/metaprompt` when another agent or app needs to generate a clean `task.json`-style spec before calling `/task/start`. ## Continue a task Send new instructions to the same sandboxed task: refinements, more rows, fixes, or follow-up constraints. ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/8fab6f34/continue" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "message": "Add founder LinkedIn URLs for every row, then continue until there are 25 rows." }' ``` Every route that advances a task has a streaming twin, with the same body and an SSE response. They are listed in the [route map](#route-map) below, and [Live messages](/docs/guides/streaming) covers the event names and SSE handling. ## Read status and output ```bash Status theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS "https://api.autumn.ai/task/8fab6f34" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` ```bash Output theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS "https://api.autumn.ai/task/8fab6f34/output?limit=100" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` ```bash List theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS "https://api.autumn.ai/task" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` Status responses include the task phase/status, credit usage, compatibility, and last event metadata; see [Task lifecycle](/docs/concepts/lifecycle) for reading them correctly. Output responses return rows from the active output file; see [Outputs and sources](/docs/concepts/outputs) for their shape. ## Stop Stop a task when the caller explicitly cancels it. The task returns to `plan`. ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/8fab6f34/stop" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` ## Route map | Method | Path | Use | | ------ | ------------------------------------- | --------------------------------------------------------- | | `POST` | `/task` | Start from a prompt. | | `POST` | `/task/stream` | Start from a prompt and stream the current turn. | | `POST` | `/task/start` | Start from a task spec plus optional prompt. | | `POST` | `/task/start/stream` | Start from a task spec and stream the current turn. | | `GET` | `/task` | List recent tasks. | | `GET` | `/task/{task_id}` | Read status and metadata. | | `GET` | `/task/{task_id}/stream` | Subscribe to live task events. | | `GET` | `/task/{task_id}/output` | Fetch output rows. | | `GET` | `/task/{task_id}/outputs` | List named output artifacts. | | `GET` | `/task/{task_id}/outputs/{output_id}` | Fetch rows for one output artifact. | | `POST` | `/task/{task_id}/continue` | Send another message to the same task. | | `POST` | `/task/{task_id}/continue/stream` | Continue and stream the current turn. | | `POST` | `/task/{task_id}/execute` | Ask the task to focus on output production. | | `POST` | `/task/{task_id}/execute/stream` | Execute and stream the current turn. | | `POST` | `/task/{task_id}/stop` | Stop a run and return the task to plan. | | `GET` | `/credits` | Check credits. | | `POST` | `/tasks/draft` | Create an empty task to attach uploads to. | | `POST` | `/upload-url` | Presign a `.csv`/`.txt`/`.md` upload for a task. | | `POST` | `/validate-upload` | Validate an uploaded file and get its `input_files` name. | ## Next Status codes and the ones worth designing around. Telling a finished task from one that has not started. # Errors Source: https://www.autumn.ai/docs/api/errors One error body. Branch on `error`. Retry when `retryable` is true. Every error has the same body. Branch on `error`. Show `message` to a person. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "error": "out_of_credits", "message": "Out of credits. Add credits at https://platform.autumn.ai (Settings > Usage), then send the request again. Retrying without credits fails the same way.", "retryable": false, "resolve": "https://platform.autumn.ai", "request_id": "req_3f9c2a1b0d4e5f6a7b8c" } ``` | Field | When | Meaning | | ------------------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------- | | `error` | always | Stable `snake_case` code. It does not change between releases. | | `message` | always | What went wrong and what to do next. | | `retryable` | always | `true`: the same request can succeed later. `false`: change the request, key, balance or id first. | | `request_id` | always | Also the `X-Request-ID` header. A client-sent `X-Request-ID` (1-64 characters from `A-Z a-z 0-9 _ . : -`) is echoed. Quote it to support. | | `retry_after` | `429`, `503` | Seconds to wait. Also the `Retry-After` header. | | `resolve` | `402` | Where to fix the cause. | | `param`, `detail` | `422` | The field that failed validation, and the validator output. | | `task_id`, `task_created` | some `4xx` | The task the error refers to. `task_created: false` on a refused `POST /task`: no task exists. | ## Codes | Status | `error` | `retryable` | What to do | | ------------ | -------------------------------------------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | | `400`, `422` | `invalid_request` | no | `422`: a field failed validation. Fix the field in `param`. `400`: the body is valid but Autumn rejects it. Read `message`. | | `401` | `unauthorized` | no | Send the full key as `X-API-Key` or `Authorization: Bearer`. The response carries `WWW-Authenticate`. | | `402` | `out_of_credits` | no | Add credits at `resolve`, then send the request again. | | `404` | `task_not_found` | no | Check the `task_id`, or list tasks with `GET /task`. | | `404` | `not_found` | no | The route does not exist. `message` points at the route list. | | `405` | `method_not_allowed` | no | Wrong HTTP method for the route. Check the method in the OpenAPI spec. | | `413` | `payload_too_large` | no | Send large inputs through `POST /upload-url`. | | `415` | `unsupported_media_type` | no | Send the body as JSON with `Content-Type: application/json`. | | `409` | `task_executing` | yes | A turn is running. Poll `GET /task/{task_id}/state` until `active` is false, then send again. Stop only to abandon the turn. | | `409` | `task_in_cron_mode` | no | The task runs on a schedule. Switch it to chat mode in the platform, or start a new task. | | `409` | `task_exists` | no | A task with that `task_id` exists. Continue it with `POST /task/{task_id}/continue`. | | `429` | `rate_limited` | yes | Wait `retry_after` seconds. See [Rate limits](/docs/api/rate-limits). | | `500` | `internal_error` | yes | If the body carries `task_id`, the task exists: continue it. Otherwise send again. If it repeats, contact support with `request_id`. | | `502` | `bad_gateway` | yes | An upstream service failed. Send the request again shortly. | | `503` | `service_unavailable`, `at_capacity`, `auth_unavailable` | yes | Wait `retry_after` seconds, then send the request again. | ## Retry Read `retryable`. Do not infer it from the status. * `true`: wait `retry_after` seconds when present, else a short backoff, then send the same request again. * `false`: the same request fails the same way. Change the request, key, balance or id first. ## One turn at a time A task runs one turn at a time. `409 task_executing` on continue or execute: poll state until the turn ends, then send again. Serialize calls per `task_id`. Do not stop a turn to get a message through; stop abandons its work. ## Terminal errors `402 out_of_credits` on continue or execute means the turn did not start. The task stays in `plan` and does not resume when credits arrive: add credits, then send the request again. See [Task lifecycle](/docs/concepts/lifecycle). ## Streaming After an SSE stream opens, a failure arrives as a `beanstalk_error` event, not an HTTP status. See [Live messages](/docs/guides/streaming). # Rate limits Source: https://www.autumn.ai/docs/api/rate-limits Where Autumn applies rate limits, the numbers, and how to handle a 429. Task starts, continues, and executes are governed by your credit balance, not by a per-minute quota. A run that exhausts credits fails with `402`, not `429`; see [Errors](/docs/api/errors). Two surfaces have a quota, per account: | Route | Limit | | --------------------- | ----------------------------------------------------------------- | | `GET /task/{task_id}` | 180 per minute, 20,000 per day, and 2 requests in flight at once. | | `POST /upload-url` | 30 per minute, 2,000 per day. | ## The 429 body ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "error": "rate_limited", "message": "Too many task reads; retry shortly.", "retryable": true, "retry_after": 10, "request_id": "req_3f9c2a1b0d4e5f6a7b8c" } ``` `retry_after` is in seconds. The same value is sent as the `Retry-After` header. ## Handling 429 Wait `retry_after` seconds, then send the same request again. A `429` is transient: the task, the file, and the `task_id` are all still valid, so the retry picks up where it left off. Polling is the usual cause. Poll `GET /task/{task_id}` no faster than once every few seconds, or use `GET /task/{task_id}/stream` and let the server push events instead. ## Credits Check the balance any time: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS "https://api.autumn.ai/credits" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` Status responses also carry credit usage for the task, so you can attribute spend per run rather than only in aggregate. # Writing task prompts Source: https://www.autumn.ai/docs/best-practices/prompting How to phrase a task so the agent infers the right work, and what to pin down explicitly. Autumn plans from your prompt. A vague prompt does not fail. It produces a plausible task that answers a slightly different question, which is harder to notice than an error. ## Keep every specific the user gave you If you are passing a user's request through to Autumn, preserve their specifics verbatim: names, URLs, constraints, exclusions, desired fields, counts, geography, and examples. Summarizing the request is where detail gets lost. ```txt Vague theme={"theme":{"light":"github-light","dark":"github-dark"}} Find some fintech companies ``` ```txt Specific theme={"theme":{"light":"github-light","dark":"github-dark"}} Find 50 US-based fintech companies that raised a Series A in 2025. For each: company name, domain, funding amount, lead investor, CEO name. Exclude crypto-native companies. ``` ## Say how many `target_count` on the output, or a count in the prompt, tells the agent when to stop. Without one it decides for itself, and "find companies" has no natural end. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "prompt": "Find AI infrastructure startups hiring founding engineers", "output": { "kind": "research", "target_count": 20 } } ``` ## Name the columns you want If you already know the shape, declare it rather than describing it. A schema is a contract; a sentence is a hint. See [Structured output](/docs/guides/structured-output). ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "output": { "kind": "research", "schema": { "company": { "type": "str" }, "domain": { "type": "url" }, "notes": { "type": "str" } }, "schema_order": ["company", "domain", "notes"] } } ``` ## Add per-row quality rules Rules are what keep a list honest. State the bar each row must clear: * must be Series A or later * must be US-based * must have a current CTO title * must cite a source for the funding figure Without a stated bar, the agent decides what "counts", and it will fill rows it can find rather than the rows you meant. ## Decide whether a question is worth it `clarify: false` is the default and the right choice for automation. Reach for `clarify: true` only when someone is around to answer, and the answer would change the work. See [Human in the loop](/docs/guides/human-in-the-loop). ## Restate the goal when continuing When you continue a task, rewrite the user's follow-up into a clear instruction that states the **current** goal, not just their raw words. "Add a column" is clear to a human reading the thread and ambiguous to an agent reading one message. ```txt Raw words theme={"theme":{"light":"github-light","dark":"github-dark"}} also linkedin ``` ```txt Restated theme={"theme":{"light":"github-light","dark":"github-dark"}} Add each company's founder LinkedIn URL to every existing row, then continue until there are 25 rows total. ``` See [Follow-up tasks](/docs/guides/follow-up). ## Prompting for Scout A well-specified prompt is what makes the faster tier viable. If the columns, the bar, and the count are all pinned down, `scout` has less to infer. If the task still has to decide *where* to look, stay on `ranger`. See [Model tiers](/docs/concepts/model-tiers). ## Checklist Count, columns, per-row rules, exclusions, and every specific the user gave you. Restate the current goal as one clear instruction rather than forwarding a reply. # Task lifecycle Source: https://www.autumn.ai/docs/concepts/lifecycle The states a task moves through, and how to tell when it has actually finished. `GET /task/{task_id}` reports where a task is: | Field | Meaning | | ---------- | ------------------------------------------------------------------------------------------------- | | `status` | `plan`, `execute`, or `deleted`. `plan` covers both "not started yet" and "finished and resting". | | `activity` | What the task is doing right now. `idle` means no turn is in flight. | | `phase` | The phase of the current turn. | | `tier` | The model tier the task started on, `ranger` or `scout`. | ## Knowing when a task is done This is the one piece of Autumn that reliably trips people up, so it is worth stating precisely. A finished task returns to `status: "plan"` with `activity: "idle"`. But `plan` is *also* the state a task sits in **before** it executes. So `status` alone cannot tell you a task is done. Read on its own, it will tell you a task that has not started yet is finished. A task is **still working** while any of these hold: * `phase` is `execute` * `status` is `execute` or `running` * `activity` is `executing`, `running`, `planning`, or `thinking` It has **stopped** when none of those hold, or when `status`/`activity` is `deleted`, or `error` is `out_of_credits`/`error`. Include the `deleted` and `error` cases in your poll loop. A loop that waits only for `status: "plan"` with `activity: "idle"` never exits on a task that was deleted or ran out of credits. It spins forever on a task that is never coming back. ## A correct poll loop ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} ACTIVE_STATUSES = {"execute", "running"} ACTIVE_ACTIVITIES = {"executing", "running", "planning", "thinking"} def is_terminal(task): if task.get("status") == "deleted" or task.get("activity") == "deleted": return True if task.get("error") in {"out_of_credits", "error"}: return True return not (task.get("phase") == "execute" or task.get("status") in ACTIVE_STATUSES or task.get("activity") in ACTIVE_ACTIVITIES) ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const ACTIVE_STATUSES = new Set(["execute", "running"]); const ACTIVE_ACTIVITIES = new Set(["executing", "running", "planning", "thinking"]); const isTerminal = (t) => t.status === "deleted" || t.activity === "deleted" || ["out_of_credits", "error"].includes(t.error) || !(t.phase === "execute" || ACTIVE_STATUSES.has(t.status) || ACTIVE_ACTIVITIES.has(t.activity)); ``` Prefer live events over polling? See [Live messages](/docs/guides/streaming). ## After a task finishes A `task_id` stays valid once a turn ends. Read status and output any time, and use `POST /task/{task_id}/continue` to start another turn on the same task. Stopping a running task with `POST /task/{task_id}/stop` also returns it to `plan`. # Model tiers Source: https://www.autumn.ai/docs/concepts/model-tiers Ranger and Scout: choosing a tier, and when the choice is locked in. Every task runs on one model tier, chosen at start with `version` and fixed for the life of the task. | `version` | Tier | Character | | --------- | ------ | ----------------------------------------------------------------------------- | | `ranger` | Ranger | Most capable model, deepest reasoning. The default when `version` is omitted. | | `scout` | Scout | Fast responses on a tuned harness. | ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "Find 20 AI infrastructure startups hiring founding engineers.", "version": "scout", "clarify": false }' ``` ## Choosing a tier Reach for `scout` on bounded, well-specified work where latency matters more than depth, and stay on `ranger` for open-ended research. | Signal | Tier | | -------------------------------------------- | -------- | | The columns and the source are already known | `scout` | | A fixed list of inputs to enrich | `scout` | | Latency matters more than depth | `scout` | | The task has to decide *where* to look | `ranger` | | Facts need cross-checking across sources | `ranger` | | The request is open-ended or ambiguous | `ranger` | A well-specified prompt is what makes `scout` viable; see [Writing task prompts](/docs/best-practices/prompting). ## The tier is fixed at start `version` only applies to the start routes. `/task/{task_id}/continue` and `/task/{task_id}/execute` stay on the tier the task started with. Read the tier back from `GET /task/{task_id}` as `tier`. `ranger` and `scout` are the only accepted values; anything else is rejected with `403` and `{"error": "forbidden"}`. # Outputs and sources Source: https://www.autumn.ai/docs/concepts/outputs What a task produces: output kinds, rows built from cells, and the sources behind every value. A task writes **output rows**. `output` is the shape signal: it tells Autumn where durable rows should go for the current task contract. Keep `output` singular. If the artifact you want changes later, continue the task in plan mode and replan before executing again. ## Output kinds | Kind | Use | Typical path | | ---------- | ----------------------------------------------------------------------- | --------------------------------- | | `research` | Lists, claims, evidence, jobs, sources, broad web research. | `outputs/ai-infra-startups.jsonl` | | `person` | Rich person profiles, identity resolution, social links, relationships. | `outputs/scott-stephenson.jsonl` | | `company` | Company profiles, funding, team, hiring, tech stack, news. | `outputs/deepgram.jsonl` | The same agent loop plans, executes, writes files, and streams events for every output kind. `GET /task/{task_id}/output` returns the task output rows, and `GET /task/{task_id}/outputs` lists known row artifacts. ## Rows are made of cells Output rows are **cells**, not bare values. Every field pairs its value with the source it came from, so each row carries its own provenance: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "rows": [ { "title": { "value": "Acme Infra", "source_id": "s1" }, "source_url": { "value": "https://acme.example", "source_id": "s1" }, "_sources": { "s1": "https://acme.example" } } ] } ``` This is the part that surprises people writing their first integration: `row["title"]` is an object, not a string. Flatten `{"value": ...}` to plain values when you only want the data, and read `_sources` when you need to show or audit where a value came from. Keys prefixed with `_` are row metadata, not columns: `_row_id`, `_sources`, and lineage or validation fields. Skip them when presenting results. See [Structured output](/docs/guides/structured-output) for a flatten helper. ## Reading a specific output To read one named artifact, use `GET /task/{task_id}/outputs/{output_id}`, or pass `?output=output_id` to `/output`. ## Next Declare the exact columns you want back. Pick the tier that fits the work. # The task model Source: https://www.autumn.ai/docs/concepts/tasks Autumn exposes one primitive: a task. Everything else is a way to start, watch, or read one. A **task** is a goal you hand to Autumn. It gets its own sandbox and agent, plans an approach, works the web, and writes output rows. It keeps running in the cloud after your request returns. A goal in plain language, or a structured spec carrying a schema, rules, and input rows. The agent turns the goal into `task.json` — the approach it intends to take, before it spends anything. The task gets its own container and workspace, and both persist across turns. Progress streams while the task runs; finished rows land in the task's output. Every task has a durable `task_id`. That id is the handle for everything else: status, streaming, continuation, files, and output. Store the returned `task_id`. It stays valid after the run finishes. Start from a prompt with `/task`, or from a `task.json`-style spec with `/task/start`. `clarify: false` plans without asking. `clarify: true` allows one blocking question. ## Two ways to start | Start mode | Use when | | ------------------------------------- | ------------------------------------------------------------------------------------------ | | `POST /task` with a `prompt` | You have natural language and want Autumn to infer the task shape. | | `POST /task/start` with a `task` spec | Your app already knows the shape: known columns, a repeatable job, or a saved `task.json`. | Choose `/task/start` for enrichment jobs with known inputs, workflows your own app generates, repeatable research with a fixed output schema, or a task restored from a saved spec. Choose `/task` when you only have a user request. Use `GET /task/metaprompt` when another agent or app needs to generate a clean `task.json`-style spec before calling `/task/start`. ## Planning and `clarify` `clarify` is the only planning knob. Left at its default of `false`, the agent plans, infers defaults, and executes without stopping. Set to `true`, it may ask **one** blocking question before execution. Use `clarify: true` only when a caller is present and a wrong assumption would cost more than a short question. [Human in the loop](/docs/guides/human-in-the-loop) covers both modes and the review-then-continue pattern. ## Turns A task runs one **turn** at a time. Starting a task is a turn; so is continuing it. A turn ends with a `done` event, and the task returns to rest. The task itself is not finished in any final sense. You can continue it later, and it picks up the same plan, rows, and task-local files. This is why continuing beats starting over: a new task loses the plan and the rows. Because a task runs one turn at a time, continuing or executing while a turn is still in flight is rejected with `409`, not queued. See [Errors](/docs/api/errors). ## Next The states a task moves through, and how to tell when it is done. What a task produces, and how every value carries its source. # Let an agent drive Autumn Source: https://www.autumn.ai/docs/cookbook/agent-driven Give a coding agent the whole task surface: generate a spec, start it, and manage the loop. Autumn's caller does not have to be your code. An agent with the [Skill](/docs/skill) installed can run the entire loop itself: turn a user's request into a task spec, start it, wait, and report the rows. This recipe is the shape of that handoff. ## 1. Install the skill ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} npx skills add https://www.autumn.ai ``` The skill teaches the agent the defaults that matter: `clarify: false`, keep the `task_id`, continue instead of restarting, and read rows before reporting results. Other install paths are on the [Skill](/docs/skill) page. ## 2. Let the agent write the spec, not just the prompt An agent relaying a user's words loses their specifics. Instead, have it fetch `GET /task/metaprompt`, which returns the task spec schema plus a metaprompt for caller-side planning, and generate a clean `task.json`-style spec: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS "https://api.autumn.ai/task/metaprompt" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` The agent fills in `brief`, the output `schema`, and `target_count` from the user's request, then starts with `POST /task/start`. A spec survives the relay; a paraphrase does not. [Writing task prompts](/docs/best-practices/prompting) is the rubric to hold it to. **Decision:** for a one-off question the user typed, plain `POST /task` with their words passed through verbatim is fine. Reach for the metaprompt when the agent is constructing the task on the user's behalf. ## 3. Wait without hallucinating The two rules that keep an agent honest while a task runs: * A start response only means the task was accepted. Poll `GET /task/{task_id}` with the full terminal check from [Task lifecycle](/docs/concepts/lifecycle) before claiming anything. * Report from the rows, never from status text. `GET /task/{task_id}/output` is the only source of results. ## 4. Route refinements back to the same task When the user says "add a column" or "find more", the agent should continue the existing task, restating the goal as one clear instruction: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/$TASK_ID/continue" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "Add each company'\''s founder LinkedIn URL to every existing row."}' ``` A `409` here means a turn is still in flight; the agent should wait and retry rather than starting a duplicate task. See [Errors](/docs/api/errors). ## Guardrails worth writing into the agent's instructions * Default to `clarify: false`; the agent is rarely there to answer a blocking question. * Never print the API key, in output or in generated code. * One task per goal. Refinements continue it; only an unrelated goal starts a new one. ## Related Install paths and the ready-made prompt to pair with it. The one-link version for coding agents building against Autumn. # Run Autumn from a background worker Source: https://www.autumn.ai/docs/cookbook/background-worker Start tasks from a queue, survive restarts, and land the rows in your own store. Autumn tasks keep running in the cloud after your request returns, which makes them a natural fit for a worker: start the task, persist the `task_id`, and let the worker die and come back without losing anything. This recipe is the wiring that makes that safe. ## 1. Check credits before a batch A worker that starts fifty tasks against an empty balance produces fifty `402`s. Check once per batch, not per task: ```python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os, requests AUTUMN = "https://api.autumn.ai" HEADERS = {"X-API-Key": os.environ["AUTUMN_API_KEY"]} credits = requests.get(f"{AUTUMN}/credits", headers=HEADERS).json() if not credits.get("unlimited") and credits["credits_remaining"] <= 0: raise RuntimeError("out of credits, pausing queue") ``` ## 2. Start the task, then persist the id first The `task_id` is your resume point. Write it to your database **before** doing anything else with the response. If the worker crashes one line later, the task is still running in the cloud and the stored id is how you find it again. ```python theme={"theme":{"light":"github-light","dark":"github-dark"}} task = requests.post(f"{AUTUMN}/task", headers=HEADERS, json={ "prompt": job.prompt, "clarify": False, }).json() db.jobs.update(job.id, autumn_task_id=task["task_id"], state="running") ``` **Decision:** if your jobs have a known shape (fixed columns, repeatable brief), start from a spec with `/task/start` instead. See [The task model](/docs/concepts/tasks). ## 3. Poll with the full terminal check Workers are exactly where a sloppy exit condition hurts most, because nobody is watching the loop spin. Use the complete check from [Task lifecycle](/docs/concepts/lifecycle), including the `deleted` and `out_of_credits` cases, and poll on a lazy interval; a research task does not need sub-second updates. ```python theme={"theme":{"light":"github-light","dark":"github-dark"}} import time while True: task = requests.get(f"{AUTUMN}/task/{task_id}", headers=HEADERS).json() if is_terminal(task): # the exact function from Task lifecycle break time.sleep(10) ``` ## 4. Serialize writes per task A task runs one turn at a time, so two workers continuing the same `task_id` produce a `409`, not a queue. Route all writes for one task through one worker (or take a per-task lock), and treat `409` as "try again after the current turn", never as a failure. See [Errors](/docs/api/errors). ## 5. Land the rows Fetch the rows, flatten the cells into your own schema, and keep `_sources` if anything downstream needs to audit a value: ```python theme={"theme":{"light":"github-light","dark":"github-dark"}} rows = requests.get( f"{AUTUMN}/task/{task_id}/output", headers=HEADERS, params={"limit": 1000}, ).json()["rows"] for row in rows: flat = {k: v["value"] for k, v in row.items() if not k.startswith("_") and isinstance(v, dict) and "value" in v} db.results.insert(job_id=job.id, **flat) ``` ## Crash recovery On restart, reread the stored ids and resume polling; the tasks never stopped. If you lose the ids entirely, `GET /task` lists recent tasks so you can reconcile against your queue. ## Related The terminal check this worker depends on. Sending refinements to a task the worker already finished. # Stream a task into your UI Source: https://www.autumn.ai/docs/cookbook/live-dashboard Show users live agent progress, then refresh the table when the turn ends. A task that runs for minutes needs to show the user something better than a spinner. The SSE routes emit the same events the Autumn dashboard renders, so your UI can narrate the work as it happens: what the agent is doing now, errors as they occur, and rows the moment the turn ends. ## 1. Keep the API key on your server Every stream route requires your API key, so the browser must never connect to `api.autumn.ai` directly. Start the task server-side, then either proxy the SSE stream through your backend or forward its events over your own channel. ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}} // server: start the task, return only the task_id to the browser const { task_id } = await fetch("https://api.autumn.ai/task", { method: "POST", headers: { "X-API-Key": process.env.AUTUMN_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ prompt, clarify: false }), }).then((r) => r.json()); ``` ## 2. Subscribe on the server, relay to the client `GET /task/{task_id}/stream` attaches to the task and replays recent events if a turn is already active, so a user who opens the page mid-run still sees context: ```javascript theme={"theme":{"light":"github-light","dark":"github-dark"}} // server: proxy the task's event stream const upstream = await fetch(`https://api.autumn.ai/task/${taskId}/stream`, { headers: { "X-API-Key": process.env.AUTUMN_API_KEY }, }); // pipe upstream.body to the client response with SSE headers ``` This split (one process starts, another watches) is exactly what the subscribe route is for; see [Live messages](/docs/guides/streaming) for the event parsing itself. ## 3. Map events to UI states Each event carries a `type`, a `summary`, and `data`. The `summary` field is written to be shown, so the cheap version of this UI is a scrolling activity feed of summaries. A step up is a small state machine: | Event | UI | | ----------------- | ------------------------------------------------------------------------------------------- | | `tool_start` | Add an in-progress step to the activity feed. | | `tool_result` | Mark that step done. | | `text_delta` | Append to the agent's running commentary. | | `beanstalk_error` | Surface the error inline; the stream, not an HTTP status, carries failures once it is open. | | `done` | Close the feed, fetch rows, render the table. | ## 4. On done, fetch the rows `done` ends the turn, not the task. Refresh the table from `GET /task/{task_id}/output`, flattening cells for display and keeping `_sources` so each value can link to where it came from. [Outputs and sources](/docs/concepts/outputs) covers the cell shape. ## 5. Wire the follow-up box to continue The natural next interaction is the user asking for changes. Send that through `POST /task/{task_id}/continue/stream` and reuse the same event pipeline for the new turn. Disable the box while a turn is in flight; a submit during one returns `409`. **Decision:** if your UI only needs a progress bar and a finished table, skip the stream entirely and poll `GET /task/{task_id}` with the terminal check from [Task lifecycle](/docs/concepts/lifecycle). Streaming earns its complexity when users watch. ## Related The SSE mechanics: routes, parsing, and event names. Put a human reviewer behind this UI. # Cookbook Source: https://www.autumn.ai/docs/cookbook/overview Complete jobs, built by composing the API: pipelines, workers, agents, and UIs. The [Guides](/docs/guides/structured-output) each cover one capability, complete with code. These recipes cover **jobs that span several of them**, where the value is the order you do things in and the decision at each seam, not the mechanics of any single step. If a job maps to exactly one capability, it lives in Guides, not here. ## Pipelines Declared schema, live events, human review, and correction in place. ## Production wiring Queue-driven tasks that survive worker restarts and land rows in your store. Live agent progress for your users, with the key kept server-side. ## Agents A coding agent that writes the spec, starts the task, and manages the loop. ## Single-capability jobs Upload rows you have and fill in the missing columns. Declare columns and get them back validated. # Build a reviewed list Source: https://www.autumn.ai/docs/cookbook/reviewed-list Compose a declared schema, live events, human review, and continuation into one repeatable job. The [Quickstart](/docs/quickstart) runs a task start to finish. This is what you build once that is no longer enough: a list that a person checks before anyone trusts it, and that gets corrected in place rather than regenerated. Each step links to the guide that covers its mechanics. What this page adds is the **order**, and the decision at each seam. ## 1. Declare the shape, don't describe it Start from a spec rather than a prompt. A reviewer can only check rows against a declared shape, and a prose description is not one. → [Structured output](/docs/guides/structured-output) for `output.schema` and `schema_order` → [Writing task prompts](/docs/best-practices/prompting) for the per-row rules that set the bar **Decision:** if the columns aren't known yet, you are still exploring. Use a prompt and this pipeline later. ## 2. Watch the first run, don't poll it For the first run of a new spec, stream it. You are not waiting for an answer, you are looking for the agent misreading the brief, which shows up in the tool calls long before it shows up in the rows. → [Live messages](/docs/guides/streaming) for the SSE routes and event names **Decision:** once the spec is stable, switch to polling. Streaming is for when you are still learning what the task does. ## 3. Read rows with their sources Fetch the rows and keep the cells rather than flattening immediately. Review is exactly the case where `_sources` earns its keep: a reviewer needs to see *why* a value is claimed. → [Outputs and sources](/docs/concepts/outputs) for cell shape and `_sources` ## 4. Correct in place Send the reviewer's verdict back to the same task. The plan, the rows, and the task-local files all survive; a new task would lose them. → [Follow-up tasks](/docs/guides/follow-up) for `continue` → [Human in the loop](/docs/guides/human-in-the-loop) for interleaving review and agent turns **Decision:** continue when the reviewer is refining the same goal. Start fresh only when the goal itself changed. ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/$TASK_ID/continue" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "Drop every row without a cited source for raised_usd, then continue until there are 50 rows."}' ``` Restate the goal rather than forwarding the reviewer's words. The agent sees one message, not the review thread the verdict came from, so "drop the bad ones" carries nothing. ## 5. Repeat The `task_id` stays valid indefinitely. Steps 3 and 4 loop as many times as review needs, and the task keeps everything it learned. ## Related The single-pass version of this. The same loop, starting from rows you already have. # FAQ Source: https://www.autumn.ai/docs/faq Short answers to the questions that come up while integrating Autumn. Answers here are the short version. Each one links to the page that covers the topic properly. ## Tasks Yes. A `task_id` is durable. Read status and output any time, and continue the task with new instructions whenever you want more from it. See [The task model](/docs/concepts/tasks). Continue whenever the request refines previous work: add a column, find more rows, narrow the criteria, fix empty fields. A continued task keeps its plan, rows, and task-local files; a new task starts from nothing. Start fresh only when the goal itself is unrelated. See [Follow-up tasks](/docs/guides/follow-up). A task runs one turn at a time. Continuing or executing while a turn is in flight is rejected with `409` rather than queued. Wait for the current turn to end, or stop it with `POST /task/{task_id}/stop`. See [Errors](/docs/api/errors). No. The agent always plans. `clarify: false` means it infers defaults and proceeds without stopping; `clarify: true` allows one blocking question before execution. See [Human in the loop](/docs/guides/human-in-the-loop). No. `version` applies to the start routes only, and the task stays on that tier for its whole life, including every continue. Read it back as `tier` on `GET /task/{task_id}`. See [Model tiers](/docs/concepts/model-tiers). ## Waiting and reading results Two common causes. First, a finished task returns to `status: "plan"`, which is also its state before executing, so waiting on `status` alone misreads it. Second, loops that only wait for `plan` plus `idle` never exit on a task that was deleted or ran out of credits. [Task lifecycle](/docs/concepts/lifecycle) has the complete terminal check to copy. Output rows are made of cells. Every field pairs its value with the source it came from: `{"value": "Acme", "source_id": "s1"}`. Flatten to plain values when you only want the data, and keep the cells when you need provenance. See [Outputs and sources](/docs/concepts/outputs). Keys prefixed with `_` are row metadata, not columns: `_row_id`, `_sources`, and lineage or validation fields. Skip them when presenting results. [Structured output](/docs/guides/structured-output) includes a flatten helper that drops them. No. Streaming is optional. Poll `GET /task/{task_id}` when you only care about the result, and reach for the SSE routes when you want to watch the agent work. See [Live messages](/docs/guides/streaming). ## Keys, credits, and limits Either `X-API-Key: YOUR_KEY` or `Authorization: Bearer YOUR_KEY`. Use the full key you copied when creating it; the shortened key shown later in settings is display-only and returns `401`. See [API overview](/docs/api-routes#authentication). `GET /credits` returns the balance, and task status responses carry per-task credit usage. A task that runs out of credits fails with `402` and an `error` of `out_of_credits`. See [Rate limits](/docs/api/rate-limits). `ranger` and `scout` are the only accepted values for `version`. Anything else returns `422` with `{"error": "invalid_request", "param": "version"}`. See [Model tiers](/docs/concepts/model-tiers). `.csv`, `.txt`, `.md`, and `.markdown`, up to 10 MB and 10,000 rows. Upload through the presign flow, and send the `PUT` to the presigned URL without any Autumn auth headers. See [Attach a CSV](/docs/guides/file-uploads). Still stuck? The [Cookbook](/docs/cookbook/overview) walks through complete pipelines, and [llms-full.txt](https://www.autumn.ai/docs/llms-full.txt) packs the whole developer surface into one file you can hand to an agent. # Attach a CSV Source: https://www.autumn.ai/docs/guides/file-uploads Upload a CSV, text, or markdown file and enrich every row in a task. Autumn accepts `.csv`, `.txt`, `.md`, and `.markdown` uploads up to **10 MB and 10,000 rows**. Uploading is three calls: create a task to attach to, presign, then validate. ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} # 1. get a task to attach the file to (skip if you already have a task_id) curl -X POST https://api.autumn.ai/tasks/draft \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Lead enrichment"}' # -> {"task_id":"ab12..."} # 2. presign curl -X POST https://api.autumn.ai/upload-url \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"task_id":"ab12...","filename":"leads.csv"}' # -> {"upload_url":"https://...","filename":"leads.csv"} # 3. PUT the bytes to upload_url with NO Autumn auth headers, then validate curl -X PUT "$UPLOAD_URL" -H "Content-Type: application/octet-stream" --data-binary @leads.csv curl -X POST https://api.autumn.ai/validate-upload \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"task_id":"ab12...","filename":"leads.csv"}' ``` Send the `PUT` to `upload_url` **without** `X-API-Key` or `Authorization`. The presigned URL carries its own signature, and an extra auth header will be rejected. ## What validation returns `/validate-upload` converts a CSV to task-local JSONL and returns the filename to pass as `input_files`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "filename": "upload_9f2c1ab3.jsonl", "rows": 240, "fields": ["name", "email", "company"], "renamed": [], "delimiter": ",", "extra_columns": 0 } ``` | Field | Meaning | | --------------- | ---------------------------------------------------------------------------------------------------------------------- | | `filename` | Pass this in `input_files` when starting or continuing a task. | | `rows` | Data rows accepted, excluding the header. | | `fields` | Final column names, after de-duplication and blank-header naming. | | `renamed` | Columns Autumn had to rename, with the original name for each. | | `delimiter` | Detected delimiter. Comma unless the header parses as a single column, in which case `;`, tab, and `\|` are tried. | | `extra_columns` | Columns added because some row had more cells than the header. Those cells are kept as `column_N` rather than dropped. | Check `renamed` and `extra_columns` before you rely on column names. A messy header is repaired rather than rejected, so the names you get back may not be the names you sent. Autumn reserves `_row_id` for its own row identity. A CSV that already has a `_row_id` column keeps its values under `_row_id_2`. ## Enrich the uploaded rows Pass the validated filename as `input_files` and describe the columns you want added: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -X POST https://api.autumn.ai/task \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "For every uploaded row, find the company domain, employee count, and current CEO name. Leave a field empty rather than guessing.", "input_files": ["upload_9f2c1ab3.jsonl"], "clarify": false }' ``` "Leave a field empty rather than guessing" is worth stating explicitly. Enrichment fills what it can find, and an unstated bar becomes a guessed one. See [Writing task prompts](/docs/best-practices/prompting). Then wait for the turn to finish and read the rows back, exactly as for any other task: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS "https://api.autumn.ai/task/$TASK_ID/output?limit=1000" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` Enriched values come back as cells with `_sources`, so you can show where each filled value came from. See [Outputs and sources](/docs/concepts/outputs). `/upload-url` is rate limited per account. Exceeding it returns `429`; retry after a short pause. See [Rate limits](/docs/api/rate-limits). ## Related Declare the exact columns you want added. Waiting for the enrichment turn to finish. # Follow-up tasks Source: https://www.autumn.ai/docs/guides/follow-up Continue the same task with new instructions instead of starting over. Every task has a durable `task_id`. To refine, expand, or fix results, **continue** the same task: the agent keeps the plan, the output rows, and the task-local files. ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} # 1. start curl -sS -X POST "https://api.autumn.ai/task" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Find 20 AI infrastructure startups hiring founding engineers", "clarify": false}' # 2. send more instructions to the same task curl -sS -X POST "https://api.autumn.ai/task/$TASK_ID/continue" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "Add each company'\''s founder LinkedIn URL, and find 10 more rows"}' # 3. read the result curl -sS "https://api.autumn.ai/task/$TASK_ID/output" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os, requests AUTUMN = "https://api.autumn.ai" HEADERS = {"X-API-Key": os.environ["AUTUMN_API_KEY"]} # start a task task = requests.post(f"{AUTUMN}/task", headers=HEADERS, json={ "prompt": "Find 20 AI infrastructure startups hiring founding engineers", "clarify": False, }).json() task_id = task["task_id"] # send more instructions to the same task requests.post(f"{AUTUMN}/task/{task_id}/continue", headers=HEADERS, json={ "message": "Add each company's founder LinkedIn URL, and find 10 more rows", }) # read the result rows = requests.get(f"{AUTUMN}/task/{task_id}/output", headers=HEADERS).json()["rows"] ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const AUTUMN = "https://api.autumn.ai"; const HEADERS = { "X-API-Key": process.env.AUTUMN_API_KEY, "Content-Type": "application/json", }; const { task_id } = await fetch(`${AUTUMN}/task`, { method: "POST", headers: HEADERS, body: JSON.stringify({ prompt: "Find 20 AI infrastructure startups hiring founding engineers", clarify: false, }), }).then((r) => r.json()); await fetch(`${AUTUMN}/task/${task_id}/continue`, { method: "POST", headers: HEADERS, body: JSON.stringify({ message: "Add each company's founder LinkedIn URL, and find 10 more rows", }), }); const { rows } = await fetch(`${AUTUMN}/task/${task_id}/output`, { headers: HEADERS }) .then((r) => r.json()); ``` Wait for the continue turn to finish the same way you wait for the first one: poll `GET /task/{task_id}` until `status: "plan"` and `activity: "idle"`, or use `POST /task/{task_id}/continue/stream` and read events until `done`. See [Live messages](/docs/guides/streaming). ## When to continue vs. start fresh Continue when the user references previous work: "add a column", "find more", "narrow to US-only", "fix the empty fields". Start a new task only for unrelated work. When you continue, rewrite the user's request into a clear instruction stating the current goal, not just their raw words. ## Execute and stop * `POST /task/{task_id}/execute` pushes an existing task toward producing output from its current plan. Use it after a task has been planned but is sitting idle. * `POST /task/{task_id}/stop` stops a run and returns the task to `plan`. ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/$TASK_ID/execute" \ -H "X-API-Key: $AUTUMN_API_KEY" curl -sS -X POST "https://api.autumn.ai/task/$TASK_ID/stop" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` Continuing a task keeps the model tier it started with. `version` is a start-only field. ## Related Let the agent ask a clarifying question first. Watch each turn as it happens. # Human in the loop Source: https://www.autumn.ai/docs/guides/human-in-the-loop Let the agent ask a clarifying question, or hand control back and forth. `clarify` is the only planning knob. By default (`clarify: false`) the agent infers reasonable defaults and executes without asking. Set `clarify: true` when a human is present and a missing answer would materially change the work. | Value | Agent behavior | | ------- | ----------------------------------------------------------------------------- | | `false` | Plan, infer defaults, and execute without asking. The default for automation. | | `true` | Allow **one** blocking planning question before execution. | ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Build a list of fintech companies", "clarify": true}' ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os, requests AUTUMN = "https://api.autumn.ai" HEADERS = {"X-API-Key": os.environ["AUTUMN_API_KEY"]} # clarify=true: may ask one question, e.g. geography or target count task = requests.post(f"{AUTUMN}/task", headers=HEADERS, json={ "prompt": "Build a list of fintech companies", "clarify": True, }).json() ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const task = await fetch("https://api.autumn.ai/task", { method: "POST", headers: { "X-API-Key": process.env.AUTUMN_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ prompt: "Build a list of fintech companies", clarify: true }), }).then((r) => r.json()); ``` With `clarify: true` the task initializes in plan mode and can stop before execution. Stream the turn (or poll status) to see the question, answer it with `POST /task/{task_id}/continue`, then let it execute. ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} # answer the planning question on the same task curl -sS -X POST "https://api.autumn.ai/task/$TASK_ID/continue" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "US only, Series A or later, 50 rows"}' ``` ## Review, then continue A common pattern: run the first part, let a human review the rows, then continue the same task with corrections. ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} task_id = requests.post(f"{AUTUMN}/task", headers=HEADERS, json={ "prompt": "Find Series A fintech companies in the US", "clarify": False, }).json()["task_id"] # ... wait for the turn to finish, then fetch rows ... rows = requests.get(f"{AUTUMN}/task/{task_id}/output", headers=HEADERS).json()["rows"] # ... human reviews rows ... requests.post(f"{AUTUMN}/task/{task_id}/continue", headers=HEADERS, json={ "message": "Drop anything past Series A and add the CEO name column", }) ``` Because the `task_id` is durable, you can interleave agent turns and human review as many times as you need. See [Follow-up tasks](/docs/guides/follow-up). ## Guidance * For background automation, keep `clarify: false`. * Use `clarify: true` only when the user is present to answer. * When continuing after review, restate the current goal as a clear instruction rather than passing the user's raw words. * `POST /task/{task_id}/stop` returns a running task to `plan` if a reviewer needs to intervene mid-run. # Live messages Source: https://www.autumn.ai/docs/guides/streaming Stream Server-Sent Events as the agent plans and executes. Stream messages as the agent works: planning, tool calls, and progress. Autumn emits Server-Sent Events on the `/stream` routes, with the same event names the dashboard uses. Two ways in: | Route | Use | | ---------------------------- | -------------------------------------------------------------------------------- | | `POST /task/stream` | Start a task from a prompt and stream the turn it kicks off. | | `GET /task/{task_id}/stream` | Subscribe to an existing task. Recent events replay if a turn is already active. | ## Start and stream ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -N -X POST "https://api.autumn.ai/task/stream" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Find the top story on Hacker News", "clarify": false}' ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os, json, requests with requests.post( "https://api.autumn.ai/task/stream", headers={"X-API-Key": os.environ["AUTUMN_API_KEY"]}, json={"prompt": "Find the top story on Hacker News", "clarify": False}, stream=True, ) as r: event = None for line in r.iter_lines(decode_unicode=True): if not line: continue if line.startswith("event:"): event = line[6:].strip() elif line.startswith("data:"): data = json.loads(line[5:].strip()) print(f"[{event}] {data.get('summary', '')}") if event == "done": break ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const res = await fetch("https://api.autumn.ai/task/stream", { method: "POST", headers: { "X-API-Key": process.env.AUTUMN_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ prompt: "Find the top story on Hacker News", clarify: false }), }); const reader = res.body.pipeThrough(new TextDecoderStream()).getReader(); let buffer = ""; while (true) { const { value, done } = await reader.read(); if (done) break; buffer += value; const chunks = buffer.split("\n\n"); buffer = chunks.pop() ?? ""; for (const chunk of chunks) { const event = chunk.match(/^event:\s*(.*)$/m)?.[1]; const data = chunk.match(/^data:\s*(.*)$/m)?.[1]; if (data) console.log(`[${event}]`, JSON.parse(data).summary ?? ""); } } ``` ## Subscribe to a running task Already have a `task_id`? Attach to it. This is the route to use when one process starts the task and another watches it. ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -N "https://api.autumn.ai/task/8fab6f34/stream" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` `GET /task/{task_id}/stream` only streams events for that `task_id`. When the turn emits `done`, the stream can close. Reconnect later only if you need the next active turn. ## Event names | Event | Meaning | | ----------------- | -------------------------------------------------- | | `tool_start` | A task operation or tool call began. | | `tool_result` | A task operation or tool call produced a result. | | `text_delta` | Assistant or status text from the sandboxed agent. | | `beanstalk_error` | A user-visible task error. | | `done` | The current turn finished. | Each message carries a `type`, a `summary`, and `data`. Treat `done` as end-of-turn, not end-of-task; a task can run more turns if you continue it. ## Streaming the other routes Every route that advances a task has a streaming twin. Same body, SSE response: | Blocking | Streaming | | ------------------------------- | -------------------------------------- | | `POST /task` | `POST /task/stream` | | `POST /task/start` | `POST /task/start/stream` | | `POST /task/{task_id}/continue` | `POST /task/{task_id}/continue/stream` | | `POST /task/{task_id}/execute` | `POST /task/{task_id}/execute/stream` | ## Polling instead of streaming Streaming is optional. Poll `GET /task/{task_id}` when you only care about the result; a long-running task doesn't need a held-open connection. Getting the loop's exit condition right is subtler than it looks: a finished task returns to `status: "plan"`, which is also its state before execution. See [Task lifecycle](/docs/concepts/lifecycle) for the complete terminal check and a copy-paste loop. ## Related The raw SSE interface and route map. Continue a task and stream the next turn. # Structured output Source: https://www.autumn.ai/docs/guides/structured-output Declare the exact columns a task should return, and read them back as typed rows. By default Autumn infers the shape of its output from your prompt. When your app already knows the columns it wants, declare them with `output.schema` on [`POST /task/start`](/docs/api-routes#start-from-a-task-spec) and every row comes back in that shape. ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/start" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "task": { "brief": "Find 20 AI infrastructure startups hiring founding engineers.", "output": { "id": "ai-infra-startups", "kind": "research", "path": "outputs/ai-infra-startups.jsonl", "target_count": 20, "schema": { "company": { "type": "str" }, "domain": { "type": "url" }, "notes": { "type": "str" }, "sources": { "type": "list[url]" } }, "schema_order": ["company", "domain", "notes", "sources"] } }, "clarify": false }' ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os, requests AUTUMN = "https://api.autumn.ai" HEADERS = {"X-API-Key": os.environ["AUTUMN_API_KEY"]} task = requests.post(f"{AUTUMN}/task/start", headers=HEADERS, json={ "task": { "brief": "Find 20 AI infrastructure startups hiring founding engineers.", "output": { "id": "ai-infra-startups", "kind": "research", "path": "outputs/ai-infra-startups.jsonl", "target_count": 20, "schema": { "company": {"type": "str"}, "domain": {"type": "url"}, "notes": {"type": "str"}, "sources": {"type": "list[url]"}, }, "schema_order": ["company", "domain", "notes", "sources"], }, }, "clarify": False, }).json() ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const task = await fetch("https://api.autumn.ai/task/start", { method: "POST", headers: { "X-API-Key": process.env.AUTUMN_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ task: { brief: "Find 20 AI infrastructure startups hiring founding engineers.", output: { id: "ai-infra-startups", kind: "research", path: "outputs/ai-infra-startups.jsonl", target_count: 20, schema: { company: { type: "str" }, domain: { type: "url" }, notes: { type: "str" }, sources: { type: "list[url]" }, }, schema_order: ["company", "domain", "notes", "sources"], }, }, clarify: false, }), }).then((r) => r.json()); ``` ## Field types `schema` is a flat map of column name to type. Supported types: | Type | Meaning | | ----------------------------- | --------------------------- | | `str` | Text. | | `int` | Whole number. | | `float` | Decimal number. | | `bool` | True or false. | | `url` | A URL, validated as one. | | `list[str]`, `list[url]`, ... | A list of any of the above. | `schema_order` fixes column order for readback and exports. Keep the schema flat: one row per entity, one column per fact. ## Reading typed rows back `GET /task/{task_id}/output` returns rows whose fields are **cells**, not bare values. Each cell pairs the value with the source it came from: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "rows": [ { "company": { "value": "Acme Infra", "source_id": "s1" }, "domain": { "value": "https://acme.example", "source_id": "s1" }, "sources": { "value": ["https://acme.example/careers"], "source_id": "s2" }, "_sources": { "s1": "https://acme.example", "s2": "https://acme.example/careers" } } ] } ``` Flatten the cells when you want plain data, and keep `_sources` when you need to show or audit provenance: ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} def flatten(row): return {k: v["value"] for k, v in row.items() if not k.startswith("_") and isinstance(v, dict) and "value" in v} rows = requests.get( f"{AUTUMN}/task/{task['task_id']}/output", headers=HEADERS, params={"limit": 100}, ).json()["rows"] for row in rows: print(flatten(row)) ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const flatten = (row) => Object.fromEntries( Object.entries(row) .filter(([k, v]) => !k.startsWith("_") && v && typeof v === "object" && "value" in v) .map(([k, v]) => [k, v.value]), ); const { rows } = await fetch(`${AUTUMN}/task/${task.task_id}/output?limit=100`, { headers: HEADERS, }).then((r) => r.json()); rows.map(flatten); ``` Validate the flattened rows against your own types (Pydantic, Zod, or whatever your app already uses) and drop rows that don't fit. Keep `output` singular. If the artifact you want changes later, continue the task and replan rather than sending a second `output`. [Outputs and sources](/docs/concepts/outputs) covers why. ## Output kinds `kind` tells Autumn what sort of artifact it is building: `research`, `person`, or `company`. See [Outputs and sources](/docs/concepts/outputs) for what each one is for. ## Related The full task spec, field by field. Add a column to results you already have. # Introduction Source: https://www.autumn.ai/docs/index Intelligence agents for the public web. Hand off a goal, get back finished, sourced data. Autumn turns a single request into finished, sourced data. Give it a goal and it plans, searches the web, scrapes pages, cross-checks facts, and returns clean output rows with the sources behind every value. One API call does the work of a whole research and enrichment pipeline, and it keeps running in the cloud while you do something else. Every task gets a durable `task_id`, its own sandbox and agent, task-local files, streamed events, and output rows you can fetch any time. Start a task, walk away, and come back to results. When you need changes, continue the same task instead of starting over. Autumn is one HTTP API. Start with the [Quickstart](/docs/quickstart), read the [Task API](/docs/api-routes) for every route, or install the [Skill](/docs/skill) to give another agent the same task surface. ## Quick start ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"prompt": "Find 20 AI infrastructure startups hiring founding engineers", "clarify": false}' ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os, requests r = requests.post( "https://api.autumn.ai/task", headers={"X-API-Key": os.environ["AUTUMN_API_KEY"]}, json={"prompt": "Find 20 AI infrastructure startups hiring founding engineers", "clarify": False}, ) print(r.json()["task_id"]) ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const res = await fetch("https://api.autumn.ai/task", { method: "POST", headers: { "X-API-Key": process.env.AUTUMN_API_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ prompt: "Find 20 AI infrastructure startups hiring founding engineers", clarify: false, }), }); const { task_id } = await res.json(); ``` The response includes a `task_id`. Keep it. Use it to stream events, continue the task, read status, and fetch output. ## The model Autumn exposes one public primitive: a **task**. You hand it a goal; it plans, works the web, and writes output rows you can fetch any time. One planning flag, `clarify`, decides whether it may stop to ask a question first. [The task model](/docs/concepts/tasks) covers this properly: start modes, turns, and why continuing a task beats starting a new one. ## When to use Autumn Reach for Autumn when the work is too big or too slow for a single chat turn and you want it done end to end: * finding or enriching companies, people, jobs, filings, pages, or contacts * collecting rows with sources and evidence * scraping or checking multiple public sources * continuing a previous task without starting over * producing output files or task-local artifacts Avoid Autumn for quick questions your agent can answer directly. ## API key Create an API key in Autumn settings under **API**, then keep it in an environment variable: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} export AUTUMN_API_KEY=your_key ``` Every request sends it as `X-API-Key` or `Authorization: Bearer`. See [Authentication](/docs/api-routes#authentication). ## Next Start a task, wait for it, and read the rows. HTTP routes for starting, streaming, continuing, and reading tasks. Install the Autumn skill in Claude Code or any agent that reads skills. Drop Autumn into your coding agent with one link. # Principles Source: https://www.autumn.ai/docs/principles The design decisions behind Autumn, and what they buy you. Autumn exists to make web research and enrichment something you hand off, not something you babysit. A few decisions follow from that, and they explain most of how the API behaves. **One primitive.** Everything is a task. There are no separate products for scraping, enrichment, and research; there is one agent that plans the work your goal requires. Learn the task and you have learned the platform. **Finished means sourced.** A row you cannot audit is a liability. Every value in every output row carries the source it came from, so "done" includes the evidence, not just the data. **Durable by default.** A `task_id` outlives the request that created it and the run that finished it. Results are there when you come back, and the task can always take another instruction. **Continue, don't restart.** Refinement is the normal case, so tasks keep their plan, rows, and files across turns. Fixing a list should cost one message, not a rerun. **Ask at most once.** Automation cannot answer questions, so the agent infers defaults and proceeds. One flag, `clarify`, permits one blocking question when a human is actually there. **Agents are first-class callers.** The API is one HTTP surface with an installable [Skill](/docs/skill) and an [llms-full.txt](https://www.autumn.ai/docs/llms-full.txt) twin, so another agent can drive Autumn as easily as your code does. # Quickstart Source: https://www.autumn.ai/docs/quickstart Start your first Autumn task over HTTP and read the rows it produces. One `POST` starts a cloud agent that does the research. You keep the `task_id`, wait while it works, then read finished rows. One host, and every route is in the spec: ```txt theme={"theme":{"light":"github-light","dark":"github-dark"}} Base URL: https://api.autumn.ai OpenAPI: https://api.autumn.ai/openapi.json Auth: X-API-Key: YOUR_AUTUMN_API_KEY ``` ## 1. Get an API key Create an API key in Autumn settings under **API**, then put it in your environment: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} export AUTUMN_API_KEY=your_key ``` Every request sends it as `X-API-Key` (or `Authorization: Bearer`). ## 2. Start a task ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "prompt": "List the top 20 posts on Hacker News today with their points", "clarify": false }' ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os, requests AUTUMN = "https://api.autumn.ai" HEADERS = {"X-API-Key": os.environ["AUTUMN_API_KEY"]} task = requests.post( f"{AUTUMN}/task", headers=HEADERS, json={"prompt": "List the top 20 posts on Hacker News today with their points", "clarify": False}, ).json() task_id = task["task_id"] ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const AUTUMN = "https://api.autumn.ai"; const HEADERS = { "X-API-Key": process.env.AUTUMN_API_KEY, "Content-Type": "application/json", }; const res = await fetch(`${AUTUMN}/task`, { method: "POST", headers: HEADERS, body: JSON.stringify({ prompt: "List the top 20 posts on Hacker News today with their points", clarify: false, }), }); const { task_id } = await res.json(); ``` The response is your handle on the task: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "task_id": "8fab6f34", "status": "execute", "phase": "execute", "stream_url": "/task/8fab6f34/stream", "output_url": "/task/8fab6f34/output" } ``` Store `task_id`. It stays valid after the run finishes. ## 3. Wait for it to finish Poll `GET /task/{task_id}`. A finished task returns to `status: "plan"` with `activity: "idle"`. Don't poll on `status` alone. `plan` is also the state a task sits in *before* it executes, so `status: "plan"` by itself does not mean finished. A task is still working while `phase` is `execute`, `status` is `execute`/`running`, or `activity` is `executing`/`running`/`planning`/`thinking`. Treat `deleted` and an `error` of `out_of_credits`/`error` as terminal too, or the loop will never exit. ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import time ACTIVE_STATUSES = {"execute", "running"} ACTIVE_ACTIVITIES = {"executing", "running", "planning", "thinking"} def is_terminal(task): if task.get("status") == "deleted" or task.get("activity") == "deleted": return True if task.get("error") in {"out_of_credits", "error"}: return True return not (task.get("phase") == "execute" or task.get("status") in ACTIVE_STATUSES or task.get("activity") in ACTIVE_ACTIVITIES) while True: task = requests.get(f"{AUTUMN}/task/{task_id}", headers=HEADERS).json() if is_terminal(task): break time.sleep(2) ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const ACTIVE_STATUSES = new Set(["execute", "running"]); const ACTIVE_ACTIVITIES = new Set(["executing", "running", "planning", "thinking"]); const isTerminal = (t) => t.status === "deleted" || t.activity === "deleted" || ["out_of_credits", "error"].includes(t.error) || !(t.phase === "execute" || ACTIVE_STATUSES.has(t.status) || ACTIVE_ACTIVITIES.has(t.activity)); let task; do { await new Promise((r) => setTimeout(r, 2000)); task = await fetch(`${AUTUMN}/task/${task_id}`, { headers: HEADERS }).then((r) => r.json()); } while (!isTerminal(task)); ``` ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} # poll every 2s until status=plan and activity=idle while :; do curl -sS "https://api.autumn.ai/task/$TASK_ID" -H "X-API-Key: $AUTUMN_API_KEY" sleep 2 done ``` This is the complete terminal check, including the `deleted` and out-of-credits cases. [Task lifecycle](/docs/concepts/lifecycle) explains why each one is in there. Prefer live events over polling? See [Live messages](/docs/guides/streaming). ## 4. Read the rows ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS "https://api.autumn.ai/task/$TASK_ID/output?limit=100" \ -H "X-API-Key: $AUTUMN_API_KEY" ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} rows = requests.get( f"{AUTUMN}/task/{task_id}/output", headers=HEADERS, params={"limit": 100}, ).json()["rows"] for row in rows: print({k: v["value"] for k, v in row.items() if isinstance(v, dict) and "value" in v}) ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const { rows } = await fetch( `${AUTUMN}/task/${task_id}/output?limit=100`, { headers: HEADERS }, ).then((r) => r.json()); ``` Each field arrives as a cell, `{"value": ..., "source_id": ...}`, so every value carries the source behind it. Flatten to plain values when you just want the data, and keep the cells when you need provenance. See [Outputs](/docs/concepts/outputs). ## 5. Continue instead of restarting The `task_id` is durable. To refine or extend results, send the same task new instructions rather than starting over: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -sS -X POST "https://api.autumn.ai/task/$TASK_ID/continue" \ -H "X-API-Key: $AUTUMN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"message": "Add the submitting user for every row, and find 10 more"}' ``` ## What a task can do * **Data extraction**: scrape sites and collect structured rows with sources * **Enrichment**: fill in people, companies, jobs, contacts, filings * **Multi-step research**: search across many sources, compare, and summarize * **List building**: find N entities that match criteria, with per-row evidence * **Continuation**: refine, expand, or fix a previous task without starting over ## Next Declare the exact columns you want back. Stream events as the agent works. Continue the same task with new instructions. Every route, field, and response shape. # Skill Source: https://www.autumn.ai/docs/skill Install the Autumn Skill for agent workflow guidance. The Autumn Skill teaches an agent to use Autumn as an async task system: default to `clarify=false`, start a durable `task_id`, stream or poll status, fetch output, and continue existing tasks instead of starting over. ## Install ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} npx skills add https://www.autumn.ai ``` This reads Autumn's skill manifest and installs the skill wherever your agent keeps them. ## Direct file Point any agent that loads a skill from a URL at the file itself: ```txt theme={"theme":{"light":"github-light","dark":"github-dark"}} https://www.autumn.ai/skill.md ``` ## Claude Code project skill ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} mkdir -p .claude/skills/autumn curl -L https://www.autumn.ai/skill.md -o .claude/skills/autumn/SKILL.md ``` ## Claude Code personal skill ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} mkdir -p ~/.claude/skills/autumn curl -L https://www.autumn.ai/skill.md -o ~/.claude/skills/autumn/SKILL.md ``` ## Prompt after install ```txt theme={"theme":{"light":"github-light","dark":"github-dark"}} Use the installed Autumn skill for Autumn tasks. When I ask for research, scraping, enrichment, list building, or structured data collection: 1. Check credits with GET /credits when useful. 2. Start natural-language tasks with POST /task and {"prompt": "...", "clarify": false}. 3. Start known task specs with POST /task/start. 4. Continue with POST /task/{task_id}/continue when the user refines the task. 5. Poll GET /task/{task_id} while the task is executing, and fetch rows with GET /task/{task_id}/output before reporting results. Use https://api.autumn.ai with my Autumn API key in the Authorization: Bearer header. ``` # Vibecoding Source: https://www.autumn.ai/docs/vibecoding Drop Autumn into your coding agent with one link. Copy this link and paste it into your coding agent (Cursor, Claude Code, Windsurf, etc.). It contains everything the agent needs to build with Autumn. ``` https://www.autumn.ai/docs/llms-full.txt ``` For a shorter index: ``` https://www.autumn.ai/docs/llms.txt ``` ## What's in it `llms-full.txt` is the entire Autumn developer surface in one file optimized for LLMs: * the task model and `clarify` semantics * every Task API route with request and response shapes * streaming events, output rows, and file uploads * the Skill install and setup ## Prompt to get started After pasting the link, you can say: ```txt theme={"theme":{"light":"github-light","dark":"github-dark"}} Use the Autumn Task API to build this. Autumn runs durable research/enrichment tasks over HTTP: POST /task with a prompt, keep the task_id, stream or poll while it works, then read rows from GET /task/{task_id}/output. Default to clarify=false for automation. Don't print my API key. ```