curl --request POST 'https://api.voicecheap.ai/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
--data-urlencode 'code=mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' \
--data-urlencode 'redirect_uri=https://assistant.example.com/oauth/callback' \
--data-urlencode 'code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' \
--data-urlencode 'resource=https://api.voicecheap.ai/mcp'
const input = {
grant_type: 'authorization_code',
client_id: 'mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
code: 'mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC',
redirect_uri: 'https://assistant.example.com/oauth/callback',
code_verifier: 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk',
resource: 'https://api.voicecheap.ai/mcp',
};
const response = await fetch('https://api.voicecheap.ai/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams(input),
redirect: 'manual',
});
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"POST",
"https://api.voicecheap.ai/oauth/token",
headers={"Content-Type":"application/x-www-form-urlencoded"},
data={"grant_type": "authorization_code", "client_id": "mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "code": "mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", "redirect_uri": "https://assistant.example.com/oauth/callback", "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", "resource": "https://api.voicecheap.ai/mcp"},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
OAuth- und MCP-Protokoll
Einen Autorisierungscode eintauschen oder ein Refresh-Token rotieren
Rufen Sie kurzlebige MCP-Zugriffstokens mithilfe des S256-Autorisierungscodes eines öffentlichen Clients oder seines aktuellen Aktualisierungstokens ab.
POST
/
oauth
/
token
curl --request POST 'https://api.voicecheap.ai/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
--data-urlencode 'code=mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' \
--data-urlencode 'redirect_uri=https://assistant.example.com/oauth/callback' \
--data-urlencode 'code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' \
--data-urlencode 'resource=https://api.voicecheap.ai/mcp'
const input = {
grant_type: 'authorization_code',
client_id: 'mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
code: 'mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC',
redirect_uri: 'https://assistant.example.com/oauth/callback',
code_verifier: 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk',
resource: 'https://api.voicecheap.ai/mcp',
};
const response = await fetch('https://api.voicecheap.ai/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams(input),
redirect: 'manual',
});
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"POST",
"https://api.voicecheap.ai/oauth/token",
headers={"Content-Type":"application/x-www-form-urlencoded"},
data={"grant_type": "authorization_code", "client_id": "mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "code": "mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", "redirect_uri": "https://assistant.example.com/oauth/callback", "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", "resource": "https://api.voicecheap.ai/mcp"},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
Rufen Sie kurzlebige MCP-Zugriffstokens mithilfe des S256-Autorisierungscodes eines öffentlichen Clients oder seines aktuellen Aktualisierungstokens ab.
POST https://api.voicecheap.ai/oauth/token
Authentifizierung
Keine HTTP-Clientauthentifizierung. Senden Sie client_id im URL-kodierten Anfragetext. Jeder Authorization-Header sowie client_secret oder client_assertion werden abgelehnt.Anfragetext
Anzeigen grant_type: authorization_code
Anzeigen grant_type: authorization_code
string
erforderlich
Die von der dynamischen Registrierung zurückgegebene client_id oder die exakte öffentliche HTTPS-URL des Client-Metadatendokuments.Mindestlänge: 1. Höchstlänge: 2048. Muster:
^[^\u0000-\u001F\u007F]+$.string
erforderlich
Erforderliche exakte Ressourcen-Audience: Verwenden Sie den Wert resource aus den Metadaten der geschützten Ressource dieser Umgebung. In der Produktion ist dies https://api.voicecheap.ai/mcp. Ein anderer Origin, Pfad oder ein abschließender Schrägstrich wird abgelehnt.Format: “uri”.
field
erforderlich
Wert gemäß dem vollständigen Eingabeschema.Erforderlicher Wert: “authorization_code”.
string
erforderlich
Einmalcode, der an den exakt registrierten Callback zurückgegeben wird.Mindestlänge: 1. Höchstlänge: 256. Muster:
^mcp_code_[A-Za-z0-9_-]{43}$.string
erforderlich
Muss genau dem Callback entsprechen, der an diesen Code und diese Registrierung gebunden ist.Mindestlänge: 1. Höchstlänge: 2048. Muster:
^[^\u0000-\u001F\u007F]+$.string
erforderlich
Ursprünglicher PKCE-Verifier, mit dem die S256 code_challenge der Autorisierungsanfrage berechnet wurde.Mindestlänge: 43. Höchstlänge: 128. Muster:
^[A-Za-z0-9._~-]{43,128}$.Anzeigen grant_type: refresh_token
Anzeigen grant_type: refresh_token
string
erforderlich
Die von der dynamischen Registrierung zurückgegebene client_id oder die exakte öffentliche HTTPS-URL des Client-Metadatendokuments.Mindestlänge: 1. Höchstlänge: 2048. Muster:
^[^\u0000-\u001F\u007F]+$.string
erforderlich
Erforderliche exakte Ressourcen-Audience: Verwenden Sie den Wert resource aus den Metadaten der geschützten Ressource dieser Umgebung. In der Produktion ist dies https://api.voicecheap.ai/mcp. Ein anderer Origin, Pfad oder ein abschließender Schrägstrich wird abgelehnt.Format: “uri”.
field
erforderlich
Wert gemäß dem vollständigen Eingabeschema.Erforderlicher Wert: “refresh_token”.
string
erforderlich
Das aktuelle, noch nicht verbrauchte Refresh-Token eines für refresh_token registrierten Clients.Mindestlänge: 1. Höchstlänge: 256. Muster:
^mcp_refresh_[A-Za-z0-9_-]{43}$.string
Durch Leerzeichen getrennte Teilmenge der ursprünglichen Berechtigungen, optional einschließlich offline_access. Nicht unterstützte Namen, leere Werte und zusätzliche Berechtigungen werden abgelehnt; Duplikate werden entfernt. Ein expliziter scope behält nur die aufgeführten Produkt- und Identitätsberechtigungen bei und kann alle Produktberechtigungen entfernen. Ohne scope bleibt die aktuelle Autorisierung bestehen; ist OpenID Connect nicht verfügbar, werden jedoch Identitätsberechtigungen entfernt.Mindestlänge: 1. Höchstlänge: 2048. Muster:
^ *(?: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))* *$.Technisches Schema
Technisches Schema
{
"oneOf": [
{
"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."
},
"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"
]
},
"grant_type": {
"const": "authorization_code"
},
"code": {
"type": "string",
"minLength": 1,
"maxLength": 256,
"pattern": "^mcp_code_[A-Za-z0-9_-]{43}$",
"description": "Single-use code returned to the exact registered callback."
},
"redirect_uri": {
"type": "string",
"minLength": 1,
"maxLength": 2048,
"pattern": "^[^\\u0000-\\u001F\\u007F]+$",
"description": "Must exactly equal the callback bound to this code and registration."
},
"code_verifier": {
"type": "string",
"minLength": 43,
"maxLength": 128,
"pattern": "^[A-Za-z0-9._~-]{43,128}$",
"description": "Original PKCE verifier used to calculate the authorization request's S256 code_challenge."
}
},
"required": [
"grant_type",
"client_id",
"resource",
"code",
"redirect_uri",
"code_verifier"
],
"not": {
"anyOf": [
{
"required": [
"client_secret"
]
},
{
"required": [
"client_assertion"
]
}
]
},
"additionalProperties": true
},
{
"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."
},
"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"
]
},
"grant_type": {
"const": "refresh_token"
},
"refresh_token": {
"type": "string",
"minLength": 1,
"maxLength": 256,
"pattern": "^mcp_refresh_[A-Za-z0-9_-]{43}$",
"description": "The current unconsumed refresh token from a client registered for refresh_token."
},
"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 subset of the original permissions, optionally including offline_access. Unsupported names, empty values, and added permissions are rejected; duplicates are removed. An explicit scope keeps only the listed product and identity permissions and may remove every product permission. Omit scope to retain the current grant, except identity permissions are dropped if OpenID Connect is unavailable.",
"examples": [
"account:read projects:read offline_access"
]
}
},
"required": [
"grant_type",
"client_id",
"resource",
"refresh_token"
],
"not": {
"anyOf": [
{
"required": [
"client_secret"
]
},
{
"required": [
"client_assertion"
]
}
]
},
"additionalProperties": true
}
]
}
Anfragebeispiele
Beachten Sie die für diese Route dokumentierte Kodierung und Authentifizierung. Die Antwortstruktur und Idempotenzregeln der Aktions-API gelten nur für Aktionsaufrufe.curl --request POST 'https://api.voicecheap.ai/oauth/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA' \
--data-urlencode 'code=mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' \
--data-urlencode 'redirect_uri=https://assistant.example.com/oauth/callback' \
--data-urlencode 'code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' \
--data-urlencode 'resource=https://api.voicecheap.ai/mcp'
const input = {
grant_type: 'authorization_code',
client_id: 'mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
code: 'mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC',
redirect_uri: 'https://assistant.example.com/oauth/callback',
code_verifier: 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk',
resource: 'https://api.voicecheap.ai/mcp',
};
const response = await fetch('https://api.voicecheap.ai/oauth/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams(input),
redirect: 'manual',
});
console.log(response.status, await response.text());
import os
import requests
response = requests.request(
"POST",
"https://api.voicecheap.ai/oauth/token",
headers={"Content-Type":"application/x-www-form-urlencoded"},
data={"grant_type": "authorization_code", "client_id": "mcp_client_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA", "code": "mcp_code_CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC", "redirect_uri": "https://assistant.example.com/oauth/callback", "code_verifier": "dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk", "resource": "https://api.voicecheap.ai/mcp"},
timeout=120,
allow_redirects=False,
)
print(response.status_code, response.text)
Antwort
Ein opakes Bearer-Zugriffstoken, seine verbleibende Gültigkeitsdauer in Sekunden, die gewährten Berechtigungen und ein Refresh-Token, wenn der Client refresh_token registriert hat. expires_in beträgt höchstens 900 und kann kurz vor Ablauf der Autorisierung kleiner sein.HTTP 200
{
"access_token": "mcp_access_DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
"token_type": "Bearer",
"expires_in": 900,
"refresh_token": "mcp_refresh_EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
"scope": "account:read projects:read offline_access"
}
Antwortheader
{
"Cache-Control": "no-store",
"Pragma": "no-cache"
}
Hinweise zur Operation
- Erkannte skalare Parameter müssen genau einmal als nicht leere Zeichenfolgen ohne ASCII-Steuerzeichen oder DEL übergeben werden. Wiederholte Abfrage- oder Formularfelder werden als Arrays dekodiert und beim Lesen als Skalare abgelehnt.
- Verwenden Sie URL-codierte Formulardaten, beispielsweise curl —data-urlencode für jedes Feld. Ein JSON-Token-Body wird mit invalid_request abgelehnt.
- Die resource-Zielgruppe ist für beide Grant-Typen erforderlich und muss exakt mit der MCP-URL der Umgebung übereinstimmen, die den Code oder das Aktualisierungstoken ausgestellt hat.
- Der Austausch eines Autorisierungscodes erfordert die ursprüngliche client_id, die exakte redirect_uri und den passenden S256 code_verifier. Codes laufen nach 2 Minuten ab und sind nur einmal verwendbar.
- Der Token-Endpunkt lehnt jeden übergebenen Authorization-Header ab, einschließlich Basic und Bearer, sowie jedes client_secret- oder client_assertion-Feld im Anfragetext.
- Zugriffstoken sind höchstens 15 Minuten gültig. Wenn refresh_token registriert ist, laufen die Verbindung und die Refresh-Token-Familie 30 Tage nach der Zustimmung des Benutzers ab; eine Rotation verlängert diese Frist nicht.
- Ob refresh_token zurückgegeben wird, hängt von den registrierten Grant-Typen ab. Es hängt nicht davon ab, ob offline_access in der Autorisierungsanfrage enthalten ist. Der zurückgegebene scope ergänzt offline_access immer dann, wenn ein Refresh-Token zurückgegeben wird.
- Senden Sie zur Erneuerung grant_type=refresh_token mit client_id, dem aktuellen refresh_token, resource und optional einem eingeschränkten scope. Ersetzen Sie das gespeicherte Refresh-Token atomar durch den neuen Wert.
- Die Wiederverwendung eines verbrauchten Autorisierungscodes oder eines rotierten Refresh-Tokens widerruft die gesamte Verbindung einschließlich aller ihrer Zugriffstoken. Lösen Sie denselben Code oder dasselbe Refresh-Token nicht gleichzeitig mehrfach ein.
- Erneuerungsanfragen fügen niemals Berechtigungen hinzu. Bei einem expliziten scope bleiben nur die angeforderten Produkt- und Identitätsberechtigungen erhalten; offline_access bewahrt ausgelassene Produktberechtigungen nicht.
- Tokens sind an den gewährenden Nutzer, den Client, die Ressourcen-Audience, die aktuelle Teameigentümerschaft und den aktiven kostenpflichtigen Zugriff gebunden. Eine widerrufene Berechtigung oder geänderte Eigentümerschaft erfordert eine erneute Verbindung.
- Das öffentliche Token-Limit beträgt 60 Anfragen pro Minute und Client-IP und gilt gemeinsam für alle Worker. URL-codierte Bodys sind auf 32 KiB begrenzt.
- Bei OAuth-Fehlern werden error und error_description zurückgegeben. Fehler des Body-Parsers können bereits zuvor im Fehlerformat des Integrationsparsers zurückgegeben werden.
- openid und email sind Identitätsberechtigungen, getrennt von Produktberechtigungen, und werden nur akzeptiert, wenn sie angekündigt werden. email erfordert openid. Bei der ersten Autorisierung verwendet eine Anfrage nur mit Identitäts-Scopes die auf dem Zustimmungsbildschirm angezeigten Standard-Produktberechtigungen.
- Die von der dynamischen Registrierung zurückgegebene client_id oder die exakte öffentliche HTTPS-URL des Client-Metadatendokuments.
- Wenn openid gewährt wurde, gibt der Austausch des Autorisierungscodes zusätzlich ein mit RS256 signiertes id_token zurück. Prüfen Sie Signatur, Aussteller, Zielgruppe, Ablaufzeit und gegebenenfalls nonce. Gewährte Identitäts-Scopes erscheinen in scope der Tokenantwort; Erneuerungsantworten geben kein neues id_token aus.
- Wenn OpenID Connect nicht mehr verfügbar ist, behält eine Erneuerung ohne scope die Produktberechtigungen bei und entfernt Identitätsberechtigungen. Eine ausdrückliche Anfrage nicht verfügbarer Identitäts-Scopes gibt invalid_scope zurück.
- Wenn das Konto gelöscht oder deaktiviert wurde, gibt der Token-Endpunkt invalid_grant mit HTTP 400 zurück.
Fehler
| HTTP-Status | Code | Bedeutung oder Behebung |
|---|---|---|
| 400 | invalid_request | Der Anfragetext oder ein erkannter Parameter ist ungültig, fehlt, ist doppelt vorhanden oder hat die falsche Kodierung. |
| 400 | invalid_client | Die client_id ist unbekannt, es wurde eine HTTP-Clientauthentifizierung übergeben oder es wurde client_secret/client_assertion übergeben. |
| 400 | invalid_target | Die Ressourcen-Audience fehlt oder stimmt nicht genau mit der MCP-Ressource überein. |
| 400 | unsupported_grant_type | Der Grant wird nicht unterstützt, oder refresh_token wurde für diesen Client nicht registriert. |
| 400 | invalid_grant | Der Code oder das Token ist ungültig, abgelaufen, widerrufen, erneut verwendet, nicht passend oder für das aktuelle Konto/Team nicht mehr autorisiert. |
| 400 | invalid_scope | Eine Refresh-Anfrage versucht, Berechtigungen hinzuzufügen, oder enthält nicht unterstützte Berechtigungsbereiche. |
| 413 | REQUEST_TOO_LARGE | Die Anfrage überschreitet die zulässige Größe des Anfragetexts. JSON ist auf 1 MiB und URL-kodierte Formulare sind auf 32 KiB begrenzt. |
| 415 | UNSUPPORTED_CONTENT_TYPE | Der Body-Parser der Integration akzeptiert nur JSON oder URL-codierte Formulardaten. Die Route kann ausdrücklich eine dieser Codierungen erfordern. |
| 429 | temporarily_unavailable | Das öffentliche Anfrageratenlimit für OAuth wurde erreicht. Warten Sie vor einem erneuten Versuch das aktuelle Zeitfenster ab. |
| 500 | server_error | Die Autorisierung ist vorübergehend nicht verfügbar. Versuchen Sie es später erneut. |
War diese Seite hilfreich?

