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'
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());
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)
OAuth y protocolo MCP
Iniciar la autorización de cuenta MCP
Crea una solicitud de autorización de corta duración y redirige al usuario a la página de inicio de sesión y consentimiento de permisos de VoiceCheap.
GET
/
oauth
/
authorize
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'
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());
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)
Crea una solicitud de autorización de corta duración y redirige al usuario a la página de inicio de sesión y consentimiento de permisos de VoiceCheap.
GET https://api.voicecheap.ai/oauth/authorize
Autenticación
Ninguna en esta ruta. El flujo de consentimiento posterior del navegador requiere que el usuario inicie sesión, y la aprobación requiere acceso a una cuenta de pago apta.Parámetros de consulta
string
requerido
El client_id devuelto por el registro dinámico o la URL HTTPS pública exacta del documento de metadatos del cliente.Longitud mínima: 1. Longitud máxima: 2048. Patrón:
^[^\u0000-\u001F\u007F]+$.string
requerido
Debe coincidir exactamente con una de las redirect_uris registradas de este cliente.Longitud mínima: 1. Longitud máxima: 2048. Patrón:
^[^\u0000-\u001F\u007F]+$.field
requerido
Valor definido por el esquema completo de entrada.Valor obligatorio: “code”.
field
Valor definido por el esquema completo de entrada.Valor obligatorio: “query”. Valor predeterminado: “query”.
string
requerido
Resumen SHA-256 en Base64url del code_verifier original, sin relleno.Longitud mínima: 43. Longitud máxima: 43. Patrón:
^[A-Za-z0-9_-]{43}$.field
requerido
Valor definido por el esquema completo de entrada.Valor obligatorio: “S256”.
string
requerido
Audiencia exacta del recurso requerida: usa el valor resource de los metadatos del recurso protegido de este entorno. En producción es https://api.voicecheap.ai/mcp. Se rechaza un origen, una ruta o una barra final diferente.Formato: “uri”.
string
Permisos de scopes_supported separados por espacios, que pueden incluir offline_access. Se rechazan los nombres no admitidos y los valores que solo contienen espacios en blanco; se eliminan los duplicados. Si se omite scope o no se indican permisos de producto, por ejemplo solo openid o solo offline_access, se selecciona la intersección de los ámbitos de lectura predeterminados y los ámbitos de producto registrados para este cliente. email requiere openid; email solo se rechaza. Los permisos de producto solicitados deben estar registrados para este cliente. Los permisos de identidad deben solicitarse explícitamente y ser aprobados por el usuario; omitir scope no solicita permisos de identidad.Longitud mínima: 1. Longitud máxima: 2048. Patrón:
^ *(?: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))* *$.string
Valor opaco opcional que se devuelve en el callback final. Usa un valor nuevo e impredecible y verifícalo en el cliente.Longitud mínima: 1. Longitud máxima: 2048. Patrón:
^[^\u0000-\u001F\u007F]+$.string
Nonce opaco opcional que se devuelve en el ID token cuando se concede openid. Verifícalo en el cliente.Longitud mínima: 1. Longitud máxima: 2048. Patrón:
^[^\u0000-\u001F\u007F]+$.string
Valor de texto.Valor obligatorio: “consent”.
Esquema técnico
Esquema técnico
{
"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
}
Ejemplos de solicitud
Sigue la codificación y la autenticación documentadas para esta ruta. El formato envolvente y las reglas de idempotencia de la API de acciones solo se aplican a las invocaciones de acciones.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'
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());
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)
Respuesta
Redirección HTTP a la página de consentimiento de VoiceCheap. No hay cuerpo de resultado JSON. Location contiene un valor request opaco; después, el usuario inicia sesión y elige los permisos.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
Cabeceras de respuesta
{
"Cache-Control": "no-store",
"Pragma": "no-cache",
"Referrer-Policy": "no-referrer",
"Location": "https://app.voicecheap.ai/mcp/authorize?request=mcp_req_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
}
Notas de la operación
- Los parámetros escalares reconocidos deben proporcionarse una sola vez como cadenas no vacías, sin caracteres de control ASCII ni DEL. Los campos repetidos de consulta o formulario se decodifican como arrays y se rechazan al leerse como escalares.
- Codifica cada valor de consulta para URL. redirect_uri debe usar exactamente la forma registrada para este cliente.
- Usa solo S256; no se admiten PKCE plain ni respuestas implicit/token. Conserva el code_verifier original de 43–128 caracteres para el canje del token.
- El parámetro resource es obligatorio y debe coincidir exactamente con la URL del recurso MCP del entorno seleccionado.
- El conjunto predeterminado de ámbitos de producto es account:read usage:read projects:read transcription:read subtitles:read tts:read voices:read images:read thumbnails:read. Una solicitud con valores predeterminados se limita a los ámbitos registrados por el cliente; si no queda ningún ámbito de producto, la autorización falla.
- Un ámbito que solo contiene offline_access usa la selección predeterminada de ámbitos del producto. offline_access se elimina antes de mostrar o conceder permisos del producto.
- Las solicitudes de consentimiento caducan tras 10 minutos y solo pueden responderse una vez. El usuario solo puede aprobar un subconjunto no vacío de los permisos de producto solicitados.
- Tras la aprobación, el callback del cliente recibe code, iss y el state original cuando se haya proporcionado. El código de autorización caduca a los 2 minutos y puede canjearse una vez.
- Tras la denegación, la URL de retorno del cliente recibe error=access_denied, error_description, iss y el state original, si se proporcionó; no se emite ningún code.
- Los metadatos del cliente no válidos, las discrepancias de redirección, PKCE, scopes o resource generan directamente errores JSON de OAuth; no se redirigen a un callback sin validar.
- El límite público de autorización es de 30 solicitudes por minuto por IP de cliente, compartido entre los procesos de trabajo.
- openid y email son permisos de identidad, distintos de los permisos del producto, y solo se aceptan cuando se anuncian. email requiere openid. Durante la autorización inicial, una solicitud que solo contiene permisos de identidad usa los permisos predeterminados del producto mostrados en la pantalla de consentimiento.
- El client_id devuelto por el registro dinámico o la URL HTTPS pública exacta del documento de metadatos del cliente.
- OpenID Connect admite prompt=consent. Se rechazan otros valores de prompt y max_age; no se admite autorización silenciosa ni forzar un nuevo inicio de sesión.
Errores
| Estado HTTP | Código | Significado o solución |
|---|---|---|
| 400 | invalid_request | El cuerpo o un parámetro reconocido no es válido, falta, está duplicado o tiene una codificación incorrecta. |
| 400 | invalid_client | El client_id es desconocido o su documento de metadatos no se puede recuperar o validar. |
| 400 | unsupported_response_type | response_type no es code. |
| 400 | invalid_target | Falta resource o no es exactamente la URL MCP del entorno. |
| 400 | invalid_scope | Un ámbito de producto solicitado no es compatible, no está registrado o no deja ningún permiso utilizable. |
| 429 | temporarily_unavailable | Se ha alcanzado el límite público de frecuencia de solicitudes OAuth. Espera a que termine la ventana actual antes de reintentarlo. |
| 500 | server_error | La autorización no está disponible temporalmente. Vuelve a intentarlo más tarde. |
| 503 | temporarily_unavailable | Los metadatos del cliente no están disponibles temporalmente. Vuelve a intentarlo más tarde. |
¿Esta página le ayudó?

