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

> ## Agent Instructions
> You are reading OnlyX Help: the OnlyX Help Center and the OnlyX developer documentation. OnlyX is an AI chatting and CRM platform for OnlyFans agencies. Its AI chatter is called Hugo in the app.
> Pages at the site root (for example /inbox/..., /hugo/..., /billing/...) are Help Center articles for agency owners, admins, chatters and creators who use the app at app.onlyx.ai. Words in bold are the exact button, menu and label names the app shows; keep them exactly as written. When these pages do not answer a question, the person can email support at support@onlyx.ai.
> Pages under /developers are the developer documentation. REST API base URL: https://api.onlyx.ai/v1 (authenticate with `Authorization: Bearer <API key>`; keys start with onx_sk_ and are created in app.onlyx.ai under Settings > API & MCP). MCP server: https://mcp.onlyx.ai/mcp (OAuth, or a Bearer API key). In the API the AI chatter is `ai` on the wire. Money is integer US cents in fields ending in Cents; timestamps are UTC ISO-8601.
> Rules for assistants acting on a user's behalf: discover ids with list calls and never invent them; before any call that reaches a real fan or the live OnlyFans account (sending a message, releasing a chat to the AI, turning AI on for a chat, resolving a hand-off, turning review mode off, changing the welcome message, creating a tracking link) show the user the exact content and get explicit confirmation; send every POST with an Idempotency-Key and reuse it on retry; never resend a message whose delivery status is unconfirmed; never ask a creator for her OnlyFans password or codes - she signs in herself through a connect link and the OnlyX Login app.

# Reorder a level's media

> Sets the order of one side of a level: `preview` is the order fans see the teasers, `paid` the unlock order. List the media ids of that side in the order you want; any you leave out follow them in their current order, and an id that is not on that side of the level is a `400`. Returns the whole updated content board. Nothing is sent to fans: the AI uses active ladders in its own conversations. AI content writes are limited to 60 a minute per credential.

**Scope:** requires `ai:write`.

**Rate limits:** 60 changes per 60 seconds per credential — on top of the general limit of 120 requests per 60 seconds per credential.

**Idempotency:** send an `Idempotency-Key` header to make retries safe: a replay within 24 hours returns the original response with `Idempotent-Replayed: true`.



## OpenAPI

````yaml /developers/api-reference/openapi.json put /v1/creators/{creatorId}/ai-content/levels/{levelId}/media/order
openapi: 3.1.0
info:
  contact:
    email: developers@onlyx.ai
    name: OnlyX developers
    url: https://docs.onlyx.ai/
  description: >
    The OnlyX API runs your OnlyX workspace from your own code and AI tools:
    creators and their

    connection, the fan inbox, fans, vault media, statistics, the AI chatter's
    setup and tracking links.


    **Authentication.** Send an API key as `Authorization: Bearer onx_sk_…`
    (create one in OnlyX under

    Settings → API & MCP), or an OAuth access token issued to a connected app.
    Keys belong to the

    workspace, carry scopes, and can be limited to some creators.


    **Conventions.** JSON with camelCase fields; timestamps are ISO-8601 UTC
    with a `Z`; money is integer

    US cents (fields end in `Cents`). Lists return `{"data": [...], "hasMore":
    bool, "nextCursor": string|null}`

    and page with `limit` and `cursor`.


    **Scopes.** Every operation names the scope it needs in `x-required-scope`
    and in its description; a

    credential without it gets `403 INSUFFICIENT_SCOPE`.


    **Errors and limits.** Errors are `{"error": {"code", "message",
    "requestId"}}`; every response

    carries `X-Request-Id`. The default limit is 120 requests per 60 seconds per

    credential, reported in `X-RateLimit-*` headers; over it you get `429
    RATE_LIMITED` with `Retry-After`.

    Operations with limits of their own list them in `x-rate-limits`.


    **Idempotency and safety.** Every write accepts an `Idempotency-Key` header
    (required when sending a

    message, adding a creator and creating a tracking link): retry with the same
    key and you get the

    original answer instead of a second action. Operations marked
    `x-reaches-fans: true` can reach a real

    fan or change the live OnlyFans account.


    Guides, the MCP server and more: [docs.onlyx.ai](https://docs.onlyx.ai).
  summary: >-
    Run your OnlyX workspace (creators, inbox, fans, stats and the AI chatter)
    from code and AI tools.
  title: OnlyX API
  version: 1.0.0
servers:
  - description: Production
    url: https://api.onlyx.ai
security:
  - bearerAuth: []
tags:
  - description: 'Who you are: the workspace and credential behind a key.'
    name: Workspace
  - description: >-
      The creators your workspace manages: list, read, add, rename, and the AI
      switch.
    name: Creators
  - description: >-
      Connecting a creator's OnlyFans account: connect links she opens on her
      own device, and the connection status to poll.
    name: Connect
  - description: >-
      The fan inbox: list and count conversations, read state, take over,
      release, and the per-chat AI switch.
    name: Conversations
  - description: Read message history and send text, free media and paid messages to fans.
    name: Messages
  - description: Conversations the AI chatter handed to your team, and resolving them.
    name: Hand-offs
  - description: >-
      Fans, their purchases, fan lists, and your team's notes, custom names and
      mute flag.
    name: Fans
  - description: >-
      Each creator's OnlyFans vault: media ids for messages and levels, and
      thumbnails.
    name: Media
  - description: >-
      Today, revenue, audience, the cached overview report, and each creator's
      transaction ledger.
    name: Stats
  - description: The brief the AI chatter follows to chat as each creator.
    name: AI persona
  - description: 'The AI content ladder: folders, ladders, priced levels and their media.'
    name: AI content
  - description: >-
      Follow-ups, review mode, the master AI switch, and OnlyFans' welcome
      message.
    name: AI settings
  - description: >-
      OnlyFans tracking and trial links, your cost fields, and creating new
      links.
    name: Tracking links
externalDocs:
  description: OnlyX developer documentation
  url: https://docs.onlyx.ai
paths:
  /v1/creators/{creatorId}/ai-content/levels/{levelId}/media/order:
    put:
      tags:
        - AI content
      summary: Reorder a level's media
      description: >-
        Sets the order of one side of a level: `preview` is the order fans see
        the teasers, `paid` the unlock order. List the media ids of that side in
        the order you want; any you leave out follow them in their current
        order, and an id that is not on that side of the level is a `400`.
        Returns the whole updated content board. Nothing is sent to fans: the AI
        uses active ladders in its own conversations. AI content writes are
        limited to 60 a minute per credential.


        **Scope:** requires `ai:write`.


        **Rate limits:** 60 changes per 60 seconds per credential — on top of
        the general limit of 120 requests per 60 seconds per credential.


        **Idempotency:** send an `Idempotency-Key` header to make retries safe:
        a replay within 24 hours returns the original response with
        `Idempotent-Replayed: true`.
      operationId: reorderLevelMedia
      parameters:
        - description: The creator id (`cre_…`).
          in: path
          name: creatorId
          required: true
          schema:
            description: The creator id (`cre_…`).
            title: Creatorid
            type: string
        - description: The level (set) id (`set_…`).
          in: path
          name: levelId
          required: true
          schema:
            description: The level (set) id (`set_…`).
            title: Levelid
            type: string
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ReorderLevelMediaRequest'
        required: true
      responses:
        '200':
          content:
            application/json:
              example:
                collections:
                  - active: true
                    description: A slow tease that ends in the shower.
                    folderId: fld_1a2b3c4d5e6f7a8b9c0d
                    id: col_2b3c4d5e6f7a8b9c0d1e
                    levelCount: 2
                    mode: sequential
                    name: Shower set
                    position: 1
                creatorId: cre_8f2c1a9b0d7e4c3f2a1b
                folders:
                  - collectionCount: 1
                    id: fld_1a2b3c4d5e6f7a8b9c0d
                    name: Sexting
                    position: 1
                levels:
                  - active: true
                    availableInPaidMessages: true
                    collectionId: col_2b3c4d5e6f7a8b9c0d1e
                    description: Two selfies in a towel.
                    free: true
                    highlight: the one where I get ready
                    id: set_3c4d5e6f7a8b9c0d1e2f
                    name: Opener
                    paid: []
                    position: 1
                    preview:
                      - durationSeconds: null
                        id: '4498297883'
                        thumbnailUrl: >-
                          https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297883/thumbnail
                        type: photo
                    priceCents: 0
                    stats:
                      purchased: 0
                      revenueCents: 0
                      sent: 40
                    tags:
                      - Solo
                      - Teasing
                  - active: true
                    availableInPaidMessages: true
                    collectionId: col_2b3c4d5e6f7a8b9c0d1e
                    description: Four-minute shower video.
                    free: false
                    highlight: null
                    id: set_4d5e6f7a8b9c0d1e2f3a
                    name: Shower video
                    paid:
                      - durationSeconds: 241
                        id: '4498297884'
                        thumbnailUrl: >-
                          https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297884/thumbnail
                        type: video
                    position: 2
                    preview: []
                    priceCents: 1500
                    stats:
                      purchased: 9
                      revenueCents: 13500
                      sent: 31
                    tags:
                      - Shower
                vault:
                  assigned: 3
                  total: 512
                  unassigned: 509
              schema:
                $ref: '#/components/schemas/ContentBoard'
          description: The whole content board after the change.
          headers:
            Idempotent-Replayed:
              $ref: '#/components/headers/Idempotent-Replayed'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '400':
          content:
            application/json:
              examples:
                VALIDATION_ERROR:
                  summary: VALIDATION_ERROR
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: 'role: Field required'
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
                VALIDATION_ERROR_UNKNOWN_MEDIA:
                  summary: VALIDATION_ERROR (not on this side of the level)
                  value:
                    error:
                      code: VALIDATION_ERROR
                      message: >-
                        mediaIds: `4498297886` is not preview media on this
                        level
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
              schema:
                $ref: '#/components/schemas/Error'
          description: >-
            The request is not valid and was not carried out. Fix it before
            retrying. `VALIDATION_ERROR`: the request is not valid; `message`
            names the field and the problem. `VALIDATION_ERROR`: a media id is
            not on that side of the level.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          content:
            application/json:
              examples:
                INSUFFICIENT_SCOPE:
                  summary: INSUFFICIENT_SCOPE
                  value:
                    error:
                      code: INSUFFICIENT_SCOPE
                      message: This key does not have the `ai:write` scope.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
                WORKSPACE_SUSPENDED:
                  summary: WORKSPACE_SUSPENDED
                  value:
                    error:
                      code: WORKSPACE_SUSPENDED
                      message: This workspace is suspended.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
              schema:
                $ref: '#/components/schemas/Error'
          description: >-
            The credential may not do this. `INSUFFICIENT_SCOPE`: the credential
            lacks the `ai:write` scope (the `WWW-Authenticate` header names it;
            an OAuth token's message says "token" instead of "key").
            `WORKSPACE_SUSPENDED`: the workspace is suspended.
          headers:
            WWW-Authenticate:
              $ref: '#/components/headers/WWW-Authenticate'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '404':
          content:
            application/json:
              examples:
                CREATOR_NOT_FOUND:
                  summary: CREATOR_NOT_FOUND
                  value:
                    error:
                      code: CREATOR_NOT_FOUND
                      message: Creator not found.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
                NOT_FOUND_LEVEL:
                  summary: NOT_FOUND (level)
                  value:
                    error:
                      code: NOT_FOUND
                      message: Not found.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
              schema:
                $ref: '#/components/schemas/Error'
          description: >-
            Not found. An id that does not exist, belongs to another workspace,
            or is outside this credential's creators all get the same answer.
            `CREATOR_NOT_FOUND`: no creator with this `creatorId` is visible to
            this credential. `NOT_FOUND`: no level with this id belongs to this
            creator.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '409':
          content:
            application/json:
              examples:
                IDEMPOTENCY_IN_PROGRESS:
                  summary: IDEMPOTENCY_IN_PROGRESS
                  value:
                    error:
                      code: IDEMPOTENCY_IN_PROGRESS
                      message: >-
                        A request with this Idempotency-Key is still being
                        processed. Retry in a few seconds.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
                IDEMPOTENCY_KEY_REUSED:
                  summary: IDEMPOTENCY_KEY_REUSED
                  value:
                    error:
                      code: IDEMPOTENCY_KEY_REUSED
                      message: >-
                        This Idempotency-Key was already used for a different
                        request. Use a new key for a new request.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
              schema:
                $ref: '#/components/schemas/Error'
          description: >-
            The request conflicts with the current state.
            `IDEMPOTENCY_KEY_REUSED`: this `Idempotency-Key` was already used
            for a different request (or by another credential). Use a new key
            for a new request. `IDEMPOTENCY_IN_PROGRESS`: a request with this
            `Idempotency-Key` is still running. Retry in a few seconds with the
            same key.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '429':
          content:
            application/json:
              examples:
                RATE_LIMITED:
                  summary: RATE_LIMITED (general limit)
                  value:
                    error:
                      code: RATE_LIMITED
                      message: Too many requests. Try again in 12 seconds.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
                RATE_LIMITED_1:
                  summary: RATE_LIMITED (60 changes per 60 seconds per credential)
                  value:
                    error:
                      code: RATE_LIMITED
                      message: >-
                        Too many AI content changes: at most 60 a minute per
                        credential. Try again shortly.
                      requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
              schema:
                $ref: '#/components/schemas/Error'
          description: >-
            Over a rate limit (`RATE_LIMITED`): the general limit, or this
            operation's own (60 changes per 60 seconds per credential). Wait
            `Retry-After` seconds, then retry — with the same `Idempotency-Key`
            for a write.
          headers:
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            X-RateLimit-Limit:
              $ref: '#/components/headers/X-RateLimit-Limit'
            X-RateLimit-Remaining:
              $ref: '#/components/headers/X-RateLimit-Remaining'
            X-RateLimit-Reset:
              $ref: '#/components/headers/X-RateLimit-Reset'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
        '500':
          $ref: '#/components/responses/InternalError'
components:
  parameters:
    IdempotencyKey:
      description: >-
        Optional. A unique value (8 to 64 letters, digits, `-` or `_`; a UUID is
        ideal) that makes a retry safe: the same key with the same request
        within 24 hours returns the stored response, with `Idempotent-Replayed:
        true`, instead of doing the work twice. The same key with a different
        request is `409 IDEMPOTENCY_KEY_REUSED`; while the first request still
        runs it is `409 IDEMPOTENCY_IN_PROGRESS`. A malformed key is `400
        VALIDATION_ERROR`.
      example: 3b1f7c2e-9d4a-4e8b-a6c1-5f0d2e7b9a14
      in: header
      name: Idempotency-Key
      required: false
      schema:
        maxLength: 64
        minLength: 8
        pattern: ^[A-Za-z0-9_-]{8,64}$
        type: string
  schemas:
    ReorderLevelMediaRequest:
      additionalProperties: false
      examples:
        - mediaIds:
            - '4498297885'
            - '4498297883'
          role: preview
      properties:
        mediaIds:
          description: >-
            Media ids of that side in the new order; any you leave out follow
            them.
          items:
            description: >-
              An OnlyFans vault media id (a string of digits), or `ox:<id>` for
              an item of an OnlyX library.
            maxLength: 40
            minLength: 1
            type: string
          maxItems: 500
          minItems: 1
          type: array
        role:
          description: Which side of the level to reorder.
          enum:
            - paid
            - preview
          type: string
      required:
        - role
        - mediaIds
      title: ReorderLevelMediaRequest
      type: object
    ContentBoard:
      description: >-
        A creator's whole AI content setup. Every AI content write returns the
        updated board.
      examples:
        - collections:
            - active: true
              description: A slow tease that ends in the shower.
              folderId: fld_1a2b3c4d5e6f7a8b9c0d
              id: col_2b3c4d5e6f7a8b9c0d1e
              levelCount: 2
              mode: sequential
              name: Shower set
              position: 1
          creatorId: cre_8f2c1a9b0d7e4c3f2a1b
          folders:
            - collectionCount: 1
              id: fld_1a2b3c4d5e6f7a8b9c0d
              name: Sexting
              position: 1
          levels:
            - active: true
              availableInPaidMessages: true
              collectionId: col_2b3c4d5e6f7a8b9c0d1e
              description: Two selfies in a towel.
              free: true
              highlight: the one where I get ready
              id: set_3c4d5e6f7a8b9c0d1e2f
              name: Opener
              paid: []
              position: 1
              preview:
                - durationSeconds: null
                  id: '4498297883'
                  thumbnailUrl: >-
                    https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297883/thumbnail
                  type: photo
              priceCents: 0
              stats:
                purchased: 0
                revenueCents: 0
                sent: 40
              tags:
                - Solo
                - Teasing
            - active: true
              availableInPaidMessages: true
              collectionId: col_2b3c4d5e6f7a8b9c0d1e
              description: Four-minute shower video.
              free: false
              highlight: null
              id: set_4d5e6f7a8b9c0d1e2f3a
              name: Shower video
              paid:
                - durationSeconds: 241
                  id: '4498297884'
                  thumbnailUrl: >-
                    https://api.onlyx.ai/v1/creators/cre_8f2c1a9b0d7e4c3f2a1b/media/4498297884/thumbnail
                  type: video
              position: 2
              preview: []
              priceCents: 1500
              stats:
                purchased: 9
                revenueCents: 13500
                sent: 31
              tags:
                - Shower
          vault:
            assigned: 3
            total: 512
            unassigned: 509
      properties:
        collections:
          description: Ladders, by position.
          items:
            $ref: '#/components/schemas/Collection'
          type: array
        creatorId:
          description: The creator this board belongs to.
          type: string
        folders:
          description: Folders, by position.
          items:
            $ref: '#/components/schemas/Folder'
          type: array
        levels:
          description: Every level of every ladder, by ladder and then by rung.
          items:
            $ref: '#/components/schemas/Level'
          type: array
        vault:
          $ref: '#/components/schemas/VaultUsage'
          description: How much of the vault the ladders use.
      required:
        - creatorId
        - folders
        - collections
        - levels
        - vault
      title: ContentBoard
      type: object
    Error:
      properties:
        error:
          properties:
            code:
              description: Stable, machine-readable error code.
              type: string
            message:
              description: What went wrong, in a sentence for a person.
              type: string
            requestId:
              description: >-
                The id of this request (also in the `X-Request-Id` header).
                Quote it to support.
              type: string
          required:
            - code
            - message
            - requestId
          type: object
      required:
        - error
      type: object
    Collection:
      properties:
        active:
          description: '`false` pauses the whole ladder: the AI offers none of its levels.'
          type: boolean
        description:
          anyOf:
            - type: string
            - type: 'null'
          description: The theme, in words the AI can use.
        folderId:
          anyOf:
            - type: string
            - type: 'null'
          description: The folder it is filed in, or `null`.
        id:
          description: The ladder id (`col_…`).
          type: string
        levelCount:
          description: Levels in this ladder.
          type: integer
        mode:
          description: >-
            `sequential`: the AI offers each fan the first level they have not
            bought, and never skips ahead. `standard`: the AI may offer any
            level whenever it fits the conversation.
          enum:
            - sequential
            - standard
          type: string
        name:
          type: string
        position:
          description: Order on the board, from 1.
          type: integer
      required:
        - id
        - folderId
        - name
        - mode
        - description
        - active
        - position
        - levelCount
      title: Collection
      type: object
    Folder:
      properties:
        collectionCount:
          description: Ladders in this folder.
          type: integer
        id:
          description: The folder id (`fld_…`).
          type: string
        name:
          type: string
        position:
          description: Order on the board, from 1.
          type: integer
      required:
        - id
        - name
        - position
        - collectionCount
      title: Folder
      type: object
    Level:
      properties:
        active:
          description: '`false` pauses this level.'
          type: boolean
        availableInPaidMessages:
          description: '`false` keeps the level on the board but out of chats.'
          type: boolean
        collectionId:
          description: The ladder it belongs to.
          type: string
        description:
          anyOf:
            - type: string
            - type: 'null'
          description: What is in it, in words the AI can use.
        free:
          description: >-
            `true` when the level is free: everything on it is given away as
            preview media.
          type: boolean
        highlight:
          anyOf:
            - type: string
            - type: 'null'
          description: A hook line the AI can lead with.
        id:
          description: The level id (`set_…`).
          type: string
        name:
          anyOf:
            - type: string
            - type: 'null'
          description: What your team calls it.
        paid:
          description: Media locked behind the price, in unlock order.
          items:
            $ref: '#/components/schemas/ContentMedia'
          type: array
        position:
          description: >-
            Its rung in the ladder, from 1. In a sequential ladder, the order
            fans climb.
          type: integer
        preview:
          description: Free teaser media, in the order fans see it.
          items:
            $ref: '#/components/schemas/ContentMedia'
          type: array
        priceCents:
          description: >-
            The floor price in cents: the AI may sell higher, never lower. `0`
            makes the level free.
          type: integer
        stats:
          $ref: '#/components/schemas/LevelStats'
          description: 'AI-attributed: what the AI chatter offered and sold from this level.'
        tags:
          description: Tags matched against what fans talk about.
          items:
            type: string
          type: array
      required:
        - id
        - collectionId
        - name
        - position
        - priceCents
        - free
        - tags
        - highlight
        - description
        - availableInPaidMessages
        - active
        - stats
        - preview
        - paid
      title: Level
      type: object
    VaultUsage:
      properties:
        assigned:
          description: Items placed on a level.
          type: integer
        total:
          description: Items in her vault.
          type: integer
        unassigned:
          description: Items not on any level yet.
          type: integer
      required:
        - total
        - assigned
        - unassigned
      title: VaultUsage
      type: object
    ContentMedia:
      properties:
        durationSeconds:
          anyOf:
            - type: integer
            - type: 'null'
          description: Length of a video or audio item, when known.
        id:
          description: >-
            An OnlyFans vault media id (a string of digits), or `ox:<id>` for an
            item of an OnlyX library.
          type: string
        thumbnailUrl:
          anyOf:
            - type: string
            - type: 'null'
          description: >-
            API URL of a small preview image (needs your credential with
            `media:read`); `null` when none is available.
        type:
          anyOf:
            - enum:
                - photo
                - video
                - gif
                - audio
              type: string
            - type: 'null'
          description: The media type, when known.
      required:
        - id
        - type
        - durationSeconds
        - thumbnailUrl
      title: ContentMedia
      type: object
    LevelStats:
      description: >-
        Sales by the AI chatter only: offers and sales your team made are not
        counted here.
      properties:
        purchased:
          description: Times fans bought it from the AI.
          type: integer
        revenueCents:
          description: What those AI sales earned, in cents.
          type: integer
        sent:
          description: Times the AI offered it.
          type: integer
      required:
        - sent
        - purchased
        - revenueCents
      title: LevelStats
      type: object
  headers:
    Idempotent-Replayed:
      description: >-
        `true` when this response is the stored answer to an earlier request
        with the same `Idempotency-Key`: nothing was done again. Absent on a
        first answer.
      schema:
        enum:
          - 'true'
        type: string
    X-RateLimit-Limit:
      description: >-
        Requests allowed in the current window of the tightest limit this
        request counted against.
      example: 120
      schema:
        type: integer
    X-RateLimit-Remaining:
      description: Requests left in that window.
      example: 117
      schema:
        type: integer
    X-RateLimit-Reset:
      description: When that window resets, as Unix epoch seconds.
      example: 1790431380
      schema:
        type: integer
    X-Request-Id:
      description: >-
        The id of this request. Your own `X-Request-Id` (8 to 64 letters, digits
        or `-`) is echoed back; otherwise OnlyX creates one. Also in every error
        body as `requestId`: quote it to support.
      example: req-3f9a1c2b7d4e5f60a1b2c3d4
      schema:
        type: string
    WWW-Authenticate:
      description: >-
        The authentication challenge (RFC 6750), for example `Bearer
        error="insufficient_scope", scope="messages:send"`.
      schema:
        type: string
    Retry-After:
      description: Seconds to wait before trying again.
      example: 12
      schema:
        type: integer
  responses:
    Unauthorized:
      content:
        application/json:
          examples:
            INVALID_API_KEY:
              summary: INVALID_API_KEY
              value:
                error:
                  code: INVALID_API_KEY
                  message: The API key is invalid, expired or revoked.
                  requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
            INVALID_TOKEN:
              summary: INVALID_TOKEN
              value:
                error:
                  code: INVALID_TOKEN
                  message: The access token is invalid, expired or revoked.
                  requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
            UNAUTHORIZED:
              summary: UNAUTHORIZED
              value:
                error:
                  code: UNAUTHORIZED
                  message: >-
                    Authentication required. Send your API key as
                    `Authorization: Bearer onx_sk_…`.
                  requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
          schema:
            $ref: '#/components/schemas/Error'
      description: >-
        No credential was sent (`UNAUTHORIZED`), or it is invalid, expired or
        revoked (`INVALID_API_KEY` for API keys, `INVALID_TOKEN` for OAuth
        access tokens: refresh the token or reconnect the app). Too many failed
        attempts from one address with credentials OnlyX never issued are
        answered `429 RATE_LIMITED` instead.
      headers:
        WWW-Authenticate:
          $ref: '#/components/headers/WWW-Authenticate'
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
    InternalError:
      content:
        application/json:
          examples:
            INTERNAL_ERROR:
              summary: INTERNAL_ERROR
              value:
                error:
                  code: INTERNAL_ERROR
                  message: Something went wrong on our side.
                  requestId: req-3f9a1c2b7d4e5f60a1b2c3d4
          schema:
            $ref: '#/components/schemas/Error'
      description: >-
        Something went wrong on OnlyX's side (`INTERNAL_ERROR`). Retry with
        backoff (reuse the `Idempotency-Key` for a write); quote `requestId` to
        support if it persists.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/X-Request-Id'
  securitySchemes:
    bearerAuth:
      bearerFormat: onx_sk_… API key or onx_at_… access token
      description: >-
        An API key (`onx_sk_…`) created in OnlyX under Settings → API & MCP, or
        an OAuth access token (`onx_at_…`) issued to a connected app. Send it as
        `Authorization: Bearer <credential>`. API keys may also be sent as
        `X-API-Key: <key>`.
      scheme: bearer
      type: http

````