{
  "components": {
    "schemas": {
      "Challenge": {
        "description": "An Altcha challenge. The browser script solves it; pass the result to verify.",
        "properties": {
          "algorithm": {
            "const": "SHA-256",
            "type": "string"
          },
          "challenge": {
            "type": "string"
          },
          "difficulty": {
            "type": "string"
          },
          "expires": {
            "description": "Unix seconds",
            "type": "integer"
          },
          "honeypot": {
            "description": "Name of the honeypot field the script adds",
            "type": "string"
          },
          "maxnumber": {
            "type": "integer"
          },
          "salt": {
            "type": "string"
          },
          "signature": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Site": {
        "properties": {
          "automation": {
            "description": "Automation-signal sensitivity (default balanced).",
            "enum": [
              "off",
              "balanced",
              "strict"
            ],
            "type": "string"
          },
          "challenge_ttl_seconds": {
            "type": "integer"
          },
          "created_at": {
            "format": "date-time",
            "type": "string"
          },
          "difficulty": {
            "default": "medium",
            "description": "Challenge difficulty: low (about 0.05 s on a laptop), medium (about 0.2 s, the default) or high (about 0.8 s). Choosing it needs a plan with custom difficulty; otherwise it is always medium. The removed value auto is accepted as medium.",
            "enum": [
              "low",
              "medium",
              "high"
            ],
            "type": "string"
          },
          "honeypot_field": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "origins": {
            "description": "Allowed hosts; empty means any origin.",
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "public_key": {
            "examples": [
              "pk_live_…"
            ],
            "type": "string"
          },
          "secret_prefix": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "Stats": {
        "properties": {
          "automation_signals": {
            "items": {
              "properties": {
                "count": {
                  "type": "integer"
                },
                "reason": {
                  "type": "string"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "days": {
            "items": {
              "properties": {
                "challenges": {
                  "type": "integer"
                },
                "day": {
                  "format": "date",
                  "type": "string"
                },
                "verify_fail": {
                  "type": "integer"
                },
                "verify_ok": {
                  "type": "integer"
                }
              },
              "type": "object"
            },
            "type": "array"
          },
          "quota": {
            "properties": {
              "cap": {
                "description": "where verify starts answering 402: the limit in a capped month, -1 (no cap) otherwise",
                "type": "integer"
              },
              "capped": {
                "description": "this month follows two months over the limit",
                "type": "boolean"
              },
              "limit": {
                "type": "integer"
              },
              "over_last_month": {
                "description": "one more month over and the next month is capped",
                "type": "boolean"
              },
              "plan": {
                "description": "plan key: free, starter or pro",
                "type": "string"
              },
              "resets_at": {
                "format": "date-time",
                "type": "string"
              },
              "used": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "site": {
            "type": "string"
          },
          "totals": {
            "properties": {
              "automated": {
                "type": "integer"
              },
              "challenges": {
                "type": "integer"
              },
              "fail": {
                "properties": {
                  "automation": {
                    "type": "integer"
                  },
                  "expired": {
                    "type": "integer"
                  },
                  "honeypot": {
                    "type": "integer"
                  },
                  "invalid": {
                    "type": "integer"
                  },
                  "quota": {
                    "type": "integer"
                  },
                  "replay": {
                    "type": "integer"
                  },
                  "wrong_site": {
                    "type": "integer"
                  }
                },
                "type": "object"
              },
              "rate_limited": {
                "type": "integer"
              },
              "solved": {
                "type": "integer"
              },
              "suspect": {
                "type": "integer"
              },
              "verify_fail": {
                "type": "integer"
              },
              "verify_ok": {
                "type": "integer"
              }
            },
            "type": "object"
          },
          "window_days": {
            "type": "integer"
          }
        },
        "type": "object"
      },
      "VerifyFail": {
        "properties": {
          "automation": {
            "description": "Automated-browser verdict. Present when automation signals are on. In mode log it is advice only; in mode enforce a refused token answers ok false, reason automation.",
            "properties": {
              "mode": {
                "enum": [
                  "log",
                  "enforce"
                ],
                "type": "string"
              },
              "reasons": {
                "description": "Signal codes, hard first: webdriver, headless_ua, driver_globals, no_origin, webdriver_tampered, software_gl, no_interaction, untrusted_click, no_pointer_path, fast_submit, no_signals, non_browser_ua, no_sec_fetch, hosting_ip",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "score": {
                "description": "Sum of the soft signal weights",
                "type": "integer"
              },
              "verdict": {
                "enum": [
                  "clean",
                  "suspect",
                  "automated"
                ],
                "type": "string"
              }
            },
            "type": "object"
          },
          "ok": {
            "const": false,
            "type": "boolean"
          },
          "reason": {
            "enum": [
              "expired",
              "replay",
              "invalid",
              "wrong_site",
              "honeypot",
              "quota",
              "automation"
            ],
            "type": "string"
          },
          "site": {
            "type": "string"
          }
        },
        "type": "object"
      },
      "VerifyOK": {
        "properties": {
          "automation": {
            "description": "Automated-browser verdict. Present when automation signals are on. In mode log it is advice only; in mode enforce a refused token answers ok false, reason automation.",
            "properties": {
              "mode": {
                "enum": [
                  "log",
                  "enforce"
                ],
                "type": "string"
              },
              "reasons": {
                "description": "Signal codes, hard first: webdriver, headless_ua, driver_globals, no_origin, webdriver_tampered, software_gl, no_interaction, untrusted_click, no_pointer_path, fast_submit, no_signals, non_browser_ua, no_sec_fetch, hosting_ip",
                "items": {
                  "type": "string"
                },
                "type": "array"
              },
              "score": {
                "description": "Sum of the soft signal weights",
                "type": "integer"
              },
              "verdict": {
                "enum": [
                  "clean",
                  "suspect",
                  "automated"
                ],
                "type": "string"
              }
            },
            "type": "object"
          },
          "difficulty": {
            "type": "string"
          },
          "ok": {
            "const": true,
            "type": "boolean"
          },
          "origin": {
            "type": "string"
          },
          "site": {
            "type": "string"
          },
          "solved_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "description": "An account API key (Settings → API keys) or an OAuth 2.1 access token from https://bot403.com/oauth/authorize. Scopes: sites:read, sites:write, stats:read, verify.",
        "scheme": "bearer",
        "type": "http"
      },
      "siteKey": {
        "description": "The site's secret key (sk_live_…), shown once when the site is created. Also accepted as the `secret` body field.",
        "scheme": "bearer",
        "type": "http"
      }
    }
  },
  "info": {
    "contact": {
      "email": "hello@bot403.com"
    },
    "description": "Bot403 is an invisible bot shield for HTML forms: one script tag makes the browser solve a small proof of work, and your server checks it with one call. The free plan covers 5,000 checks a month. Prices include VAT. Going over the monthly limit never stops verification; only a month that follows two months over in a row is capped, and then the verify endpoint answers 402 with reason \"quota\" above the limit. It never fails open.",
    "termsOfService": "https://bot403.com/legal/terms",
    "title": "Bot403 API",
    "version": "1.2.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/billing/checkout": {
      "post": {
        "operationId": "billingCheckout",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "interval": {
                    "enum": [
                      "month",
                      "year"
                    ],
                    "type": "string"
                  },
                  "plan": {
                    "default": "pro",
                    "enum": [
                      "starter",
                      "pro"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "interval"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "url": {
                      "format": "uri",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "The Stripe Checkout URL"
          },
          "400": {
            "description": "No price for that plan and interval"
          },
          "401": {
            "description": "No session"
          },
          "403": {
            "description": "CSRF token missing or wrong"
          },
          "409": {
            "description": "already_subscribed: the account has a paid plan; change it in the Customer Portal"
          },
          "503": {
            "description": "billing_disabled (no Stripe key) or billing_unconfigured (stripe-setup not run)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Start a Stripe Checkout for a paid plan (session only); open the returned URL"
      }
    },
    "/billing/portal": {
      "post": {
        "operationId": "billingPortal",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "url": {
                      "format": "uri",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "The Stripe Customer Portal URL"
          },
          "401": {
            "description": "No session"
          },
          "403": {
            "description": "CSRF token missing or wrong"
          },
          "503": {
            "description": "billing_disabled (no Stripe key)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Open the Stripe Customer Portal: card, invoices, interval, cancel (session only)"
      }
    },
    "/challenge": {
      "get": {
        "operationId": "getChallenge",
        "parameters": [
          {
            "description": "The site's public key",
            "in": "query",
            "name": "pk",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Challenge"
                }
              }
            },
            "description": "A challenge"
          },
          "403": {
            "description": "Origin not allowed for this site"
          },
          "404": {
            "description": "Unknown public key"
          },
          "429": {
            "description": "Too many challenge requests from this IP or for this site"
          }
        },
        "security": [],
        "summary": "Get a challenge for a site (called by the browser script)"
      }
    },
    "/me": {
      "get": {
        "operationId": "getMe",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "csrf": {
                      "type": "string"
                    },
                    "plan": {
                      "type": "object"
                    },
                    "plans": {
                      "type": "array"
                    },
                    "usage": {
                      "type": "object"
                    },
                    "user": {
                      "type": "object"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Account"
          },
          "401": {
            "description": "No credential"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "The signed-in account: user, plan, usage, CSRF token, catalog plans"
      }
    },
    "/me/apps": {
      "get": {
        "operationId": "listApps",
        "responses": {
          "200": {
            "description": "Apps"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List connected OAuth apps"
      }
    },
    "/me/apps/{client}": {
      "delete": {
        "operationId": "revokeApp",
        "parameters": [
          {
            "in": "path",
            "name": "client",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Disconnected"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Disconnect an app (session only)"
      }
    },
    "/me/email-preferences": {
      "get": {
        "operationId": "getEmailPreferences",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "alerts": {
                      "description": "Site alerts: the script runs without server checks, or a working site broke",
                      "type": "boolean"
                    },
                    "setup": {
                      "description": "Setup tips: a site that never loaded the script, and the first verification",
                      "type": "boolean"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Preferences"
          },
          "401": {
            "description": "No session"
          }
        },
        "summary": "Which optional emails the account gets: setup tips and site alerts (session only)"
      },
      "put": {
        "operationId": "putEmailPreferences",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "alerts": {
                    "description": "Site alerts: the script runs without server checks, or a working site broke",
                    "type": "boolean"
                  },
                  "setup": {
                    "description": "Setup tips: a site that never loaded the script, and the first verification",
                    "type": "boolean"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "alerts": {
                      "description": "Site alerts: the script runs without server checks, or a working site broke",
                      "type": "boolean"
                    },
                    "setup": {
                      "description": "Setup tips: a site that never loaded the script, and the first verification",
                      "type": "boolean"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Preferences"
          },
          "400": {
            "description": "Neither field sent"
          },
          "401": {
            "description": "No session"
          },
          "403": {
            "description": "CSRF token missing or wrong"
          }
        },
        "summary": "Turn setup tips or site alerts on or off (session only). A field that is left out keeps its value."
      }
    },
    "/me/keys": {
      "get": {
        "operationId": "listKeys",
        "responses": {
          "200": {
            "description": "Keys"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List account API keys"
      },
      "post": {
        "operationId": "createKey",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "scopes": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Created"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Create an account API key (session only); the key is in the answer once"
      }
    },
    "/me/keys/{id}": {
      "delete": {
        "operationId": "revokeKey",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Revoked"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Revoke an account API key (session only)"
      }
    },
    "/me/logout": {
      "post": {
        "operationId": "logout",
        "responses": {
          "204": {
            "description": "Signed out"
          },
          "401": {
            "description": "No session"
          },
          "403": {
            "description": "CSRF token missing or wrong"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Sign out: end the current session and clear the cookie (session only)"
      }
    },
    "/me/sessions": {
      "get": {
        "operationId": "listSessions",
        "responses": {
          "200": {
            "description": "Sessions"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List signed-in devices"
      }
    },
    "/me/sessions/{id}": {
      "delete": {
        "operationId": "revokeSession",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Signed out"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Sign a device out (session only)"
      }
    },
    "/sites": {
      "get": {
        "operationId": "listSites",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "limit": {
                      "type": "integer"
                    },
                    "plan": {
                      "type": "string"
                    },
                    "sites": {
                      "items": {
                        "$ref": "#/components/schemas/Site"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Sites"
          },
          "401": {
            "description": "No or invalid account credential"
          },
          "403": {
            "description": "Token lacks the scope"
          }
        },
        "security": [
          {
            "bearerAuth": [
              "sites:read"
            ]
          }
        ],
        "summary": "List your sites"
      },
      "post": {
        "operationId": "createSite",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "name": {
                    "maxLength": 100,
                    "type": "string"
                  }
                },
                "required": [
                  "name"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/Site"
                    },
                    {
                      "properties": {
                        "secret_key": {
                          "type": "string"
                        }
                      },
                      "type": "object"
                    }
                  ]
                }
              }
            },
            "description": "Created"
          },
          "400": {
            "description": "Name missing"
          },
          "402": {
            "description": "The plan's site limit is reached (Free 2; Pro has no limit)"
          }
        },
        "security": [
          {
            "bearerAuth": [
              "sites:write"
            ]
          }
        ],
        "summary": "Create a site; the secret key is in the answer once"
      }
    },
    "/sites/{id}": {
      "delete": {
        "operationId": "deleteSite",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          }
        },
        "security": [
          {
            "bearerAuth": [
              "sites:write"
            ]
          }
        ],
        "summary": "Delete a site and its statistics"
      },
      "get": {
        "operationId": "getSite",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Site"
                }
              }
            },
            "description": "Site"
          },
          "404": {
            "description": "Not yours or missing"
          }
        },
        "security": [
          {
            "bearerAuth": [
              "sites:read"
            ]
          }
        ],
        "summary": "One site"
      },
      "put": {
        "operationId": "updateSite",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "automation": {
                    "description": "Omit to keep the current value",
                    "enum": [
                      "off",
                      "balanced",
                      "strict"
                    ],
                    "type": "string"
                  },
                  "challenge_ttl_seconds": {
                    "maximum": 3600,
                    "minimum": 60,
                    "type": "integer"
                  },
                  "difficulty": {
                    "default": "medium",
                    "description": "Challenge difficulty: low (about 0.05 s on a laptop), medium (about 0.2 s, the default) or high (about 0.8 s). Choosing it needs a plan with custom difficulty; otherwise it is always medium. The removed value auto is accepted as medium.",
                    "enum": [
                      "low",
                      "medium",
                      "high"
                    ],
                    "type": "string"
                  },
                  "honeypot_field": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  },
                  "origins": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "name",
                  "challenge_ttl_seconds"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Updated site"
          },
          "400": {
            "description": "A setting failed validation"
          }
        },
        "security": [
          {
            "bearerAuth": [
              "sites:write"
            ]
          }
        ],
        "summary": "Update settings (name, origins, difficulty, expiry, honeypot)"
      }
    },
    "/sites/{id}/rotate": {
      "post": {
        "operationId": "rotateSiteSecret",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "secret_key": {
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "New secret"
          }
        },
        "security": [
          {
            "bearerAuth": [
              "sites:write"
            ]
          }
        ],
        "summary": "Rotate the secret key; the new key is in the answer once"
      }
    },
    "/sites/{id}/stats": {
      "get": {
        "operationId": "getSiteStats",
        "parameters": [
          {
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "in": "query",
            "name": "days",
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            },
            "description": "Statistics"
          }
        },
        "security": [
          {
            "bearerAuth": [
              "stats:read"
            ]
          }
        ],
        "summary": "Statistics of one site by account credential"
      }
    },
    "/stats": {
      "get": {
        "operationId": "getStats",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Stats"
                }
              }
            },
            "description": "Statistics"
          },
          "401": {
            "description": "Secret key missing or wrong"
          }
        },
        "security": [
          {
            "siteKey": []
          }
        ],
        "summary": "The site's totals, daily series and account quota for the plan's window"
      }
    },
    "/verify": {
      "post": {
        "operationId": "verifyToken",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "secret": {
                    "description": "The secret key when no Authorization header can be set",
                    "type": "string"
                  },
                  "solution": {
                    "description": "The token from the form field _bot403 (also accepted as altcha or _bot403)",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            },
            "application/x-www-form-urlencoded": {
              "schema": {
                "description": "The whole form may be posted; the token field and the honeypot field are read.",
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/VerifyOK"
                    },
                    {
                      "$ref": "#/components/schemas/VerifyFail"
                    }
                  ]
                }
              }
            },
            "description": "ok true, or ok false with a reason other than quota"
          },
          "400": {
            "description": "Body not parseable"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "ok": {
                      "const": false,
                      "type": "boolean"
                    },
                    "reason": {
                      "const": "unauthorized",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Secret key missing or wrong"
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "ok": {
                      "const": false,
                      "type": "boolean"
                    },
                    "reason": {
                      "const": "quota",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Only in a capped month (after two calendar months over the plan in a row), above the limit. The token is not burned; it verifies after an upgrade."
          },
          "413": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "ok": {
                      "const": false,
                      "type": "boolean"
                    },
                    "reason": {
                      "const": "too_large",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Body above 64 KB"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "ok": {
                      "const": false,
                      "type": "boolean"
                    },
                    "reason": {
                      "const": "rate_limited",
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "Above the plan's verify calls a minute for this site (Free 100, Starter 1,000, Pro 3,000)"
          }
        },
        "security": [
          {
            "siteKey": []
          }
        ],
        "summary": "Verify a solved token; counts one verification on success"
      }
    }
  },
  "servers": [
    {
      "url": "https://bot403.com/api/v1"
    }
  ]
}