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

# Create access token

> RFC 6749 client-credentials grant for active service accounts. Supply grant_type=client_credentials, client_id=<service-account UUID>, and client_secret=<full tfk_live_... or tfk_test_... service-account API key>. Client credentials may instead be sent with HTTP Basic authentication. Tokens use the configured auth.jwtExpirySeconds capped at 900 seconds and carry the service account's current workspace role, effective permissions, and effective API scopes.



## OpenAPI

````yaml api-reference/openapi.json POST /api/v1/oauth/token
openapi: 3.1.0
info:
  description: >-
    TetraFi is an API for institutional trading across on-chain and off-chain
    venues: discover assets, request quotes, place an order by quote id and read
    its status. API keys sign every request.


    Asset-pair quotes: every tagged union is tagged by `kind`; only the outcome
    of `/prices` rows and `sources[]` entries is tagged by `status`.
  title: TetraFi API
  version: 1.0.0-beta.1
servers:
  - description: Production. Uses real assets and venue accounts.
    url: https://api.tetrafi.io
  - description: >-
      Shared development sandbox backed by the dev testnet chain registry. Use
      testnet assets and your workspace's sandbox/testnet venue accounts; makers
      are not simulated. Credentials and workspaces are environment-specific.
    url: https://api-dev.tetrafi.io
security:
  - api_key: []
tags:
  - description: >-
      Exchange service-account credentials for a token, and read the credential
      you are calling with: its identity, scopes and rate limits.
    name: auth
  - description: >-
      Discover the assets, chains and venues you can trade, and read or stream
      their indicative prices.
    name: trading
  - description: >-
      Request firm or indicative quotes for an asset pair from every eligible
      venue, requote one, and read a quote request again.
    name: quotes
  - description: >-
      Place an order from a quote you hold, follow its status, and cancel it
      before it is sent to a venue.
    name: orders
  - description: >-
      Your trade history: every order and venue trade, with its settlement and
      settlement obligations.
    name: trades
  - description: >-
      Your venue accounts' settlement windows, obligations, movements and
      schedules, and the plan of what is due across them.
    name: settlements
  - description: Balances across the workspace's wallets and venue accounts.
    name: treasury
  - description: >-
      One venue account's balances, deposit instructions and history, credit and
      ledger.
    name: venue-accounts
  - description: >-
      The workspace's venue accounts, with where their funds are held and each
      venue's key state.
    name: venue-enablements
  - description: >-
      Register endpoints for signed event deliveries, rotate their secrets, send
      test deliveries and read the delivery log.
    name: webhooks
  - description: >-
      The workspace's verification state, the capabilities it allows, and its
      fee schedule.
    name: workspaces
  - description: >-
      Read up to 20 resources in one request, each answered exactly as its own
      GET.
    name: batch
paths:
  /api/v1/oauth/token:
    post:
      tags:
        - auth
      summary: Exchange client credentials for a token
      description: >-
        RFC 6749 client-credentials grant for active service accounts. Supply
        grant_type=client_credentials, client_id=<service-account UUID>, and
        client_secret=<full tfk_live_... or tfk_test_... service-account API
        key>. Client credentials may instead be sent with HTTP Basic
        authentication. Tokens use the configured auth.jwtExpirySeconds capped
        at 900 seconds and carry the service account's current workspace role,
        effective permissions, and effective API scopes.
      operationId: oauth_token
      requestBody:
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/OAuthTokenRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthTokenResponse'
          description: Short-lived service-account bearer token
          headers:
            Deprecation:
              description: >-
                Present when this operation is deprecated: an RFC 9745
                structured date, for example @1792443399. Absence makes no
                deprecation claim.
              schema:
                type: string
            Link:
              description: >-
                When deprecation applies, links to the deprecation notice with
                rel=deprecation; other link relations may also be sent.
              schema:
                type: string
            RateLimit:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.1 structured
                dictionary, for example `limit=100, remaining=41, reset=19`.
                Remaining is the admitted decision's headroom; reset is whole
                seconds until quota next becomes available, not an epoch or a
                promise of a full burst refill. On a limiter's 429 remaining is
                0 and reset equals Retry-After. Accepted key, route and
                per-address policies are compared by lowest remaining, then
                longest reset. A venue refusal without a known quota makes no
                rate-limit header claim.
              schema:
                type: string
            RateLimit-Policy:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.5: quota and
                window in seconds, for example `100;w=60`. Sent on every status
                when a finite limiter counted the request. The applicable policy
                closest to exhaustion is reported (section 3.2): lowest
                remaining, then longest reset. On a limiter's 429 this is
                exactly the policy that refused; if a venue discloses no quota,
                the headers are absent.
              schema:
                type: string
            Sunset:
              description: >-
                Present when retirement is scheduled: the HTTP-date after which
                this version may stop being served (RFC 8594).
              schema:
                type: string
            x-request-id:
              description: >-
                The request's id: the caller's valid `X-Request-Id`, or a
                generated UUID v4. Quote it when asking for support.
              schema:
                type: string
        '400':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthErrorResponse'
          description: >-
            invalid_grant (no grant_type, or an unreadable form),
            unsupported_grant_type (a grant other than client_credentials), or
            unauthorized_client with error_uri naming
            SIGNED_KEY_NOT_EXCHANGEABLE (a key that requires request signing or
            holds venue trading signs each request instead)
          headers:
            Deprecation:
              description: >-
                Present when this operation is deprecated: an RFC 9745
                structured date, for example @1792443399. Absence makes no
                deprecation claim.
              schema:
                type: string
            Link:
              description: >-
                When deprecation applies, links to the deprecation notice with
                rel=deprecation; other link relations may also be sent.
              schema:
                type: string
            RateLimit:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.1 structured
                dictionary, for example `limit=100, remaining=41, reset=19`.
                Remaining is the admitted decision's headroom; reset is whole
                seconds until quota next becomes available, not an epoch or a
                promise of a full burst refill. On a limiter's 429 remaining is
                0 and reset equals Retry-After. Accepted key, route and
                per-address policies are compared by lowest remaining, then
                longest reset. A venue refusal without a known quota makes no
                rate-limit header claim.
              schema:
                type: string
            RateLimit-Policy:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.5: quota and
                window in seconds, for example `100;w=60`. Sent on every status
                when a finite limiter counted the request. The applicable policy
                closest to exhaustion is reported (section 3.2): lowest
                remaining, then longest reset. On a limiter's 429 this is
                exactly the policy that refused; if a venue discloses no quota,
                the headers are absent.
              schema:
                type: string
            Sunset:
              description: >-
                Present when retirement is scheduled: the HTTP-date after which
                this version may stop being served (RFC 8594).
              schema:
                type: string
            x-request-id:
              description: >-
                The request's id: the caller's valid `X-Request-Id`, or a
                generated UUID v4. Quote it when asking for support.
              schema:
                type: string
        '401':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthErrorResponse'
          description: >-
            invalid_client: the client id or secret is wrong, or the key is not
            an active service account's
          headers:
            Deprecation:
              description: >-
                Present when this operation is deprecated: an RFC 9745
                structured date, for example @1792443399. Absence makes no
                deprecation claim.
              schema:
                type: string
            Link:
              description: >-
                When deprecation applies, links to the deprecation notice with
                rel=deprecation; other link relations may also be sent.
              schema:
                type: string
            RateLimit:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.1 structured
                dictionary, for example `limit=100, remaining=41, reset=19`.
                Remaining is the admitted decision's headroom; reset is whole
                seconds until quota next becomes available, not an epoch or a
                promise of a full burst refill. On a limiter's 429 remaining is
                0 and reset equals Retry-After. Accepted key, route and
                per-address policies are compared by lowest remaining, then
                longest reset. A venue refusal without a known quota makes no
                rate-limit header claim.
              schema:
                type: string
            RateLimit-Policy:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.5: quota and
                window in seconds, for example `100;w=60`. Sent on every status
                when a finite limiter counted the request. The applicable policy
                closest to exhaustion is reported (section 3.2): lowest
                remaining, then longest reset. On a limiter's 429 this is
                exactly the policy that refused; if a venue discloses no quota,
                the headers are absent.
              schema:
                type: string
            Sunset:
              description: >-
                Present when retirement is scheduled: the HTTP-date after which
                this version may stop being served (RFC 8594).
              schema:
                type: string
            WWW-Authenticate:
              description: >-
                Always sent with invalid_client (401): `Basic
                realm="oauth/token"` (RFC 6749 section 5.2).
              schema:
                type: string
            x-request-id:
              description: >-
                The request's id: the caller's valid `X-Request-Id`, or a
                generated UUID v4. Quote it when asking for support.
              schema:
                type: string
        '503':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthErrorResponse'
          description: >-
            temporarily_unavailable: the client's current authority could not be
            read; retry
          headers:
            Deprecation:
              description: >-
                Present when this operation is deprecated: an RFC 9745
                structured date, for example @1792443399. Absence makes no
                deprecation claim.
              schema:
                type: string
            Link:
              description: >-
                When deprecation applies, links to the deprecation notice with
                rel=deprecation; other link relations may also be sent.
              schema:
                type: string
            RateLimit:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.1 structured
                dictionary, for example `limit=100, remaining=41, reset=19`.
                Remaining is the admitted decision's headroom; reset is whole
                seconds until quota next becomes available, not an epoch or a
                promise of a full burst refill. On a limiter's 429 remaining is
                0 and reset equals Retry-After. Accepted key, route and
                per-address policies are compared by lowest remaining, then
                longest reset. A venue refusal without a known quota makes no
                rate-limit header claim.
              schema:
                type: string
            RateLimit-Policy:
              description: >-
                draft-ietf-httpapi-ratelimit-headers-07 section 3.5: quota and
                window in seconds, for example `100;w=60`. Sent on every status
                when a finite limiter counted the request. The applicable policy
                closest to exhaustion is reported (section 3.2): lowest
                remaining, then longest reset. On a limiter's 429 this is
                exactly the policy that refused; if a venue discloses no quota,
                the headers are absent.
              schema:
                type: string
            Sunset:
              description: >-
                Present when retirement is scheduled: the HTTP-date after which
                this version may stop being served (RFC 8594).
              schema:
                type: string
            x-request-id:
              description: >-
                The request's id: the caller's valid `X-Request-Id`, or a
                generated UUID v4. Quote it when asking for support.
              schema:
                type: string
      security:
        - {}
components:
  schemas:
    OAuthTokenRequest:
      description: >-
        An RFC 6749 client-credentials token request, form-encoded. Its field
        names are the

        standard's, so OAuth client libraries send it unchanged.
      properties:
        client_id:
          description: >-
            The service account's id. Omit it when the credentials are sent with
            HTTP Basic.
          type:
            - string
            - 'null'
        client_secret:
          description: >-
            The service account's full API key (`tfk_live_…` or `tfk_test_…`).
            Omit it when the

            credentials are sent with HTTP Basic.
          type:
            - string
            - 'null'
        grant_type:
          description: Always `client_credentials`.
          type:
            - string
            - 'null'
      type: object
    OAuthTokenResponse:
      description: An RFC 6749 access token response.
      properties:
        access_token:
          description: 'The bearer token: send it as `Authorization: Bearer <access_token>`.'
          type: string
        expires_in:
          description: >-
            Seconds until the token expires (at most 900). Request a new one
            before then.
          format: int64
          minimum: 0
          type: integer
        scope:
          description: The token's API scopes, space-separated.
          type: string
        token_type:
          description: Always `Bearer`.
          type: string
      required:
        - access_token
        - token_type
        - expires_in
        - scope
      type: object
    OAuthErrorResponse:
      description: >-
        An RFC 6749 error response: the token endpoint answers the standard's
        body, not `ApiError`.
      properties:
        error:
          $ref: '#/components/schemas/OAuthErrorCode'
          description: >-
            The RFC 6749 error code: `invalid_client` (401), `invalid_grant`,
            `unsupported_grant_type`

            or `unauthorized_client` (400), or `temporarily_unavailable` (503).
        error_description:
          description: >-
            Why the client was refused, when the RFC 6749 code alone does not
            say.
          type:
            - string
            - 'null'
        error_uri:
          description: >-
            The error-code reference for a TetraFi cause the RFC 6749 code does
            not name

            (`SIGNED_KEY_NOT_EXCHANGEABLE`).
          type:
            - string
            - 'null'
      required:
        - error
      type: object
    OAuthErrorCode:
      description: >-
        RFC 6749 section 5.2 error identifiers, plus the standard
        temporary-unavailability code.


        New values may be added; treat unknown values as other.
      enum:
        - invalid_client
        - invalid_grant
        - unsupported_grant_type
        - unauthorized_client
        - temporarily_unavailable
      type: string
      x-extensible-enum: true
  securitySchemes:
    api_key:
      description: >-
        Send the API key in `X-API-Key`.


        **Request signing.** A key with signing enabled (enabled for the key in
        its workspace's credential settings, which return the signing secret
        once; see [Sign
        requests](https://docs.tetrafi.io/authentication#sign-requests)) must
        also sign every request:


        - `X-Timestamp`: the current Unix time in seconds, within 300 seconds of
        the server clock (at most 10 seconds ahead of it on a request that sends
        `X-Nonce`).

        - `X-Nonce`: a fresh random value for each request, 16 to 128 characters
        of `A-Z`, `a-z`, `0-9`, `-` and `_` (a UUID fits). Required on a write
        (POST, PUT, PATCH, DELETE); optional on a read (GET, HEAD).

        - `X-Signature`: lower-case hex HMAC-SHA256 of the canonical string,
        keyed with the signing secret's 32 bytes (the secret is 64 hex
        characters; decode it first).


        The canonical string is joined by `\n`, with no trailing newline: the
        `X-Timestamp` value, the `X-Nonce` value, the upper-case method, the
        path with its query exactly as sent (`/api/v1/orders?limit=1`), and the
        lower-case hex SHA-256 of the exact body bytes (the SHA-256 of an empty
        body when there is none). A request without `X-Nonce` (a read) omits the
        nonce line and signs four lines.


        A nonce is accepted once per key: the same nonce again inside the window
        is refused, whatever the body, so two identical writes in one second
        each carry their own nonce and both succeed, and a retry signs again
        with a new nonce. Every API server shares one nonce record, so a nonce
        accepted by one server is refused by all of them. Rate admission runs
        first: a rate-limited write (429) does not consume its nonce, and a
        replay sent while the key is rate limited is answered 429; otherwise a
        replay spends a rate token and is refused. A read without a nonce
        changes nothing, so an identical signed read inside the window is
        admitted again. A write whose window has already passed on the nonce
        record's clock when its nonce is recorded is refused as
        `TIMESTAMP_OUT_OF_RANGE`. If the nonce record cannot be read or written
        the request is refused with 503 `API_KEY_UNAVAILABLE`; the nonce may
        have been consumed, so sign again with a new `X-Timestamp` and `X-Nonce`
        before retrying.


        A signing refusal is a 401 `AUTH_REQUIRED` whose `details.reason` names
        the cause: `SIGNATURE_REQUIRED` (a header is missing),
        `SIGNATURE_INVALID` (a malformed header or a wrong signature),
        `TIMESTAMP_OUT_OF_RANGE`, `NONCE_REQUIRED` (a write without `X-Nonce`),
        `NONCE_INVALID` (a malformed or repeated `X-Nonce` header),
        `SIGNATURE_REPLAYED` (the nonce was already accepted).
        `SIGNATURE_PREDATES_RESTART` and 429 `REPLAY_WINDOW_FULL` are reserved
        and not answered today.
      in: header
      name: X-API-Key
      type: apiKey
      x-request-signing:
        algorithm: HMAC-SHA256
        canonicalRequest:
          - timestamp
          - nonce
          - method
          - pathWithQuery
          - bodySha256Hex
        canonicalRequestWithoutNonce:
          - timestamp
          - method
          - pathWithQuery
          - bodySha256Hex
        canonicalSeparator: |+

        nonceFutureSkewSeconds: 10
        nonceHeader: X-Nonce
        noncePattern: ^[A-Za-z0-9_-]{16,128}$
        nonceRequiredMethods:
          - POST
          - PUT
          - PATCH
          - DELETE
        refusal:
          error: AUTH_REQUIRED
          reasons:
            - SIGNATURE_REQUIRED
            - SIGNATURE_INVALID
            - TIMESTAMP_OUT_OF_RANGE
            - NONCE_REQUIRED
            - NONCE_INVALID
            - SIGNATURE_REPLAYED
          status: 401
        reserved:
          - error: AUTH_REQUIRED
            reason: SIGNATURE_PREDATES_RESTART
            status: 401
          - error: REPLAY_WINDOW_FULL
            status: 429
        secretEncoding: hex
        signatureEncoding: hex-lower
        signatureHeader: X-Signature
        timestampHeader: X-Timestamp
        timestampWindowSeconds: 300
      x-tetrafi-scopes:
        compliance_read:
          description: View compliance policies, denials, evidence, and reports
          permission: Read compliance
          permissionIds:
            - ReadCompliance
        fee_schedule_read:
          description: >-
            Read the current and upcoming fee rates for this workspace. Does not
            change rates.
          permission: Read fee schedule
          permissionIds:
            - ReadFeeSchedule
        orders_read:
          description: View order status and history
          permission: Read orders
          permissionIds:
            - ReadOrders
        orders_write:
          description: Submit orders for execution
          permission: Submit orders
          permissionIds:
            - SubmitOrders
        prices_read:
          description: >-
            Read-only access to prices and recorded quotes. Also select Submit
            orders to request new quotes.
          permission: Read quotes
          permissionIds:
            - ReadQuotes
        quotes_read:
          description: >-
            Read-only access to prices and recorded quotes. Also select Submit
            orders to request new quotes.
          permission: Read quotes
          permissionIds:
            - ReadQuotes
        quotes_request:
          description: >-
            Read-only access to prices and recorded quotes. Also select Submit
            orders to request new quotes. Submit orders for execution
          permission: Read quotes + Submit orders
          permissionIds:
            - ReadQuotes
            - SubmitOrders
        settlements_read:
          description: See settlement status and detail.
          permission: Read settlements
          permissionIds:
            - ReadSettlements
        trades_read:
          description: View trade history and audit trails
          permission: Read trades
          permissionIds:
            - ReadTrades
        treasury_read:
          description: >-
            See permitted accounts, balances, payouts and Runs, and refresh
            balances. Does not move money.
          permission: Treasury read
          permissionIds:
            - ReadWallets
        webhooks_manage:
          description: >-
            Configure endpoints and events, test deliveries, read outcomes and
            redeliver. Requires your current Manage webhooks permission.
          permission: Manage webhooks
          permissionIds:
            - ManageWebhooks

````

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