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 protocollo MCP
Avvia l'autorizzazione dell'account MCP
Crea una richiesta di autorizzazione di breve durata e reindirizza l’utente alla pagina VoiceCheap di accesso e consenso alle autorizzazioni.
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 richiesta di autorizzazione di breve durata e reindirizza l’utente alla pagina VoiceCheap di accesso e consenso alle autorizzazioni.
GET https://api.voicecheap.ai/oauth/authorize
Autenticazione
Nessuna su questa rotta. Il successivo flusso di consenso nel browser richiede che l’utente effettui l’accesso e l’approvazione richiede l’accesso a un account a pagamento idoneo.Parametri di query
string
obbligatorio
Il client_id restituito dalla registrazione dinamica o l’URL HTTPS pubblico esatto del documento di metadati del client.Lunghezza minima: 1. Lunghezza massima: 2048. Pattern:
^[^\u0000-\u001F\u007F]+$.string
obbligatorio
Deve corrispondere esattamente a uno dei redirect_uris registrati per questo client.Lunghezza minima: 1. Lunghezza massima: 2048. Pattern:
^[^\u0000-\u001F\u007F]+$.field
obbligatorio
Valore definito dallo schema di input completo.Valore obbligatorio: “code”.
field
Valore definito dallo schema di input completo.Valore obbligatorio: “query”. Valore predefinito: “query”.
string
obbligatorio
Digest SHA-256 in Base64url del code_verifier originale, senza padding.Lunghezza minima: 43. Lunghezza massima: 43. Pattern:
^[A-Za-z0-9_-]{43}$.field
obbligatorio
Valore definito dallo schema di input completo.Valore obbligatorio: “S256”.
string
obbligatorio
Audience esatta della risorsa richiesta: usa il valore resource dei metadati della risorsa protetta di questo ambiente. In produzione è https://api.voicecheap.ai/mcp. Un’origine, un percorso o una barra finale differenti vengono rifiutati.Formato: “uri”.
string
Autorizzazioni di scopes_supported separate da spazi, che possono includere offline_access. I nomi non supportati e i valori composti solo da spazi vengono rifiutati; i duplicati vengono rimossi. Omettere scope o non indicare autorizzazioni di prodotto, ad esempio solo openid o solo offline_access, seleziona l’intersezione tra gli scope di lettura predefiniti e gli scope di prodotto registrati per questo client. email richiede openid; email da solo viene rifiutato. Le autorizzazioni di prodotto richieste devono essere registrate per questo client. Le autorizzazioni di identità devono essere richieste esplicitamente e approvate dall’utente; omettere scope non richiede autorizzazioni di identità.Lunghezza minima: 1. Lunghezza massima: 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))* *$.string
Valore opaco facoltativo restituito nel callback finale. Usa un nuovo valore imprevedibile e verificalo nel client.Lunghezza minima: 1. Lunghezza massima: 2048. Pattern:
^[^\u0000-\u001F\u007F]+$.string
Nonce opaco facoltativo ripetuto nell’ID token quando openid è concesso. Verificalo nel client.Lunghezza minima: 1. Lunghezza massima: 2048. Pattern:
^[^\u0000-\u001F\u007F]+$.string
Valore testuale.Valore obbligatorio: “consent”.
Schema tecnico
Schema tecnico
{
"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
}
Esempi di richiesta
Segui la codifica e l’autenticazione documentate per questa route. L’involucro e le regole di idempotenza dell’API delle azioni si applicano solo alle invocazioni di azioni.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)
Risposta
Reindirizzamento HTTP alla pagina di consenso di VoiceCheap. Non è presente un corpo del risultato JSON. Location contiene un valore request opaco; l’utente quindi accede e sceglie le autorizzazioni.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
Intestazioni della risposta
{
"Cache-Control": "no-store",
"Pragma": "no-cache",
"Referrer-Policy": "no-referrer",
"Location": "https://app.voicecheap.ai/mcp/authorize?request=mcp_req_BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
}
Note sull’operazione
- I parametri scalari riconosciuti devono essere forniti una sola volta come stringhe non vuote, senza caratteri di controllo ASCII o DEL. I campi ripetuti nella query o nel modulo vengono decodificati come array e rifiutati quando vengono letti come scalari.
- Applica la codifica URL a ogni valore della query. redirect_uri deve usare esattamente la grafia registrata per questo client.
- Usa solo S256; PKCE plain e le risposte implicit/token non sono supportati. Conserva il code_verifier originale di 43–128 caratteri per lo scambio del token.
- Il parametro resource è obbligatorio e deve corrispondere esattamente all’URL della risorsa MCP dell’ambiente selezionato.
- L’insieme predefinito degli ambiti del prodotto è account:read usage:read projects:read transcription:read subtitles:read tts:read voices:read images:read thumbnails:read. Una richiesta con valori predefiniti viene limitata agli ambiti registrati dal client; se non rimangono ambiti del prodotto, l’autorizzazione fallisce.
- Uno scope composto soltanto da offline_access usa la selezione predefinita degli scope del prodotto. offline_access viene rimosso prima di mostrare o concedere le autorizzazioni del prodotto.
- Le richieste di consenso scadono dopo 10 minuti ed è possibile rispondere una sola volta. L’utente può approvare solo un sottoinsieme non vuoto delle autorizzazioni del prodotto richieste.
- Dopo l’approvazione, il callback del client riceve code, iss e lo state originale, se fornito. Il codice di autorizzazione scade dopo 2 minuti e può essere scambiato una sola volta.
- Dopo il rifiuto, il callback del client riceve error=access_denied, error_description, iss e il valore state originale, se fornito; non viene emesso alcun codice.
- Metadati del client non validi, mancate corrispondenze di reindirizzamento, PKCE, scope o resource producono direttamente errori OAuth in JSON; non vengono reindirizzati a un callback non convalidato.
- Il limite pubblico di autorizzazione è di 30 richieste al minuto per IP del client, condiviso tra i worker.
- openid ed email sono autorizzazioni di identità, separate da quelle del prodotto, accettate solo se dichiarate. email richiede openid. Durante l’autorizzazione iniziale, una richiesta con soli ambiti di identità usa le autorizzazioni di prodotto predefinite mostrate nella schermata di consenso.
- Il client_id restituito dalla registrazione dinamica o l’URL HTTPS pubblico esatto del documento di metadati del client.
- Per OpenID Connect è supportato prompt=consent. Gli altri valori di prompt e max_age vengono rifiutati; l’autorizzazione silenziosa e l’accesso recente forzato non sono supportati.
Errori
| Stato HTTP | Codice | Significato o risoluzione |
|---|---|---|
| 400 | invalid_request | Il corpo o un parametro riconosciuto non è valido, è mancante, è duplicato oppure ha una codifica errata. |
| 400 | invalid_client | Il client_id è sconosciuto oppure il documento di metadati non può essere recuperato o convalidato. |
| 400 | unsupported_response_type | response_type non è code. |
| 400 | invalid_target | resource è assente oppure non corrisponde esattamente all’URL MCP dell’ambiente. |
| 400 | invalid_scope | Uno scope del prodotto richiesto non è supportato, non è registrato oppure non lascia alcuna autorizzazione utilizzabile. |
| 429 | temporarily_unavailable | È stato raggiunto il limite di frequenza delle richieste OAuth pubbliche. Attendi il termine della finestra corrente prima di riprovare. |
| 500 | server_error | L’autorizzazione è temporaneamente non disponibile. Riprova più tardi. |
| 503 | temporarily_unavailable | I metadati del client sono temporaneamente indisponibili. Riprova più tardi. |
Questa pagina è stata utile?

