Documentation Index
Fetch the complete documentation index at: https://open.manus.ai/docs/llms.txt
Use this file to discover all available pages before exploring further.
Questions or issues? Contact us at api-support@manus.ai.
Manus supports OAuth2 for third-party integrations that act on behalf of a user. OAuth apps are scoped to a team — only members of the same team can authorize the app.
Team only: OAuth app creation and authorization require a Team account. Personal accounts cannot create or authorize OAuth apps.
App management
Creating an OAuth app
Create an OAuth app from the Manus Integrations settings. 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).
Secret management
Each app can have up to 5 active client secrets, enabling zero-downtime rotation. Create and revoke secrets from the Manus Integrations settings.
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.
Update your application
Configure your app to use the new secret.
Verify
Confirm the new secret works in production.
Revoke the old secret
Revoke the old secret in the settings page. It is immediately invalidated.
OAuth flow
Overview
The implementation follows RFC 6749 (Authorization Code Grant) and RFC 7636 (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 Integrations settings.
| 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 | |
use_connectors | Use third-party connectors | Must also specify connector UIDs |
use_my_browsers | Use My Browser connector | Independent from use_connectors |
use_my_browsers is a separate scope from use_connectors — they do not overlap.
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
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}"
}'
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}"
}'
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).
Success response:
{
"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 |
Step 4: Refresh tokens
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 OAuth app has been deleted
- The app’s scopes were expanded (adding new scopes or connector UIDs invalidates all existing tokens)
Revoking tokens
App-side: revoke a single token (RFC 7009)
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).
- PKCE-issued tokens do not require
client_secret for revocation.
User-side: revoke grants
Users can view and revoke authorized OAuth apps from Authorized Apps settings. Revoking an app invalidates all of its active tokens.
Available endpoints
Include the access token in the Authorization header:
curl https://api.manus.ai/v2/task.list \
-H "Authorization: Bearer {access_token}"
OAuth tokens can access the following v2 endpoints. Each endpoint page lists its required scope.
| Endpoint | Required scope |
|---|
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 |
project.create | create_project or manage_all_tasks |
project.list | create_project or manage_all_tasks |
connector.list | create_task or manage_all_tasks |
skill.list | 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 |
Endpoints not listed above — including agent.*, webhook.*, usage.*, and website.* — are API Key only and cannot be accessed with OAuth tokens.
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.
| Token scope | Visible tasks |
|---|
create_task | Only tasks created by this OAuth app |
manage_all_tasks | 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 Integrations settings. During authorization, the consent page shows your app’s connector list and the user chooses which ones to grant.
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:
{
"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
OAuth 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 Integrations settings.
To customize which skills are available for a specific task, pass skill IDs in message.enable_skills when calling task.create or task.sendMessage. To force Manus to use specific skills, pass them in message.force_skills.
Webhook
Each OAuth app can configure a dedicated webhook URL to receive event notifications. Set the webhook URL in the Manus Integrations settings. The URL must be HTTPS.
Webhook events are scoped to the OAuth 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 guide for event types and the Webhook 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 for per-endpoint limits.
Exceeding any limit returns HTTP 429 Too Many Requests.
Error handling
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 |
{
"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:
{
"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 for handling):
{
"code": "permission_denied",
"message": "insufficient_scope: connector {uid} not granted"
}
Best practices
- Store secrets securely.
client_secret is only shown once at creation. Use a secrets manager — never hardcode it.
- Request minimal scopes. Only request what your app actually needs. Avoid
manage_all_tasks unless you truly need access to all user tasks.
- Implement token refresh. Access tokens expire in 24 hours. Use the refresh token to renew automatically.
- Handle token invalidation gracefully. On
401, try refreshing. If refresh fails, redirect the user to re-authorize.
- Rotate secrets regularly. Use multi-secret support for zero-downtime rotation.
- Prefer PKCE for client-side apps. Native apps and SPAs should use PKCE — never embed a
client_secret in client-side code.
- Validate the
state parameter. Always verify the returned state matches the value you sent to prevent CSRF attacks.
- Implement backoff on 429. Token endpoints are limited to 60 req/min. Use exponential backoff with jitter.