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

# Exchange a workload OIDC token for a short-lived API key

> Trade the OIDC token a workload's platform issued for a Mixpeek API key.

Configure a workload identity provider on the organization first (``PATCH
/v1/organizations`` with ``workload_identity_providers``, or Studio >
Settings > Organization > Workload identity). The workload then sends its
token here with the provider's ``provider_id`` and uses the returned
``access_token`` as ``Authorization: Bearer <access_token>`` until
``expires_at``. No API key is needed to call this route.

On Vercel, the token is ``getVercelOidcToken()`` from ``@vercel/oidc``; on
GitHub Actions it is ``core.getIDToken(audience)`` with ``permissions:
id-token: write``.



## OpenAPI

````yaml post /v1/auth/token-exchange
openapi: 3.1.0
info:
  title: Mixpeek API
  description: >-
    This is the Mixpeek API, providing access to various endpoints for data
    processing and retrieval.
  termsOfService: https://mixpeek.com/terms
  contact:
    name: Mixpeek Support
    url: https://mixpeek.com/contact
    email: info@mixpeek.com
  version: '0.82'
servers:
  - url: https://api.mixpeek.com
    description: Production
security:
  - BearerAuth: []
paths:
  /v1/auth/token-exchange:
    post:
      tags:
        - Authentication
      summary: Exchange a workload OIDC token for a short-lived API key
      description: >-
        Trade the OIDC token a workload's platform issued for a Mixpeek API key.


        Configure a workload identity provider on the organization first
        (``PATCH

        /v1/organizations`` with ``workload_identity_providers``, or Studio >

        Settings > Organization > Workload identity). The workload then sends
        its

        token here with the provider's ``provider_id`` and uses the returned

        ``access_token`` as ``Authorization: Bearer <access_token>`` until

        ``expires_at``. No API key is needed to call this route.


        On Vercel, the token is ``getVercelOidcToken()`` from ``@vercel/oidc``;
        on

        GitHub Actions it is ``core.getIDToken(audience)`` with ``permissions:

        id-token: write``.
      operationId: token_exchange_v1_auth_token_exchange_post
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TokenExchangeRequest'
        required: true
        description: >-
          Keys this body does not declare are refused with 422 extra_forbidden
          naming the accepted keys (since 2026-11-02).
        x-unknown-keys:
          until: '2026-11-02'
          then: 422 extra_forbidden
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenExchangeResponse'
        '400':
          description: Bad Request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: The token failed verification or the provider is unknown.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: The token's claims do not match the provider's conditions.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '404':
          description: Not Found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '422':
          description: Unprocessable Entity
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429':
          description: Too many exchanges for this provider in the last minute.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal Server Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '503':
          description: Service Unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
      security: []
components:
  schemas:
    TokenExchangeRequest:
      properties:
        provider_id:
          type: string
          minLength: 1
          title: Provider Id
          description: The workload identity provider configured on the organization.
        subject_token:
          type: string
          minLength: 1
          title: Subject Token
          description: >-
            The OIDC token the workload's platform issued: on Vercel,
            getVercelOidcToken() or the x-vercel-oidc-token header; on GitHub
            Actions, core.getIDToken(audience).
        ttl_seconds:
          anyOf:
            - type: integer
              maximum: 3600
              minimum: 60
            - type: 'null'
          title: Ttl Seconds
          description: >-
            Requested key lifetime. Capped at the provider's token_ttl_seconds
            and at the subject token's own expiry plus the provider lifetime.
      additionalProperties: false
      type: object
      required:
        - provider_id
        - subject_token
      title: TokenExchangeRequest
      description: Exchange a workload's OIDC token for a short-lived Mixpeek API key.
      examples:
        - provider_id: wip_abc123
          subject_token: <the workload's OIDC token>
    TokenExchangeResponse:
      properties:
        access_token:
          type: string
          title: Access Token
          description: The API key. Shown once.
        token_type:
          type: string
          const: Bearer
          title: Token Type
          default: Bearer
        expires_in:
          type: integer
          title: Expires In
          description: Seconds until the key expires.
        expires_at:
          type: string
          format: date-time
          title: Expires At
          description: When the key expires (UTC).
        key_id:
          type: string
          title: Key Id
          description: Identifier of the minted key, for audit.
        organization_id:
          type: string
          title: Organization Id
          description: Organization the key belongs to.
        permissions:
          items:
            $ref: '#/components/schemas/Permission'
          type: array
          title: Permissions
          description: Permissions of the key.
      type: object
      required:
        - access_token
        - expires_in
        - expires_at
        - key_id
        - organization_id
        - permissions
      title: TokenExchangeResponse
      description: >-
        A short-lived API key. Send it as ``Authorization: Bearer
        <access_token>``.
    ErrorResponse:
      properties:
        success:
          type: boolean
          title: Success
          description: Always false for error responses
          default: false
        status:
          type: integer
          title: Status
          description: HTTP status code for this error
        error:
          $ref: '#/components/schemas/ErrorDetail'
          description: Error details payload
      type: object
      required:
        - status
        - error
      title: ErrorResponse
      description: Error response model.
      examples:
        - error:
            details:
              id: ns_123
              resource: namespace
            message: Namespace not found
            type: NotFoundError
          status: 404
          success: false
    Permission:
      type: string
      enum:
        - read
        - write
        - delete
        - admin
      title: Permission
      description: |-
        Simplified API key permissions.

        This four-value enum replaces the legacy 16-permission model. Keep usage
        simple: prefer the least privileged option that satisfies the workflow.

        Hierarchy (strongest -> weakest): ADMIN > DELETE > WRITE > READ.
    ErrorDetail:
      properties:
        message:
          type: string
          title: Message
          description: Human-readable error message
        type:
          type: string
          title: Type
          description: Stable error type identifier (machine-readable)
        code:
          anyOf:
            - type: string
            - type: 'null'
          title: Code
          description: >-
            Fine-grained error code for programmatic handling (e.g.,
            namespace_name_taken, feature_extractor_not_found). Present only
            when consumers may need to branch on a specific error condition.
        details:
          anyOf:
            - additionalProperties: true
              type: object
            - type: 'null'
          title: Details
          description: >-
            Optional structured details to help debugging (validation errors,
            IDs, etc.)
      type: object
      required:
        - message
        - type
      title: ErrorDetail
      description: Error detail model.
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: >-
        Mixpeek API key, sent as `Authorization: Bearer mxp_sk_...`. Create one
        in Studio under Settings → API Keys, or with an admin key via `POST
        /v1/organizations/users/{user_email}/api-keys`. A missing, malformed,
        unknown, revoked, inactive or expired key returns 401; a key without the
        permission, scope or plan an operation needs returns 403.

````

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