BASE167 Games API

The Games API from BASE167 — 8 operation(s) for games.

Operations 8

POST /api/games/claim-entry Get a voucher to mint this season's Entry pass #
POST /api/games/enroll Register a competition wallet against an Entry pass #
POST /api/games/claim-winner Get a voucher to mint a rank-stamped Winner badge #
POST /api/games/set-name Set or clear the display name shown against a wallet #
POST /api/games/set-handle Set or clear the X handle shown against a wallet #
GET /api/games/leaderboard The live standings, top holders and the collector board #
GET /api/games/results Published final results for every completed season #
GET /api/games/state Season, phase, config and boards #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/base167-com:base167-com-games-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

base167-com-games-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: BASE167 Games API
  version: 1.0.0
  summary: Claim BASE167 and take part in Degen Games without a browser.
  description: 'Every write action follows one shape: POST a wallet address, receive a short-lived server-signed voucher plus ready-to-send calldata in `call`, then submit one transaction from that wallet. No login, session, cookie or CAPTCHA. Vouchers bind msg.sender, so the sending wallet must be the wallet the voucher was issued for. Prizes have no claim function and are paid manually. There is also a remote MCP server at https://base167.com/mcp exposing these same actions as named tools, with no API key and no OAuth.'
servers:
- url: https://base167.com
tags:
- name: Games
paths:
  /api/games/claim-entry:
    post:
      operationId: claimEntry
      summary: Get a voucher to mint this season's Entry pass
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - address
              properties:
                address:
                  $ref: '#/components/schemas/Address'
      responses:
        '200':
          description: Eligibility result, with a voucher and prepared call when eligible. Outside the Pass window (any phase other than seatMarket or setup) this returns eligible:false with the phase, not an error.
          content:
            application/json:
              schema:
                type: object
                required:
                - eligible
                properties:
                  eligible:
                    type: boolean
                  reason:
                    type: string
                  season:
                    type: integer
                  signature:
                    $ref: '#/components/schemas/Hex'
                  expiry:
                    type: integer
                  call:
                    $ref: '#/components/schemas/PreparedCall'
                  alreadyClaimed:
                    type: boolean
                    description: True when this wallet already holds this season's Entry pass. No voucher is issued; a second claim would revert AlreadyClaimed.
                  phase:
                    type: string
                    enum:
                    - pre
                    - seatMarket
                    - setup
                    - preGame
                    - game
                    - settled
                    description: The season phase this answer was computed in. Passes are claimable only in seatMarket and setup.
                  opensAt:
                    type: integer
                    description: Unix seconds at which the Entry pass window opens. Present only in phase 'pre', where the window is still ahead.
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          description: The snapshot for this season has not been taken yet.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      tags:
      - Games
  /api/games/enroll:
    post:
      operationId: enroll
      summary: Register a competition wallet against an Entry pass
      description: 'Only during the setup phase. Any wallet may be enrolled, including a smart account, and prior history is fine. What is enforced is the balance at the opening bell: at least $5 USDC, at most 0.0002 ETH of gas, and nothing else of value. Scoring counts USDC only, so an unscored asset sold mid-season would read as profit.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - player
              - gameWallet
              properties:
                player:
                  $ref: '#/components/schemas/Address'
                gameWallet:
                  $ref: '#/components/schemas/Address'
      responses:
        '200':
          description: Voucher and prepared call for SeasonFactory.enroll.
          content:
            application/json:
              schema:
                type: object
                required:
                - ok
                - season
                - tokenId
                - signature
                - expiry
                - call
                properties:
                  ok:
                    const: true
                  season:
                    type: integer
                  tokenId:
                    type: integer
                  signature:
                    $ref: '#/components/schemas/Hex'
                  expiry:
                    type: integer
                  call:
                    $ref: '#/components/schemas/PreparedCall'
        '400':
          $ref: '#/components/responses/BadRequest'
        '403':
          description: 'The player holds no Entry pass for this season. IMPORTANT: ownership is read at the chain''s `safe` block, which trails the head by roughly 15-35 blocks (about 30-60 seconds on Base). A pass minted moments ago is therefore not visible yet, and this 403 is expected and temporary -- wait for the safe tag to pass your mint and retry rather than treating it as final.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Enrolment window closed, or the competition wallet belongs to another player.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: The competition wallet was rejected on a rule. Enrolment does NOT reject a wallet for having code or a history; the balance rule is enforced later, at the opening bell.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      tags:
      - Games
  /api/games/claim-winner:
    post:
      operationId: claimWinner
      summary: Get a voucher to mint a rank-stamped Winner badge
      description: 'Mints an NFT only. It moves no value: prize payouts are manual and have no claim function.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - address
              properties:
                address:
                  $ref: '#/components/schemas/Address'
      responses:
        '200':
          description: Eligibility result, with rank, voucher and prepared call when eligible.
          content:
            application/json:
              schema:
                type: object
                required:
                - eligible
                properties:
                  eligible:
                    type: boolean
                  season:
                    type: integer
                  rank:
                    type: integer
                  signature:
                    $ref: '#/components/schemas/Hex'
                  expiry:
                    type: integer
                  call:
                    $ref: '#/components/schemas/PreparedCall'
        '400':
          $ref: '#/components/responses/BadRequest'
        '409':
          description: Final results are not published yet.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
      tags:
      - Games
  /api/games/set-name:
    post:
      operationId: setName
      summary: Set or clear the display name shown against a wallet
      description: 'Off-chain: this stores a label on our server and sends no transaction, so there is no prepared call. The caller signs a plain text message with the wallet being named. Smart-contract wallets are supported (ERC-1271, ERC-6492 for counterfactual accounts, ERC-8010 for 7702-delegated EOAs), so a Base Account works. Send an empty name to clear it.


        The message must byte-match exactly:


        Set my Degen Games name to: {name}

        Domain: base167.com Degen Games

        Expires: {expiry}


        {name} is the trimmed name, {expiry} is unix seconds. Expiry must be in the future and no more than 900 seconds ahead. Sign it as a personal_sign / EIP-191 message, the same string, with no extra whitespace or trailing newline.


        A name ending in .eth must be one the wallet actually resolves to, or the request is a 403.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - address
              - name
              - signature
              - expiry
              properties:
                address:
                  $ref: '#/components/schemas/Address'
                name:
                  type: string
                  description: Trimmed display name. Empty string clears it.
                signature:
                  $ref: '#/components/schemas/Hex'
                expiry:
                  $ref: '#/components/schemas/SignatureExpiry'
      responses:
        '200':
          description: The name was stored.
          content:
            application/json:
              schema:
                type: object
                required:
                - ok
                - name
                properties:
                  ok:
                    const: true
                  name:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/BadSignature'
        '403':
          description: The name is a Basename or ENS name this wallet does not own.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: The name failed the content rules (length, characters, or a blocked word).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/VerifyUnavailable'
      tags:
      - Games
  /api/games/set-handle:
    post:
      operationId: setHandle
      summary: Set or clear the X handle shown against a wallet
      description: 'Identical in shape to set-name, and equally off-chain: no transaction, no prepared call. The signed message uses a DIFFERENT prefix on purpose, so a signature captured for one action can never be replayed as the other.


        The message must byte-match exactly:


        Set my Degen Games X handle to: {handle}

        Domain: base167.com Degen Games

        Expires: {expiry}


        {handle} is the trimmed handle, {expiry} is unix seconds, valid for at most 900 seconds. Send an empty handle to clear it.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - address
              - handle
              - signature
              - expiry
              properties:
                address:
                  $ref: '#/components/schemas/Address'
                handle:
                  type: string
                  description: Trimmed X handle. Empty string clears it.
                signature:
                  $ref: '#/components/schemas/Hex'
                expiry:
                  $ref: '#/components/schemas/SignatureExpiry'
      responses:
        '200':
          description: The handle was stored.
          content:
            application/json:
              schema:
                type: object
                required:
                - ok
                - handle
                properties:
                  ok:
                    const: true
                  handle:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/BadSignature'
        '422':
          description: The handle failed the content rules.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/VerifyUnavailable'
      tags:
      - Games
  /api/games/leaderboard:
    get:
      operationId: getLeaderboard
      summary: The live standings, top holders and the collector board
      description: 'The live or final standings, plus the top holders and the live collector board. Two different freshness facts apply and should not be conflated: the response is cached for 60 seconds, while the holder snapshot behind `updatedAt` is refreshed daily by a scheduled job and can be up to a day old. Available whether or not a season is running, which is why the standalone leaderboard page is always live.'
      responses:
        '200':
          description: Standings, holders and collectors, each enriched with a resolved identity.
          content:
            application/json:
              schema:
                type: object
                required:
                - updatedAt
                - holders
                - collectors
                - standings
                properties:
                  updatedAt:
                    type: integer
                    description: Unix seconds the holder snapshot was taken. Refreshed daily by a scheduled job, so this can be up to a day old -- it is not the 60-second response cache. 0 means no snapshot exists yet.
                  holders:
                    type: array
                    items:
                      $ref: '#/components/schemas/BoardRow'
                  collectors:
                    type: array
                    items:
                      $ref: '#/components/schemas/BoardRow'
                  standings:
                    type:
                    - object
                    - 'null'
                    description: Live or final scores -- the same board /api/games/state returns, ranked by percentage gain. Null until the opening bell has passed and the first scoring run has completed, which is normal and not an error. A final board appears here only once it has been published.
      tags:
      - Games
  /api/games/results:
    get:
      operationId: getResults
      summary: Published final results for every completed season
      description: A season appears here only after its final results are published. An empty list is the normal answer before the first season ends, not an error. Winner entries carry a rank and the badge that can be minted for it -- they do not carry a prize amount, because prizes are paid manually and have no claim function.
      responses:
        '200':
          description: Every published season, newest first.
          content:
            application/json:
              schema:
                type: object
                required:
                - seasons
                properties:
                  seasons:
                    type: array
                    items:
                      type: object
      tags:
      - Games
  /api/games/state:
    get:
      operationId: getState
      summary: Season, phase, config and boards
      description: 'The live source for anything that changes: never cache these values in a static file.'
      responses:
        '200':
          description: Current season state.
          content:
            application/json:
              schema:
                type: object
                properties:
                  season:
                    type: integer
                  phase:
                    type: object
                    properties:
                      phase:
                        type: string
                        enum:
                        - pre
                        - seatMarket
                        - setup
                        - preGame
                        - game
                        - settled
                        description: 'pre: before the snapshot. seatMarket: snapshot taken, Entry passes claimable and tradeable. setup: the enrolment and funding window. preGame: enrolment closed, waiting for the opening bell. game: trading, between the bells. settled: the closing bell has passed.'
                      nextBoundary:
                        type: integer
                        description: Unix seconds at which the phase changes next.
                    description: Where the season is right now. Read this rather than comparing the timestamps yourself. The six values are the ones the server actually emits -- until 2026-08-29 this schema published pre/setup/live/final, of which only two existed, so an agent branching on 'live' or 'final' never matched.
                  config:
                    $ref: '#/components/schemas/SeasonConfig'
                  holders:
                    type: array
                    items:
                      $ref: '#/components/schemas/BoardRow'
                    description: The holder snapshot for this season, ranked. Present once the snapshot has been taken; trimmed to displayHolders rows, which is a DISPLAY bound and not the eligibility bound (topHolders).
                  enrolled:
                    type:
                    - object
                    - 'null'
                    description: Who has registered a competition wallet. Null before enrolment opens.
                    properties:
                      total:
                        type: integer
                        description: Everyone enrolled, not just the rows returned.
                      rows:
                        type: array
                        items:
                          $ref: '#/components/schemas/BoardRow'
                        description: 'Trimmed to displayRoster: every row costs an eth_call on a cache miss.'
                  collectors:
                    type: array
                    items:
                      $ref: '#/components/schemas/BoardRow'
                    description: 'The collector board: current Entry pass holders, ranked by pass count then BASE167 balance. finalsCollectorSeats Finals seats are drawn from it.'
                  leaderboard:
                    type:
                    - object
                    - 'null'
                    description: Live or final scores. Null until the opening bell has passed and the first scoring run has completed -- which is normal, not an error.
      tags:
      - Games
components:
  schemas:
    SignatureExpiry:
      type: integer
      description: Unix seconds. Must be in the future and at most 900 seconds ahead; the same value must appear in the signed message. It bounds the replay window, which is why an unbounded expiry is rejected rather than ignored.
    Error:
      type: object
      required:
      - error
      properties:
        error:
          type: string
    Address:
      type: string
      pattern: ^0x[a-fA-F0-9]{40}$
      description: A mixed-case address MUST carry a valid EIP-55 checksum; an all-lowercase address is always accepted. A correctly-shaped address with a bad checksum returns 400 BAD_CHECKSUM.
    Hex:
      type: string
      pattern: ^0x[a-fA-F0-9]*$
    BoardRow:
      type: object
      description: One ranked wallet. `identity` carries the resolved display name, Basename or X handle where one is known.
      required:
      - address
      properties:
        address:
          $ref: '#/components/schemas/Address'
        identity:
          type: object
    PreparedCall:
      type: object
      description: A ready-to-send transaction. Submit it from the same wallet the voucher was issued for; the contract binds msg.sender.
      required:
      - chainId
      - to
      - data
      - value
      properties:
        chainId:
          type: integer
          const: 8453
        to:
          $ref: '#/components/schemas/Address'
        data:
          allOf:
          - $ref: '#/components/schemas/Hex'
          description: 'Calldata for the action, with an ERC-8021 builder-code suffix appended after the ABI arguments. The suffix is data the contracts ignore -- it attributes the transaction to base167 on Base''s builder dashboard -- and every action built here carries it, whether it came from the browser, this API or the MCP server. Send the bytes EXACTLY as given: re-encoding the call from its arguments drops the suffix, and trimming it changes nothing else about what the transaction does.'
        value:
          type: string
          const: '0x0'
    SeasonConfig:
      type: object
      description: The season's settings and addresses. Everything that decides WHO may enter and WHEN. Until 2026-08-29 this was published as a bare {"type":"object"}, so the single richest object in the API was undocumented. Timestamps are unix seconds; amounts are raw integer strings in the token's own decimals, never floats.
      properties:
        season:
          type: integer
          description: Season number. Seasons are sequential and only one is current.
        chainId:
          type: integer
          const: 8453
          description: Base mainnet.
        base167:
          $ref: '#/components/schemas/Address'
          description: The BASE167 token.
        factory:
          $ref: '#/components/schemas/Address'
          description: 'SeasonFactory: claimEntry, enroll and claimWinner all target this.'
        entryNFT:
          $ref: '#/components/schemas/Address'
          description: This season's Entry pass (ERC-721).
        winnersNFT:
          $ref: '#/components/schemas/Address'
          description: This season's Winner badge (ERC-721). Minting one moves no value.
        usdc:
          $ref: '#/components/schemas/Address'
          description: The USDC contract scoring is measured in.
        entryMarketplaceUrl:
          type: string
          description: Where Entry passes can be bought or sold during seatMarket.
        exclusions:
          type: array
          items:
            $ref: '#/components/schemas/Address'
          description: 'Addresses removed from the holder snapshot by design: the treasury, the burn address, the token itself and the liquidity pool.'
        snapshotAt:
          type: integer
          description: Unix seconds. The holder snapshot is taken; the Entry pass becomes claimable.
        enrollOpenAt:
          type: integer
          description: Unix seconds. Enrolment opens.
        enrollCloseAt:
          type: integer
          description: Unix seconds. Enrolment closes.
        openingBellAt:
          type: integer
          description: Unix seconds. Trading starts and the competition wallet is judged on its balances.
        closingBellAt:
          type: integer
          description: Unix seconds. Trading ends; scoring and publication follow.
        snapshotBlock:
          type:
          - integer
          - 'null'
          description: Block the snapshot was pinned to. Null until the job runs; written once and never changed.
        startBlock:
          type:
          - integer
          - 'null'
          description: Block the opening bell was pinned to. Null until the bell; one-shot.
        closingBlock:
          type:
          - integer
          - 'null'
          description: Block the closing bell was pinned to. Null until the bell; one-shot.
        topHolders:
          type: integer
          description: 'ELIGIBILITY: how many wallets may claim an Entry pass. Read this rather than assuming a number -- it has changed between seasons.'
        displayHolders:
          type: integer
          description: 'DISPLAY ONLY: how many rows the site renders. Not an eligibility bound. Do not confuse it with topHolders.'
        displayRoster:
          type: integer
          description: 'DISPLAY ONLY: how many enrolled rows the site resolves and renders.'
        winnersCount:
          type: integer
          description: 'How many places count as winners: each mints a rank-stamped Winner badge and takes a Finals seat. NOT how many are PAID -- only the podium is paid.'
        minStakeUSDC:
          type: string
          description: 'Raw USDC (6dp) a competition wallet must hold at the opening bell. "5000000" is $5. There is no ceiling: ranking is by percentage return, so a larger stake buys no advantage.'
        stakeToleranceUSDC:
          type: string
          description: Raw USDC (6dp) of slack allowed under minStakeUSDC. "500000" is $0.50.
        gasAllowanceWei:
          type: string
          description: Maximum native ETH, in wei, the competition wallet may hold at the opening bell. "200000000000000" is 0.0002 ETH. More than this is a disqualification.
        finalsCollectorSeats:
          type: integer
          description: How many Finals seats are drawn from the collector board.
        base167DeployBlock:
          type: integer
          description: Block the BASE167 token was deployed at. The floor for any log scan -- start here rather than at block 0, or an eth_getLogs range will be rejected.
        entryNFTDeployBlock:
          type:
          - integer
          - 'null'
          description: 'Block this season''s EntryNFT was deployed at, and the floor for any scan of ITS logs. Optional: a season synced before 2026-09-02 has no pin and falls back to base167DeployBlock, which is correct but scans a far wider range.'
        prizePotBase167:
          type: integer
          description: The season prize pot in WHOLE BASE167 (not wei). Paid to the podium only. Always stated in BASE167 and never as a cash value.
        prizeBreakdown:
          type: array
          description: The podium split. Sums to prizePotBase167 and descends strictly. Places outside it mint a Winner badge and take a Finals seat but are paid nothing.
          items:
            type: object
            required:
            - place
            - amount
            properties:
              place:
                type: integer
              amount:
                type: integer
                description: Whole BASE167.
      required:
      - season
      - chainId
      - factory
      - entryNFT
      - winnersNFT
      - snapshotAt
      - enrollOpenAt
      - enrollCloseAt
      - openingBellAt
      - closingBellAt
      - topHolders
      - winnersCount
      - minStakeUSDC
      - gasAllowanceWei
      - prizePotBase167
      - prizeBreakdown
  responses:
    BadRequest:
      description: Malformed JSON, address or signature.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
            properties:
              code:
                type: string
                enum:
                - INVALID_ADDRESS
                - BAD_CHECKSUM
                description: BAD_CHECKSUM means the address is correctly shaped but its mixed-case EIP-55 checksum does not verify -- send it all-lowercase or fix the checksum. INVALID_ADDRESS means it is not an address at all.
              reason:
                type: string
    BadSignature:
      description: The signature did not verify against this address. The usual cause is a message that does not byte-match the template, most often a different expiry, a trimmed name, or an added newline.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    VerifyUnavailable:
      description: 'No chain could be reached to verify the signature, so it is unknown whether it is good. This is NOT a rejection: retry. Reporting it as a bad signature would send a smart-wallet holder off to debug a wallet that works.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    RateLimited:
      description: 'Over 5 requests per minute. Retry-After: 60.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'