# agent.detail Source: https://open.manus.ai/docs/v2/agent.detail GET /v2/agent.detail Retrieves an agent's details including its nickname, description, and associated task. Use [agent.update](https://open.manus.ai/docs/v2/agent.update) to modify, or [task.list](https://open.manus.ai/docs/v2/task.list) with `scope=agent_subtask` to view this agent's subtasks. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # agent.list Source: https://open.manus.ai/docs/v2/agent.list GET /v2/agent.list Lists all custom agents in your account. Use the returned IDs in [task.list](https://open.manus.ai/docs/v2/task.list) with `scope=agent_subtask` to view subtasks, or in [agent.detail](https://open.manus.ai/docs/v2/agent.detail) for full details. See the [Agents](https://open.manus.ai/docs/v2/agents-overview) guide. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # agent.update Source: https://open.manus.ai/docs/v2/agent.update POST /v2/agent.update Updates an agent's nickname and description. Use [agent.detail](https://open.manus.ai/docs/v2/agent.detail) to view current values before updating. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # Agents Source: https://open.manus.ai/docs/v2/agents-overview Interact with agents and their tasks via the API Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). Agents are custom AI entities in Manus with their own identity (nickname and description) that can be customized for specific use cases. This includes the agents you create in the Cue app. Each agent has a **main task** that serves as its persistent conversation thread. You can manage agents and interact with their tasks through the API. Every account comes with a default **IM (Instant Messaging) agent** for general-purpose conversations. You can access it directly using [shortcuts](#shortcuts) without looking up its UUID. ## Quick start: talk to an agent Every agent's `task_id` from [agent.list](https://open.manus.ai/docs/v2/agent.list) or [agent.detail](https://open.manus.ai/docs/v2/agent.detail) is its main task. Pass it as `task_id` to [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) to talk to that agent. For the IM agent, the shortcut `agent-default-main_task` resolves to the same task, so no lookup is needed: **cURL** ```bash theme={null} # Send a message to the IM agent curl -X POST https://api.manus.ai/v2/task.sendMessage \ -H "Content-Type: application/json" \ -H "x-manus-api-key: $MANUS_API_KEY" \ -d '{ "task_id": "agent-default-main_task", "message": { "content": "Summarize today's tech news" } }' ``` **Python** ```python theme={null} import requests response = requests.post( "https://api.manus.ai/v2/task.sendMessage", headers={ "Content-Type": "application/json", "x-manus-api-key": MANUS_API_KEY, }, json={ "task_id": "agent-default-main_task", "message": {"content": "Summarize today's tech news"}, }, ) print(response.json()) ``` Then poll for the agent's response: ```bash theme={null} curl 'https://api.manus.ai/v2/task.listMessages?task_id=agent-default-main_task&order=desc&limit=5' \ -H 'x-manus-api-key: $MANUS_API_KEY' ``` ## Shortcuts The following shortcuts are available so you don't need to look up UUIDs first: | Shortcut | Used as | Description | | - | - | - | | `agent-default-main_task` | `task_id` | The IM agent's main task. Accepted anywhere a `task_id` is expected. | | `agent-default` | `agent_id` | The IM agent. Use in [task.list](https://open.manus.ai/docs/v2/task.list) with `scope=agent_subtask`. | ## Managing agents Use the `agent.*` endpoints to list, view, and update your agents: | Action | Endpoint | | - | - | | List all agents | [agent.list](https://open.manus.ai/docs/v2/agent.list) | | View agent details | [agent.detail](https://open.manus.ai/docs/v2/agent.detail) | | Update nickname / description | [agent.update](https://open.manus.ai/docs/v2/agent.update) | ## Agent subtasks Agents can create subtasks during execution. To view an agent's subtasks, use [task.list](https://open.manus.ai/docs/v2/task.list) with `scope=agent_subtask`: ```bash theme={null} curl 'https://api.manus.ai/v2/task.list?scope=agent_subtask&agent_id=agent-default' \ -H 'x-manus-api-key: $MANUS_API_KEY' ``` Subtasks have `task_type: "agent_subtask"` in the response and can be interacted with like any other task — [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage), [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages), [task.stop](https://open.manus.ai/docs/v2/task.stop), etc. # artifact.list Source: https://open.manus.ai/docs/v2/artifact.list GET /v2/artifact.list Lists generated task artifacts from the authenticated user's Manus Library, newest first. Temporary input files from file.upload are not included. See the [Artifacts](https://open.manus.ai/docs/v2/artifacts) guide. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only artifacts from tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. > > **Guide:** Filter rules, artifact categories, URL lifetimes, pagination, and error codes are in the [Artifacts](https://open.manus.ai/docs/v2/artifacts) guide. # Artifacts Source: https://open.manus.ai/docs/v2/artifacts List, filter, and page through generated task outputs in the Manus Library Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). [artifact.list](https://open.manus.ai/docs/v2/artifact.list) returns generated task outputs from the authenticated user's Manus Library. It does not return temporary input files uploaded through [file.upload](https://open.manus.ai/docs/v2/file.upload). ## Quick start List generated spreadsheets: ```bash theme={null} curl 'https://api.manus.ai/v2/artifact.list?type=spreadsheets&limit=20' \ -H "x-manus-api-key: $MANUS_API_KEY" ``` An example response containing one matching artifact: ```json theme={null} { "ok": true, "request_id": "request_example", "data": [ { "id": "artifact_example", "task_id": "task_example", "filename": "forecast.xlsx", "display_name": "Forecast", "type": "spreadsheets", "file_type": "file", "favorite": false } ], "has_more": false } ``` ## Filters All filters are combined with AND semantics. Parameter formats and defaults are in the [artifact.list](https://open.manus.ai/docs/v2/artifact.list) reference. `oauth_client_id` and `api_key_id` are mutually exclusive. Passing both returns `400 invalid_argument`. OAuth apps with only `create_task` are already limited to their own app's tasks: filtering by `api_key_id` or by another app's `oauth_client_id` returns `403 permission_denied`. When neither credential filter is present, API keys, OAuth apps with `manage_all_tasks`, and trusted OAuth clients can list all artifacts owned by the user, including outputs from Manus UI tasks. Restricted OAuth apps with only `create_task` always have an implicit source filter for their own app, even when neither parameter is sent. Credential-filtered lists may omit older artifacts that lack indexed source metadata. This also applies to the implicit filter for restricted `create_task` OAuth apps; omitting the filter parameters does not make those artifacts accessible to that app. An unfiltered request with an API key, `manage_all_tasks`, or a trusted OAuth client can still return these artifacts. Historical source metadata is not backfilled as part of this release. ## Artifact categories | `type` | Included formats | | - | - | | `all` | All generated artifacts | | `website` | Manus Website outputs and WebDev websites, including legacy WebDev outputs without an indexed platform | | `mobile_app` | WebDev mobile applications | | `game` | WebDev games | | `documents` | `pdf`, `doc`, `docx`, `text`, `md`, `mdx`, `txt` | | `slides` | Manus Slides and Slide XML outputs | | `spreadsheets` | `xlsx`, `xls`, `csv`, `tsv`, `numbers`, `ods` | | `images` | `jpg`, `jpeg`, `png`, `gif`, `webp`, `svg`, `bmp`, `heic`, `heif` | | `videos` | `mp4`, `avi`, `mov`, `wmv`, `webm`, `mkv`, `m4v`, `mpg`, `mpeg` | | `audio` | `mp3`, `wav`, `flac`, `aac`, `ogg`, `wma`, `m4a`, `aiff`, `opus` | | `others` | Artifacts outside the categories above | The ten specific categories are mutually exclusive and together cover `all` for the same indexed data and access scope. Each response item's `type` is the category used by the filter; `all` is only a request value. Classification uses the indexed Library file type and extension, rather than the current filename or `platform_type` returned with the artifact. Website, WebDev, and Slides classification takes precedence over extension-based categories: a Slides record with a `pdf` extension remains `slides`, and a WebDev record with an unrecognized indexed platform extension belongs to `others`. The format list does not guarantee that an agent can generate every listed format. ## URLs and resources * Downloadable artifacts return `url`. * Website and WebDev artifacts can return a site URL. An unpublished WebDev artifact can have no URL. * Mobile WebDev artifacts can return an application `logo` when one is available. * Addon artifacts return `resource_uri` instead of exposing an internal `manus-resource://` value as a download URL. * `task_id` and credential filters refer to the artifact's original creation task, not its most recent editing task. Only artifacts with an active creation task owned by the authenticated user are returned; collaboration access alone does not include a task. * Credential IDs come from the creation-time record. Deleting an API key does not erase that ID; its display name may be absent. * `source` is omitted when no API key or OAuth client ID can be attributed to the creation task. This includes UI-created tasks and API-created tasks without recorded credential IDs. An omitted `source` does not imply that the task was created in the UI. Slides and Markdown conversion are separate from artifact classification. To retrieve Slides attachments as PowerPoint, or Markdown attachments as PDF or Word, use [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages) with `slides_format=pptx` or `markdown_format=pdf` / `markdown_format=docx`. ## Pagination and ordering Results are ordered by creation time descending, with stable identifier tie-breakers. Name searches use the same ordering. Pagination has no 10,000-result offset window. When `has_more` is true, pass `next_cursor` to the next request with the same authenticated user, credential scope, filters, and `limit`. A cursor from another query is rejected. Treat cursors as opaque; restart without a cursor when changing the query. A page may contain fewer than `limit` artifacts, or even be empty, while `has_more` is true: deleted, blocked, inaccessible, and duplicate search hits are removed before returning results. Continue until `has_more` is false. A dependency failure returns an error; retry the same request and cursor rather than advancing. Within one traversal, an artifact is returned at most once by `id` and by nonempty `resource_uri`, even when it has projections in several tasks. Retrying a retained cursor replays that page and rechecks current access; apply the replay as a replacement for that page. If combining separate traversals, deduplicate by `resource_uri` when present, otherwise by `id`. Cursors expire after 5 minutes without use or 15 minutes from the start of the traversal. Only the latest 3 produced pages remain replayable. Each user can retain up to 32 traversals; opening more evicts the least recently used one. An expired, evicted, or older cursor returns `400 invalid_argument`; restart without a cursor. A traversal is limited to 2,000 pages and bounded server state; exceeding capacity returns `429 resource_exhausted`, not an end-of-list response. Refine the query before restarting. This is a live list, not a snapshot. New artifacts created after the first page normally appear on a fresh traversal. Changes to an artifact's sort position or visibility during traversal can change which items are returned. Manus-managed private CDN URLs in `url` and `cover_image` pass through the same re-signing path used by Manus Library whenever this endpoint builds a response. A successful re-sign creates a URL with a 48-hour lifetime. Treat signed URLs as temporary and call `artifact.list` again instead of storing one as a permanent artifact identifier. Re-signing is best-effort: if the signing service is unavailable, the stored URL is returned unchanged and can already be expired. Website URLs do not use this expiry, and Addon artifacts use `resource_uri`. ## Errors | Status / code | When | | - | - | | `400 invalid_argument` | Both credential filters are present, `type` is unsupported, `limit` is outside 1–100, `cursor` is invalid, expired, outside the replay window, or does not match the query. | | `403 permission_denied` | An OAuth app with only `create_task` filters by `api_key_id` or another app's `oauth_client_id`. | | `429 resource_exhausted` | The request rate or traversal capacity limit is reached. For traversal capacity, refine the query and restart without a cursor. | | `503 unavailable` | Search, source metadata, artifact details, or pagination state are temporarily unavailable. Retry the same cursor. | # Attachments Source: https://open.manus.ai/docs/v2/attachments Resolve file and website references in task message content. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). Use this guide when rendering `assistant_message.content` returned by [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages). The API returns the original message content from the task without rewriting file paths or Manus resource protocols. Use the surrounding response fields and the related APIs described below to resolve supported Markdown links or images in the application. Resolve each Markdown link or image destination by type: 1. Render HTTP and HTTPS destinations normally. Do not match them against attachment paths. 2. Resolve `manus-webdev://` destinations as described in [Website checkpoints](#website-checkpoints). 3. Match absolute execution-environment paths against message attachments as described in [File paths](#file-paths). 4. Remove link or image nodes that use another unsupported non-HTTP protocol. When a file or Manus resource reference cannot be resolved with the required context, remove that link or image node from the rendered output. Preserve the surrounding message text. The API does not perform this rendering step for the application. ## File paths An assistant can reference an output file by its execution-environment path: ```markdown theme={null} [Download the report](/home/ubuntu/report.pdf) ``` When the same message contains a matching attachment, `attachments[].path` identifies that reference and `attachments[].url` provides the downloadable HTTP/HTTPS URL: ```json theme={null} { "assistant_message": { "content": "[Download the report](/home/ubuntu/report.pdf)", "attachments": [ { "type": "file", "filename": "report.pdf", "content_type": "application/pdf", "path": "/home/ubuntu/report.pdf", "url": "https://private.manuscdn.com/...", "file_uid": "FILE_UID", "version_uid": "VERSION_UID" } ] } } ``` Parse the Markdown link or image destination, URL-decode it once, and compare it with `attachments[].path`. After a match, use `attachments[].url` as the link destination or image source. If no attachment matches this execution-environment path, remove the link or image node from the rendered output. Do not request `path` directly: it is a path inside the task's execution environment, not a public URL. `path` is optional. It is omitted for attachments that do not have a usable execution-environment path. Download URLs are temporary. If a URL stops working, call `task.listMessages` again to read the current attachment URL. Do not persist a signed URL as permanent file identity. When present, use `file_uid` and `version_uid` to correlate the source output file and version across messages. * No v2 endpoint accepts either UID as input, and neither resolves a download URL. * They are unrelated to the `file_id` of temporary input files from [file.upload](https://open.manus.ai/docs/v2/file.upload), and to the website checkpoint `version_id` in `manus-webdev://` links. * The same `file_uid` can appear in different tasks with different `url` values. Do not assume it belongs to the current task. * A transformed download, such as `slides_format=pptx` or `markdown_format=docx`, returns derived bytes while the UIDs still identify the source attachment version. ## Website checkpoints A website result can appear as a Markdown destination in this form: ```text theme={null} manus-webdev:// ``` The value after the scheme is the checkpoint `version_id` for the website attached to the current task. Call [website.listCheckpoints](https://open.manus.ai/docs/v2/website.listCheckpoints) with the same `task_id`, then match the value against `data[].version_id`. If the checkpoint cannot be resolved, remove the link node from the rendered output. Website checkpoint `version_id` and attachment `version_uid` are unrelated identifiers. Do not use an attachment `version_uid` with `website.listCheckpoints`. Use [website.status](https://open.manus.ai/docs/v2/website.status) to read the current published URL and version. A checkpoint's successful generation status does not mean that version is currently published. ## Other link protocols HTTP and HTTPS destinations can be rendered normally. Manus is gradually expanding public recovery support for other protocols. For now, an API client should remove Markdown link or image nodes whose destinations use another unsupported non-HTTP protocol. Remove only the link or image node. Preserve the surrounding message text. The API returns the original message content and does not perform this rendering step for the client. # Authentication Source: https://open.manus.ai/docs/v2/authentication Authenticate with the Manus API using API keys or OAuth2 tokens Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). The Manus API supports two authentication methods. Every request must include one of the following headers: | Header | Value | Best for | | - | - | - | | `x-manus-api-key` | Your API key | Your own integrations and scripts | | `Authorization` | `Bearer {access_token}` | Third-party OAuth2 apps acting on behalf of a user | > [!NOTE] > > Some endpoints accept only API keys and OAuth tokens from a `Trusted team client` or `Trusted public client`. Other OAuth clients cannot access these endpoints. Each endpoint page notes the supported authentication methods and required OAuth scopes. ## API Key ### Create an API key **1. Open API settings** Go to [Manus Developers settings](https://manus.im/app#settings/developers) in the Manus webapp. **2. Generate a key** Click **Create API Key** and give it a descriptive name (e.g. "production", "dev-testing"). Each account can have up to **50** API keys. **3. Copy and store securely** Copy the key immediately — it will only be shown once. Store it in a secure location such as an environment variable or secrets manager. > [!WARNING] > > Keep your API keys secure and never share them publicly. Each key provides full access to your Manus account. If a key is compromised, revoke it immediately from the settings page. > [!TIP] > > Rate limits apply **per user** (shared across all of your API keys). See [Rate Limits](https://open.manus.ai/docs/v2/rate-limits) for the per-endpoint numbers. ### Use the API key Include the key in the `x-manus-api-key` header with every request: **cURL** ```bash theme={null} curl -X POST https://api.manus.ai/v2/task.create \ -H "Content-Type: application/json" \ -H "x-manus-api-key: $MANUS_API_KEY" \ -d '{ "message": { "content": "hello" } }' ``` **Python** ```python theme={null} import os import requests response = requests.post( "https://api.manus.ai/v2/task.create", headers={ "Content-Type": "application/json", "x-manus-api-key": os.environ["MANUS_API_KEY"], }, json={ "message": { "content": "hello" } }, ) print(response.json()) ``` **TypeScript** ```typescript theme={null} const response = await fetch("https://api.manus.ai/v2/task.create", { method: "POST", headers: { "Content-Type": "application/json", "x-manus-api-key": process.env.MANUS_API_KEY!, }, body: JSON.stringify({ message: { content: "hello", }, }), }); const data = await response.json(); console.log(data); ``` ## OAuth2 Bearer Token For third-party apps that act on behalf of team users, use OAuth2 access tokens. Include the token in the `Authorization` header: ```bash theme={null} curl https://api.manus.ai/v2/task.list \ -H "Authorization: Bearer {access_token}" ``` Standard OAuth clients are scoped. Some endpoints require a specific scope, such as `create_task` or `manage_all_tasks`, while others require no OAuth scope. Each endpoint page states its requirement. See the [Open App](https://open.manus.ai/docs/v2/open-app) guide for the complete setup flow, available scopes, and token lifecycle. To identify the user associated with an API key or OAuth token, call [user.me](https://open.manus.ai/docs/v2/user.me). It returns the user ID. API Key and Trusted client callers also receive the user's display name, email, and avatar. The endpoint is read-only and does not require an additional OAuth scope. > [!NOTE] > > **Team only:** Open App creation and authorization require a Team account. Only users in the same team as the app creator can authorize the app. ## Authentication errors If the key or token is missing, the API returns: ```json theme={null} { "ok": false, "request_id": "req_abc123", "error": { "code": "unauthenticated", "message": "missing authentication: require either API Key or Bearer Token" } } ``` Invalid, expired, or revoked credentials also return `unauthenticated`. OAuth clients must use the documented message keywords to distinguish token refresh from reauthorization. See [Authentication errors](https://open.manus.ai/docs/v2/open-app#authentication-errors-http-401). # browser.onlineList Source: https://open.manus.ai/docs/v2/browser.onlineList GET /v2/browser.onlineList Lists the user's online browser clients. Use the returned `client_id` with [task.confirmAction](https://open.manus.ai/docs/v2/task.confirmAction) when the agent triggers a `needConnectMyBrowser` waiting event. See the [Task Lifecycle](https://open.manus.ai/docs/v2/task-lifecycle#using-my-browser) guide. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `use_my_browsers`. > * **Trusted client:** Full access. # connector.list Source: https://open.manus.ai/docs/v2/connector.list GET /v2/connector.list Lists connectors installed in the current user's account. Use the returned IDs in the `connectors` array of [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). See the [Connectors](https://open.manus.ai/docs/v2/connectors) guide for setup. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. Returns only connectors the user granted to the client. > * **Trusted client:** Full access. > > **Setup:** See the [Connectors](https://open.manus.ai/docs/v2/connectors) guide. # Connectors Source: https://open.manus.ai/docs/v2/connectors Connect external apps to Manus and use them in API tasks Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). ## Setup Before using a connector via the API, authorize it in the Manus web app: 1. Go to your integrations page on [manus.im](https://manus.im). 2. Click the connector you want to add and complete the OAuth flow. 3. Once connected, use its UUID in your API requests. ## Using connectors in the API Pass connector UUIDs in the `connectors` array of the `message` object when creating a task: **cURL** ```bash theme={null} curl -X POST https://api.manus.ai/v2/task.create \ -H "Content-Type: application/json" \ -H "x-manus-api-key: $MANUS_API_KEY" \ -d '{ "message": { "content": "Check my inbox for anything urgent and summarize it", "connectors": ["9444d960-ab7e-450f-9cb9-b9467fb0adda"] } }' ``` **Python** ```python theme={null} import requests response = requests.post( "https://api.manus.ai/v2/task.create", headers={ "Content-Type": "application/json", "x-manus-api-key": MANUS_API_KEY, }, json={ "message": { "content": "Check my inbox for anything urgent and summarize it", "connectors": ["9444d960-ab7e-450f-9cb9-b9467fb0adda"], } }, ) print(response.json()) ``` You can pass multiple connectors in a single task: ```json theme={null} { "message": { "content": "Check my calendar for tomorrow and email a summary to john@example.com", "connectors": [ "9444d960-ab7e-450f-9cb9-b9467fb0adda", "dd5abf31-7ad3-4c0b-9b9a-f0a576645baf" ] } } ``` ## Available connectors You can also retrieve available connectors programmatically via [connector.list](https://open.manus.ai/docs/v2/connector.list). | Connector | UUID | | - | - | | Slack | `001e6a99-5585-4b3e-b8cb-533fe24d7788` | | Notion | `9c27c684-2f4f-4d33-8fcf-51664ea15c00` | | Zapier | `433d2fe0-e56d-42b2-8625-9996eab0bb1d` | | Asana | `219459c8-f04d-41af-9a0d-6f9159bf9205` | | monday.com | `40ecbda4-5aaf-4e95-bf54-679299ea1c19` | | Make | `f8405590-5602-4fee-bfd6-f221623e6f72` | | Linear | `982c169d-0c89-4dbd-95fd-30b49cc2f71e` | | Atlassian | `74d21d62-2ba7-4840-a918-c8327db5c711` | | ClickUp | `e08b2bda-a4a6-488a-b397-c72f0923bdf4` | | OpenAI | `942ea72c-09f6-46f0-b4b3-f9890a6edbc5` | | Supabase | `84ab78ef-139c-48ff-acd4-cba718b8a484` | | Vercel | `a50c5d31-af5e-4e01-a992-057663a7ee1f` | | Anthropic | `815b5a30-463e-4662-8da7-081e3b5dfc7d` | | Neon | `9a0c8590-c0d9-498b-9b3d-bd0df0dbc134` | | Google Gemini | `4157dedf-1326-4be8-9295-51416c7dba62` | | Prisma Postgres | `4c55391d-38ea-4a36-a670-a59a1c7680cb` | | Sentry | `838d5e1c-7dd4-4782-9429-c459126707c7` | | Hugging Face | `bdfa81ea-c0ca-4022-bba1-805c48b583c1` | | Perplexity | `2a574fdc-89ab-4ad7-b334-e2c156201b6f` | | Cohere | `bbec86c8-29f6-4149-9bba-d5c66bd6a701` | | HubSpot | `b389f747-6221-41aa-9dbb-732a97a02ea6` | | Intercom | `73f5f556-978a-4f8a-85b3-ef2eec4473e5` | | ElevenLabs | `23181678-c628-4c53-9a77-36778a36bbe5` | | Stripe | `29986b52-7cbb-4d5e-9263-dd0abacaf28d` | | Grok | `491cde51-195c-4e72-96ea-8d80557c3b58` | | PayPal for Business | `e90398ef-c17d-46e8-86d6-0bd98642cbbb` | | OpenRouter | `c55a74cf-a236-4eda-8885-365d336cae4b` | | RevenueCat | `a104e1ac-73e5-482f-96e6-8b95f4756f27` | | Ahrefs | `305b3b49-32ce-4b2b-a355-3492fe85d17f` | | Close | `9b37aa72-4089-4f25-b774-122860ba61fa` | | Xero | `7c635638-0b9f-40f4-b5c8-6f2762416d79` | | Similarweb | `700c656f-b4a4-4e39-a886-a20782d99b6f` | | Dropbox | `2918a878-d84d-47af-94ce-4967b72506f5` | | My Browser | `be268223-40b2-4f3c-a907-c12eb1699283` | | Flux | `5c305236-d14e-43f7-93ff-b288afd26f09` | | Airtable | `d669ca60-22cf-4e16-93d4-845071f9216c` | | Dify | `888c4ef0-4ed7-4f8b-ade0-55a86fc531dc` | | Kling | `99474cab-58bf-47ae-af0e-43c156703be9` | | Gmail | `9444d960-ab7e-450f-9cb9-b9467fb0adda` | | Google Calendar | `dd5abf31-7ad3-4c0b-9b9a-f0a576645baf` | | Tripo AI | `3db6c7f4-0ce6-4b76-baad-c6e3c4882acd` | | Cloudflare | `119e6b13-c2e3-48db-b568-f82191de6b4e` | | Google Drive | `f8900a57-4bd7-46cc-83a3-5ebd2420a817` | | PostHog | `89dac2c3-74d0-4f94-86d1-0ee6c4566193` | | Playwright | `356d5bc1-fb9f-4fa1-babb-05039dc09d63` | | n8n | `d6b4170a-4001-450d-823a-287dfd9716a7` | | Jam | `45d392d3-d308-4cdb-8a2d-5d249bcec594` | | Outlook Mail | `d485c6dd-4939-40fb-9c4a-c9821971468b` | | Canva | `c63d86db-4c98-483a-af0c-f94721d7f2a5` | | Stripe API | `fb659ead-d821-40cc-ab35-1cad9af13649` | | Webflow | `1d489fb9-0601-4ea7-9942-b866657178c1` | | Outlook Calendar | `4bca3029-d276-4644-898d-578a723361b2` | | Cloudflare API | `80bca437-287e-4407-adf0-1a0b298528e5` | | Supabase API | `86a04f98-35cf-4099-9044-ab851a473cf5` | | Wix | `d0fa4acf-7cf6-4402-bd84-82a850342a79` | | Granola | `0d21d573-1ee0-484b-8e91-aed6534dbb19` | | Fireflies | `1b62b634-58e9-4b49-b327-339cc5aaeaf5` | | tl;dv | `f7bbbff0-61fe-458b-975a-3e2f6a91269c` | | Firecrawl | `abb9ed36-e693-44ab-be3d-1f5c3bb02294` | | Todoist | `2900673c-afaa-4dfa-901d-00a6b3f7275e` | | Polygon.io | `376008de-cd2a-4bfb-93aa-2652b8585c8e` | | ZoomInfo | `d1edd2c7-392f-4132-bcf7-7f86efe1db54` | | Mailchimp Marketing | `331ff697-8348-4ed7-a596-7df98740fc1f` | | Apollo | `bb2a05d0-d728-48eb-b796-9b71e4f9c9ee` | | Metabase | `9fe14dac-4288-4371-91a8-86a36051a865` | | Explorium | `3cb9f78b-b53a-49ef-b65e-b56eeddd641d` | | Serena | `f7f15fe8-15cf-4fb9-a546-720f16dcf5e6` | | JSONBin.io | `c8298c13-6d9a-4847-9f1f-1523952fddbd` | | HeyGen | `c183add9-c22c-4199-b7f2-d885571afa3a` | | GitHub | `bbb0df76-66bd-4a24-ae4f-2aac4750d90b` | | Apify | `cf19c9d0-5f91-4e7a-af04-593febb5c80c` | | Sales AI Assistant | `fd15db79-1975-4579-8d0a-cbc72b28fac1` | | Spend | `bc3176ba-efd9-427d-8455-fe64483e8940` | | Quick Experiments | `7f5d51a1-c7b7-442f-a99b-b176cc71a8e8` | | Instagram Creator Marketplace | `9777f7bd-4ca3-431a-98d6-a7ed5221dd81` | ## Connector selection `message.connectors` and the top-level `clear_connectors` field together decide the task's connector selection. An empty `message.connectors` array is treated the same as omitting the field. Passing a non-empty `message.connectors` together with `clear_connectors: true` returns `InvalidArgument`. Connectors not installed in your account return `InvalidArgument`. For [task.create](https://open.manus.ai/docs/v2/task.create): | Input | Behavior | | - | - | | `message.connectors` non-empty | The task starts with the listed connectors | | `clear_connectors: true` | The task starts without connectors; project and account defaults are not loaded | | Both omitted (or `connectors: []`), `project_id` provided | The task starts with the project's default connectors | | Both omitted (or `connectors: []`), `project_id` omitted | The task starts with the connectors you enabled by default in your account; installed but disabled connectors are not loaded | To change your account defaults, visit the integrations page on [manus.im](https://manus.im) and enable or disable connectors. For [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage): | Input | Behavior | | - | - | | `message.connectors` non-empty | Replaces the task's connector selection for this and later turns | | `clear_connectors: true` | Clears the task's connector selection for this and later turns | | Both omitted (or `connectors: []`) | Keeps the task's current selection; connectors uninstalled or revoked since then are skipped | On a follow-up message, omitting `message.connectors` does not re-resolve project or account defaults. Passing `connectors: []` does not clear the selection; use `clear_connectors: true`. Clearing the selection only affects connectors. Other task features may still provide tools. ```json theme={null} // task.create — start without connectors { "message": { "content": "..." }, "clear_connectors": true } // task.sendMessage — replace the selection for this and later turns { "task_id": "...", "message": { "content": "...", "connectors": ["9444d960-ab7e-450f-9cb9-b9467fb0adda"] } } // task.sendMessage — clear the selection { "task_id": "...", "message": { "content": "..." }, "clear_connectors": true } // task.sendMessage — keep the current selection (default) { "task_id": "...", "message": { "content": "..." } } ``` ## Privacy & Security All connectors use secure OAuth authentication. Your credentials are never shared with Manus directly. You can revoke access at any time from the integrations page on [manus.im](https://manus.im). # Overview Source: https://open.manus.ai/docs/v2/data-integrations-overview Access built-in third-party data directly in Manus Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). Data Sources give you access to premium third-party data built into Manus. These sources let you enrich tasks with real-time information from external platforms—without managing API keys, credentials, or integrations. ![Data Source in sessions](https://mintcdn.com/manus-api/sanvowI_pLkpBpIK/images/screenshot/data-sources_indicator.png?fit=max\&auto=format\&n=sanvowI_pLkpBpIK\&q=85\&s=5a9a3a8fd860165e6d5a8112142ec55d) ## How to Use Data Integration Simply describe the data you need in your prompt, and Manus will automatically select and use the appropriate data source. ## Use Cases > **Market Research** > > Gather competitive intelligence from social media, company profiles, and financial data. > **Investment Analysis** > > Analyze stock performance, SEC filings, and market insights for informed decisions. > **Content Discovery** > > Find and analyze trending content across YouTube and TikTok. > **Economic Research** > > Access global economic indicators and macroeconomic data for research. ## Notes > [!NOTE] > > All data sources are included with your Manus subscription. No additional API keys or setup required. > [!NOTE] > > Data availability and rate limits vary by provider and may be subject to additional restrictions. Manus automatically handles API calls and caching for optimal performance. > [!WARNING] > > Data from third-party sources is subject to their terms of service and data freshness policies. Always verify critical information from official sources. # Similarweb Source: https://open.manus.ai/docs/v2/data-integrations-similarweb Access website traffic and digital market intelligence data ## Overview Manus integrates Similarweb data access directly into your workflow. Without additional configuration or API management, you can access comprehensive website analytics and digital market intelligence simply through natural language prompts. ## How to Use Simply mention the data you need in your prompt. Manus will automatically use Similarweb to fetch the information when related info is detected. Traffic Analysis Copy the contents from the code block Ask Manus Show me monthly visits, bounce rate, and pages per visit for example.com over the last 6 months. Include month-over-month changes. Marketing Channels Copy the contents from the code block Ask Manus Break down the marketing channel mix for example.com. What percentage comes from direct, organic search, paid, social, referral, and display? Geographic Analysis Copy the contents from the code block Ask Manus Show me the top 10 countries by traffic share for example.com in 2025 Q4. I need to understand their geographic footprint. Keywords Overview ```text theme={null} Query the global search volume, clicks, and the composition of organic vs. paid traffic for the keyword 'manus'. ``` Website Analysis Keywords ```text theme={null} Analyze the main search traffic keywords for 'manus.im', listing the top keywords along with their traffic share and search intent. ``` Incoming Traffic: Referrals Desktop ```text theme={null} Query the main external referring websites for 'manus.im' on desktop, and list their traffic contribution share. ``` Incoming Traffic: Referrals Mobile Web ```text theme={null} Query the main referring sources for 'manus.im' on mobile web, to see which websites mobile users are jumping from. ``` Outgoing Traffic: Outgoing Referrals Mobile Web ```text theme={null} Analyze the outbound traffic of 'manus.im' mobile users, to see which domains users visit most frequently after leaving the site. ``` Keywords Landing Pages ```text theme={null} Query which specific URLs under the 'manus.im' domain receive the most organic search traffic, along with the desktop and mobile share. ``` Popular Pages ```text theme={null} Get the top popular pages on the 'manus.im' website based on overall traffic, and their respective share of the total site traffic. ``` ## Available Endpoints The table below lists all supported endpoints. Click any endpoint name to view detailed API documentation and parameters: ### Endpoint Overview | Endpoint | Unit Cost (Credits) | Description | | - | - | - | | Get Unique Visit | 4 | Total number of unique visitors to a domain within a specific timeframe | | Get Global Rank (Desktop+Mobile Web) | 4 | Website’s ranking compared to all websites globally | | Get Total Visits (Desktop+Mobile Web) | 4 | Total number of visits to the website | | Get Bounce Rate (Desktop+Mobile Web) | 4 | Percentage of visitors who leave after viewing one page | | Get Total Traffic by Country (Desktop+Mobile Web) | 28 | Geographic distribution of website traffic | | Get Traffic Sources by Marketing Channel (Desktop) | 28 | Breakdown of desktop traffic channels | | Get Traffic Sources by Marketing Channel (Mobile) | 28 | Breakdown of mobile traffic channels | | Get Keywords Overview | 68 per keyword | Overall search performance for specific keywords | | Get Website Analysis Keywords | 0.50 per keyword | Specific keywords driving search traffic to a domain | | Get Incoming Traffic: Referrals Desktop | 12 | External websites driving traffic to target site on Desktop | | Get Incoming Traffic: Referrals Mobile Web | 12 | External websites driving traffic to target site on Mobile | | Get outgoing Traffic: Outgoing Referrals Mobile Web | 12 | Where users go after leaving the target site on Mobile | | Get Keywords Landing Pages | 0.40 per landing page | Specific URLs receiving the most organic/paid search traffic | | Get Popular Pages | 12 | Most visited pages across all traffic channels | ### Data Details | Endpoint | Regional Granularity | Accessible Information | | - | - | - | | Get Unique Visit | Worldwide | Share of desktop-only UV; share of mobile web-only UV; share of UV across both mobile web and desktop | | Get Global Rank (Desktop+Mobile Web) | Worldwide | Monthly Global Rank | | Get Total Visits (Desktop+Mobile Web) | Worldwide | Total visits to the website across desktop and web mobile | | Get Bounce Rate (Desktop+Mobile Web) | Worldwide | Monthly Bounce Rate | | Get Total Traffic by Country (Desktop+Mobile Web) | By Country | Country Name, Country Ranking by share, Share of traffic by country, Total visits by country, Pages per visit by country, Average time by country, Bounce rate by country | | Get Traffic Sources by Marketing Channel (Desktop) | Worldwide | Estimated organic and paid desktop visits by channel (Organic Search, Paid Search, Direct, Display Ads, Email, Referrals and Social) | | Get Traffic Sources by Marketing Channel (Mobile) | Worldwide | Estimated organic and paid mobile visits by channel (Organic Search, Paid Search, Direct, Display Ads, Email, Referrals and Social) | | Get Keywords Overview | Worldwide | Total search volume, clicks, zero-clicks, search difficulty, and organic/paid traffic composition for specific keywords | | Get Website Analysis Keywords | Worldwide | Keyword list, traffic share, CPC, and search intent (navigational, informational, etc.) | | Get Incoming Traffic: Referrals Desktop | Worldwide | Top referring domains and their traffic share on Desktop | | Get Incoming Traffic: Referrals Mobile Web | Worldwide | Top referring domains and their traffic share on Mobile | | Get Outgoing Traffic: Outgoing Referrals Mobile Web | Worldwide | Top destination domains and their traffic share after users leave the site on Mobile | | Get Keywords Landing Pages | Worldwide | Top URLs receiving search traffic, clicks, traffic share, and keyword count (Search traffic only) | | Get Popular Pages | Worldwide | Top pages by total visits across all channels, traffic share, and change | ## Price Model This data integration follows Similarweb's multiplier-based pricing model, where costs are calculated by multiplying multiple factors. [Learn more about pricing →](https://developers.similarweb.com/docs/data-credits-unpublished-whats-new-in-v40) See the table below for detailed pricing factors: ### Pricing Factors | Factor | Description | Multiplier | | - | - | - | | **Domains** | Number of unique domains requested | 1x per domain | | **Pages** | Number of pages requested | 1x | | **Keywords** | Number of keywords searched | 1x | | **Granularity** | Data resolution *Monthly data only* | 1x | | **Countries** | Number of countries queried *Global = 1x, specific countries might add cost* | 1x per country | | **Time Span** | Historical data range *Max: 12 months* | 1x per month | | **Unit Cost** | Base cost varies by endpoint category | Varies by endpoint | > [!NOTE] > > **Important Notes** > > * Data is available at **monthly granularity only** > * Maximum **12 months** of historical data available > * Available to **Pro plan users** > * Consumes **paid subscription or add-on credits only** > * Each user can use a maximum of 20,000 Manus credits for Similarweb integration per month. > [!NOTE] > > Manus automatically optimizes queries to minimize costs while delivering accurate results. Session Credits Usage is tracked in your dashboard. ### Example Calculations > [!TIP] > > **Cost** = **Domains** x **Granularity** × **Countries** × **Time Span** x **Unit Cost** > [!NOTE] > > The above calculations reflect Data API costs only. Total session credits include additional charges for AI processing, computation, and other features used during the session. > [!WARNING] > > Data accuracy is determined by Similarweb's statistical scope and algorithms. Estimates may vary by website. Always verify critical data with multiple sources. ## Reference * [Similarweb Developer Documentation](https://developers.similarweb.com/docs/similarweb-web-traffic-api) * [Similarweb Data Credits System](https://developers.similarweb.com/docs/data-credits-unpublished-whats-new-in-v40) * [Data Accuracy and Methodology](https://support.similarweb.com/hc/en-us/articles/360002219177-Similarweb-s-Data-Accuracy) *** Need help with Similarweb data? Ask Manus in natural language and it will handle the technical details for you. # file.delete Source: https://open.manus.ai/docs/v2/file.delete POST /v2/file.delete Deletes a file. Files are automatically deleted 48 hours after upload, so manual deletion is only needed for early cleanup. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. > * **Trusted client:** Full access. # file.detail Source: https://open.manus.ai/docs/v2/file.detail GET /v2/file.detail Retrieves a file's details including upload status, size, and expiration time. For an uploaded, unexpired file, also returns a temporary GET download URL and its expiration time at the top level of the response. Use this to download an uploaded attachment for validation before creating a task. Check that `file.status` is `uploaded` before using the file in [task.create](https://open.manus.ai/docs/v2/task.create). Files expire 48 hours after upload. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. > * **Trusted client:** Full access. ## Download an uploaded file After sending the file bytes to the PUT URL returned by [file.upload](/docs/v2/file.upload), call `file.detail` with the returned `file.id`. This also checks a pending upload, so a completed upload can become available for download immediately. You can download the attachment for content validation before passing its `file_id` to a task. The response includes these optional fields at the top level, alongside `file`: | Field | JSON type | Meaning | | - | - | - | | `download_url` | string | Presigned URL for a GET request. Use it as returned; no Manus API key or OAuth token is needed for the download. | | `download_expires_at` | string | Unix timestamp in seconds, encoded as a decimal string. It describes the link's expiration; `file.expires_at` describes the file's lifetime. | Both fields are returned only when `file.status` is `uploaded` and the file has not expired. Pending, failed (`error`), and expired files retain their metadata response without download fields. A deleted, missing, or other user's file returns HTTP 404 with `error.code: "not_found"`. The download link is valid for at most **3 minutes**, shortened to the file's remaining lifetime. Deleting the file can invalidate it earlier. Call `file.detail` again to obtain a fresh link while the file remains available. # file.upload Source: https://open.manus.ai/docs/v2/file.upload POST /v2/file.upload Creates a file record and returns a presigned upload URL. Upload the file content to the returned `upload_url` via PUT before it expires. Use [file.detail](https://open.manus.ai/docs/v2/file.detail) to check upload status or download the file. Then use the `file.id` as `file_id` in [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) message content. See [Limits](https://open.manus.ai/docs/v2/file.upload#limits). Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. > * **Trusted client:** Full access. ## Limits | Limit | Value | | - | - | | Size per file | 512 MB | | Total storage per account | 10 GB | | `upload_url` validity | 3 minutes | | File lifetime | 48 hours after upload | | Blocked types | Executable and script files, such as `.exe`, `.sh`, `.bat`, `.dmg` | Exceeding a size limit returns `QuotaExceededError`. Files attached inline in a task message instead of through `file.upload` have a lower cap: `file_url` and decoded `file_data` are limited to 20 MB each. Upload larger files first and pass the returned `file.id` as `file_id`. # Hidden application context Source: https://open.manus.ai/docs/v2/hidden-application-context Send application context to the agent without rendering it as user-visible message text. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!NOTE] > > The `hidden` value is available only to a **Trusted public client**. Other callers can omit `visibility` or use its default value, `visible`. API keys, standard OAuth clients, legacy clients, and Trusted team clients cannot send or read hidden application text. Use hidden application context when the agent needs partner-supplied information that should not appear in the user-visible message body. The LLM receives all content parts in their original order, so a hidden part keeps its position relative to the visible text around it. Hidden text can affect agent behavior and skill selection. ## Send hidden text Set `visibility: "hidden"` on individual text parts in `task.create` or `task.sendMessage`: ```json theme={null} { "message": { "content": [ {"type": "text", "text": "Build my website"}, {"type": "text", "text": "Additional application context", "visibility": "hidden"} ] } } ``` `visibility` defaults to `visible`, and plain string content remains visible. Every message must contain at least one non-empty visible text part or valid visible file or voice part. Hidden file and voice parts are not supported. When `task.create` sets the top-level [`website`](https://open.manus.ai/docs/v2/website#edit-a-website-in-a-new-task) field, the website counts as visible content, so a hidden text part alone can carry the edit instruction. Hidden text counts toward the message token limit. The API returns `InvalidArgument` (HTTP 400) for all-hidden messages, unsupported visibility values, whitespace-only visible text, or hidden file and voice parts. A caller that is not a Trusted public client receives `PermissionDenied` (HTTP 403) when it attempts to send hidden text. ## Read hidden text Use a Bearer token from the same Trusted public client and set `verbose=true` on `task.listMessages`. Existing task access restrictions still apply. ```bash theme={null} curl --request GET \ --url 'https://api.manus.ai/v2/task.listMessages?task_id=&verbose=true' \ --header 'Authorization: Bearer ' ``` Visible text remains in `user_message.content`. Hidden text is returned separately in `user_message.hidden_content`: ```json theme={null} { "type": "user_message", "user_message": { "content": "Build my website", "hidden_content": ["Additional application context"] } } ``` `hidden_content` preserves the order among hidden text parts. It does not encode each hidden part's position relative to visible text. Other callers and non-verbose requests omit the field. ## Display behavior Hidden text is omitted from user-facing messages, history, previews, and title input. Model responses may still refer to the hidden context. # Overview Source: https://open.manus.ai/docs/v2/integrations-overview Use Manus from your favorite apps Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). Integrations bring Manus into your existing workflow tools. Instead of switching to the Manus app, you can create tasks, receive notifications, and interact with Manus directly from platforms like Slack, Zapier, and more. **Use cases:** * Start Manus tasks from Slack channels or direct messages * Receive task completion notifications in Slack * Trigger Manus workflows from Zapier automations ## Popular integrations > **[Slack](/docs/v2/integrations-slack)** > > Start sessions directly from Slack channels or DM the Manus bot > ![Zapier](https://cdn.simpleicons.org/zapier/FF4F00) > > **Zapier**\\ > > Add Manus as a step in your Zapier workflows > > [Open](https://manus.im/docs/integrations/zapier) ## Setup Integrations can be configured from your Manus workspace settings. Use OAuth for secure authorization. # Slack Source: https://open.manus.ai/docs/v2/integrations-slack Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). ## Overview The Manus Slack integration lets you create sessions directly from Slack channels or with the Manus bot. *** ## Requirements * A Slack workspace where you have permission to install apps * A Manus Account *** ## Installation 1. Go to **Manus Settings → Integrations → Slack** 2. Click **Connect** 3. Install the app and complete setup ![Slack Integration](https://mintcdn.com/manus-api/jYbGpArvQsxpaz_z/images/screenshot/integration_slack.png?fit=max\&auto=format\&n=jYbGpArvQsxpaz_z\&q=85\&s=3e8f66a4740d1dc1a7909da49409fbe1) *** ## Usage * Tag @manus in threads in channel or send a direct message to the Manus bot * Use `mute` or `unmute` to control thread activity *** ## Changelog ### November 27, 2025 We’ve updated Manus Slack App behavior based on user feedback. | Scenario | Previous Behavior | Updated Behavior | | - | - | - | | **Direct @Manus in a channel** | Manus replies directly under the message and automatically starts a Manus thread. | *No change, behavior remains the same.* | | **@Manus in a reply within a non-Manus thread** | A new Manus thread would be created. | Manus now replies directly under the message without creating a new thread. | | **User reply behavior inside Manus threads** | Manus proactively listens and replies within the thread. | Manus will only reply when explicitly mentioned. | # Introduction Source: https://open.manus.ai/docs/v2/introduction Integrate Manus AI agents into your workflows with the Manus API Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!WARNING] > > **You are viewing API v2** — the latest version of the Manus API. API v1 has been deprecated and will be removed in the future. If you still need the v1 docs, see [API v1 documentation](https://open.manus.ai/docs/v1/overview). # Manus API The Manus API allows you to programmatically create and manage AI agent tasks. Build automations, orchestrate multi-step workflows, and integrate Manus into your applications through a simple REST API. > **[Get your API key](/docs/v2/authentication)** > > Before making API calls, you'll need to create an API key. Head over to Authentication to get started. > **[Install the API skill](/docs/v2/manus-api-skill)** > > Give Codex and other compatible coding agents current Manus API integration guidance. ## What you can do > **[Tasks](/docs/v2/create-task)** > > Create tasks, send follow-up messages, and retrieve results — full multi-turn conversation support > **[Projects](/docs/v2/create-project)** > > Organize tasks with shared instructions that apply automatically > **[Files](/docs/v2/upload-file)** > > Upload files as task attachments — PDFs, images, CSVs, and more > **[Webhooks](/docs/v2/create-webhook)** > > Get real-time notifications when tasks complete or need input > **[Skills](/docs/v2/list-skills)** > > Extend agent capabilities with built-in and custom skills > **[Agents](/docs/v2/list-agents)** > > Manage and configure your custom agents ## Base URL All API requests are made to: ``` https://api.manus.ai ``` ## Response format All responses use a consistent wrapper: **Success:** ```json theme={null} { "ok": true, "request_id": "req_abc123", ... } ``` **Error:** ```json theme={null} { "ok": false, "request_id": "req_abc123", "error": { "code": "invalid_argument", "message": "task_id is required" } } ``` | Error code | Description | | - | - | | `unauthenticated` | Missing or invalid API key or OAuth token | | `invalid_argument` | Missing or invalid request parameters | | `not_found` | The requested resource does not exist | | `permission_denied` | The authenticated caller lacks permission or a required OAuth scope | | `rate_limited` | Too many requests — see [Rate Limits](https://open.manus.ai/docs/v2/rate-limits) for per-endpoint limits and backoff guidance | | `internal` | Internal server error (HTTP 500) | # Manus API skill Source: https://open.manus.ai/docs/v2/manus-api-skill Install the official Manus API skill in Codex and other compatible coding agents Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). Install the official Manus API skill to give your coding agent up-to-date routing and integration guidance for API v2. The website-hosted skill reads the live documentation when it needs exact endpoint schemas, authentication behavior, validation rules, or limits. ## Install Let the Skills CLI detect your supported coding agents and choose where to install the skill: ```bash theme={null} npx skills add https://open.manus.ai/docs ``` To install it globally for Codex without prompts: ```bash theme={null} npx skills add https://open.manus.ai/docs --skill manus-api --agent codex --global --yes ``` > [!NOTE] > > The skill does not contain an API key or OAuth token. Configure credentials in your application or local environment as described in [Authentication](/docs/v2/authentication). ## Use in Manus No installation is needed inside Manus itself: type `/manus-api` in a task to invoke the official skill and have Manus build your API integration with the same up-to-date guidance. ## What the skill covers * Task creation, lifecycle, multi-turn conversations, and action confirmations * Structured output, files, projects, connectors, and custom skills * Webhooks, usage, website publishing, agents, and browser clients * API-key authentication and OAuth2 Open Apps The installed skill treats the live Manus API documentation as authoritative and verifies endpoint-specific details before generating integration code. ## Keep it current Update installed skills with the Skills CLI: ```bash theme={null} npx skills update manus-api ``` For the complete API reference, start with the [Manus API introduction](/docs/v2/introduction) or inspect the [API v2 OpenAPI specification](/docs/v2/openapi_v2.json). # Open App Source: https://open.manus.ai/docs/v2/open-app Build an Open App to act on behalf of team users via OAuth2 Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). An **Open App** is a third-party integration that acts on behalf of a Manus user. Instead of using a static API key tied to a single account, an Open App lets each user grant your app access through a standard OAuth2 authorization flow, after which your app receives access tokens to call the Manus API on their behalf. Open Apps are scoped to a team — only members of the same team can authorize the app. This guide covers how to create an Open App, run the OAuth2 flow, and use the resulting tokens. > [!WARNING] > > **Team only:** Open App creation and authorization require a Team account. Personal accounts cannot create or authorize Open Apps. # App management ## Creating an Open App Create an Open App from the [Manus Developers settings](https://manus.im/app#settings/developers/open-apps). Fill in the app name, description, redirect URIs, and homepage URL. After creation, you'll receive a `client_id` and an initial `client_secret`. **The secret is only shown once** — store it securely. ### Redirect URI rules * Must be an absolute URI (include scheme). * No wildcards (`*`). No fragments (`#`). * Forbidden schemes: `javascript`, `data`, `file`, `about`, `vbscript`. * `http` / `https` must include a host. * Custom schemes are allowed (e.g. `com.example.app://oauth`) for native apps. * Matched exactly at authorization time ([RFC 6749 §3.1.2](https://datatracker.ietf.org/doc/html/rfc6749#section-3.1.2)). ## App types | Type | Description | Who can create | | - | - | - | | `team` | Standard OAuth client. Access is limited to the scopes you configure. Only users in the same team can authorize. | Any team member | | `trusted_team` | Trusted team client. After authorization, it has the same permissions as an API key — all scopes are bypassed. Only users in the same team can authorize. | Team Owner or Admin only | | `trusted_public` | Trusted public client. It bypasses standard endpoint scope restrictions like `trusted_team`, any Manus user can authorize it across teams, and it supports hidden text content. | Partners only | ### Standard OAuth client A standard OAuth client is the default Open App type. Access is restricted to the scopes you configure, and only users in the same team as the client owner can authorize it. This type is suitable for most third-party integrations. ### Trusted team client A trusted team client is designed for internal integrations that need unrestricted access to the Manus API, similar to using an API key but with per-user authorization. Choose the app type on the same page where you configure scopes in the [Manus Developers settings](https://manus.im/app#settings/developers/open-apps); an existing standard client can be upgraded there. Only a Team Owner or Admin can create or upgrade to this type. Key differences from standard OAuth clients: * Ignores all scope restrictions — can access every API endpoint including admin-only ones * Can view and manage all tasks (not limited to tasks created by the app) * Has full access to all connectors without per-connector user authorization * The consent page warns users that the app will have full access to their data * Upgrading an existing client to trusted invalidates all previously issued tokens (users must re-authorize) **When to use:** * Internal team tools that need full API access * Automation that requires managing all user resources **When NOT to use:** * Third-party integrations (use a standard `team` client with minimal scopes) * Clients that only need to create and manage their own tasks (use `create_task` scope instead) ### Trusted public client A trusted public client bypasses standard endpoint scope restrictions like a trusted team client, but is not restricted to a single team — any Manus user can authorize it. Hidden text content is an additional capability available only to a `Trusted public client`, not to a `Trusted team client` or API key; see [Hidden application context](https://open.manus.ai/docs/v2/hidden-application-context). This type is currently not publicly available and is only offered to approved partners. Contact [api-support@manus.ai](mailto:api-support@manus.ai) if you are interested. ## Secret management Each app can have up to **5** active client secrets, enabling zero-downtime rotation. Create and revoke secrets from the [Manus Developers settings](https://manus.im/app#settings/developers/open-apps). **1. Create a new secret** Generate a new secret in the settings page. The secret is shown in plaintext — **this is the only time it's visible**. **2. Update your application** Configure your app to use the new secret. **3. Verify** Confirm the new secret works in production. **4. Revoke the old secret** Revoke the old secret in the settings page. It is immediately invalidated. # OAuth flow ## Overview The implementation follows [RFC 6749](https://datatracker.ietf.org/doc/html/rfc6749) (Authorization Code Grant) and [RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636) (PKCE). Three modes are supported: | Mode | Use case | Requires `client_secret` | | - | - | - | | **PKCE + Secret** (Recommended) | Backend with extra security (OAuth 2.1) | Yes | | **Secret** | Backend services | Yes | | **PKCE** | Native apps, CLIs, SPAs | No | ## Scopes Configure the scopes your app can request in the [Manus Developers settings](https://manus.im/app#settings/developers/open-apps). | Scope | Description | Notes | | - | - | - | | `create_task` | Create and manage tasks | Can only access tasks created by this app | | `manage_all_tasks` | Manage all of the user's tasks | Broad access — use only when necessary | | `create_project` | Create projects | Covers `project.create` and `project.list` only; `project.detail` and `project.update` require `manage_all_tasks` | | `use_connectors` | Use third-party connectors | Must also specify connector UIDs | | `use_my_browsers` | Use My Browser connector | Independent from `use_connectors` | > [!NOTE] > > `use_my_browsers` is a separate scope from `use_connectors` — they do not overlap. > [!TIP] > > [Trusted team clients](#trusted-team-client) and [trusted public clients](#trusted-public-client) bypass all scope restrictions — you do not need to configure scopes for them. ## Authorization flow ### Step 1: Redirect to authorization Send the user to the consent page: ``` https://manus.im/openapi/oauth?client_id={client_id}&redirect_uri={redirect_uri}&state={state} ``` | Parameter | Required | Description | | - | - | - | | `client_id` | Yes | Your app's client ID. | | `redirect_uri` | Yes | Must exactly match one of the registered redirect URIs. | | `state` | Recommended | An opaque random string to prevent CSRF attacks. Returned unchanged in the callback — verify it matches before proceeding. | The consent page displays the app's name, requested scopes, and connector list. The user reviews and approves. The scope is determined automatically from the app's configuration. ### Step 2: Receive the authorization code After approval, the user is redirected to your registered callback: ``` {redirect_uri}?code={code}&state={state} ``` Authorization code properties: * Format: `code_{client_id}_{shortuuid}` * Expires in **10 minutes** * Single-use (atomic consumption, prevents replay) ### Step 3: Exchange code for tokens **PKCE + Secret (Recommended)** ```bash theme={null} curl -X POST https://api.manus.ai/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "authorization_code", "code": "{authorization_code}", "redirect_uri": "{redirect_uri}", "client_id": "{client_id}", "client_secret": "{client_secret}", "code_verifier": "{code_verifier}" }' ``` **Secret** ```bash theme={null} curl -X POST https://api.manus.ai/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "authorization_code", "code": "{authorization_code}", "redirect_uri": "{redirect_uri}", "client_id": "{client_id}", "client_secret": "{client_secret}" }' ``` **PKCE** ```bash theme={null} curl -X POST https://api.manus.ai/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "authorization_code", "code": "{authorization_code}", "redirect_uri": "{redirect_uri}", "client_id": "{client_id}", "code_verifier": "{code_verifier}" }' ``` Also supports `application/x-www-form-urlencoded` and `Authorization: Basic` header for client credentials ([RFC 6749 §2.3.1](https://datatracker.ietf.org/doc/html/rfc6749#section-2.3.1)). **Success response:** ```json theme={null} { "access_token": "eyJhbGciOiJI...", "token_type": "Bearer", "expires_in": 86400, "refresh_token": "refresh_xxx_xxx_xxx", "scope": "create_task use_connectors" } ``` | Field | Format | Lifetime | | - | - | - | | `access_token` | JWT | **24 hours** | | `refresh_token` | `refresh_{shortuuid}_{shortuuid}_{shortuuid}` | **30 days** | ### Identify the authorized user If your app needs a stable Manus user ID for account linking, call [user.me](https://open.manus.ai/docs/v2/user.me) with the access token. Trusted clients also receive the user's display name, email, and avatar: ```bash theme={null} curl https://api.manus.ai/v2/user.me \ -H "Authorization: Bearer {access_token}" ``` Do not parse undocumented claims from the access token. `user.me` does not require an additional OAuth scope and does not modify user data. ### Step 4: Refresh tokens ```bash theme={null} curl -X POST https://api.manus.ai/oauth/token \ -H "Content-Type: application/json" \ -d '{ "grant_type": "refresh_token", "refresh_token": "{refresh_token}", "client_id": "{client_id}", "client_secret": "{client_secret}" }' ``` * **PKCE + Secret flow:** both `client_secret` and `code_verifier` are **required** for refresh. * **Secret flow:** `client_secret` is **required** for refresh. * **PKCE flow:** `client_secret` is **not** required for refresh. * Refresh atomically revokes the old token pair and issues new ones (prevents refresh token replay). ## Token invalidation A token is invalid when any of these apply: * Expired * Explicitly revoked * The associated Open App has been deleted * The app's scopes were expanded (adding new scopes or connector UIDs invalidates all existing tokens) * The client was upgraded to [trusted team](#trusted-team-client) type ## Revoking tokens ### App-side: revoke a single token (RFC 7009) ```bash theme={null} curl -X POST https://api.manus.ai/oauth/revoke \ -H "Content-Type: application/json" \ -d '{ "token": "{access_token_or_refresh_token}", "token_type_hint": "access_token", "client_id": "{client_id}", "client_secret": "{client_secret}" }' ``` * `token_type_hint` is optional (`access_token` or `refresh_token`) — optimizes lookup order. * Always returns HTTP **200** if client credentials are valid, regardless of whether the token exists ([RFC 7009](https://datatracker.ietf.org/doc/html/rfc7009)). * PKCE-issued tokens do not require `client_secret` for revocation. ### User-side: revoke grants Users can view and revoke authorized Open Apps from [Authorized Apps settings](https://manus.im/app#settings/data-controls/authorized-apps). Revoking an app invalidates all of its active tokens. ## Available endpoints Include the access token in the `Authorization` header: ```bash theme={null} curl https://api.manus.ai/v2/task.list \ -H "Authorization: Bearer {access_token}" ``` Standard OAuth clients can access the following v2 endpoints. Each endpoint page lists its required scope. Trusted clients can access every v2 endpoint without scopes. | Endpoint | Required scope | | - | - | | `user.me` | None | | `task.create` | `create_task` or `manage_all_tasks` | | `task.detail` | `create_task` or `manage_all_tasks` | | `task.list` | `create_task` or `manage_all_tasks` | | `task.update` | `create_task` or `manage_all_tasks` | | `task.stop` | `create_task` or `manage_all_tasks` | | `task.delete` | `create_task` or `manage_all_tasks` | | `task.sendMessage` | `create_task` or `manage_all_tasks` | | `task.listMessages` | `create_task` or `manage_all_tasks` | | `task.confirmAction` | `create_task` or `manage_all_tasks` | | `artifact.list` | `create_task` or `manage_all_tasks` | | `project.create` | `create_project` or `manage_all_tasks` | | `project.list` | `create_project` or `manage_all_tasks` | | `project.detail` | `manage_all_tasks` | | `project.update` | `manage_all_tasks` | | `connector.list` | `create_task` or `manage_all_tasks` | | `skill.list` | `create_task` or `manage_all_tasks` | | `skill.detail` | `create_task` or `manage_all_tasks` | | `file.upload` | `create_task` or `manage_all_tasks` | | `file.detail` | `create_task` or `manage_all_tasks` | | `file.delete` | `create_task` or `manage_all_tasks` | | `browser.onlineList` | `use_my_browsers` | | `webhook.publicKey` | None | | `website.status` | None | | `website.listCheckpoints` | None | | `website.publish` | None | | `website.update` | None | > [!WARNING] > > Standard OAuth clients cannot access endpoints that are not listed above, including `agent.*`, `webhook.create`, `webhook.list`, `webhook.delete`, and `usage.*`. They can call `skill.list` and `skill.detail` with `create_task` or `manage_all_tasks`; see [skill.list](https://open.manus.ai/docs/v2/skill.list) for the returned skills. # API behavior with OAuth This section covers how the API behaves differently when using OAuth tokens compared to API keys. ## Task visibility With `create_task` scope, your app can only see and operate on tasks it created. With `manage_all_tasks`, all of the user's tasks are accessible — same as API key. Trusted clients always have full access to all tasks. This client boundary does not extend to `website.*`; see [Website access](https://open.manus.ai/docs/v2/website#website-access). For `artifact.list`, restricted `create_task` clients are always filtered to their own app's creation tasks. Older artifacts without indexed source metadata may be omitted even when no credential filter is passed. See the [Artifacts](https://open.manus.ai/docs/v2/artifacts) guide for source filtering and pagination behavior. | Token scope | Visible tasks | | - | - | | `create_task` | Only tasks created by this Open App | | `manage_all_tasks` | All of the user's tasks | | Trusted client | All of the user's tasks | ## Connectors If your app uses connectors (e.g. GitHub, Notion), enable the `use_connectors` scope and select the connectors your app needs in the [Manus Developers settings](https://manus.im/app#settings/developers/open-apps). During authorization, the consent page shows your app's connector list and the user chooses which ones to grant. Trusted clients have full access to all connectors and skip per-connector authorization. Users can revoke individual connectors at any time, so your app should not assume a previously authorized connector will always be available. The API handles unauthorized connectors differently depending on how you pass them: * **Explicitly passed in `message.connectors`** — returns an error if the user has not authorized the connector: ```json theme={null} { "code": "permission_denied", "message": "insufficient_scope: connector {uid} not granted" } ``` * **Not passed (relying on defaults)** — unauthorized connectors are silently filtered out. The task is created normally but without those connectors. When you encounter a connector authorization error, redirect the user to update their grants: ``` https://manus.im/oauth-apps/connector-consent?client_id={client_id} ``` ## Skills Open Apps can bundle private skills (up to **50** per app) that are automatically available to Manus in tasks created by the app. Manage skills from the [Manus Developers settings](https://manus.im/app#settings/developers/open-apps). An Open App can call [`skill.list`](https://open.manus.ai/docs/v2/skill.list) to list installed skills. This inventory call does not change task skill selection. See that endpoint for the returned scope and `project_id` rules, and [task.create](https://open.manus.ai/docs/v2/task.create) for task skill selection. To customize which skills are available for a specific task, pass skill IDs in `message.enable_skills` when calling [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). To force Manus to use specific skills, pass them in `message.force_skills`. ## Webhook Each Open App can configure a dedicated webhook URL to receive event notifications. Set the webhook URL in the [Manus Developers settings](https://manus.im/app#settings/developers/open-apps). The URL must be HTTPS. > [!NOTE] > > Webhook events are scoped to the Open App — you will only receive notifications for tasks created through this app's API, not tasks created manually by the user in the Manus client. See the [Webhooks](https://open.manus.ai/docs/v2/webhooks-overview) guide for event types and the [Webhook Security](https://open.manus.ai/docs/v2/webhooks-security) guide for signature verification. # Reference ## Rate limits ### OAuth endpoints | Endpoint | Limit | | - | - | | `POST /oauth/token` | 60 / min per `client_id` | | `POST /oauth/revoke` | 60 / min per `client_id` | ### OpenAPI v2 endpoints When calling v2 endpoints with an OAuth token, the same **per-user** rate limits apply as with API keys. All tokens belonging to the same user share a single counter. See [Rate Limits](https://open.manus.ai/docs/v2/rate-limits) for per-endpoint limits. Exceeding any limit returns HTTP **429 Too Many Requests**. ## Error handling ### Authentication errors (HTTP 401) When calling OpenAPI v2 endpoints, the following 401 errors may occur: | Message keyword | Meaning | Action | | - | - | - | | `bearer token is invalid or revoked` | Token expired or was revoked | Refresh the token (see flow below) | | `reauthorization_required` | App configuration changed (e.g. upgraded to trusted team, scopes expanded), old tokens invalidated | Skip refresh — redirect user to re-authorize | | `invalid token` | JWT is malformed or signature is invalid | Check that the token is correct | | `missing authentication` | No authentication header provided | Check the `Authorization` header | **Recommended 401 handling flow:** ``` Receive 401 → Message contains "reauthorization_required"? → Redirect user to authorization URL (do NOT attempt refresh) Otherwise → Attempt refresh token → Refresh succeeds: retry the request with new access token → Refresh fails (400 invalid_grant): redirect user to re-authorize ``` ### Token endpoint errors (`/oauth/token` and `/oauth/revoke`) | `error` | HTTP status | Description | | - | - | - | | `invalid_request` | 400 | Missing or malformed parameters | | `invalid_client` | 401 | Invalid `client_id` or `client_secret` | | `invalid_grant` | 400 | Code is invalid, expired, or already used | | `unsupported_grant_type` | 400 | Unsupported `grant_type` value | | `invalid_scope` | 400 | Requested scope not configured on the app | | `server_error` | 500 | Internal server error | ```json theme={null} { "error": "invalid_grant", "error_description": "authorization grant is invalid or expired" } ``` All responses include an `X-Request-Id` header for troubleshooting. ### Insufficient scope When calling an OpenAPI v2 endpoint without the required scope: ```json theme={null} { "code": "permission_denied", "message": "insufficient_scope: required one of [create_task, manage_all_tasks]" } ``` When using a connector the user has not authorized (see [Connectors](#connectors) for handling): ```json theme={null} { "code": "permission_denied", "message": "insufficient_scope: connector {uid} not granted" } ``` ## Best practices 1. **Store secrets securely.** `client_secret` is only shown once at creation. Use a secrets manager — never hardcode it. 2. **Request minimal scopes.** Only request what your app actually needs. Avoid `manage_all_tasks` unless you truly need access to all user tasks. 3. **Implement token refresh.** Access tokens expire in 24 hours. Use the refresh token to renew automatically. 4. **Handle 401 correctly.** Check for `reauthorization_required` before attempting refresh — see [Authentication errors](#authentication-errors-http-401) for the full flow. 5. **Rotate secrets regularly.** Use multi-secret support for zero-downtime rotation. 6. **Prefer PKCE for client-side apps.** Native apps and SPAs should use PKCE — never embed a `client_secret` in client-side code. 7. **Validate the `state` parameter.** Always verify the returned `state` matches the value you sent to prevent CSRF attacks. 8. **Implement backoff on 429.** Token endpoints are limited to 60 req/min. Use exponential backoff with jitter. # project.create Source: https://open.manus.ai/docs/v2/project.create POST /v2/project.create Creates a new project. Projects let you group related tasks and apply shared instructions. Pass the returned ID as `project_id` in [task.create](https://open.manus.ai/docs/v2/task.create) to create tasks within this project. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_project` or `manage_all_tasks`. > * **Trusted client:** Full access. # project.detail Source: https://open.manus.ai/docs/v2/project.detail GET /v2/project.detail Retrieves a project's full configuration: name, instruction, default connectors, and default skills. [project.list](https://open.manus.ai/docs/v2/project.list) returns only each project's ID, name, and creation time; call this endpoint before [project.update](https://open.manus.ai/docs/v2/project.update) to read the current values. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `manage_all_tasks`. `create_project` alone is not sufficient. > * **Trusted client:** Full access. > > The user must own the project or be a project member. Otherwise, the request returns `404 not_found`. # project.list Source: https://open.manus.ai/docs/v2/project.list GET /v2/project.list Lists all projects. Use the returned IDs as `project_id` in [task.create](https://open.manus.ai/docs/v2/task.create) or [task.list](https://open.manus.ai/docs/v2/task.list). Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_project` or `manage_all_tasks`. > * **Trusted client:** Full access. # project.update Source: https://open.manus.ai/docs/v2/project.update POST /v2/project.update Updates a project's name, instruction, default connectors, or default skills. Omitted fields are unchanged; a request with no updatable field returns `400 invalid_argument`. `connector_ids` and `skill_ids` replace the entire list. Returns the full updated configuration in the same shape as [project.detail](https://open.manus.ai/docs/v2/project.detail). Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `manage_all_tasks`. `create_project` alone is not sufficient. > * **Trusted client:** Full access. > > The user must own the project or be a project member with edit permission. ## Update rules * Send `project_id` and at least one of `name`, `instruction`, `connector_ids`, or `skill_ids`. Omitted fields keep their current values. * An empty string clears `instruction`. `name` cannot be cleared. * `connector_ids` and `skill_ids` replace the entire list rather than adding to it. Pass `[]` to clear a list. To add or remove one item, read the current list with [project.detail](https://open.manus.ai/docs/v2/project.detail) and send the full new list. * The response contains the full updated configuration in the same shape as `project.detail`. ## Errors | Status | Cause | | - | - | | `400 invalid_argument` | `project_id` is missing; no updatable field is present; `name` is blank or longer than 255 characters; `instruction` exceeds 65,535 UTF-8 bytes; `connector_ids` has more than 500 entries or `skill_ids` more than 50; a list entry is not a non-empty string of at most 128 bytes; or a connector ID does not exist. | | `400 failed_precondition` | A connector is not installed or authorized in the user's account, or a Skill Hub skill has no available version. | | `403 permission_denied` | The user can view the project but cannot edit it; a Standard OAuth client lacks `manage_all_tasks`; or a connector was not granted to the app. | | `404 not_found` | The project does not exist or the user is not a member, or a skill ID is unknown or cannot be used as a project default skill. | | `429 rate_limited` | The `project.update` limit was exceeded; see [Rate Limits](https://open.manus.ai/docs/v2/rate-limits). | # Rate Limits Source: https://open.manus.ai/docs/v2/rate-limits Per-user request limits for v2 endpoints Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). The Manus API enforces **per-user** rate limits on every v2 endpoint. All API keys that belong to the same user share a single counter, and limits are measured in requests per minute. There is currently no tier differentiation — the same limit applies regardless of subscription plan. ## Limits by endpoint ### User | Endpoint | Limit | | - | - | | `user.me` | 100 / min | ### Tasks | Endpoint | Limit | | - | - | | `task.create` | 10 / min | | `task.sendMessage` | 10 / min | | `task.detail` | 100 / min | | `task.list` | 100 / min | | `task.listMessages` | 100 / min | | `task.update` | 40 / min | | `task.stop` | 40 / min | | `task.delete` | 40 / min | | `task.confirmAction` | 40 / min | ### Projects | Endpoint | Limit | | - | - | | `project.create` | 40 / min | | `project.list` | 100 / min | | `project.detail` | 100 / min | | `project.update` | 40 / min | `project.detail` shares its counter with `project.list`, and `project.update` shares its counter with `project.create`. ### Skills | Endpoint | Limit | | - | - | | `skill.list` | 100 / min | | `skill.detail` | 100 / min | ### Agents | Endpoint | Limit | | - | - | | `agent.list` | 100 / min | | `agent.detail` | 100 / min | | `agent.update` | 40 / min | ### Files | Endpoint | Limit | | - | - | | `file.upload` | 40 / min | | `file.detail` | 100 / min | | `file.delete` | 40 / min | ### Artifacts | Endpoint | Limit | | - | - | | `artifact.list` | 100 / min | ### Webhooks | Endpoint | Limit | | - | - | | `webhook.create` | 40 / min | | `webhook.list` | 100 / min | | `webhook.delete` | 40 / min | ### Usage | Endpoint | Limit | | - | - | | `usage.list` | 600 / min | | `usage.teamStatistic` | 600 / min | | `usage.teamLog` | 600 / min | ### Connectors | Endpoint | Limit | | - | - | | `connector.list` | 100 / min | ### Browser | Endpoint | Limit | | - | - | | `browser.onlineList` | 100 / min | ### Website | Endpoint | Limit | | - | - | | `website.status` | 100 / min | | `website.listCheckpoints` | 100 / min | | `website.publish` | 40 / min | | `website.update` | 40 / min | ## Error response Requests that exceed the limit return HTTP `429` with the `rate_limited` error code: ```json theme={null} { "ok": false, "request_id": "req_abc123", "error": { "code": "rate_limited", "message": "Rate limit exceeded. Please retry after a short backoff." } } ``` ## Best practices * **Back off on 429** with exponential delay plus jitter; don't retry immediately in a tight loop. * **Prefer webhooks over polling** for task progress — see [Webhooks](https://open.manus.ai/docs/v2/webhooks-overview). Each `task.listMessages` poll counts against the 100 / min limit for that endpoint. * **Use cursor pagination** (`cursor` + `next_cursor`) on list endpoints so a single logical read can span minutes without a burst. * **Cache stable values** such as the public key returned by [`webhook.publicKey`](https://open.manus.ai/docs/v2/webhook.publicKey) — it rarely changes. # skill.detail Source: https://open.manus.ai/docs/v2/skill.detail GET /v2/skill.detail Retrieves one skill's details and a temporary download URL for its current archive. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Any skill the user can download in Manus: own, team, project (read access), official, installed Hub, and authorized App skills. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. Only skills owned by this App; other IDs return `NotFound` (HTTP 404). > * **Trusted client:** Same as API Key. The endpoint returns one skill's metadata and a download link for its current archive. Download the archive and read `SKILL.md` inside it when you need the skill's front matter or files. The download link expires after 24 hours; call `skill.detail` again for a new link. Earlier versions are not returned. Use [skill.list](https://open.manus.ai/docs/v2/skill.list) to get skill IDs. # skill.list Source: https://open.manus.ai/docs/v2/skill.list GET /v2/skill.list Lists installed skills available for task selection. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth and returned skills:** > > * **API Key:** The user's available skills. Pass `project_id` to include project skills. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. Returns only skills owned by its Open App. Passing `project_id` returns `InvalidArgument` (HTTP 400). > * **Trusted client:** The user's available skills and its App's skills. Pass `project_id` to include project skills. The endpoint lists installed skills regardless of their enabled state. Listing a skill does not enable it. Use the returned ID in `message.enable_skills` or `message.force_skills` of [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) to select skills for a task. # Structured Output Source: https://open.manus.ai/docs/v2/structured-output Get agent results in a specific JSON format Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). When you need the agent's result in a specific JSON format — for example, extracting entities, filling a form, or returning data to your application — use Structured Output. You provide a JSON Schema, and the agent guarantees a result conforming to that schema after the task completes. ## Quick Start Pass `structured_output_schema` when creating a task: ```bash theme={null} curl -X POST https://api.manus.ai/v2/task.create \ -H 'x-manus-api-key: ' \ -H 'Content-Type: application/json' \ -d '{ "message": { "content": "What is the capital of France?" }, "structured_output_schema": { "type": "object", "properties": { "country": { "type": "string" }, "capital": { "type": "string" } }, "required": ["country", "capital"], "additionalProperties": false } }' ``` After the task completes, there are two ways to retrieve the result: ### Polling via API Use [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages) and look for the `structured_output_result` event: ```bash theme={null} curl 'https://api.manus.ai/v2/task.listMessages?task_id=&order=asc' \ -H 'x-manus-api-key: ' ``` ```json theme={null} { "type": "structured_output_result", "structured_output_result": { "success": true, "value": { "country": "France", "capital": "Paris" } } } ``` ### Push via Webhook If you have a [webhook](https://open.manus.ai/docs/v2/webhooks-overview) configured, the `task_stopped` callback includes the result in `task_detail.structured_output`: ```json theme={null} { "event_id": "task_stopped_abc123_1714000000", "event_type": "task_stopped", "task_detail": { "task_id": "abc123", "task_title": "...", "task_url": "...", "message": "...", "stop_reason": "finish", "structured_output": { "success": true, "value": { "country": "France", "capital": "Paris" }, "error": null } } } ``` ## How It Works 1. You provide a JSON Schema with your [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) request. 2. The agent runs normally — browsing, searching, coding, etc. 3. When the task finishes (`stop_reason: finish`), an extraction pass reads the conversation and produces a result matching your schema. 4. The result is delivered via [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages) and [webhook callback](https://open.manus.ai/docs/v2/webhooks-overview). > [!NOTE] > > The extraction is a post-processing step — it does not change how the agent works. The agent completes its task as usual, then a separate model extracts the structured result from the conversation. ### Schema Lifecycle The schema works as **arm once, fire once**: ``` task.create / task.sendMessage (with schema) │ ▼ Schema Armed ◄──────────────── task.sendMessage (with new schema) │ ├─ agent asks user (stop_reason: ask) │ → schema stays armed │ → user replies → agent continues │ │ ├─ agent finishes (stop_reason: finish) │ → extraction fires │ → result delivered │ │ │ ▼ │ Schema Consumed │ │ │ ├─ task.sendMessage WITHOUT schema → no extraction │ └─ task.sendMessage WITH schema → re-armed (go back to top) ``` * **Armed** — passing `structured_output_schema` in [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) arms the schema for extraction. * **Not consumed on `ask`** — if the agent pauses to ask the user a question (`stop_reason: ask`), the schema stays armed. It will fire when the task eventually finishes. * **Fired on `finish`** — when the task completes (`stop_reason: finish`), extraction runs and the schema is consumed. The result is delivered via the events API and webhook. * **Re-arm to extract again** — after the schema is consumed, subsequent task completions will not trigger extraction. To extract again, pass a new `structured_output_schema` with your next [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). ## Schema Requirements The schema uses a strict subset of [JSON Schema](https://json-schema.org/) designed for reliable extraction. This ensures the output can always be deterministically validated and parsed. ### Root Type The top-level schema must be `"type": "object"`. You cannot use a bare `string`, `array`, or other primitive as the root. ### Supported Types | Type | Description | Example | | - | - | - | | `string` | Text value | `{ "type": "string" }` | | `number` | Floating-point number | `{ "type": "number" }` | | `integer` | Whole number | `{ "type": "integer" }` | | `boolean` | `true` or `false` | `{ "type": "boolean" }` | | `null` | Null value (typically used with nullable patterns) | `{ "type": "null" }` | | `object` | Nested object (must follow object rules below) | See below | | `array` | Array of items (must specify `items` schema) | `{ "type": "array", "items": { "type": "string" } }` | ### Supported Keywords | Keyword | Usage | Example | | - | - | - | | `enum` | Restrict a value to a fixed set of options | `{ "type": "string", "enum": ["low", "medium", "high"] }` | | `description` | Document the purpose of a field (does not affect validation) | `{ "type": "string", "description": "ISO 8601 date" }` | | `anyOf` | Union types, most commonly used for nullable fields | `{ "anyOf": [{ "type": "string" }, { "type": "null" }] }` | | Type arrays | Shorthand for nullable — equivalent to `anyOf` with `null` | `{ "type": ["string", "null"] }` | | `$ref` / `$defs` | Reuse schema definitions and define recursive structures | See example below | ### Object Rules Every `object` in the schema — root or nested — must follow these two rules: 1. **`additionalProperties` must be `false`** — Only explicitly defined properties are allowed. This prevents unexpected fields in the output. 2. **`required` must list all properties** — Every property defined in `properties` must appear in the `required` array. Optional fields should use a nullable type instead (e.g., `{ "type": ["string", "null"] }`). ```json theme={null} { "type": "object", "properties": { "name": { "type": "string" }, "age": { "type": "integer" }, "nickname": { "type": ["string", "null"] } }, "required": ["name", "age", "nickname"], "additionalProperties": false } ``` ### Schema Reuse with `$ref` / `$defs` Use `$defs` to define reusable sub-schemas and `$ref` to reference them. This is especially useful for recursive structures: ```json theme={null} { "type": "object", "properties": { "root": { "$ref": "#/$defs/TreeNode" } }, "required": ["root"], "additionalProperties": false, "$defs": { "TreeNode": { "type": "object", "properties": { "label": { "type": "string" }, "children": { "type": "array", "items": { "$ref": "#/$defs/TreeNode" } } }, "required": ["label", "children"], "additionalProperties": false } } } ``` ### Nesting Depth The maximum nesting depth for objects and arrays is **5 levels**. Schemas exceeding this limit will be rejected. ### Unsupported Keywords The following JSON Schema keywords are **not supported** and will cause a validation error if included: | Category | Keywords | | - | - | | String constraints | `pattern`, `format`, `minLength`, `maxLength` | | Numeric constraints | `minimum`, `maximum`, `exclusiveMinimum`, `exclusiveMaximum`, `multipleOf` | | Array constraints | `minItems`, `maxItems`, `uniqueItems` | | Composition (except `anyOf`) | `allOf`, `oneOf`, `not` | | Conditional | `if`, `then`, `else` | > [!WARNING] > > Invalid schemas are rejected immediately with a descriptive error message (HTTP 400). See [Error Handling](#error-handling) for common error messages. ## Result Format The result always has three fields: | Field | Type | Description | | - | - | - | | `success` | boolean | Whether the agent produced a meaningful result | | `value` | (your schema) | The extracted value. Always present and conforms to your schema. When `success` is `false`, contains a zero-value fallback (see [zero-value rules](#when-success-is-false) below) | | `error` | string \| null | Error description when `success` is `false`. `null` when `success` is `true` | **When `success` is `true`:** The agent completed the task and `value` contains the extracted data: ```json theme={null} { "success": true, "value": { "country": "France", "capital": "Paris" }, "error": null } ``` **When `success` is `false`:** The extraction failed (e.g., the model call errored or the output didn't match the schema). `value` is a **zero-value fallback** that conforms to your schema's structure, and `error` explains what happened: ```json theme={null} { "success": false, "value": { "country": "", "capital": "" }, "error": "Failed to extract structured output" } ``` The zero-value rules by type: | Type | Zero value | | - | - | | `string` | `""` | | `number` / `integer` | `0` | | `boolean` | `false` | | `null` | `null` | | `object` | Object with all properties set to their respective zero values | | `array` | `[]` | | `enum` | First value in the enum list | | Nullable (`["string", "null"]` / `anyOf` with `null`) | `null` | > [!TIP] > > The `value` is always safe to destructure — it matches your schema's structure even on failure. Your application should check `success` before treating `value` as meaningful data. ## Multi-turn Conversations The schema is consumed once per task stop. In a multi-turn conversation, you can attach a new `structured_output_schema` to any [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) call: ```bash theme={null} curl -X POST https://api.manus.ai/v2/task.sendMessage \ -H 'x-manus-api-key: ' \ -H 'Content-Type: application/json' \ -d '{ "task_id": "", "message": { "content": "Now find the track listing for Oasis - Definitely Maybe" }, "structured_output_schema": { "type": "object", "properties": { "album": { "type": "string" }, "artist": { "type": "string" }, "tracks": { "type": "array", "items": { "type": "string" } } }, "required": ["album", "artist", "tracks"], "additionalProperties": false } }' ``` The behavior is: * Send a message **with** schema → schema armed → agent runs → finishes → extraction fires → schema consumed * Send a message **without** schema → agent runs → finishes → **no extraction** (previous schema was already consumed) * Send a message with a **new** schema → re-arms with the new schema, replacing any previous one * Agent pauses to ask a question (`stop_reason: ask`) → schema **not** consumed, remains armed for when the task finishes The extraction always reflects the final state of the conversation at the time the task finishes. ## Examples ### Simple extraction ```json theme={null} { "message": { "content": "How many career three-pointers has Ben Simmons made?" }, "structured_output_schema": { "type": "object", "properties": { "player": { "type": "string" }, "three_pointers_made": { "type": "integer" } }, "required": ["player", "three_pointers_made"], "additionalProperties": false } } ``` ### Nullable fields ```json theme={null} { "message": { "content": "Does The Three-Body Problem have a movie adaptation?" }, "structured_output_schema": { "type": "object", "properties": { "book": { "type": "string" }, "author": { "type": "string" }, "movie_title": { "type": ["string", "null"] } }, "required": ["book", "author", "movie_title"], "additionalProperties": false } } ``` ### Nested objects with enum ```json theme={null} { "message": { "content": "Recommend 3 movies directed by Christopher Nolan, include genre and release year" }, "structured_output_schema": { "type": "object", "properties": { "movies": { "type": "array", "items": { "type": "object", "properties": { "title": { "type": "string" }, "genre": { "type": "string", "enum": ["action", "sci-fi", "thriller", "drama"] }, "year": { "type": "integer" } }, "required": ["title", "genre", "year"], "additionalProperties": false } } }, "required": ["movies"], "additionalProperties": false } } ``` ## Error Handling ### Schema Validation Errors (HTTP 400) If the schema is invalid, the request is rejected immediately: ```json theme={null} { "ok": false, "error": { "code": "invalid_argument", "message": "structured_output_schema: .price: unsupported keyword \"minimum\"" } } ``` Common errors: | Scenario | Error message | | - | - | | Unsupported keyword | `.x: unsupported keyword "pattern"` | | Object missing `additionalProperties: false` | `"additionalProperties" must be set to false` | | `required` doesn't list all properties | `"required" must include all properties` | | Missing `type` field | `must have a "type" field` | | Not a valid JSON Schema | `not a valid JSON Schema` | ### Extraction Errors (in result) These appear as `success: false` with an error message. The `value` still contains a valid default conforming to your schema. Your application should check `success` before using `value`. | Error message | Meaning | | - | - | | `Failed to extract structured output` | The extraction model call failed | | `Extracted value does not conform to the provided schema` | The extraction produced output that doesn't match the schema | # Task Lifecycle Source: https://open.manus.ai/docs/v2/task-lifecycle Poll task status, handle confirmations, and process results Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). After creating a task with [task.create](https://open.manus.ai/docs/v2/task.create), the agent runs asynchronously. Use [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages) to poll for events and track progress. Also read [task.detail](https://open.manus.ai/docs/v2/task.detail) before treating a stopped Agent run as complete, because background work can continue independently. For push delivery, set up [Webhooks](https://open.manus.ai/docs/v2/webhooks-overview). ```bash theme={null} curl 'https://api.manus.ai/v2/task.listMessages?task_id=YOUR_TASK_ID&order=desc&limit=10' \ -H 'x-manus-api-key: YOUR_API_KEY' ``` ## Task status Look for `status_update` events in the response. The `agent_status` field tells you what to do next: | agent\_status | Meaning | Action | | - | - | - | | `running` | Agent is working | Keep polling | | `stopped` | The main Agent stopped | Read the results | | `waiting` | Needs user confirmation or input | Handle based on event type (see below) | | `error` | Task failed | Read `error_message` for details | `stopped` is not always final. When [task.detail](https://open.manus.ai/docs/v2/task.detail) reports `has_running_background_jobs: true`, a background process may wake the task again later, add messages, and change the results. Keep polling if you want them. A later message, schedule, or trigger can also start the same Task again. ## Handling `waiting` status Read `status_detail.waiting_for_event_type`. It falls into one of three cases: | Event type | Respond with | | - | - | | `messageAskUser`, `cascadeAskUser` — the agent asks a question | [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). See [Answer an agent question](#answer-an-agent-question). Do **not** use `task.confirmAction`. | | An action confirmation (see [examples](#using-task-confirmaction)) | [task.confirmAction](https://open.manus.ai/docs/v2/task.confirmAction) after reviewing the target event. See [Confirm an action](#confirm-an-action). | | Any other type, or `status_detail` / `waiting_for_event_id` missing | Fallback: [resume without a decision](#resume-without-a-decision), or direct a person to decide in Manus. | Sending any ordinary message while an action confirmation is pending skips that action; the agent continues from your message. No schema-specific input is needed. ### Answer an agent question A free-text question is answered with plain text. When the agent supplies choices, the corresponding `assistant_message` includes a `question_expectation` object: ```json theme={null} { "id": "ask_abc123", "type": "assistant_message", "assistant_message": { "content": "Which formats should I export?", "question_expectation": { "options": ["PDF", "DOCX"], "selection_mode": "multiple", "response_method": "send_message" } } } ``` | Field | Meaning | | - | - | | `options` | Display text of the choices. Not option IDs, and not an enforced answer schema. Non-empty when present in `task.listMessages`. | | `selection_mode` | `single` or `multiple`. Render the matching choice control, and still allow a free-text answer. | | `response_method` | Currently fixed to `send_message`. Never `task.confirmAction`. | | `event_id` | Webhooks only. Identifies the question event; differs from the webhook envelope `event_id`, which identifies the notification. Not a reply parameter. In `task.listMessages`, use the enclosing message's `id`. | To answer: 1. Collect the user's selection or free text. 2. Send a non-empty answer as ordinary `message.content` through [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). For multiple choices, combine the selected text into one readable message. There is no required delimiter, option-ID array, or structured submission format. 3. Do not submit an empty answer when nothing is selected; ask the user for text instead. Example answer: ```json theme={null} { "task_id": "task_abc123", "message": { "content": "Please export both PDF and DOCX." } } ``` ### Confirm an action When an action needs confirmation, the waiting `status_detail` gives its target event ID and the expected input schema: ```json theme={null} { "type": "status_update", "status_update": { "agent_status": "waiting", "status_detail": { "waiting_for_event_id": "R0ayNknItM38cc6a2DbB4W", "waiting_for_event_type": "gmailSendAction", "waiting_description": "Send email to user@example.com", "confirm_input_schema": { "type": "object", "properties": { "accept": { "type": "boolean" }, "save_draft": { "type": "boolean" } }, "required": ["accept"] } } } } ``` The waiting event tells you how to respond. The event identified by `waiting_for_event_id` tells you what the user is approving. If that event is not in the current response window, fetch it explicitly: ```bash theme={null} curl 'https://api.manus.ai/v2/task.listMessages?task_id=YOUR_TASK_ID&verbose=true&start_event_id=R0ayNknItM38cc6a2DbB4W' \ -H 'x-manus-api-key: YOUR_API_KEY' ``` The referenced Gmail event contains the structured tool input: ```json theme={null} { "id": "R0ayNknItM38cc6a2DbB4W", "type": "tool_used", "tool_used": { "tool": "gmail", "action_id": "X0SCXV59huUdjxubJrOYyx", "status": "success", "brief": "Manus is preparing Gmail message", "description": "Preparing Gmail messages", "message": { "action": "Preparing Gmail messages" }, "params": { "messages": [{ "to": ["user@example.com"], "cc": [], "bcc": [], "subject": "Project update", "content": "The complete email body", "attachments": [] }] } } } ``` Use `R0ayNknItM38cc6a2DbB4W` as `task.confirmAction.event_id`. `X0SCXV59huUdjxubJrOYyx` is the tool action ID, not the event ID. The target event exposes the original structured `params` when the confirmation came from a tool call; result-driven confirmations may also expose a structured `result`. When the target gives you nothing you can act on, use the [fallback](#resume-without-a-decision). Fetching the target event: * `tool_used` events normally require `verbose=true`. * A waiting status does not force its target event into the current page. Use `verbose=true` with `start_event_id=waiting_for_event_id` when the target is outside the current response window. #### Using `task.confirmAction` ```bash theme={null} curl -X POST 'https://api.manus.ai/v2/task.confirmAction' \ -H 'x-manus-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "task_id": "YOUR_TASK_ID", "event_id": "R0ayNknItM38cc6a2DbB4W", "input": { "accept": true } }' ``` The `input` format varies by `waiting_for_event_type`. Build it according to `confirm_input_schema`. Use the referenced tool params and result to explain the operation and populate schema fields when applicable. The table below provides common examples. | Event Type | Description | Example Input | | - | - | - | | `needConnectMyBrowser` | Select a browser from [browser.onlineList](https://open.manus.ai/docs/v2/browser.onlineList), or skip | `{ "action": "select", "client_id": "..." }` or `{ "action": "skip" }` | | `gmailSendAction` | Confirm send, or save as draft | `{ "accept": true }` or `{ "accept": true, "save_draft": true }` | | `outlookSendMailsAction` | Confirm send, or save as draft | `{ "accept": true }` or `{ "accept": true, "save_draft": true }` | | `deployAction` | Confirm deploy. Set `global_allow` to skip future confirmations | `{ "accept": true, "global_allow": true }` | | `terminalExecute` | Confirm command. Set `always_allow` to skip future confirmations | `{ "accept": true, "always_allow": true }` | | `videoGenerate` | Select video quality: `standard` (default) or `premium` | `{ "choice": "standard" }` | | `apiHighCreditNotice` | Respond to high-credit notice: `accept`, `reject`, or `do_not_show_again` | `{ "action": "accept" }` | | `googleCalendarCreate` | Confirm calendar event creation | `{ "accept": true }` | | `googleCalendarUpdate` | Confirm calendar event update | `{ "accept": true }` | | `googleCalendarDelete` | Confirm calendar event deletion | `{ "accept": true }` | | `outlookCalendarCreate` | Confirm calendar event creation | `{ "accept": true }` | | `outlookCalendarUpdate` | Confirm calendar event update | `{ "accept": true }` | | `outlookCalendarDelete` | Confirm calendar event deletion | `{ "accept": true }` | | `shopifyAction` | Confirm a Shopify delete operation | `{ "accept": true }` or `{ "accept": false }` | | `instagramCreateResult` | Publish prepared Instagram media | `{ "accept": true }` | | `metaMarketingAction` | Select at least one ad account using IDs from `tool_used.result.adAccounts[].id` | `{ "accept": true, "selectedAccountIds": ["act_123"] }` | | `metaMarketingActionResult` | Confirm marketing result. Optionally specify `mode` | `{ "accept": true }` | | `selfConfigSaveAction` | Connector configuration suggestion. Applying requires connector details the API does not expose | `{ "action": "skip" }` | | `webdevRunAction` | Run web app. `mode`: `quality` / `speed` (default) / `max` | `{ "accept": true, "mode": "speed" }` | | `webdevRunAction` (deploy) | Deploy web app. `visibility`: `owner` (default) / `team` / `public` | `{ "accept": true, "visibility": "owner" }` | | `webdevRequestSecrets` | Provide secrets as `[{key, value}]` array, or reject with `accept: false` | `{ "accept": true, "secrets": [{"key": "X", "value": "Y"}] }` | | `connectorOauthExpired` | Continue after the connector's external OAuth flow succeeds | `{ "accept": true }` after reauthorization | | `mapreduceAction` | Confirm map-reduce operation | `{ "accept": true }` | > [!NOTE] > > `confirmed: false` means the event did not consume the input and the task is still waiting. `{ "accept": false }` cancels only where the table says so; to skip without a schema-specific input, [resume without a decision](#resume-without-a-decision). ### Resume without a decision This is the fallback when `status_detail` or `waiting_for_event_id` is missing, the event type is not one you handle, or the target event gives you nothing to act on. Either direct a person to open the task in Manus, or send this message so the agent picks sensible defaults for the pending step and keeps going: ```json theme={null} { "task_id": "task_abc123", "message": { "content": "Continue and use your best judgment." } } ``` Any wording that tells the agent to proceed works. For most action confirmations this skips the pending action; the agent decides how to proceed from your message. ## Using My Browser You can let the agent use your local browser. When the agent needs a browser during execution, it will trigger a `needConnectMyBrowser` waiting event. Use [browser.onlineList](https://open.manus.ai/docs/v2/browser.onlineList) to get available clients, then select one via [task.confirmAction](https://open.manus.ai/docs/v2/task.confirmAction): ```bash theme={null} # 1. Get online browser clients curl 'https://api.manus.ai/v2/browser.onlineList' \ -H 'x-manus-api-key: YOUR_API_KEY' # 2. When needConnectMyBrowser event is received, select a browser curl -X POST 'https://api.manus.ai/v2/task.confirmAction' \ -H 'x-manus-api-key: YOUR_API_KEY' \ -H 'Content-Type: application/json' \ -d '{ "task_id": "YOUR_TASK_ID", "event_id": "evt_abc123", "input": { "action": "select", "client_id": "0e9ad711-8471-4fcc-a9de-8309f0f12c87" } }' ``` > [!WARNING] > > If `browser.onlineList` returns an empty list, no browser clients are online. Install and enable the [Manus Browser Extension](https://manus.im) first. ## Complete flow ``` 1. POST /v2/task.create → Create task (optionally with structured_output_schema) 2. GET /v2/task.listMessages → Poll for events ├─ agent_status=running → Keep polling ├─ agent_status=waiting → Check waiting_for_event_type │ ├─ messageAskUser / cascadeAskUser → POST /v2/task.sendMessage │ ├─ Action confirmation → POST /v2/task.confirmAction │ └─ Other / missing detail → Fallback: resume without a decision, or open in Manus ├─ agent_status=stopped → Read results │ ├─ structured_output_result → Extracted JSON (if schema was provided) │ └─ task.detail.has_running_background_jobs=true → Background work may wake the task again; keep polling └─ agent_status=error → Task failed, read error details ``` > [!TIP] > > **Structured Output:** If you need the result in a specific JSON format, pass `structured_output_schema` when creating the task. See the [Structured Output](https://open.manus.ai/docs/v2/structured-output) guide. # Task References Source: https://open.manus.ai/docs/v2/task-references Let the agent read earlier tasks from a new message Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). Pass task IDs in `message.task_references` on [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). The agent can then browse those tasks on demand: outline a task, search its conversation and files, and read specific parts. It does not receive their full content upfront. Get task IDs from the `task_id` of a create response or from [task.list](https://open.manus.ai/docs/v2/task.list). A task URL ends with the ID; pass only that trailing 22-character ID. ```json theme={null} { "message": { "content": "Continue the analysis from these two reports.", "task_references": ["TASK_ID_A", "TASK_ID_B"] } } ``` ## Request validation * Each entry must be a bare 22-character alphanumeric task ID. A full task URL or the `agent-default-main_task` shortcut returns `InvalidArgument` (HTTP 400). * Up to 20 entries per request. The cap is checked on the array as sent, before duplicates are removed. * Duplicates are dropped. On `task.sendMessage`, a reference to the target task itself is dropped. ## Access Access is checked when the agent reads a reference, not when you send it. A task that does not exist, or that your account cannot open, is reported to the agent as not found. The agent continues without it, and your request succeeds. Exception: an OAuth client with only the `create_task` scope can reference only tasks it created. Other IDs return `404` at request time. See [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). ## Accumulation on follow-up messages References accumulate across turns. IDs passed to `task.sendMessage` are added to the references the task already has. Sending `["B"]` to a task that already references `A` leaves it referencing both. * An empty array is a no-op. * References cannot be replaced or cleared. There is no `clear_task_references` field. * When a task accumulates more than 20 references, it keeps the 20 most recently referenced and drops the oldest. # task.confirmAction Source: https://open.manus.ai/docs/v2/task.confirmAction POST /v2/task.confirmAction Confirms a supported pending action when [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages) shows agent_status: waiting. Build input according to confirm_input_schema and review the event identified by waiting_for_event_id for tool params and result. For messageAskUser / cascadeAskUser questions, use [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) instead. See the [Task Lifecycle](https://open.manus.ai/docs/v2/task-lifecycle#using-task-confirmaction) guide; do not automatically confirm unrecognized waiting types. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. # task.create Source: https://open.manus.ai/docs/v2/task.create POST /v2/task.create Creates a new task. The task runs asynchronously. Poll for progress with [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages), send follow-ups with [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). See the [Task Lifecycle](https://open.manus.ai/docs/v2/task-lifecycle) guide for the complete flow. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, created tasks are accessible only to the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. > > **Agents:** To message an existing agent instead of creating a new task, use [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) with `agent-default-main_task` as `task_id`. See the [Agents](https://open.manus.ai/docs/v2/agents-overview) guide. > > **Websites:** To edit an existing website, set the top-level `website` field next to your instruction. See [Edit a website in a new task](https://open.manus.ai/docs/v2/website#edit-a-website-in-a-new-task). # task.delete Source: https://open.manus.ai/docs/v2/task.delete POST /v2/task.delete Deletes a task permanently. If the task is still running, use [task.stop](https://open.manus.ai/docs/v2/task.stop) first. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. > [!WARNING] > > This action is permanent. If the task is still running, use [task.stop](https://open.manus.ai/docs/v2/task.stop) to stop it first. Agent-related tasks (e.g. agent main tasks and subtasks) cannot be deleted. # task.detail Source: https://open.manus.ai/docs/v2/task.detail GET /v2/task.detail Retrieves a task's status and metadata. Use [task.listMessages](https://open.manus.ai/docs/v2/task.listMessages) for the full event history, or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage) to continue the conversation. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. # task.list Source: https://open.manus.ai/docs/v2/task.list GET /v2/task.list Lists tasks with optional filtering and cursor-based pagination. Use `scope` to filter by task type, e.g. `agent_subtask` with `agent_id` for agent subtasks. See [task.detail](https://open.manus.ai/docs/v2/task.detail) for full details on a specific task. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. # task.listMessages Source: https://open.manus.ai/docs/v2/task.listMessages GET /v2/task.listMessages Lists event messages for a task with cursor-based pagination. Use this to poll for progress after [task.create](https://open.manus.ai/docs/v2/task.create) or [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). See the [Task Lifecycle](https://open.manus.ai/docs/v2/task-lifecycle) guide for how to handle each status. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. > > **Handle status:** Read `status_update` events and respond as described in [Task Lifecycle](https://open.manus.ai/docs/v2/task-lifecycle). Answer agent questions with [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage); confirm actions with [task.confirmAction](https://open.manus.ai/docs/v2/task.confirmAction). > > **Render output:** Resolve file paths and `manus-webdev://` links in assistant content as described in [Attachments](https://open.manus.ai/docs/v2/attachments). # task.sendMessage Source: https://open.manus.ai/docs/v2/task.sendMessage POST /v2/task.sendMessage Sends a follow-up message to a task for multi-turn conversation. Use this after [task.create](https://open.manus.ai/docs/v2/task.create) to continue talking, or to answer `messageAskUser` / `cascadeAskUser` questions with ordinary message.content. For supported action confirmations, review confirm_input_schema and the target tool event, then use [task.confirmAction](https://open.manus.ai/docs/v2/task.confirmAction). Do not automatically confirm unrecognized waiting types. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. # task.stop Source: https://open.manus.ai/docs/v2/task.stop POST /v2/task.stop Stops a running task. The task status will change to `stopped`. A stopped task can still be resumed with [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage). Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. # task.update Source: https://open.manus.ai/docs/v2/task.update POST /v2/task.update Updates a task's metadata (title, sharing, visibility). Use [task.detail](https://open.manus.ai/docs/v2/task.detail) to see the current values before updating. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** > > * **API Key:** Full access. > * **Standard OAuth client:** Requires `create_task` or `manage_all_tasks`. With `create_task`, only tasks created by the same client; see [Task visibility](https://open.manus.ai/docs/v2/open-app#task-visibility). > * **Trusted client:** Full access. # usage.availableCredits Source: https://open.manus.ai/docs/v2/usage.availableCredits GET /v2/usage.availableCredits Returns the credit balance, subscription period, and refresh information for the authenticated caller. For a team sub-account, the team's shared pool balance is returned; for a personal account, the personal balance is returned. Standard OAuth clients cannot access this endpoint; trusted clients can. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # usage.list Source: https://open.manus.ai/docs/v2/usage.list GET /v2/usage.list Lists the current user's credit change history at session granularity, sorted by change time (newest first). Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # usage.teamLog Source: https://open.manus.ai/docs/v2/usage.teamLog GET /v2/usage.teamLog Lists team members' task counts and total credit consumption over the requested range, one row per user. Owners and admins see every member; members see only their own row. Enterprise teams have T+1 latency: today's data is visible the next day. Other teams aggregate in real time. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. Team accounts only; individual users receive `permission_denied`. # usage.teamStatistic Source: https://open.manus.ai/docs/v2/usage.teamStatistic GET /v2/usage.teamStatistic Returns daily credit consumption totals for the team over a date range. Owners and admins see the whole team; members see only their own consumption. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. Team accounts only; individual users receive `permission_denied`. # user.me Source: https://open.manus.ai/docs/v2/user.me GET /v2/user.me Returns the Manus user ID associated with the authenticated API key or OAuth2 access token. API Key and Trusted client callers also receive the user's display name, email, and avatar. This endpoint is read-only and does not require an OAuth scope. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or OAuth token. No OAuth scope is required. Standard OAuth clients receive only `user_id`. # webhook.create Source: https://open.manus.ai/docs/v2/webhook.create POST /v2/webhook.create Creates a webhook for receiving task event notifications. Use [webhook.publicKey](https://open.manus.ai/docs/v2/webhook.publicKey) to get the key for verifying signatures. See the [Webhooks](https://open.manus.ai/docs/v2/webhooks-overview) guide for event types. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # webhook.delete Source: https://open.manus.ai/docs/v2/webhook.delete POST /v2/webhook.delete Deletes a webhook. The endpoint will stop receiving notifications immediately. Use [webhook.list](https://open.manus.ai/docs/v2/webhook.list) to find the webhook ID. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # webhook.list Source: https://open.manus.ai/docs/v2/webhook.list GET /v2/webhook.list Lists all webhooks in your account. Use the returned IDs with [webhook.delete](https://open.manus.ai/docs/v2/webhook.delete) to remove a webhook. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or Trusted client. Standard OAuth clients cannot access this endpoint. # webhook.publicKey Source: https://open.manus.ai/docs/v2/webhook.publicKey GET /v2/webhook.publicKey Gets the public key for verifying webhook signatures. See the [Webhook Security](https://open.manus.ai/docs/v2/webhooks-security) guide for verification examples. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or OAuth token. No OAuth scope is required. # Overview Source: https://open.manus.ai/docs/v2/webhooks-overview Real-time notifications for task lifecycle events Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). ## Overview Webhooks allow you to receive real-time notifications when important events occur in your Manus tasks. When you register a webhook, Manus will send HTTP POST requests to your specified callback URL whenever these events are triggered. ## How Webhook Events Work When you create and execute tasks, these lifecycle events can trigger webhook deliveries: * **Task Creation**: Immediately after a task is successfully created via the API * **Task State Change**: When a task completes, or requires user input * **Task Deletion**: When a task created via the API is deleted, in the Manus app or through the API Each webhook delivery contains a specific event type identifier and a structured payload with relevant task information. Your endpoint will receive these as standard HTTP POST requests that you can process like any other API call. ## Setting Up Webhooks > **[Manage Webhooks](https://manus.im/app#settings/developers/webhooks)** > > Open Developers settings to create or manage webhooks. Before activating a webhook, Manus will send a test request to verify your endpoint is accessible and responding correctly. Your endpoint should: * Respond with HTTP status code 200 * Accept POST requests with JSON payloads * Respond within 10 seconds ## Event Types and Payloads ### `task_created` Event **When it triggers:** Immediately after a new task is successfully created. **Why it's useful:** Allows you to track task creation in your own systems, send confirmation emails, or update dashboards in real-time. **Payload Schema:** | Field | Type | Required | Description | | - | - | - | - | | `event_id` | string | Yes | Unique identifier for this webhook event | | `event_type` | string | Yes | Always `"task_created"` for this event | | `task_detail` | object | Yes | Task details object | | `task_detail.task_id` | string | Yes | Unique identifier for the created task | | `task_detail.task_title` | string | Yes | Human-readable title of the task | | `task_detail.task_url` | string | Yes | Direct URL to view the task in Manus app | **Example Payload:** ```json theme={null} { "event_id": "task_created_task_abc123", "event_type": "task_created", "task_detail": { "task_id": "task_abc123", "task_title": "Generate quarterly sales report", "task_url": "https://manus.im/app/task_abc123" } } ``` ### `task_stopped` Event **When it triggers:** When a task reaches a stopping point - either because it completed successfully or needs user input to proceed. **Why it's useful:** Essential for knowing when your tasks finish and what the outcome was. Enables automated workflows based on task completion. **Payload Schema:** | Field | Type | Required | Description | | - | - | - | - | | `event_id` | string | Yes | Unique identifier for this webhook event | | `event_type` | string | Yes | Always `"task_stopped"` for this event | | `task_detail` | object | Yes | Task details object | | `task_detail.task_id` | string | Yes | Unique identifier for the task | | `task_detail.task_title` | string | Yes | Human-readable title of the task | | `task_detail.task_url` | string | Yes | Direct URL to view the task in Manus app | | `task_detail.message` | string | Yes | Status message from the task execution | | `task_detail.attachments` | array | No | List of files generated by the task | | `task_detail.stop_reason` | string | Yes | Why the task stopped: `"finish"` or `"ask"` | | `task_detail.question_expectation` | object | No | Question metadata for `stop_reason: "ask"`: webhook-only `event_id` identifying the question event, `options` (empty for free text), `selection_mode` (`"single"` or `"multiple"`), and `response_method` (`"send_message"`). Continue with `task.sendMessage`, not `task.confirmAction`. | | `task_detail.structured_output` | object | No | Extracted structured data when the task was created with `structured_output_schema`. Contains `success` (boolean), `value` (your schema), and `error` (string or null). See the [Structured Output](https://open.manus.ai/docs/v2/structured-output) guide. | `question_expectation.event_id` identifies the underlying question event, not the webhook notification identified by the top-level `event_id`. It is not a reply parameter or a send-message idempotency key. In `task.listMessages`, use the enclosing message's `id`; the nested `event_id` is absent. `options` contains display text, not option IDs or mandatory exact-match answers. An empty array means free-text input; `selection_mode` defaults to `single` and is only a UI hint. For `multiple`, combine the chosen text into one readable `message.content`; no delimiter or option-ID array is required, and users may supply their own text. See [Answer an agent question](https://open.manus.ai/docs/v2/task-lifecycle#answer-an-agent-question) for a request example and unknown-method handling. **Stop Reason Values:** * `"finish"`: Task completed successfully and has final results * `"ask"`: Task paused and requires user input or confirmation to continue **Attachment Object Schema:** | Field | Type | Required | Description | | - | - | - | - | | `file_name` | string | Yes | Name of the generated file | | `url` | string | Yes | Secure download URL for the file | | `size_bytes` | integer | Yes | File size in bytes | **Example Payload (Task Completed):** ```json theme={null} { "event_id": "task_stopped_task_abc123", "event_type": "task_stopped", "task_detail": { "task_id": "task_abc123", "task_title": "Generate quarterly sales report", "task_url": "https://manus.im/app/task_abc123", "message": "I've completed the quarterly sales report analysis. The report includes revenue trends, top-performing products, and regional breakdowns.", "attachments": [ { "file_name": "q4-sales-report.pdf", "url": "https://s3.amazonaws.com/manus-files/reports/q4-sales-report.pdf", "size_bytes": 2048576 }, { "file_name": "sales-data.xlsx", "url": "https://s3.amazonaws.com/manus-files/reports/sales-data.xlsx", "size_bytes": 512000 } ], "stop_reason": "finish" } } ``` **Example Payload (User Input Required):** ```json theme={null} { "event_id": "task_stopped_task_abc123", "event_type": "task_stopped", "task_detail": { "task_id": "task_abc123", "task_title": "Book restaurant reservation", "task_url": "https://manus.im/app/task_abc123", "message": "I found several restaurants with availability. Which option would you prefer?", "attachments": [], "stop_reason": "ask", "question_expectation": { "event_id": "ask_abc123", "options": ["Bistro Milano", "Garden Terrace", "The Blue Door"], "selection_mode": "single", "response_method": "send_message" } } } ``` ### `task_deleted` Event **When it triggers:** After a task created via the API is deleted, whether in the Manus app or with [task.delete](https://open.manus.ai/docs/v2/task.delete). It is not sent when tasks are removed because the account itself is deleted. **Why it's useful:** Lets you remove or archive the task in your own systems without polling. **Payload Schema:** | Field | Type | Required | Description | | - | - | - | - | | `event_id` | string | Yes | Unique identifier for this webhook event | | `event_type` | string | Yes | Always `"task_deleted"` for this event | | `task_detail` | object | Yes | Task details object | | `task_detail.task_id` | string | Yes | Unique identifier for the deleted task | | `task_detail.task_title` | string | Yes | Latest title of the task when it was deleted | | `task_detail.task_url` | string | Yes | URL of the task in the Manus app. The task is no longer available after deletion. | **Example Payload:** ```json theme={null} { "event_id": "task_deleted_task_abc123_1760256000", "event_type": "task_deleted", "task_detail": { "task_id": "task_abc123", "task_title": "Generate quarterly sales report", "task_url": "https://manus.im/app/task_abc123" } } ``` If your endpoint misses a `task_deleted` event, call [task.list](https://open.manus.ai/docs/v2/task.list) with `include_deleted=true`. Deleted tasks are returned with `status: "deleted"` and `deleted_at`. ### Unknown Event Types Manus may add new event types. Route deliveries by `event_type`, ignore types you do not handle, and still respond with HTTP 200. ## Integration Examples ### Slack Integration Post task updates directly to Slack channels: ```javascript theme={null} // Example webhook handler for Slack integration app.post('/manus-webhook', (req, res) => { const { event_type, task_detail } = req.body; const { task_title, message, stop_reason } = task_detail || {}; if (event_type === 'task_stopped' && stop_reason === 'finish') { // Post completion message to Slack slack.chat.postMessage({ channel: '#ai-tasks', text: `✅ Task completed: ${task_title}\n${message}` }); } res.status(200).send('OK'); }); ``` ### Custom Dashboard Updates Update your internal dashboards in real-time: ```python theme={null} # Example webhook handler in Python/Flask @app.route('/manus-webhook', methods=['POST']) def handle_webhook(): data = request.json event_type = data.get('event_type') task_detail = data.get('task_detail', {}) # Update task status in your database if event_type == 'task_stopped': update_task_status( task_id=task_detail.get('task_id'), status='completed' if task_detail.get('stop_reason') == 'finish' else 'waiting', message=task_detail.get('message') ) return '', 200 ``` ## Troubleshooting ### Common Issues * **Webhook not receiving events**: Verify your URL is accessible and returns 200 status * **SSL/TLS errors**: Ensure your endpoint uses valid HTTPS certificates * **Timeout errors**: Make sure your endpoint responds within 10 seconds ### Testing Your Webhook You can test your webhook endpoint using tools like: * [webhook.site](https://webhook.site) for quick testing * [ngrok](https://ngrok.com) for local development * Postman or curl for manual testing # Webhook Security Source: https://open.manus.ai/docs/v2/webhooks-security Verify webhook signatures to ensure requests are from Manus Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). Every webhook request from Manus includes a cryptographic signature. Verifying it ensures the request is authentic and hasn't been tampered with. ## How it works Manus signs each request using **RSA-SHA256** (2048-bit key). Your server verifies the signature with our public key. **1. Extract headers** Read `X-Webhook-Signature` and `X-Webhook-Timestamp` from the incoming request. **2. Check timestamp** Reject requests older than 5 minutes to prevent replay attacks. **3. Reconstruct the signed content** Concatenate: `{timestamp}.{url}.{sha256_hex(body)}` **4. Verify signature** Verify the signature using the public key. ## Request headers | Header | Description | | - | - | | `X-Webhook-Signature` | Base64-encoded RSA-SHA256 signature | | `X-Webhook-Timestamp` | Unix timestamp (seconds) when the request was signed | ## Signature format The signature is computed over this string: ``` {timestamp}.{url}.{body_sha256_hex} ``` | Component | Description | | - | - | | `timestamp` | Value of `X-Webhook-Timestamp` | | `url` | Full webhook URL including query parameters | | `body_sha256_hex` | SHA-256 hash of the raw request body, hex-encoded | **Example:** ``` 1704067200.https://api.yourapp.com/webhooks.a1b2c3d4e5f6... ``` ## Get the public key Fetch the public key from the [webhook.publicKey](https://open.manus.ai/docs/v2/webhook.publicKey) endpoint: ```bash theme={null} curl 'https://api.manus.ai/v2/webhook.publicKey' \ -H 'x-manus-api-key: YOUR_API_KEY' ``` ```json theme={null} { "ok": true, "public_key": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQE...\n-----END PUBLIC KEY-----", "algorithm": "RSA-SHA256" } ``` > [!WARNING] > > Cache this key on your server with a reasonable TTL (e.g. 1 hour). Do not fetch it on every webhook request. ## Verification examples **Python** ```python theme={null} import base64, hashlib, time from cryptography.hazmat.primitives import hashes, serialization from cryptography.hazmat.primitives.asymmetric import padding from cryptography.exceptions import InvalidSignature def verify_webhook(public_key_pem, url, body, signature_b64, timestamp): # 1. Check timestamp freshness (5-minute window) if abs(int(time.time()) - int(timestamp)) > 300: return False # 2. Reconstruct signed content body_hash = hashlib.sha256(body).hexdigest() signed_content = f"{timestamp}.{url}.{body_hash}".encode() # 3. Verify signature try: key = serialization.load_pem_public_key(public_key_pem.encode()) key.verify( base64.b64decode(signature_b64), signed_content, padding.PKCS1v15(), hashes.SHA256() ) return True except (InvalidSignature, Exception): return False ``` **Flask handler:** ```python theme={null} @app.route("/webhooks", methods=["POST"]) def handle_webhook(): sig = request.headers.get("X-Webhook-Signature") ts = request.headers.get("X-Webhook-Timestamp") if not sig or not ts: return "Missing headers", 400 if not verify_webhook(get_cached_public_key(), request.url, request.data, sig, ts): return "Unauthorized", 401 # Process webhook data = request.json process_event(data) return "OK", 200 ``` **Node.js** ```javascript theme={null} const crypto = require("crypto"); function verifyWebhook({ publicKeyPem, url, body, signatureB64, timestamp }) { // 1. Check timestamp freshness if (Math.abs(Math.floor(Date.now() / 1000) - parseInt(timestamp)) > 300) { return false; } // 2. Reconstruct signed content const bodyHash = crypto.createHash("sha256").update(body).digest("hex"); const signedContent = `${timestamp}.${url}.${bodyHash}`; // 3. Verify signature try { const verifier = crypto.createVerify("RSA-SHA256"); verifier.update(signedContent); return verifier.verify(publicKeyPem, signatureB64, "base64"); } catch { return false; } } ``` **Express middleware:** ```javascript theme={null} app.use("/webhooks", express.raw({ type: "application/json" }), (req, res, next) => { const sig = req.headers["x-webhook-signature"]; const ts = req.headers["x-webhook-timestamp"]; if (!sig || !ts) return res.status(400).json({ error: "Missing headers" }); const fullUrl = `${req.protocol}://${req.get("host")}${req.originalUrl}`; const valid = verifyWebhook({ publicKeyPem: getCachedPublicKey(), url: fullUrl, body: req.body, signatureB64: sig, timestamp: ts, }); if (!valid) return res.status(401).json({ error: "Invalid signature" }); req.body = JSON.parse(req.body.toString()); next(); }); ``` **Go** ```go theme={null} func VerifyWebhook(publicKeyPEM []byte, url string, body []byte, signatureB64 string, timestamp int64) error { // 1. Check timestamp freshness if math.Abs(float64(time.Now().Unix()-timestamp)) > 300 { return fmt.Errorf("timestamp too old") } // 2. Reconstruct signed content bodyHash := sha256.Sum256(body) signedContent := fmt.Sprintf("%d.%s.%x", timestamp, url, bodyHash) // 3. Hash the content contentHash := sha256.Sum256([]byte(signedContent)) // 4. Parse public key and verify block, _ := pem.Decode(publicKeyPEM) pubKey, err := x509.ParsePKIXPublicKey(block.Bytes) if err != nil { return err } sig, err := base64.StdEncoding.DecodeString(signatureB64) if err != nil { return err } return rsa.VerifyPKCS1v15(pubKey.(*rsa.PublicKey), crypto.SHA256, contentHash[:], sig) } ``` **HTTP handler:** ```go theme={null} func webhookHandler(w http.ResponseWriter, r *http.Request) { sig := r.Header.Get("X-Webhook-Signature") tsStr := r.Header.Get("X-Webhook-Timestamp") if sig == "" || tsStr == "" { http.Error(w, "Missing headers", http.StatusBadRequest) return } ts, _ := strconv.ParseInt(tsStr, 10, 64) body, _ := io.ReadAll(r.Body) fullURL := fmt.Sprintf("https://%s%s", r.Host, r.RequestURI) if err := VerifyWebhook(getCachedPublicKey(), fullURL, body, sig, ts); err != nil { http.Error(w, "Unauthorized", http.StatusUnauthorized) return } w.WriteHeader(http.StatusOK) } ``` ## Best practices | Practice | Why | | - | - | | Cache the public key | Avoid fetching on every request — it rarely changes | | Verify timestamps | Reject requests older than 5 minutes to prevent replay attacks | | Use HTTPS | Ensure your webhook endpoint uses TLS | | Return generic errors | Don't expose internal details in 401 responses | # Website Source: https://open.manus.ai/docs/v2/website Manage websites built by Manus agents — inspect, version, publish, and configure Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). 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, screenshot, visibility, and the sandbox preview URL with its sandbox state * [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). ## 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). ## Open the sandbox preview `website.status` called with a `task_id` returns `preview_url` and `sandbox_status`. `preview_url` points at the task's cloud sandbox, not at the published site. * **Open it only while `running`.** While the sandbox is asleep (`sandbox_status` is `paused`), the URL stays listed but does not respond. * **Bring a sleeping preview back with a message.** Send a message to the task with [task.sendMessage](https://open.manus.ai/docs/v2/task.sendMessage); this requires permission to send messages to the task and consumes credits. The agent runs and resumes the sandbox. Then poll `website.status` with an upper bound until `sandbox_status` is `running`. * **Stop on terminal states.** `failed`, `reset_failed`, `deleted`, and `deleting` do not recover on their own; check the task in the Manus app. `not_created` means the task has no cloud sandbox, for example a task that runs on a local device. * **Do not store or share it.** `preview_url` is a temporary address. Use `site_urls` for a stable public link. * **Reading is passive.** Calling `website.status` never creates, wakes, or extends a sandbox. ## 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`, and an optional `screenshot_url`. | | **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. ### 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 | # website.listCheckpoints Source: https://open.manus.ai/docs/v2/website.listCheckpoints GET /v2/website.listCheckpoints Returns the website's current title and lists all of its checkpoints, newest first. Match `published_version_id` against `data[].version_id` to identify the live checkpoint, or call [website.publish](https://open.manus.ai/docs/v2/website.publish) to deploy the latest. See the [Website](https://open.manus.ai/docs/v2/website) guide. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or OAuth token. No OAuth scope is required. The user must own the website or have read access to its source task; see [Website access](https://open.manus.ai/docs/v2/website#website-access). # website.publish Source: https://open.manus.ai/docs/v2/website.publish POST /v2/website.publish Deploys the latest checkpoint of a website and sets its visibility. Deployment is asynchronous — poll [website.status](https://open.manus.ai/docs/v2/website.status) until `publish_status` becomes `published` or `failed`. To change metadata (title, visibility) without redeploying, use [website.update](https://open.manus.ai/docs/v2/website.update) instead. See the [Website](https://open.manus.ai/docs/v2/website) guide. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or OAuth token. No OAuth scope is required. The user must own the website or have write access to its source task; see [Website access](https://open.manus.ai/docs/v2/website#website-access). # website.status Source: https://open.manus.ai/docs/v2/website.status GET /v2/website.status Retrieves a website's current title, publish status, live URL, screenshot, and visibility. Use [website.listCheckpoints](https://open.manus.ai/docs/v2/website.listCheckpoints) to browse version history, or [website.publish](https://open.manus.ai/docs/v2/website.publish) to deploy changes. See the [Website](https://open.manus.ai/docs/v2/website) guide. When called with `task_id`, also returns the sandbox `preview_url` and `sandbox_status`. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or OAuth token. No OAuth scope is required. The user must own the website or have read access to its source task; see [Website access](https://open.manus.ai/docs/v2/website#website-access). # website.update Source: https://open.manus.ai/docs/v2/website.update POST /v2/website.update Updates website configuration without deploying. Omitted fields are unchanged; a request with no updatable field returns `400 invalid_argument`. Use [website.publish](https://open.manus.ai/docs/v2/website.publish) to deploy a new version. See the [Website](https://open.manus.ai/docs/v2/website) guide. Questions or issues? Contact us at [api-support@manus.ai](mailto:api-support@manus.ai). > [!TIP] > > **Auth:** API Key or OAuth token. No OAuth scope is required. The user must own the website or have write access to its source task; see [Website access](https://open.manus.ai/docs/v2/website#website-access).