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 e protocolo MCP
Iniciar a autorização de conta MCP
Crie uma requisição de autorização de curta duração e redirecione o usuário para a página de login e consentimento de permissões do 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)
Crie uma requisição de autorização de curta duração e redirecione o usuário para a página de login e consentimento de permissões do VoiceCheap.
GET https://api.voicecheap.ai/oauth/authorize
Autenticação
Nenhuma nesta rota. O fluxo de consentimento subsequente do navegador exige que o usuário faça login, e a aprovação exige acesso elegível a uma conta paga.Parâmetros de consulta
string
obrigatório
O client_id retornado pelo registro dinâmico ou a URL HTTPS pública exata do documento de metadados do cliente.Comprimento mínimo: 1. Comprimento máximo: 2048. Padrão:
^[^\u0000-\u001F\u007F]+$.string
obrigatório
Deve corresponder exatamente a um dos redirect_uris registrados deste cliente.Comprimento mínimo: 1. Comprimento máximo: 2048. Padrão:
^[^\u0000-\u001F\u007F]+$.field
obrigatório
Valor definido pelo esquema de entrada completo.Valor obrigatório: “code”.
field
Valor definido pelo esquema de entrada completo.Valor obrigatório: “query”. Valor padrão: “query”.
string
obrigatório
Resumo SHA-256 em Base64url do code_verifier original, sem preenchimento.Comprimento mínimo: 43. Comprimento máximo: 43. Padrão:
^[A-Za-z0-9_-]{43}$.field
obrigatório
Valor definido pelo esquema de entrada completo.Valor obrigatório: “S256”.
string
obrigatório
Público-alvo exato exigido para o recurso: use o valor resource dos metadados de recurso protegido deste ambiente. Em produção, é https://api.voicecheap.ai/mcp. Uma origem, caminho ou barra final diferente é rejeitada.Formato: “uri”.
string
Permissões de scopes_supported separadas por espaços, podendo incluir offline_access. Nomes não suportados e valores contendo apenas espaços em branco são rejeitados; duplicatas são removidas. Omitir scope ou não indicar permissões de produto, como apenas openid ou apenas offline_access, seleciona a interseção dos escopos de leitura padrão com os escopos de produto registrados para este cliente. email exige openid; email sozinho é rejeitado. As permissões de produto solicitadas devem estar registradas para este cliente. As permissões de identidade devem ser solicitadas explicitamente e aprovadas pelo usuário; omitir scope não solicita permissões de identidade.Comprimento mínimo: 1. Comprimento máximo: 2048. Padrão:
^ *(?: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 repetido no callback final. Use um novo valor imprevisível e verifique-o no cliente.Comprimento mínimo: 1. Comprimento máximo: 2048. Padrão:
^[^\u0000-\u001F\u007F]+$.string
Nonce opaco opcional retornado no token de identidade quando openid é concedido. Verifique-o no cliente.Comprimento mínimo: 1. Comprimento máximo: 2048. Padrão:
^[^\u0000-\u001F\u007F]+$.string
Valor de texto.Valor obrigatório: “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
}
Exemplos de requisição
Siga a codificação e a autenticação documentadas para esta rota. O formato de resposta e as regras de idempotência da API de ações se aplicam apenas às chamadas de ações.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)
Resposta
Redirecionamento HTTP para a página de consentimento do VoiceCheap. Não há corpo de resultado JSON. Location contém um valor request opaco; depois, o usuário faz login e escolhe as permissões.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
Cabeçalhos da resposta
{
"Cache-Control": "no-store",
"Pragma": "no-cache",
"Referrer-Policy": "no-referrer",
"Location": "https://app.voicecheap.ai/mcp/authorize?request=mcp_req_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
}
Notas da operação
- Parâmetros escalares reconhecidos devem ser fornecidos uma única vez como strings não vazias, sem caracteres de controle ASCII ou DEL. Campos de consulta/formulário repetidos são decodificados como arrays e rejeitados quando lidos como escalares.
- Aplique codificação de URL a cada valor de consulta. redirect_uri deve usar exatamente a grafia registrada para este cliente.
- Use apenas S256; PKCE plain e respostas implicit/token não são compatíveis. Mantenha o code_verifier original de 43–128 caracteres para a troca do token.
- O parâmetro resource é obrigatório e deve ser exatamente igual à URL do recurso MCP do ambiente selecionado.
- O conjunto padrão de escopos de produto é account:read usage:read projects:read transcription:read subtitles:read tts:read voices:read images:read thumbnails:read. Uma requisição que usa o padrão é restrita aos escopos registrados pelo cliente; se não restarem escopos de produto, a autorização falha.
- Um escopo composto apenas de offline_access usa a seleção padrão de escopos do produto. offline_access é removido antes de exibir ou conceder permissões do produto.
- As requisições de consentimento expiram após 10 minutos e podem ser respondidas uma vez. O usuário só pode aprovar um subconjunto não vazio das permissões de produto solicitadas.
- Após a aprovação, o callback do cliente recebe code, iss e o state original, quando fornecido. O código de autorização expira após 2 minutos e pode ser trocado uma vez.
- Após a recusa, o callback do cliente recebe error=access_denied, error_description, iss e o state original, quando fornecido; nenhum code é emitido.
- Metadados de cliente inválidos, divergências de redirecionamento, PKCE, escopos ou resource produzem erros OAuth JSON diretamente; eles não são redirecionados para um callback não validado.
- O limite público de autorização é de 30 requisições por minuto por IP de cliente, compartilhado entre os workers.
- openid e email são permissões de identidade, separadas das permissões do produto, aceitas apenas quando anunciadas. email exige openid. Na autorização inicial, uma solicitação apenas com escopos de identidade usa as permissões padrão do produto mostradas na tela de consentimento.
- O client_id retornado pelo registro dinâmico ou a URL HTTPS pública exata do documento de metadados do cliente.
- OpenID Connect aceita prompt=consent. Outros valores de prompt e max_age são rejeitados; autorização silenciosa e novo login forçado não são suportados.
Erros
| Status HTTP | Código | Significado ou recuperação |
|---|---|---|
| 400 | invalid_request | O corpo ou um parâmetro reconhecido é inválido, está ausente, está duplicado ou tem a codificação errada. |
| 400 | invalid_client | O client_id é desconhecido ou seu documento de metadados não pode ser obtido ou validado. |
| 400 | unsupported_response_type | response_type não é code. |
| 400 | invalid_target | resource está ausente ou não é exatamente a URL MCP do ambiente. |
| 400 | invalid_scope | Um escopo de produto solicitado não é compatível, não está registrado ou não deixa nenhuma permissão utilizável. |
| 429 | temporarily_unavailable | O limite de requisições OAuth públicas foi atingido. Aguarde a janela atual antes de tentar novamente. |
| 500 | server_error | A autorização está temporariamente indisponível. Tente novamente mais tarde. |
| 503 | temporarily_unavailable | Os metadados do cliente estão temporariamente indisponíveis. Tente novamente mais tarde. |
Esta página foi útil?

