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

# Refresh tokens

> Exchanges a valid refresh token for a new access and refresh token pair once the access token expires (after 15 minutes). Refresh tokens stay valid for 30 days.

The only transport the API recognizes is the HttpOnly `refresh_token` cookie exactly as set at sign-in. The cookie value is server signed, so it cannot be rebuilt from the JSON `refreshToken`. A raw JWT in the cookie, an `Authorization: Bearer` header, or a JSON body all return `401` "Refresh token not found."; no header or body transport exists. Browsers send the cookie automatically, while non-browser clients must replay the `Set-Cookie` value verbatim through a cookie jar.

<Warning>This endpoint currently rejects every refresh. A `refresh_token` cookie replayed exactly as set at sign-in returns `401` "Invalid or expired refresh token." even seconds after the `201`, while the matching `access_token` still works on `GET /auth/me`. Until this is fixed, re-run the sign-in flow (`GET /auth/siwx/challenge`, then `POST /auth/siwx/verify`) when the 15-minute access token lapses.</Warning>


## OpenAPI

````yaml /openapi.json post /auth/refresh
openapi: 3.1.0
info:
  title: Vane API
  version: 1.0.0
  summary: Cross-chain and same-chain swaps filled by an open network of solvers.
  description: >-
    Vane turns a swap into an intent: you declare what you want to receive, the
    API returns a per-order deposit address, and a solver fills the order
    against the escrowed deposit ([how solvers fill
    orders](/features/solver-auctions)).


    **Authentication.** Most endpoints accept a tenant API key sent as the
    `x-tenant-api-key` header (accountless integration). The key pre-filled in
    the API playground is a shared public key for evaluating the API. Production
    integrations use their own tenant key, requested from support
    (help@vane.xyz) and kept server-side. A JWT access token from SIWX
    wallet-signature auth also satisfies these endpoints and attributes orders
    to a user account, which adds order history (`GET /v1/orders`) and points.


    **Error behavior.** Errors use the envelope `{statusCode, message, error}`.
    Field order varies and some errors omit `error`. Most business validation
    failures (an unknown token id, a malformed address, an invalid amount, an
    unknown order UUID) return HTTP `500` with a descriptive message, while
    `400` appears only for malformed query parameters. Match on the message text
    for programmatic handling, not just the status codes.


    **The fields `exchange` and `tradePath`** describe how a quote is priced and
    routed across order-book legs. They say nothing about settlement, which
    solvers perform separately.
  contact:
    name: Vane support
    email: help@vane.xyz
    url: https://vane.xyz
  termsOfService: https://vane.xyz/terms-and-conditions
servers:
  - url: https://api.vane.xyz/api
    description: Production
security:
  - tenantApiKey: []
tags:
  - name: Tokens
    description: The token catalog, swap limits, and quotes.
  - name: Orders
    description: Create swap orders and track them to a terminal state.
  - name: Auth
    description: >-
      Optional SIWX wallet-signature authentication. Adds order history and
      points.
paths:
  /auth/refresh:
    post:
      tags:
        - Auth
      summary: Refresh tokens
      description: >-
        Exchanges a valid refresh token for a new access and refresh token pair
        once the access token expires (after 15 minutes). Refresh tokens stay
        valid for 30 days.


        The only transport the API recognizes is the HttpOnly `refresh_token`
        cookie exactly as set at sign-in. The cookie value is server signed, so
        it cannot be rebuilt from the JSON `refreshToken`. A raw JWT in the
        cookie, an `Authorization: Bearer` header, or a JSON body all return
        `401` "Refresh token not found."; no header or body transport exists.
        Browsers send the cookie automatically, while non-browser clients must
        replay the `Set-Cookie` value verbatim through a cookie jar.
      operationId: refreshTokens
      responses:
        '200':
          description: New token pair issued.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RefreshResponse'
              example:
                accessToken: >-
                  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3YzllNjY3OSJ9.example-new-access-token
                refreshToken: >-
                  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI3YzllNjY3OSJ9.example-new-refresh-token
                message: Token refreshed successfully
        '401':
          description: >-
            Refresh rejected. Two messages exist: "Refresh token not found."
            means no signed cookie arrived (every non-cookie transport gets this
            one), and "Invalid or expired refresh token." means the cookie
            arrived but the token was rejected. If a refresh fails, re-run the
            sign-in flow to obtain a new token pair.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
              examples:
                cookieMissing:
                  summary: Refresh token cookie missing (or wrong transport)
                  value:
                    message: Refresh token not found.
                    error: Unauthorized
                    statusCode: 401
                tokenRejected:
                  summary: Signed cookie arrived but token rejected
                  value:
                    message: Invalid or expired refresh token.
                    error: Unauthorized
                    statusCode: 401
      security:
        - refreshTokenCookie: []
components:
  schemas:
    RefreshResponse:
      type: object
      description: New token pair from a refresh.
      properties:
        accessToken:
          type: string
          description: New JWT access token (15 minutes).
        refreshToken:
          type: string
          description: New JWT refresh token (30 days).
        message:
          type: string
          description: >-
            Human-readable confirmation, for example `Token refreshed
            successfully`.
      required:
        - accessToken
        - refreshToken
        - message
    Error:
      type: object
      description: >-
        Canonical error envelope. Field order varies and `error` is sometimes
        omitted (the unknown-order `500` returns only `statusCode` and
        `message`); message casing varies too (`Internal Server Error` vs
        `Internal server error`). Most business validation failures return `500`
        with a descriptive message, so match on `message` for programmatic
        handling.
      properties:
        statusCode:
          type: integer
          description: HTTP status code.
        message:
          type: string
          description: >-
            Error description. The most reliable field for distinguishing
            causes.
        error:
          type: string
          description: >-
            HTTP status text, for example `Bad Request`, `Unauthorized`.
            Sometimes absent.
      required:
        - statusCode
        - message
  securitySchemes:
    tenantApiKey:
      type: apiKey
      in: header
      name: x-tenant-api-key
      x-default: c7eccc0aaed64932a85d35658fa55a4fb2d60cd3d2c529cfd643dc676ee82e82
      description: >-
        Vane's shared tenant key. Contact support for a dedicated key if you
        need custom parameters or separate order tracking.
    refreshTokenCookie:
      type: apiKey
      in: cookie
      name: refresh_token
      description: >-
        HttpOnly refresh-token cookie set by `POST /auth/siwx/verify`
        (`Path=/api/auth`, 30 days). The value is a server-signed string rather
        than the raw `refreshToken` JWT, so a raw JWT in this cookie, a Bearer
        header, or a JSON body all return `401` "Refresh token not found.".
        Browsers attach it on their own; outside a browser, replay the
        `Set-Cookie` value verbatim from a cookie jar. Used only by `POST
        /auth/refresh`.

````