> ## 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">
  openid가 부여되면 ID 토큰에 그대로 반환되는 선택적 불투명 nonce 값입니다. 클라이언트에서 검증하세요.

  최소 길이: 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>

## 응답

VoiceCheap 동의 페이지로 HTTP 리디렉션합니다. 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만 있는 범위는 기본 제품 범위 선택을 사용합니다. 제품 권한을 표시하거나 부여하기 전에 offline\_access는 제거됩니다.
* 동의 요청은 10분 후에 만료되며 한 번만 응답할 수 있습니다. 사용자는 요청된 제품 권한 중 비어 있지 않은 하위 집합만 승인할 수 있습니다.
* 승인 후 클라이언트 콜백은 code, iss 및 제공된 경우 원래 state를 받습니다. 인증 코드는 2분 후 만료되며 한 번만 교환할 수 있습니다.
* 거부 후 클라이언트 콜백에는 error=access\_denied, error\_description, iss 및 원래 제공된 state가 전달되며 코드는 발급되지 않습니다.
* 잘못된 클라이언트 메타데이터, 리디렉션 불일치, 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.