> ## Documentation Index
> Fetch the complete documentation index at: https://docs.join.tl/llms.txt
> Use this file to discover all available pages before exploring further.

# Exchange or refresh an OAuth token

> Exchanges an authorization code with its PKCE verifier, or rotates a refresh token.



## OpenAPI

````yaml /specs/openapi/jointl-api-v1.openapi.yaml post /oauth/token
openapi: 3.1.2
info:
  title: Jointl REST API and OAuth
  version: 1.0.0
  summary: Supported public HTTP contract for Jointl third-party connections.
  description: >-
    HTTP contract for Jointl REST operations, OAuth, and Zapier subscription and
    action endpoints. Jointl does not provide a public sandbox.
  termsOfService: https://join.tl/legal/terms-of-service
  contact:
    name: Jointl Support
    url: https://join.tl
servers:
  - url: https://api.join.tl
    description: Jointl production API
security: []
tags:
  - name: OAuth
    description: OAuth 2.0 and OpenID Connect endpoints.
  - name: Discovery
    description: OAuth resource and issuer discovery.
  - name: Operations
    description: Permission-filtered read operations.
  - name: Actions
    description: Prepare, human approval, and confirmation.
  - name: Zapier
    description: Endpoints restricted to the approved Jointl Zapier app.
paths:
  /oauth/token:
    post:
      tags:
        - OAuth
      summary: Exchange or refresh an OAuth token
      description: >-
        Exchanges an authorization code with its PKCE verifier, or rotates a
        refresh token.
      operationId: exchangeOAuthToken
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/OAuthTokenRequest'
      responses:
        '200':
          description: Token issued.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthTokenResponse'
        '400':
          $ref: '#/components/responses/OAuthError'
        '401':
          $ref: '#/components/responses/OAuthError'
        '429':
          $ref: '#/components/responses/RateLimited'
      security: []
components:
  schemas:
    OAuthTokenRequest:
      oneOf:
        - type: object
          properties:
            grant_type:
              type: string
              const: authorization_code
            code:
              type: string
            redirect_uri:
              type: string
              format: uri
            client_id:
              type: string
            code_verifier:
              type: string
              minLength: 43
              maxLength: 128
            resource:
              type: string
              format: uri
          required:
            - grant_type
            - code
            - redirect_uri
            - client_id
            - code_verifier
            - resource
        - type: object
          properties:
            grant_type:
              type: string
              const: refresh_token
            refresh_token:
              type: string
            client_id:
              type: string
            scope:
              type: string
            resource:
              type: string
              format: uri
          required:
            - grant_type
            - refresh_token
            - client_id
    OAuthTokenResponse:
      type: object
      properties:
        access_token:
          type: string
        token_type:
          type: string
          const: Bearer
        expires_in:
          type: integer
        refresh_token:
          type: string
        scope:
          type: string
        id_token:
          type: string
      required:
        - access_token
        - token_type
        - expires_in
        - scope
    ErrorEnvelope:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
          required:
            - code
            - message
          additionalProperties: false
        requestId:
          type: string
      required:
        - error
        - requestId
      additionalProperties: false
  headers:
    RequestId:
      description: Request correlation identifier.
      schema:
        type: string
    RetryAfter:
      description: Seconds before retrying.
      schema:
        type: integer
        minimum: 1
  responses:
    OAuthError:
      description: OAuth protocol error.
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
              error_description:
                type: string
            required:
              - error
    RateLimited:
      description: Rate limit exceeded.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
        Retry-After:
          $ref: '#/components/headers/RetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
          example:
            error:
              code: too-many-requests
              message: Too many requests.
            requestId: request_example_429

````