> ## 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.

# Échanger un code d’autorisation ou renouveler un jeton d’actualisation

> Obtenez des jetons d’accès MCP de courte durée à l’aide du code d’autorisation S256 d’un client public ou de son jeton d’actualisation actuel.

Obtenez des jetons d’accès MCP de courte durée à l’aide du code d’autorisation S256 d’un client public ou de son jeton d’actualisation actuel.

```http theme={null}
POST https://api.voicecheap.ai/oauth/token
```

## Authentification

Aucune authentification du client HTTP. Envoyez client\_id dans le corps encodé en URL. Tout en-tête Authorization et tout champ client\_secret ou client\_assertion sont rejetés.

## Corps de la requête

<Expandable title="grant_type: authorization_code">
  <ParamField body="client_id" type="string" required>
    Le client\_id renvoyé par l’enregistrement dynamique ou l’URL HTTPS publique exacte du document de métadonnées du client.

    Longueur minimale: 1. Longueur maximale: 2048. Motif: `^[^\u0000-\u001F\u007F]+$`.
  </ParamField>

  <ParamField body="resource" type="string" required>
    Audience de ressource exacte requise : utilisez la valeur resource des métadonnées de la ressource protégée de cet environnement. En production, il s’agit de [https://api.voicecheap.ai/mcp](https://api.voicecheap.ai/mcp). Une origine, un chemin ou une barre oblique finale différents sont refusés.

    Format: "uri".
  </ParamField>

  <ParamField body="grant_type" type="field" required>
    Valeur définie par le schéma d’entrée complet.

    Valeur requise: "authorization\_code".
  </ParamField>

  <ParamField body="code" type="string" required>
    Code à usage unique renvoyé à l’URL de rappel exacte enregistrée.

    Longueur minimale: 1. Longueur maximale: 256. Motif: `^mcp_code_[A-Za-z0-9_-]{43}$`.
  </ParamField>

  <ParamField body="redirect_uri" type="string" required>
    Doit correspondre exactement à l’URL de rappel liée à ce code et à cet enregistrement.

    Longueur minimale: 1. Longueur maximale: 2048. Motif: `^[^\u0000-\u001F\u007F]+$`.
  </ParamField>

  <ParamField body="code_verifier" type="string" required>
    Vérificateur PKCE d’origine utilisé pour calculer le champ S256 code\_challenge de la requête d’autorisation.

    Longueur minimale: 43. Longueur maximale: 128. Motif: `^[A-Za-z0-9._~-]{43,128}$`.
  </ParamField>
</Expandable>

<Expandable title="grant_type: refresh_token">
  <ParamField body="client_id" type="string" required>
    Le client\_id renvoyé par l’enregistrement dynamique ou l’URL HTTPS publique exacte du document de métadonnées du client.

    Longueur minimale: 1. Longueur maximale: 2048. Motif: `^[^\u0000-\u001F\u007F]+$`.
  </ParamField>

  <ParamField body="resource" type="string" required>
    Audience de ressource exacte requise : utilisez la valeur resource des métadonnées de la ressource protégée de cet environnement. En production, il s’agit de [https://api.voicecheap.ai/mcp](https://api.voicecheap.ai/mcp). Une origine, un chemin ou une barre oblique finale différents sont refusés.

    Format: "uri".
  </ParamField>

  <ParamField body="grant_type" type="field" required>
    Valeur définie par le schéma d’entrée complet.

    Valeur requise: "refresh\_token".
  </ParamField>

  <ParamField body="refresh_token" type="string" required>
    Le jeton d’actualisation actuel, encore inutilisé, d’un client enregistré pour refresh\_token.

    Longueur minimale: 1. Longueur maximale: 256. Motif: `^mcp_refresh_[A-Za-z0-9_-]{43}$`.
  </ParamField>

  <ParamField body="scope" type="string">
    Sous-ensemble des permissions d’origine séparées par des espaces, pouvant inclure offline\_access. Les noms non pris en charge, valeurs vides et permissions supplémentaires sont refusés ; les doublons sont supprimés. Un scope explicite conserve uniquement les permissions produit et d’identité indiquées et peut retirer toutes les permissions produit. Omettez scope pour conserver l’autorisation actuelle, sauf les permissions d’identité, qui sont retirées si OpenID Connect est indisponible.

    Longueur minimale: 1. Longueur maximale: 2048. Motif: `^ *(?: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>
</Expandable>

<Accordion title="Schéma technique">
  ```json theme={null}
  {
    "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
      }
    ]
  }
  ```
</Accordion>

## Exemples de requêtes

Suivez l’encodage et l’authentification documentés pour cette route. L’enveloppe et les règles d’idempotence de l’API d’actions s’appliquent uniquement aux invocations d’actions.

<RequestExample>
  ```bash cURL theme={null}
  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'
  ```

  ```javascript JavaScript theme={null}
  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());
  ```

  ```python Python theme={null}
  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)
  ```
</RequestExample>

## Réponse

Un jeton d’accès Bearer opaque, sa durée de validité restante en secondes, les autorisations accordées et un jeton d’actualisation si le client a enregistré refresh\_token. expires\_in vaut au maximum 900 et peut être inférieur à l’approche de l’expiration de l’autorisation.

```json HTTP 200 theme={null}
{
  "access_token": "mcp_access_DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
  "token_type": "Bearer",
  "expires_in": 900,
  "refresh_token": "mcp_refresh_EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE",
  "scope": "account:read projects:read offline_access"
}
```

## En-têtes de réponse

```json theme={null}
{
  "Cache-Control": "no-store",
  "Pragma": "no-cache"
}
```

## Notes de l’opération

* Les paramètres scalaires reconnus doivent être fournis une seule fois, sous forme de chaînes non vides sans caractères de contrôle ASCII ni DEL. Les champs de requête ou de formulaire répétés sont décodés en tableaux et rejetés lorsqu’ils sont lus comme des scalaires.
* Utilisez des données de formulaire encodées en URL, par exemple curl --data-urlencode pour chaque champ. Un corps de jeton en JSON est rejeté avec invalid\_request.
* L’audience resource est obligatoire pour les deux types d’autorisation et doit correspondre exactement à l’URL MCP de l’environnement ayant émis le code ou le jeton d’actualisation.
* L’échange du code d’autorisation nécessite le client\_id d’origine, le redirect\_uri exact et le code\_verifier S256 correspondant. Les codes expirent après 2 minutes et sont à usage unique.
* Le point de terminaison des jetons rejette tout en-tête Authorization fourni, y compris Basic et Bearer, ainsi que tout champ client\_secret ou client\_assertion dans le corps.
* Les jetons d’accès restent valides au maximum 15 minutes. Lorsque refresh\_token est enregistré, la connexion et la famille de jetons d’actualisation expirent 30 jours après l’approbation de l’utilisateur ; le renouvellement ne prolonge pas cette échéance.
* Le renvoi de refresh\_token dépend des types d’octroi enregistrés. Il ne dépend pas de l’inclusion de offline\_access dans la requête d’autorisation. Le champ scope renvoyé inclut offline\_access chaque fois qu’un jeton d’actualisation est renvoyé.
* Pour renouveler, envoyez grant\_type=refresh\_token avec client\_id, le refresh\_token actuel, resource et, facultativement, un scope restreint. Remplacez de façon atomique le jeton d’actualisation stocké par la nouvelle valeur.
* Réutiliser un code d’autorisation déjà consommé ou un jeton d’actualisation remplacé révoque toute la connexion, y compris tous ses jetons d’accès. N’échangez pas simultanément le même code ou jeton d’actualisation.
* Le renouvellement n’ajoute jamais de permissions. Avec un scope explicite, seules les permissions produit et d’identité demandées sont conservées ; offline\_access ne conserve pas les permissions produit omises.
* Les jetons sont liés à l’utilisateur qui les a autorisés, au client, à l’audience de la ressource, au propriétaire actuel de l’équipe et à l’accès payant actif. Une autorisation révoquée ou un changement de propriétaire impose une reconnexion.
* La limite publique des jetons est de 60 requêtes par minute et par adresse IP client, partagée entre les workers. Les corps encodés en URL sont limités à 32 KiB.
* Les échecs OAuth renvoient error et error\_description. Les échecs d’analyse du corps peuvent être renvoyés plus tôt au format d’erreur de l’analyseur d’intégration.
* openid et email sont des permissions d’identité, distinctes des permissions produit, acceptées uniquement lorsqu’elles sont annoncées. email nécessite openid. Lors de l’autorisation initiale, une demande contenant seulement des permissions d’identité utilise les permissions produit par défaut affichées sur l’écran de consentement.
* Le client\_id renvoyé par l’enregistrement dynamique ou l’URL HTTPS publique exacte du document de métadonnées du client.
* Quand openid est accordé, l’échange du code d’autorisation renvoie aussi un id\_token signé avec RS256. Vérifiez sa signature, son émetteur, son audience, son expiration et le nonce s’il a été fourni. Les permissions d’identité accordées figurent dans scope de la réponse ; le renouvellement n’émet pas de nouvel id\_token.
* Si OpenID Connect devient indisponible, un renouvellement sans scope conserve les permissions produit et retire celles d’identité. Demander explicitement des permissions d’identité indisponibles renvoie invalid\_scope.
* Si le compte a été supprimé ou désactivé, l’endpoint de tokens renvoie invalid\_grant avec HTTP 400.

## Erreurs

| Statut HTTP | Code | Signification ou solution |
| - | - | - |
| 400 | `invalid_request` | Le corps ou un paramètre reconnu est invalide, manquant, en double ou mal encodé. |
| 400 | `invalid_client` | Le client\_id est inconnu, une authentification HTTP du client a été fournie, ou un client\_secret/client\_assertion a été fourni. |
| 400 | `invalid_target` | L’audience de la ressource est absente ou ne correspond pas exactement à la ressource MCP. |
| 400 | `unsupported_grant_type` | Le type d’octroi n’est pas pris en charge, ou refresh\_token n’a pas été enregistré pour ce client. |
| 400 | `invalid_grant` | Le code ou le jeton est invalide, expiré, révoqué, réutilisé, incohérent ou n’est plus autorisé pour le compte ou l’équipe actuels. |
| 400 | `invalid_scope` | Une requête d’actualisation tente d’ajouter des autorisations ou contient des portées non prises en charge. |
| 413 | `REQUEST_TOO_LARGE` | La requête dépasse la taille de corps autorisée. Le JSON est limité à 1 MiB et les formulaires encodés en URL à 32 KiB. |
| 415 | `UNSUPPORTED_CONTENT_TYPE` | L’analyseur de corps de l’intégration accepte uniquement le JSON ou les formulaires encodés en URL. La route peut exiger spécifiquement l’un de ces encodages. |
| 429 | `temporarily_unavailable` | La limite de fréquence des requêtes OAuth publiques a été atteinte. Attendez la fin de la fenêtre en cours avant de réessayer. |
| 500 | `server_error` | L’autorisation est temporairement indisponible. Réessayez plus tard. |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.