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

# 开始 MCP 账户授权

> 创建短期有效的授权请求，并将用户重定向到 VoiceCheap 登录及权限同意页面。

创建短期有效的授权请求，并将用户重定向到 VoiceCheap 登录及权限同意页面。

```http theme={null}
GET https://api.voicecheap.ai/oauth/authorize
```

## 身份验证

此路由无需身份验证。浏览器后续的授权同意流程要求用户登录，批准连接还要求具备符合条件的付费账户访问权限。

## 查询参数

<ParamField query="client_id" type="string" required>
  动态注册返回的 client\_id，或客户端元数据文档的精确公开 HTTPS URL。

  最小长度: 1. 最大长度: 2048. 匹配模式: `^[^\u0000-\u001F\u007F]+$`.
</ParamField>

<ParamField query="redirect_uri" type="string" required>
  必须与此客户端已注册的某个 redirect\_uris 完全匹配。

  最小长度: 1. 最大长度: 2048. 匹配模式: `^[^\u0000-\u001F\u007F]+$`.
</ParamField>

<ParamField query="response_type" type="field" required>
  由完整输入架构定义的值。

  指定值: "code".
</ParamField>

<ParamField query="response_mode" type="field">
  由完整输入架构定义的值。

  指定值: "query". 默认值: "query".
</ParamField>

<ParamField query="code_challenge" type="string" required>
  原始 code\_verifier 的 Base64url SHA-256 摘要，不含填充。

  最小长度: 43. 最大长度: 43. 匹配模式: `^[A-Za-z0-9_-]{43}$`.
</ParamField>

<ParamField query="code_challenge_method" type="field" required>
  由完整输入架构定义的值。

  指定值: "S256".
</ParamField>

<ParamField query="resource" type="string" required>
  必须使用完全匹配的资源受众：请使用此环境受保护资源元数据中的 resource 值。生产环境中为 [https://api.voicecheap.ai/mcp。不同的源地址、路径或末尾斜杠均会被拒绝。](https://api.voicecheap.ai/mcp。不同的源地址、路径或末尾斜杠均会被拒绝。)

  格式: "uri".
</ParamField>

<ParamField query="scope" type="string">
  以空格分隔、选自 scopes\_supported 的权限，可包含 offline\_access。不支持的名称和仅含空白字符的值会被拒绝；重复项会被移除。省略 scope 或不提供任何产品权限（例如仅提供 openid 或 offline\_access）时，会选择默认读取范围与此客户端已注册产品范围的交集。email 必须与 openid 一起使用；仅提供 email 会被拒绝。请求的产品权限必须已为此客户端注册。身份权限必须显式请求并由用户批准；省略 scope 不会请求任何身份权限。

  最小长度: 1. 最大长度: 2048. 匹配模式: `^ *(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email)(?: +(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email))* *$`.
</ParamField>

<ParamField query="state" type="string">
  可选的不透明值，会在最终回调中原样返回。请使用新的不可预测值，并在客户端验证。

  最小长度: 1. 最大长度: 2048. 匹配模式: `^[^\u0000-\u001F\u007F]+$`.
</ParamField>

<ParamField query="nonce" type="string">
  可选的不透明 nonce 值，授予 openid 后会原样包含在 ID 令牌中。请在客户端验证。

  最小长度: 1. 最大长度: 2048. 匹配模式: `^[^\u0000-\u001F\u007F]+$`.
</ParamField>

<ParamField query="prompt" type="string">
  文本值。

  指定值: "consent".
</ParamField>

<Accordion title="技术架构">
  ```json theme={null}
  {
    "type": "object",
    "properties": {
      "client_id": {
        "type": "string",
        "minLength": 1,
        "maxLength": 2048,
        "pattern": "^[^\\u0000-\\u001F\\u007F]+$",
        "description": "The client_id returned by dynamic registration, or the exact public HTTPS URL of the client metadata document."
      },
      "redirect_uri": {
        "type": "string",
        "minLength": 1,
        "maxLength": 2048,
        "pattern": "^[^\\u0000-\\u001F\\u007F]+$",
        "description": "Must exactly match one of this client's registered redirect_uris."
      },
      "response_type": {
        "const": "code"
      },
      "response_mode": {
        "const": "query",
        "default": "query"
      },
      "code_challenge": {
        "type": "string",
        "minLength": 43,
        "maxLength": 43,
        "pattern": "^[A-Za-z0-9_-]{43}$",
        "description": "Base64url SHA-256 digest of the original code_verifier, without padding."
      },
      "code_challenge_method": {
        "const": "S256"
      },
      "resource": {
        "type": "string",
        "format": "uri",
        "description": "Required exact resource audience: use the resource value from this environment's protected-resource metadata. In production this is https://api.voicecheap.ai/mcp. A different origin, path, or trailing slash is rejected.",
        "examples": [
          "https://api.voicecheap.ai/mcp"
        ]
      },
      "scope": {
        "type": "string",
        "minLength": 1,
        "maxLength": 2048,
        "pattern": "^ *(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email)(?: +(?:account:read|usage:read|settings:read|settings:write|team:read|team:write|projects:read|projects:write|projects:delete|translations:write|transcription:read|transcription:write|subtitles:read|subtitles:write|tts:read|tts:write|voices:read|voices:write|images:read|images:write|thumbnails:read|thumbnails:write|folders:read|folders:write|glossary:read|glossary:write|webhooks:read|webhooks:write|publishing:read|publishing:write|offline_access|openid|email))* *$",
        "description": "Space-delimited permissions from scopes_supported, optionally including offline_access. Unsupported names and whitespace-only values are rejected; duplicates are removed. Omitting scope or supplying no product scopes, such as openid alone or offline_access alone, selects the default read scopes intersected with this client's registered product scopes. email requires openid; email alone is rejected. Requested product permissions must be registered for this client. Identity permissions must be explicitly requested and approved by the user; omitting scope requests no identity permissions.",
        "examples": [
          "account:read projects:read offline_access"
        ]
      },
      "state": {
        "type": "string",
        "minLength": 1,
        "maxLength": 2048,
        "pattern": "^[^\\u0000-\\u001F\\u007F]+$",
        "description": "Optional opaque value echoed on the final callback. Use a fresh unpredictable value and verify it in the client."
      },
      "nonce": {
        "type": "string",
        "minLength": 1,
        "maxLength": 2048,
        "pattern": "^[^\\u0000-\\u001F\\u007F]+$",
        "description": "Optional opaque nonce echoed in the ID token when openid is granted. Verify it in the client."
      },
      "prompt": {
        "type": "string",
        "const": "consent"
      }
    },
    "required": [
      "client_id",
      "redirect_uri",
      "response_type",
      "code_challenge",
      "code_challenge_method",
      "resource"
    ],
    "additionalProperties": true
  }
  ```
</Accordion>

## 请求示例

请遵循此路由文档规定的编码和身份验证方式。操作 API 的封装格式和幂等性规则仅适用于操作调用。

<RequestExample>
  ```bash cURL theme={null}
  curl --request GET 'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state'
  ```

  ```javascript JavaScript theme={null}
  const input = {
    client_id: 'mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
    redirect_uri: 'https://assistant.example.com/oauth/callback',
    response_type: 'code',
    response_mode: 'query',
    code_challenge: 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM',
    code_challenge_method: 'S256',
    resource: 'https://api.voicecheap.ai/mcp',
    scope: 'account:read projects:read offline_access',
    state: 'example-client-csrf-state',
  };
  const response = await fetch(
    'https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state',
    {
      method: 'GET',
      headers: {},
      redirect: 'manual',
    },
  );
  console.log(response.status, await response.text());
  ```

  ```python Python theme={null}
  import os
  import requests

  response = requests.request(
      "GET",
      "https://api.voicecheap.ai/oauth/authorize?client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA&redirect_uri=https%3A%2F%2Fassistant.example.com%2Foauth%2Fcallback&response_type=code&response_mode=query&code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM&code_challenge_method=S256&resource=https%3A%2F%2Fapi.voicecheap.ai%2Fmcp&scope=account%3Aread+projects%3Aread+offline_access&state=example-client-csrf-state",
      headers={},
      timeout=120,
      allow_redirects=False,
  )
  print(response.status_code, response.text)
  ```
</RequestExample>

## 响应

HTTP 重定向至 VoiceCheap 授权同意页面。不返回 JSON 结果体。Location 包含一个不透明的 request 值；随后用户登录并选择权限。

```http theme={null}
HTTP/1.1 302 Found
Cache-Control: no-store
Pragma: no-cache
Referrer-Policy: no-referrer
Location: https://app.voicecheap.ai/mcp/authorize?request=mcp_req_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
```

## 响应头

```json theme={null}
{
  "Cache-Control": "no-store",
  "Pragma": "no-cache",
  "Referrer-Policy": "no-referrer",
  "Location": "https://app.voicecheap.ai/mcp/authorize?request=mcp_req_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
}
```

## 操作说明

* 受支持的标量参数必须仅提供一次，值须为不含 ASCII 控制字符或 DEL 的非空字符串。重复的查询或表单字段会解码为数组，在按标量读取时会被拒绝。
* 请对每个查询值进行 URL 编码。redirect\_uri 必须与此客户端注册时的拼写完全一致。
* 仅使用 S256；不支持 plain PKCE 和 implicit/token 响应。请保留原始的 43–128 个字符的 code\_verifier，用于令牌兑换。
* resource 参数为必填，且必须与所选环境的 MCP 资源 URL 完全一致。
* 默认产品权限范围集合为 account:read usage:read projects:read transcription:read subtitles:read tts:read voices:read images:read thumbnails:read。使用默认值的请求会收窄至客户端已注册的权限范围；若未剩余任何产品权限范围，授权将失败。
* 仅包含 offline\_access 的 scope 会使用默认产品权限范围。显示或授予产品权限前，会移除 offline\_access。
* 授权同意请求在 10 分钟后过期，且只能答复一次。用户只能批准所请求产品权限的非空子集。
* 批准后，客户端回调会收到 code、iss，以及最初提供的 state（如有）。授权码在 2 分钟后过期，且只能兑换一次。
* 拒绝授权后，客户端回调会收到 error=access\_denied、error\_description、iss，以及提供时的原始 state；不会签发 code。
* 无效的客户端元数据、重定向不匹配、PKCE、scopes 或 resource 问题会直接返回 OAuth JSON 错误；不会重定向到未经验证的回调地址。
* 公共授权接口的限流为每个客户端 IP 每分钟 30 次请求，由所有工作进程共享。
* openid 和 email 是独立于产品权限的身份权限，仅在公布支持时接受。email 需要 openid。在首次授权时，仅包含身份权限的请求会使用同意页面显示的默认产品权限。
* 动态注册返回的 client\_id，或客户端元数据文档的精确公开 HTTPS URL。
* OpenID Connect 支持 prompt=consent。其他 prompt 值和 max\_age 会被拒绝；不支持静默授权或强制重新登录。

## 错误

| HTTP 状态 | 代码 | 含义或恢复方式 |
| - | - | - |
| 400 | `invalid_request` | 请求体或已识别的参数无效、缺失、重复或编码错误。 |
| 400 | `invalid_client` | client\_id 未知，或无法获取或验证客户端元数据文档。 |
| 400 | `unsupported_response_type` | response\_type 不是 code。 |
| 400 | `invalid_target` | 缺少 resource，或其与该环境的 MCP URL 不完全一致。 |
| 400 | `invalid_scope` | 请求的某个产品权限范围不受支持、未注册，或未留下任何可用权限。 |
| 429 | `temporarily_unavailable` | 已达到公开 OAuth 请求速率上限。请等待当前时间窗口结束后重试。 |
| 500 | `server_error` | 授权暂时不可用。请稍后重试。 |
| 503 | `temporarily_unavailable` | 客户端元数据暂时不可用。请稍后重试。 |


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