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

> ## Agent Instructions
> Use Stable documentation by default. Honor an explicit Beta request or a URL under /docs/beta/. If the requested version conflicts with the installed CLI package or API origin, clarify the target before writing integration code.
> Pages under /docs/beta/ document Beta; other product pages document Stable. Keep the CLI package, commands, API origin, and credentials within the selected version. State the documentation version in your answer.
> For MCP search, always pass version: Stable or version: Beta. Unfiltered search mixes both versions. For filesystem reads, keep Beta queries under /beta/ and exclude /beta/ from Stable queries; discover paths before reading them.
> The public docs base is https://photon.codes/docs. Convert MCP page paths to public URLs under that base, preserving /beta/ when present. Read https://photon.codes/docs/skill.md for version selection and https://photon.codes/docs/llms.txt for the version indexes.

# Exchange device code or refresh token

> Exchanges an authorized device code or a refresh token for an access token and rotating refresh token. Accepts JSON and form-encoded bodies. While polling, wait at least interval seconds and increase the interval on slow_down. Store the new refresh token after every successful grant.



## OpenAPI

````yaml https://api.photon.codes/openapi.json post /v1/auth/device/token
openapi: 3.1.0
info:
  title: Photon API
  version: 1.0.0
servers:
  - url: https://api.photon.codes
security: []
paths:
  /v1/auth/device/token:
    post:
      tags:
        - Device Authorization
      summary: Exchange device code or refresh token
      description: >-
        Exchanges an authorized device code or a refresh token for an access
        token and rotating refresh token. Accepts JSON and form-encoded bodies.
        While polling, wait at least interval seconds and increase the interval
        on slow_down. Store the new refresh token after every successful grant.
      operationId: deviceToken
      parameters: []
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeviceTokenRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/DeviceTokenRequest'
        description: >-
          Exchange a device code or refresh token. Supply the matching
          grant_type and credential using JSON or form encoding.
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceTokenResponse'
          description: >-
            Token pair (snake_case OAuth wire format). Body (form-encoded or
            JSON): grant_type=urn:ietf:params:oauth:grant-type:device_code with
            device_code, or grant_type=refresh_token with refresh_token. Refresh
            tokens rotate on every grant — always store the new one.
          headers:
            Deprecation:
              $ref: '#/components/headers/Deprecation'
            Idempotent-Replayed:
              $ref: '#/components/headers/Idempotent-Replayed'
            Link:
              $ref: '#/components/headers/Link'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            Sunset:
              $ref: '#/components/headers/Sunset'
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-Trace-ID:
              $ref: '#/components/headers/X-Trace-ID'
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceTokenBadRequestResponse'
          description: >-
            authorization_pending, slow_down, access_denied, expired_token,
            invalid_grant, invalid_request, or unsupported_grant_type. Errors
            use the OAuth 2.0 format ({error, error_description?}), not
            problem+json. A 5xx problem+json response is transient; keep
            polling.
          headers:
            Deprecation:
              $ref: '#/components/headers/Deprecation'
            Idempotent-Replayed:
              $ref: '#/components/headers/Idempotent-Replayed'
            Link:
              $ref: '#/components/headers/Link'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            Sunset:
              $ref: '#/components/headers/Sunset'
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-Trace-ID:
              $ref: '#/components/headers/X-Trace-ID'
        '429':
          description: Relayed slow_down; back off the polling interval.
          headers:
            Deprecation:
              $ref: '#/components/headers/Deprecation'
            Idempotent-Replayed:
              $ref: '#/components/headers/Idempotent-Replayed'
            Link:
              $ref: '#/components/headers/Link'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            Sunset:
              $ref: '#/components/headers/Sunset'
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-Trace-ID:
              $ref: '#/components/headers/X-Trace-ID'
        '500':
          description: >-
            server_error: the login could not be completed; retry the login from
            the start.
          headers:
            Deprecation:
              $ref: '#/components/headers/Deprecation'
            Idempotent-Replayed:
              $ref: '#/components/headers/Idempotent-Replayed'
            Link:
              $ref: '#/components/headers/Link'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            Sunset:
              $ref: '#/components/headers/Sunset'
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-Trace-ID:
              $ref: '#/components/headers/X-Trace-ID'
        '503':
          content:
            application/problem+json:
              schema:
                $ref: '#/components/schemas/UpstreamUnavailableProblem'
          description: 'UPSTREAM_UNAVAILABLE: Upstream Service Unavailable'
          headers:
            Deprecation:
              $ref: '#/components/headers/Deprecation'
            Idempotent-Replayed:
              $ref: '#/components/headers/Idempotent-Replayed'
            Link:
              $ref: '#/components/headers/Link'
            RateLimit:
              $ref: '#/components/headers/RateLimit'
            RateLimit-Policy:
              $ref: '#/components/headers/RateLimit-Policy'
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            Sunset:
              $ref: '#/components/headers/Sunset'
            X-Request-ID:
              $ref: '#/components/headers/X-Request-ID'
            X-Trace-ID:
              $ref: '#/components/headers/X-Trace-ID'
      security: []
components:
  schemas:
    DeviceTokenRequest:
      oneOf:
        - $ref: '#/components/schemas/DeviceCodeGrantRequest'
        - $ref: '#/components/schemas/RefreshTokenGrantRequest'
    DeviceTokenResponse:
      additionalProperties: {}
      properties:
        access_token:
          description: Bearer access token for authenticated Photon API requests.
          type: string
        authentication_method:
          description: >-
            Authentication method used for the device login, when returned.
            Omitted for refresh grants.
          type: string
        expires_in:
          description: >-
            Access-token validity in seconds, derived from its expiry and issue
            times; defaults to 300 when unavailable.
          type: number
        refresh_token:
          description: >-
            Refresh token for the next refresh grant. Tokens rotate on every
            grant; replace the stored value with this one.
          type: string
        user:
          $ref: '#/components/schemas/DeviceTokenResponseUser'
      required:
        - access_token
        - expires_in
        - refresh_token
        - user
      type: object
    DeviceTokenBadRequestResponse:
      additionalProperties: {}
      properties:
        error:
          description: >-
            OAuth error code. During device polling, authorization_pending means
            authorization is incomplete and slow_down requests a longer polling
            interval.
          type: string
        error_description:
          description: Optional human-readable explanation of the OAuth error.
          type: string
      required:
        - error
      type: object
    UpstreamUnavailableProblem:
      additionalProperties:
        $ref: '#/components/schemas/JsonValue'
      example:
        code: UPSTREAM_UNAVAILABLE
        status: 503
        title: Upstream Service Unavailable
        type: https://photon.codes/docs/problems/upstream-unavailable
      properties:
        code:
          const: UPSTREAM_UNAVAILABLE
          type: string
        detail:
          minLength: 1
          type: string
        instance:
          minLength: 1
          type: string
        remediation:
          not: {}
        requestId:
          minLength: 1
          type: string
        status:
          const: 503
          type: number
        title:
          const: Upstream Service Unavailable
          type: string
        type:
          const: https://photon.codes/docs/problems/upstream-unavailable
          type: string
      required:
        - code
        - status
        - title
        - type
      type: object
    DeviceCodeGrantRequest:
      properties:
        device_code:
          description: >-
            device_code returned by POST /v1/auth/device/code. Required for a
            device-code grant.
          minLength: 1
          type: string
        grant_type:
          const: urn:ietf:params:oauth:grant-type:device_code
          description: >-
            Selects the device authorization grant to poll or exchange a device
            code.
          type: string
      required:
        - device_code
        - grant_type
      type: object
    RefreshTokenGrantRequest:
      properties:
        grant_type:
          const: refresh_token
          description: Selects the refresh-token grant to obtain a new token pair.
          type: string
        refresh_token:
          description: >-
            Most recently issued refresh token. Required for a refresh grant;
            replace it with the returned refresh_token after success.
          minLength: 1
          type: string
      required:
        - grant_type
        - refresh_token
      type: object
    DeviceTokenResponseUser:
      additionalProperties: {}
      description: Profile of the authenticated user.
      properties:
        email:
          description: Authenticated user's email address.
          type: string
        first_name:
          anyOf:
            - type: string
            - type: 'null'
          description: User's first name, or null when not set.
        id:
          description: >-
            Authenticated user's identity identifier; distinct from the Photon
            Account ID.
          type: string
        last_name:
          anyOf:
            - type: string
            - type: 'null'
          description: User's last name, or null when not set.
      required:
        - id
        - email
        - first_name
        - last_name
      type: object
    JsonValue:
      anyOf:
        - type: string
        - type: number
        - type: boolean
        - type: 'null'
        - items:
            $ref: '#/components/schemas/JsonValue'
          type: array
        - additionalProperties:
            $ref: '#/components/schemas/JsonValue'
          propertyNames:
            type: string
          type: object
  headers:
    Deprecation:
      description: >-
        RFC 9745 structured-field Date at which the operation was or will be
        deprecated: `@` followed by Unix seconds, for example `@1767225599`.
      schema:
        pattern: ^@-?[0-9]+$
        type: string
    Idempotent-Replayed:
      description: True when this response was replayed from an earlier attempt.
      schema:
        type: boolean
    Link:
      description: Links related to lifecycle or remediation documentation.
      schema:
        type: string
    RateLimit:
      description: Current rate-limit state.
      schema:
        type: string
    RateLimit-Policy:
      description: Rate-limit policy applied by the gateway.
      schema:
        type: string
    Retry-After:
      description: Delay before retrying, in seconds or as an HTTP date.
      schema:
        type: string
    Sunset:
      description: >-
        RFC 8594 HTTP-date (IMF-fixdate) after which the operation may become
        unavailable, for example `Thu, 31 Dec 2026 23:59:59 GMT`.
      schema:
        pattern: >-
          ^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), [0-9]{2}
          (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) [0-9]{4}
          [0-9]{2}:[0-9]{2}:[0-9]{2} GMT$
        type: string
    X-Request-ID:
      description: Identifier for this HTTP attempt.
      schema:
        type: string
    X-Trace-ID:
      description: >-
        Trace ID of this request. Sent alongside X-Request-ID when a middleware
        published a trace ID for the request.
      schema:
        pattern: ^(?!0{32}$)[0-9a-f]{32}$
        type: string

````

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