> ## Documentation Index
> Fetch the complete documentation index at: https://open.manus.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Website

> Manage websites built by Manus agents — inspect, version, publish, and configure

<sup>Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai).</sup>

Manus agents can build web apps — see the [Webapp feature](https://manus.im/features/webapp) for what the product can do. When an agent builds a site inside a task, it produces a **website** with its own version history and a hosted URL once published. The `website.*` endpoints manage those websites:

* [website.status](https://open.manus.ai/docs/v2/website.status) — inspect the current title, publish state, live URL, and visibility
* [website.listCheckpoints](https://open.manus.ai/docs/v2/website.listCheckpoints) — read the current title and browse version history
* [website.publish](https://open.manus.ai/docs/v2/website.publish) — deploy the latest checkpoint and return the current title
* [website.update](https://open.manus.ai/docs/v2/website.update) — change website configuration without redeploying

<Note>
  To have an agent **build** a website, create a task with [task.create](https://open.manus.ai/docs/v2/task.create). Once the session has a website attached, the endpoints on this page take over.

  To have an agent **edit** a website it built earlier, see [Edit a website in a new task](#edit-a-website-in-a-new-task).
</Note>

## Quickstart: publish a site

After the agent has built something (the task's session now has a website), deploy it with one call and poll for the live URL:

```bash theme={null}
# 1. Deploy the latest checkpoint — defaults to public
curl -X POST 'https://api.manus.ai/v2/website.publish' \
  -H 'x-manus-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"task_id": "session-xxx"}'
# → { "ok": true, "request_id": "req_abc123", "website_id": "site-abc", "title": "My landing page", "version_id": "v003" }

# 2. Poll status until published / failed
while true; do
  RESP=$(curl -sS "https://api.manus.ai/v2/website.status?website_id=site-abc" \
    -H 'x-manus-api-key: YOUR_API_KEY')
  STATUS=$(echo "$RESP" | jq -r .publish_status)
  echo "status: $STATUS"
  [[ "$STATUS" == "published" || "$STATUS" == "failed" ]] && break
  sleep 2
done

# 3. Read the primary site URL and open it
echo "$RESP" | jq -r '.site_urls[0]'
```

Deployment is asynchronous — `website.publish` returns immediately while the deploy runs in the background.
The response does not echo `visibility`. Read `website.status.visibility` after the publish request to confirm the effective value.

## Other common flows

**Ship an updated build.** After the agent makes more changes (new checkpoints), call `website.publish` again — it always deploys the **latest** checkpoint. There is no way to pin an older checkpoint via this API. Pass `visibility` again on every republish when the site is not `public`; omitting it resets the site to `public`.

**Publish for the owner and invited collaborators only.** Pass `"visibility": "private"` when publishing:

```bash theme={null}
curl -X POST 'https://api.manus.ai/v2/website.publish' \
  -H 'x-manus-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"website_id": "site-abc", "visibility": "private"}'
```

**Browse version history.**

```bash theme={null}
curl 'https://api.manus.ai/v2/website.listCheckpoints?task_id=session-xxx' \
  -H 'x-manus-api-key: YOUR_API_KEY'
```

Read the top-level `title` for the website's current display title. Match each `data[].version_id` against `published_version_id` in the same response to find which checkpoint is currently live. The title is website-level metadata and does not belong to an individual checkpoint.

**Change metadata without redeploying.**

```bash theme={null}
curl -X POST 'https://api.manus.ai/v2/website.update' \
  -H 'x-manus-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"website_id": "site-abc", "title": "My landing page", "visibility": "team"}'
```

Pass any supported fields — omitted fields are left unchanged. This does **not** trigger a new deployment, only a configuration update and a CDN refresh; it works even before the site has ever been published.

**Take a site offline.** There is no public unpublish endpoint at this time. If you need to take a site down, contact [api-support@manus.ai](mailto:api-support@manus.ai).

## Edit a website in a new task

To have an agent change an existing website, create a new task with the top-level `website` field next to your instruction. This works the same way as attaching the website in the Manus app: the new task opens the website and edits it.

```bash theme={null}
curl -X POST 'https://api.manus.ai/v2/task.create' \
  -H 'x-manus-api-key: YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "message": {
      "content": [
        {"type": "text", "text": "Change the hero headline to \"Spring sale\" and make the main button green."}
      ]
    },
    "website": {"id": "site-abc"}
  }'
# → { "ok": true, "request_id": "req_abc123", "task_id": "session-yyy", "task_title": "...", "task_url": "..." }
```

`website.id` is the same ID the `website.*` endpoints call `website_id` — read it from `website.status` or `website.publish`. If you only know the task that built the website, call `website.status` with that `task_id`. Do not use the `id` from [artifact.list](https://open.manus.ai/docs/v2/artifact.list): it identifies the Library item and is not always the website ID. When the task finishes, call `website.publish` with the website ID to deploy the edits, unless `auto_publish` is enabled for the website. If the site is not `public`, pass its `visibility` again; omitting it resets the site to `public` (see **Ship an updated build** above).

Rules for the `website` field:

* **Include an instruction.** `message.content` must contain non-empty text that describes the change: a plain string or a non-empty `text` part. A `hidden` text part also counts (see [Hidden application context](https://open.manus.ai/docs/v2/hidden-application-context)). A request with a website but no instruction is rejected, because the agent would not know what to change.
* **`task.create` only.** [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) has no `website` field. The task stays attached to the website, so follow-up messages only need the instruction.
* **One website, always edited.** `website` takes a single website, and there is no reference-only mode.
* **Not a content part.** Do not put the website inside `message.content`; a `{"type": "website"}` content part is rejected.
* **Web websites you own.** `website.id` must be a web website owned by the authorized user. Mobile apps and games are not accepted here. A Standard OAuth client with only the `create_task` scope can use only websites whose source task it created — the same boundary as `message.task_references`.

| Status / code | When |
| - | - |
| `400 invalid_argument` | An empty `website` object, a blank `website.id` or one with surrounding whitespace, no non-empty text instruction, or a `website` part inside `message.content` |
| `400 failed_precondition` | The website has no source task to continue editing from |
| `403 permission_denied` | The authorized user does not own the website |
| `404 not_found` | `website.id` does not exist, is not a web website (for example, a mobile app or game), or is not initialized yet; or a Standard OAuth client with only `create_task` did not create the website's source task |
| `503 unavailable` | The website could not be resolved right now — retry with backoff |

## Reference

### Anatomy of a website

| Concept | What it is |
| - | - |
| **Website** | The site itself, identified by a `website_id`. One session (`task_id`) typically owns one website. |
| **Title** | The website's current display title. It is website-level metadata and is not versioned with checkpoints. |
| **Checkpoint** | A point-in-time snapshot of the site, backed by a git commit. Has its own `version_id`, `message`, `status`, `created_at`. |
| **Publish state** | Whether the site is deployed, and which checkpoint is live. Tracked on the site, not on individual checkpoints. |
| **Visibility** | Who can access the live site (`public` / `team` / `private`). |

### Locating a website

All four endpoints accept either `task_id` or `website_id` — exactly one must be provided:

| Field | What it is | Where to get it |
| - | - | - |
| `task_id` | Session UID | Returned by task APIs (e.g. [task.create](https://open.manus.ai/docs/v2/task.create)) |
| `website_id` | Unique website ID | Returned by `website.status` and `website.publish` |

<Warning>
  Passing both `task_id` and `website_id` — or neither — returns `400 invalid_argument`. A session is expected to contain exactly one website; if more exist, the first is used.
</Warning>

### Website access

Website access is evaluated for the user represented by the API key or OAuth token. The website owner can read and write it. Other callers inherit access from the website's source task: read access allows `website.status` and `website.listCheckpoints`, while write access allows `website.publish` and `website.update`.

For `website.*`, OAuth client scopes and client identity do not further restrict which websites the authorized user can access. This differs from `task.*`: a standard client with only `create_task` can operate a website whose source task was not created by that client, provided the authorized user has the required website access.

A request returns `403 permission_denied` when the authorized user lacks the required access.

### Site URLs

When a site is published, `website.status` returns `site_urls` — an array of every hostname the site can be reached on, ordered from default to most specific:

1. **Space URL** — `https://{space_id}.manus.space`. Always present for a published site.
2. **Sub-domain URL** — `https://{sub_domain}.manus.space`. Only when the owner has configured a sub-domain.
3. **Custom domains** — `https://{custom_domain}` for each active custom domain bound by the owner.

For a simple "open the site" flow, `site_urls[0]` is enough — it's always the space URL. The array is empty whenever `publish_status` is not `published`.

### Publish states

| `publish_status` | Meaning | What to do |
| - | - | - |
| `unpublished` | Never published, or previously taken down | Call `website.publish` |
| `publishing` | Deployment in progress | Poll again |
| `published` | Live — `site_urls` is reachable | Read `site_urls` / `version_id` |
| `failed` | Last deployment failed | Retry `website.publish` |

### Checkpoint status vs. publish state

A checkpoint's own `status` (`pending` / `success` / `failed` / `unspecified`) only says whether the snapshot was generated successfully — a `success` checkpoint is **not** automatically live. To find the live version, compare `website.status.version_id` (or `website.listCheckpoints.published_version_id`) against `data[].version_id`.

### Visibility

| Value | Who can access | Notes |
| - | - | - |
| `public` | Anyone on the internet | Default for `website.publish` |
| `team` | Team members of the site owner | Team accounts only |
| `private` | Owner and invited collaborators | Available in `website.publish` and `website.update` |

Sites may additionally cap the maximum visibility they accept — for example, a team-only site cannot be set to `public`. Requests that exceed the allowed visibility return `403 permission_denied`.

### `website.publish` vs. `website.update`

| | `website.publish` | `website.update` |
| - | - | - |
| Triggers deploy | ✅ Deploys the latest checkpoint | ❌ Configuration only |
| Default `visibility` | `public` when omitted or empty; replaces the current value | Omitted = unchanged; empty string is invalid |
| Precondition | At least one checkpoint (`400 failed_precondition` otherwise) | None |
| Side effects | Runs the deployment pipeline | Refreshes CDN in the background |

### Errors

| Status / code | When |
| - | - |
| `401 unauthenticated` | Missing or invalid API key or OAuth token |
| `400 invalid_argument` | Both `task_id` and `website_id` passed, neither passed, invalid `visibility`, or `website.update` with nothing to update |
| `400 failed_precondition` | `website.publish` called on a site with no checkpoint, or on a site that cannot be published yet: publishing requires a membership, configured secrets, or publishing configuration the site does not have, or the latest build is not ready to publish |
| `403 permission_denied` | Caller lacks access to the site, or the requested `visibility` exceeds what the site allows |
| `404 not_found` | No website for the given session, or `website_id` does not exist / is not a website / is not initialized yet |
| `409 aborted` | The website changed while the request was being processed — retry |
| `500 internal` | Server-side error — include `request_id` when reporting |
| `503 unavailable` | The website service is temporarily unavailable — retry with backoff |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.