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

# Trocar um código de autorização ou rotacionar um refresh token

> Obtenha tokens de acesso MCP de curta duração usando o código de autorização S256 de um cliente público ou seu token de atualização atual.

Obtenha tokens de acesso MCP de curta duração usando o código de autorização S256 de um cliente público ou seu token de atualização atual.

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

## Autenticação

Sem autenticação HTTP do cliente. Envie client\_id no corpo codificado em URL. Qualquer cabeçalho Authorization, client\_secret ou client\_assertion é rejeitado.

## Corpo da requisição

<Expandable title="grant_type: authorization_code">
  <ParamField body="client_id" type="string" required>
    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]+$`.
  </ParamField>

  <ParamField body="resource" type="string" required>
    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](https://api.voicecheap.ai/mcp). Uma origem, caminho ou barra final diferente é rejeitada.

    Formato: "uri".
  </ParamField>

  <ParamField body="grant_type" type="field" required>
    Valor definido pelo esquema de entrada completo.

    Valor obrigatório: "authorization\_code".
  </ParamField>

  <ParamField body="code" type="string" required>
    Código de uso único retornado ao callback exato registrado.

    Comprimento mínimo: 1. Comprimento máximo: 256. Padrão: `^mcp_code_[A-Za-z0-9_-]{43}$`.
  </ParamField>

  <ParamField body="redirect_uri" type="string" required>
    Deve corresponder exatamente ao callback vinculado a este código e registro.

    Comprimento mínimo: 1. Comprimento máximo: 2048. Padrão: `^[^\u0000-\u001F\u007F]+$`.
  </ParamField>

  <ParamField body="code_verifier" type="string" required>
    Verificador PKCE original usado para calcular o code\_challenge S256 da requisição de autorização.

    Comprimento mínimo: 43. Comprimento máximo: 128. Padrão: `^[A-Za-z0-9._~-]{43,128}$`.
  </ParamField>
</Expandable>

<Expandable title="grant_type: refresh_token">
  <ParamField body="client_id" type="string" required>
    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]+$`.
  </ParamField>

  <ParamField body="resource" type="string" required>
    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](https://api.voicecheap.ai/mcp). Uma origem, caminho ou barra final diferente é rejeitada.

    Formato: "uri".
  </ParamField>

  <ParamField body="grant_type" type="field" required>
    Valor definido pelo esquema de entrada completo.

    Valor obrigatório: "refresh\_token".
  </ParamField>

  <ParamField body="refresh_token" type="string" required>
    O refresh token atual ainda não consumido de um cliente registrado para refresh\_token.

    Comprimento mínimo: 1. Comprimento máximo: 256. Padrão: `^mcp_refresh_[A-Za-z0-9_-]{43}$`.
  </ParamField>

  <ParamField body="scope" type="string">
    Subconjunto das permissões originais separado por espaços, que pode incluir offline\_access. Nomes não suportados, valores vazios e permissões adicionadas são rejeitados; duplicatas são removidas. Um scope explícito mantém apenas as permissões de produto e identidade listadas e pode remover todas as permissões de produto. Omita scope para manter a autorização atual, exceto as permissões de identidade, que são removidas se OpenID Connect estiver indisponível.

    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))* *$`.
  </ParamField>
</Expandable>

<Accordion title="Esquema técnico">
  ```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>

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

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

## Resposta

Um token de acesso Bearer opaco, seu tempo de vida restante em segundos, os escopos concedidos e um refresh token quando o cliente registrou refresh\_token. expires\_in é de no máximo 900 e pode ser menor perto da expiração da concessão.

```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"
}
```

## Cabeçalhos da resposta

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

## 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.
* Use dados de formulário codificados em URL, como curl --data-urlencode por campo. Um corpo de token JSON é rejeitado com invalid\_request.
* O público-alvo resource é obrigatório para ambos os tipos de concessão e deve corresponder exatamente à URL MCP do ambiente que emitiu o código ou token de atualização.
* A troca do código de autorização exige o client\_id original, o redirect\_uri exato e um code\_verifier S256 correspondente. Os códigos expiram após 2 minutos e são de uso único.
* O endpoint de token rejeita qualquer cabeçalho Authorization fornecido, incluindo Basic e Bearer, além de qualquer campo client\_secret ou client\_assertion no corpo.
* Tokens de acesso duram no máximo 15 minutos. Com refresh\_token registrado, a conexão e a família de refresh tokens expiram 30 dias após a aprovação do usuário; a rotação não estende esse prazo.
* O retorno de refresh\_token depende dos tipos de concessão registrados. Não depende da inclusão de offline\_access na requisição de autorização. O scope retornado acrescenta offline\_access sempre que um token de atualização é retornado.
* Para renovar, envie grant\_type=refresh\_token com client\_id, o refresh\_token atual, resource e, opcionalmente, um scope mais restrito. Substitua atomicamente o refresh token armazenado pelo novo valor.
* Reutilizar um código de autorização consumido ou um token de atualização rotacionado revoga toda a conexão, incluindo todos os seus tokens de acesso. Não troque o mesmo código ou token de atualização simultaneamente.
* Solicitações de renovação nunca adicionam permissões. Com um scope explícito, apenas as permissões de produto e identidade solicitadas são mantidas; offline\_access não preserva permissões de produto omitidas.
* Os tokens são vinculados ao usuário que concedeu acesso, ao cliente, ao público-alvo do recurso, à propriedade atual da equipe e ao acesso pago ativo. Uma concessão revogada ou uma mudança de propriedade requer reconexão.
* O limite público de tokens é de 60 requisições por minuto por IP de cliente, compartilhado entre workers. Corpos codificados em URL são limitados a 32 KiB.
* Falhas OAuth retornam error e error\_description. Falhas no Body-parser podem ser retornadas antes no formato de erro do parser de integração.
* 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.
* Quando openid é concedido, a troca do código de autorização também retorna um id\_token assinado com RS256. Valide assinatura, emissor, público, expiração e nonce, se fornecido. Os escopos de identidade concedidos aparecem em scope da resposta; a renovação não emite um novo id\_token.
* Se OpenID Connect ficar indisponível, renovar sem scope mantém as permissões de produto e remove as de identidade. Solicitar explicitamente escopos de identidade indisponíveis retorna invalid\_scope.
* Se a conta tiver sido excluída ou desativada, o endpoint de tokens retorna invalid\_grant com HTTP 400.

## 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, a autenticação HTTP do cliente foi fornecida ou um client\_secret/client\_assertion foi fornecido. |
| 400 | `invalid_target` | O público-alvo do recurso está ausente ou não corresponde exatamente ao recurso MCP. |
| 400 | `unsupported_grant_type` | A concessão não é compatível, ou refresh\_token não foi registrado para este cliente. |
| 400 | `invalid_grant` | O código ou token é inválido, expirou, foi revogado, repetido, não corresponde ou não está mais autorizado para a conta/equipe atual. |
| 400 | `invalid_scope` | Uma requisição de atualização tenta adicionar permissões ou contém escopos não compatíveis. |
| 413 | `REQUEST_TOO_LARGE` | A requisição excede o tamanho permitido do corpo. JSON é limitado a 1 MiB e formulários codificados em URL a 32 KiB. |
| 415 | `UNSUPPORTED_CONTENT_TYPE` | O parser de corpo da integração aceita apenas JSON ou formulários codificados em URL. A rota pode exigir especificamente uma dessas codificações. |
| 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. |


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