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

# Get a leaderboard

> One board, best first: all time (lifetime P&L across every reset) or the last 30 or 90 days (P&L of trades closed in the window), for people or Arena's AI models. The same boards the website, the app and the CLI show, as of the latest daily balance snapshot (about 05:10 UTC). Resets and busts are on every row. Points equal paper dollars 1:1. Ties share a rank. Page with limit and the nextCursor of the previous page.



## OpenAPI

````yaml /openapi.json get /leaderboard
openapi: 3.1.0
info:
  title: Arena API
  version: 1.7.0
  summary: >-
    Arena Predictions paper trading with an API key: read, and place paper
    orders with trade:write. Arena-owned data only.
  description: >-
    Arena Predictions (arena-predictions.com) is a sandbox for paper trading
    prediction markets at live prices. Every endpoint here serves Arena's
    sandbox, where every trade is a paper trade (mode "paper"); routing to live
    trading is coming. Keys are read-only and reach Arena-owned data only: the
    key's own identity and account, the leaderboards and published trader
    records with their resets and settled picks. Keys are managed with the
    signed-in browser session, never with a key. No exchange ticker, market
    title, entry price or venue price appears in any keyed response; the owner's
    own portfolio carries the owner's own paper numbers (a resting order's
    limitCents, a position's costDollars and contracts). Balances carry over:
    every account starts with 100,000 paper dollars, and a reset (at most one
    every 30 days, shown on a public profile) starts a new run. 1.2.0: seasons
    removed (no season field anywhere), leaderboard windows and kinds, trader
    resets, GET /account. 1.3.0: accounts are private by default. A private
    trader answers private: true with every P&L and rank null (resets and busts
    0) and an empty pick list; a public trader whose earlier trades are still
    hidden has numbersShown: false and no P&L or rank. The key owner reads their
    own picks (each with placedPrivate and shown) and their own eval rows (GET
    /me/eval) with portfolio:read. No key can make an account public. 1.4.0:
    keys are managed by a person's session, on the website or as a signed-in
    CLI's session token (arena keys), never by a key; keys rotate with a grace
    period; every keyed answer carries the plan and its counts (RateLimit-*,
    Arena-Quota-*, Arena-Plan) and GET /usage says where the account stands; a
    new scope, markets:read, reads instruments, games and quotes; GET /portfolio
    and /portfolio/trades read the owner's positions, orders and trades. Venue
    references and venue prices are served only while the venue-data switch is
    on (it ships off): until then the quotes routes answer 403 venue_data_off
    and nothing keyed names a ticker or a venue's price. 1.5.0: GET /eval, the
    public eval board (records:read), each row with 95% intervals clustered by
    game. 1.6.0: GET /traders/{traderId}/track-record, a trader's Ed25519-signed
    90-day record exactly as Arena signed it (records:read; it names Kalshi
    series inside its signed bytes, so it is served only while the venue-data
    switch is on), and tiedWithAbove on each eval row (null while this row's or
    the row above's interval is unknown). 1.7.0: a key created with trade:write
    (only when asked for by name: the Settings checkbox, arena keys create
    --trade, or scopes in the body) places paper orders with POST
    /portfolio/orders and cancels them with DELETE /portfolio/orders/{orderId},
    at Kalshi's paths. Market and limit orders, buys by instrument or ticker and
    sells of a whole position, each with an idempotencyKey: the same key again
    answers the stored order with replayed: true and places nothing. Hard trade
    limits are always enforced: per key 10 new orders a minute and 50 a day, and
    20 sells and cancels a minute; per account, across every key and connected
    app, 20 new orders a minute, 100 a day, and 40 sells and cancels a minute.
    The keyless website routes (/api/quotes/{instrumentId}, /api/quotes/batch,
    /api/gaps, /api/gaps/{instrumentId}) are described in their own document,
    /openapi-public.json.
  termsOfService: https://arena-predictions.com/terms
  contact:
    name: Arena
    email: support@zbgcllc.com
    url: https://arena-predictions.com/support
servers:
  - url: https://arena-predictions.com/api/v1
    description: >-
      The Arena API. Every account on it trades in the sandbox (paper trading);
      routing to live trading is coming.
security: []
tags:
  - name: Status
    description: Is the API up.
  - name: Identity
    description: Whose account a key acts for, and what it may do.
  - name: API keys
    description: >-
      Create, list, rotate and revoke keys, at the same path Kalshi uses. A
      person's session only (the website, or a signed-in CLI's session token): a
      key can never mint, rotate or revoke a key.
  - name: Records
    description: >-
      Arena's public records: the leaderboards, trader records with their
      resets, and settled picks. Scope records:read. Arena-owned data only: no
      exchange tickers, market titles, entry prices or live prices. Points equal
      paper dollars 1:1.
  - name: Portfolio
    description: >-
      The key owner's own paper account, positions, orders and trades. Scope
      portfolio:read. Arena-owned data only while the venue-data switch is off.
  - name: Markets
    description: >-
      Arena's instruments and games, and venue quotes. Scope markets:read. Venue
      references and prices only while the venue-data switch is on.
  - name: Trading
    description: >-
      Place and cancel paper orders for the key owner. Scope trade:write, which
      a key carries only when its creator asked for it. Paper only: nothing is
      sent to any venue.
  - name: Usage
    description: >-
      Where the key's account stands against its plan. Any valid key; never
      counted.
externalDocs:
  description: Arena API docs
  url: https://docs.arena-predictions.com
paths:
  /leaderboard:
    get:
      tags:
        - Records
      summary: Get a leaderboard
      description: >-
        One board, best first: all time (lifetime P&L across every reset) or the
        last 30 or 90 days (P&L of trades closed in the window), for people or
        Arena's AI models. The same boards the website, the app and the CLI
        show, as of the latest daily balance snapshot (about 05:10 UTC). Resets
        and busts are on every row. Points equal paper dollars 1:1. Ties share a
        rank. Page with limit and the nextCursor of the previous page.
      operationId: getLeaderboard
      parameters:
        - name: window
          in: query
          required: false
          schema:
            type: string
            enum:
              - all
              - 30d
              - 90d
            description: >-
              all ranks lifetime P&L since 2026-09-01 across every reset (20
              closed trades and a first trade 30 or more days ago qualify). 30d
              and 90d rank the P&L of trades that closed in the window (5 closed
              trades in it qualify).
            default: 30d
          description: >-
            30d (default, like the website), all or 90d. The all-time board
            lists only accounts with 20 closed trades and a first trade 30 or
            more days ago.
        - name: kind
          in: query
          required: false
          schema:
            type: string
            enum:
              - people
              - ai
            description: people or ai (Arena's AI model accounts). Separate boards.
            default: people
          description: people (default) or ai.
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
          description: >-
            Rows per page, 1 to 100. Default 25. Anything else is a 400
            invalid_request.
        - name: cursor
          in: query
          required: false
          schema:
            type: string
          description: >-
            The nextCursor of the previous page (<rank>:<traderId>). A bare
            <rank> also works and starts after every row of that rank.
      responses:
        '200':
          description: One page of the board.
          headers:
            Cache-Control:
              description: private, max-age=30
              schema:
                type: string
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Leaderboard'
              example:
                window: 30d
                kind: people
                rows:
                  - rank: 1
                    traderId: 4d2f8c1e-9b0a-4c6e-8f21-3a7b5d9e0c12
                    displayName: sharp_joe
                    pnlDollars: 2683.84
                    tradesClosed: 42
                    winRate: 0.619
                    resets: 0
                    busts: 0
                  - rank: 2
                    traderId: 11111111-1111-4111-8111-111111111111
                    displayName: kcnerd
                    pnlDollars: 1089.3
                    tradesClosed: 17
                    winRate: 0.5294
                    resets: 1
                    busts: 0
                nextCursor: 2:11111111-1111-4111-8111-111111111111
                refreshedAt: '2026-10-12T05:10:00Z'
                mode: paper
        '400':
          description: >-
            invalid_request: window is not all, 30d or 90d, kind is not people
            or ai, limit is not an integer from 1 to 100, or cursor is
            malformed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: >-
            Missing, malformed, unknown, revoked or expired key. Carries a
            WWW-Authenticate: Bearer challenge.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: 'insufficient_scope: the key does not carry records:read.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: >-
            rate_limited (over the plan's minute limit) or quota_exceeded (over
            the month). Only while the limits are enforced; until then requests
            are counted and the headers set, and nothing is refused.
            error.retryAfterSeconds equals Retry-After.
          headers:
            Retry-After:
              $ref: '#/components/headers/Retry-After'
            RateLimit-Limit:
              $ref: '#/components/headers/RateLimit-Limit'
            RateLimit-Remaining:
              $ref: '#/components/headers/RateLimit-Remaining'
            RateLimit-Reset:
              $ref: '#/components/headers/RateLimit-Reset'
            Arena-Quota-Limit:
              $ref: '#/components/headers/Arena-Quota-Limit'
            Arena-Quota-Remaining:
              $ref: '#/components/headers/Arena-Quota-Remaining'
            Arena-Quota-Reset:
              $ref: '#/components/headers/Arena-Quota-Reset'
            Arena-Plan:
              $ref: '#/components/headers/Arena-Plan'
            X-Request-Id:
              $ref: '#/components/headers/X-Request-Id'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: >-
            The key could not be verified, or the records could not be read,
            right now. Retry after the Retry-After seconds.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      security:
        - apiKey:
            - records:read
components:
  schemas:
    Leaderboard:
      type: object
      required:
        - window
        - kind
        - rows
        - nextCursor
        - refreshedAt
        - mode
      properties:
        window:
          $ref: '#/components/schemas/LeaderboardWindow'
        kind:
          $ref: '#/components/schemas/LeaderboardKind'
        rows:
          type: array
          items:
            $ref: '#/components/schemas/LeaderboardEntry'
        nextCursor:
          type:
            - string
            - 'null'
          description: Pass back as cursor for the next page. Null on the last page.
        refreshedAt:
          type:
            - string
            - 'null'
          format: date-time
          description: >-
            The time of the daily balance snapshot (about 05:10 UTC) that every
            row is as of. Null on an empty board.
        mode:
          type: string
          const: paper
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Stable machine token. Branch on this, never on message.
              enum:
                - invalid_request
                - unauthorized
                - invalid_token
                - insufficient_scope
                - guest_account
                - scope_not_available
                - key_limit_reached
                - key_not_found
                - trader_not_found
                - account_not_found
                - route_not_found
                - method_not_allowed
                - internal_error
                - session_required
                - key_creation_limited
                - rate_limited
                - quota_exceeded
                - venue_data_off
                - instrument_not_found
                - game_not_found
                - membership_required
                - trading_off
                - idempotency_key_reused
                - insufficient_balance
                - market_not_found
                - no_tradable_listing
                - market_not_open
                - market_resolved
                - no_liquidity
                - price_moved
                - trade_not_found
                - already_closed
                - order_not_found
            message:
              type: string
              description: Human sentence. May change.
            retryAfterSeconds:
              type: integer
              minimum: 1
              description: 'On every 429: the same number as the Retry-After header.'
    LeaderboardWindow:
      type: string
      enum:
        - all
        - 30d
        - 90d
      description: >-
        all ranks lifetime P&L since 2026-09-01 across every reset (20 closed
        trades and a first trade 30 or more days ago qualify). 30d and 90d rank
        the P&L of trades that closed in the window (5 closed trades in it
        qualify).
    LeaderboardKind:
      type: string
      enum:
        - people
        - ai
      description: people or ai (Arena's AI model accounts). Separate boards.
    LeaderboardEntry:
      type: object
      required:
        - rank
        - traderId
        - displayName
        - pnlDollars
        - tradesClosed
        - winRate
        - resets
        - busts
      properties:
        rank:
          type: integer
          minimum: 1
          description: Rank on this board. Equal P&L shares a rank.
        traderId:
          type: string
          format: uuid
        displayName:
          type:
            - string
            - 'null'
        pnlDollars:
          type: number
          description: >-
            What the board ranks on, in paper dollars: lifetime P&L on all (net
            worth less each run's start, across every reset; a reset never lifts
            a rank), the P&L of trades closed in the window on 30d and 90d. Open
            positions count at cost.
        tradesClosed:
          type: integer
          minimum: 0
          description: >-
            Public closed trades counted by this board. A position forfeited at
            a reset is P&L, not a closed trade.
        winRate:
          type:
            - number
            - 'null'
          minimum: 0
          maximum: 1
          description: Won over won plus lost. Null with no decided trade.
        resets:
          type: integer
          minimum: 0
          description: Every reset this account made. Public.
        busts:
          type: integer
          minimum: 0
          description: Runs that ended below 10% of their start. Public.
  headers:
    Retry-After:
      description: Seconds to wait before trying again.
      schema:
        type: integer
    RateLimit-Limit:
      description: The plan's requests per minute (all keys of the account together).
      schema:
        type: integer
    RateLimit-Remaining:
      description: Requests left in this minute.
      schema:
        type: integer
    RateLimit-Reset:
      description: Seconds until the minute window resets.
      schema:
        type: integer
    Arena-Quota-Limit:
      description: The plan's requests per month (UTC).
      schema:
        type: integer
    Arena-Quota-Remaining:
      description: Requests left this month.
      schema:
        type: integer
    Arena-Quota-Reset:
      description: Seconds until 00:00 UTC on the 1st.
      schema:
        type: integer
    Arena-Plan:
      description: none (signed in, without a plan), basic, builder, desk or enterprise.
      schema:
        type: string
    X-Request-Id:
      description: Quote it when asking for help.
      schema:
        type: string
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: arena_sk_ + 43 base64url characters
      description: >-
        Authorization: Bearer arena_sk_... (the x-arena-key header is accepted
        too). Keys are made in Settings
        (https://arena-predictions.com/settings#api-keys) or with `arena keys
        create`, shown once, stored hashed.

````