> ## Documentation Index
> Fetch the complete documentation index at: https://notte-docs-anything-api-v2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Anything API

> Build and run web automations from a single API call

<Tip>
  STOP. Do not read past this section until you have read and followed [/quickstart.md](/quickstart.md).

  Goal: produce a reliable SDK automation script. The intended authoring flow is generate then edit, not write browser automation from scratch.

  Do not hand-write SDK code with element IDs, selectors, or form fields from memory. Element IDs, selectors, and field mappings must come from a live `observe()` call, CLI `notte page observe` output, or generated workflow code. Guessed browser targets fail on real pages.

  Use the Notte skill and CLI to inspect the live site, validate actions/selectors, handle auth/session state, and export workflow code with `notte sessions workflow-code` before using SDK docs or SDK code.

  SDK reference pages are for understanding, running, or editing generated workflow code. They are not the starting point for manually authoring the initial browser automation. SDK-first code is guesswork on real-world pages with dynamic selectors, auth state, CAPTCHAs, and anti-bot behavior.
</Tip>

The Anything API lets you describe a task in plain English, and Notte will build, deploy, and run a web automation function for you -- all through a single HTTP request. The response streams the agent's progress as an [AI SDK UI message stream](https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol), or you can detach and let the run continue in the background.

<CardGroup cols={2}>
  <Card title="Try it now" icon="arrow-up-right-from-square" href="https://anything.notte.cc">
    Open the Anything API web app.
  </Card>

  <Card title="Get your API key" icon="key" href="https://console.notte.cc">
    Create an account on the Console to get started.
  </Card>
</CardGroup>

## Quick start

```bash theme={null}
curl -N -X POST https://anything.notte.cc/api/anything/start \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $NOTTE_API_KEY" \
  -d '{"query": "fetch the top 3 hacker news posts"}'
```

The API streams the agent's work back as an AI SDK UI message stream. The `x-thread-id` response header identifies the thread handling your run, so you can send follow-up turns into the same thread later.

## Request

<ParamField path="query" type="string" required>
  A natural-language description of the task you want automated.
</ParamField>

<ParamField path="thread_id" type="string (UUID)">
  Send a follow-up turn into an existing thread. The sandbox state and conversation carry over. Omit to start a new thread.
</ParamField>

<ParamField path="detach" type="boolean" default="false">
  Start the run and return immediately instead of streaming. See [Detached mode](#detached-mode).
</ParamField>

<ParamField path="model" type="string">
  Optional model override for the agent.
</ParamField>

<ParamField path="reasoningEffort" type="string">
  Optional reasoning effort override for the agent.
</ParamField>

<ParamField path="version" type="string" default="v2">
  API contract version. `"v2"` is the only supported value and the default, so you can omit this field. Explicit `"v1"` returns `400` -- see [Migrating from v1](#migrating-from-v1).
</ParamField>

```json POST /api/anything/start theme={null}
{
  "query": "fetch the top 3 hacker news posts"
}
```

**Headers**

| Header          | Required | Description              |
| --------------- | -------- | ------------------------ |
| `Authorization` | Yes      | `Bearer <NOTTE_API_KEY>` |
| `Content-Type`  | Yes      | `application/json`       |

## Response

### Streamed (default)

By default, the response is an [AI SDK UI message stream](https://ai-sdk.dev/docs/ai-sdk-ui/stream-protocol) -- the same format the Vercel AI SDK's `useChat` hook consumes, so you can point a chat UI straight at the endpoint or read the stream yourself.

**Response headers**

| Header                          | Description                                                                      |
| ------------------------------- | -------------------------------------------------------------------------------- |
| `x-thread-id`                   | ID of the thread handling this run. Use it as `thread_id` in follow-up requests. |
| `x-vercel-ai-ui-message-stream` | `v1` -- the AI SDK's stream-format version. Unrelated to the retired v1 backend. |

### Detached mode

Pass `detach: true` to start the run and return immediately with `202 Accepted`:

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://anything.notte.cc/api/anything/start \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer $NOTTE_API_KEY" \
    -d '{"query": "fetch the top 3 hacker news posts", "detach": true}'
  ```

  ```python start_detached.py theme={null}
  import os

  import requests

  NOTTE_API_KEY = os.environ["NOTTE_API_KEY"]

  response = requests.post(
      "https://anything.notte.cc/api/anything/start",
      headers={
          "Authorization": f"Bearer {NOTTE_API_KEY}",
          "Content-Type": "application/json",
      },
      json={"query": "fetch the top 3 hacker news posts", "detach": True},
      timeout=30,
  )
  response.raise_for_status()  # 202 Accepted

  run = response.json()
  print("Thread ID:", run["thread_id"])
  print("Status:", run["status"])  # "started"
  print("Follow along at:", run["url"])
  ```
</CodeGroup>

The response body contains:

| Field       | Description                                                                |
| ----------- | -------------------------------------------------------------------------- |
| `thread_id` | ID of the thread handling the run (also sent as the `x-thread-id` header). |
| `url`       | Link to the thread page in the app, where you can follow the run.          |
| `status`    | `"started"`                                                                |

## Follow-up turns

Pass the `thread_id` from a previous response to continue the conversation in the same thread. The sandbox state and conversation history carry over, so the agent can build on its earlier work:

```bash theme={null}
curl -N -X POST https://anything.notte.cc/api/anything/start \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $NOTTE_API_KEY" \
  -d '{
    "query": "now also include each post'\''s comment count",
    "thread_id": "820a7cff-613b-4529-9ba4-52c7a6777713"
  }'
```

Follow-up turns work in both streamed and detached mode.

## Consuming the stream

### Python

```python consume_stream.py theme={null}
import json
import os

import requests

NOTTE_API_KEY = os.environ["NOTTE_API_KEY"]

response = requests.post(
    "https://anything.notte.cc/api/anything/start",
    headers={
        "Authorization": f"Bearer {NOTTE_API_KEY}",
        "Content-Type": "application/json",
    },
    json={"query": "fetch the top 3 hacker news posts"},
    stream=True,
    timeout=(10, 600),
)
response.raise_for_status()

# The thread ID lets you send follow-up turns later
thread_id = response.headers["x-thread-id"]
print("Thread ID:", thread_id)

for line in response.iter_lines():
    if not line:
        continue
    decoded = line.decode("utf-8")
    if not decoded.startswith("data: "):
        continue
    payload = decoded[len("data: ") :]
    if payload == "[DONE]":
        break
    chunk = json.loads(payload)
    print(chunk.get("type"), chunk)
```

### TypeScript

```typescript theme={null}
const response = await fetch("https://anything.notte.cc/api/anything/start", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${NOTTE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ query: "fetch the top 3 hacker news posts" }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}
if (!response.body) {
  throw new Error("ReadableStream not available");
}

// The thread ID lets you send follow-up turns later
const threadId = response.headers.get("x-thread-id");
console.log("Thread ID:", threadId);

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split("\n");
  buffer = lines.pop()!;

  for (const line of lines) {
    if (!line.startsWith("data: ")) continue;
    const payload = line.slice("data: ".length);
    if (payload === "[DONE]") break;
    const chunk = JSON.parse(payload);
    console.log(chunk.type, chunk);
  }
}
```

If you are building a chat interface, you can skip the manual parsing: the stream is directly compatible with the [AI SDK's `useChat` hook](https://ai-sdk.dev/docs/ai-sdk-ui/chatbot).

## Re-running a created function

When a run creates a reusable **Notte Function**, you can run it again via the [Notte CLI](https://github.com/nottelabs/notte-cli) or [SDK](/quickstart):

<CodeGroup>
  ```bash CLI theme={null}
  notte functions run \
    --function-id d3c31289-f28b-49bd-a340-95e071cfef7e \
    --vars '{"count": "3"}' \
    -o json
  ```

  ```python run_function.py theme={null}
  from notte_sdk import NotteClient

  client = NotteClient()
  result = client.functions.run(
      function_id="d3c31289-f28b-49bd-a340-95e071cfef7e",
      variables={"count": "3"},
  )
  print(result)
  ```
</CodeGroup>

## Migrating from v1

<Warning>
  The v1 backend is retired. Requests with `version: "v1"` return `400 {"error": "unsupported_version"}` with a retirement message.
</Warning>

If you were calling the v1 API:

* **Omit `version`** (or send `"v2"`). It now defaults to `"v2"`.
* **Responses are an AI SDK UI message stream** instead of the v1 SSE event feed. The v1 event types (`status`, `thinking_delta`, `done`, ...) no longer exist.
* **Follow-ups use `thread_id`.** The v1 concepts `resume_strategy`, snapshot semantics, and `claude_code_session_id` are gone: pass the `thread_id` from the `x-thread-id` response header to continue a thread.
* The `x-vercel-ai-ui-message-stream: v1` response header refers to the AI SDK's own stream-format version, not the retired v1 backend.

## Error handling

| Status | Meaning                                                                         |
| ------ | ------------------------------------------------------------------------------- |
| `400`  | Missing `query` field, invalid JSON, or `version: "v1"` (`unsupported_version`) |
| `401`  | Missing or invalid API key                                                      |
