{
  "openapi": "3.1.0",
  "info": {
    "title": "BASE167 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"
    }
  ],
  "paths": {
    "/api/check": {
      "post": {
        "operationId": "checkEligibility",
        "summary": "Check a wallet against the 167-transaction gate and get a claim voucher",
        "description": "Smart-contract wallets are supported: when the EOA nonce is short and the address has code, the count falls back to distinct outgoing asset-moving transactions, which can under-count a wallet whose activity is mostly non-transfer calls.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "address"
                ],
                "properties": {
                  "address": {
                    "$ref": "#/components/schemas/Address"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Eligibility result. When eligible, includes a voucher and a prepared call.",
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "type": "object",
                      "required": [
                        "eligible",
                        "txCount",
                        "signature",
                        "expiry",
                        "call"
                      ],
                      "properties": {
                        "eligible": {
                          "const": true
                        },
                        "txCount": {
                          "type": "integer"
                        },
                        "signature": {
                          "$ref": "#/components/schemas/Hex"
                        },
                        "expiry": {
                          "type": "integer",
                          "description": "Unix seconds; the voucher is void after this."
                        },
                        "call": {
                          "$ref": "#/components/schemas/PreparedCall"
                        }
                      }
                    },
                    {
                      "type": "object",
                      "required": [
                        "eligible",
                        "txCount",
                        "required"
                      ],
                      "properties": {
                        "eligible": {
                          "const": false
                        },
                        "txCount": {
                          "type": "integer"
                        },
                        "required": {
                          "type": "integer",
                          "const": 167
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "413": {
            "$ref": "#/components/responses/TooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          }
        }
      }
    },
    "/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"
          }
        }
      }
    },
    "/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"
          }
        }
      }
    },
    "/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"
          }
        }
      }
    },
    "/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.\n\nThe message must byte-match exactly:\n\n    Set my Degen Games name to: {name}\n    Domain: base167.com Degen Games\n    Expires: {expiry}\n\n{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.\n\nA 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"
          }
        }
      }
    },
    "/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.\n\nThe message must byte-match exactly:\n\n    Set my Degen Games X handle to: {handle}\n    Domain: base167.com Degen Games\n    Expires: {expiry}\n\n{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"
          }
        }
      }
    },
    "/api/games/leaderboard": {
      "get": {
        "operationId": "getLeaderboard",
        "summary": "Top holders and the live collector board",
        "description": "Cached for 60 seconds. Available whether or not a season is running, which is why the standalone leaderboard page is always live.",
        "responses": {
          "200": {
            "description": "Holders and collectors, each enriched with a resolved identity.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "updatedAt",
                    "holders",
                    "collectors"
                  ],
                  "properties": {
                    "updatedAt": {
                      "type": "integer",
                      "description": "Unix seconds the holder snapshot was taken. 0 means no snapshot exists yet."
                    },
                    "holders": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BoardRow"
                      }
                    },
                    "collectors": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BoardRow"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/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"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/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: wallets holding more than one Entry pass, ranked. 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."
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Address": {
        "type": "string",
        "pattern": "^0x[a-fA-F0-9]{40}$"
      },
      "Hex": {
        "type": "string",
        "pattern": "^0x[a-fA-F0-9]*$"
      },
      "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": {
            "$ref": "#/components/schemas/Hex"
          },
          "value": {
            "type": "string",
            "const": "0x0"
          }
        }
      },
      "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."
      },
      "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"
          }
        }
      },
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string"
          }
        }
      },
      "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."
          }
        },
        "required": [
          "season",
          "chainId",
          "factory",
          "entryNFT",
          "winnersNFT",
          "snapshotAt",
          "enrollOpenAt",
          "enrollCloseAt",
          "openingBellAt",
          "closingBellAt",
          "topHolders",
          "winnersCount",
          "minStakeUSDC",
          "gasAllowanceWei"
        ]
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed JSON, address or signature.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "Forbidden": {
        "description": "The request did not arrive through the expected proxy.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "TooLarge": {
        "description": "Request body over the cap.",
        "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"
            }
          }
        }
      },
      "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"
            }
          }
        }
      }
    }
  }
}
