{
  "openapi": "3.0.3",
  "info": {
    "title": "VerifyUGC Public API",
    "version": "1.0.0",
    "description": "Read-only access to the VerifyUGC global blacklist and public creator trust data. Most endpoints require an API key (the free tier allows 100 calls/day; the Pro and Max tiers raise the limit); the `/v1/public/*`, `/v1/stats/public`, `/referrals/leaderboard` and `/badge/*` endpoints are free and need no key.\n\nThis document is **generated** from the live route handlers by `npm run generate:openapi` (see `scripts/generate-openapi.mjs`). Do not edit it by hand — edit the `@openapi` annotation blocks above each route handler in `src/routes/*.ts` and re-run the generator.",
    "x-generated-by": "scripts/generate-openapi.mjs",
    "x-generated-note": "DO NOT EDIT BY HAND. Edit the @openapi blocks in src/routes/*.ts (paths) and contract/schemas.mjs (shared component schemas), then run `npm run generate:contract`."
  },
  "servers": [
    {
      "url": "https://verifyugc.dev"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Blacklist",
      "description": "Query the global scammer/ban blacklist (API key required)."
    },
    {
      "name": "Creators",
      "description": "Public creator profiles and Trust Scores (API key required)."
    },
    {
      "name": "Public",
      "description": "Free, keyless endpoints powering the on-site tools and embeds."
    },
    {
      "name": "Account",
      "description": "Endpoints scoped to the calling API key."
    },
    {
      "name": "Courses",
      "description": "Creator-education courses. List/detail are open; submitting answers requires a logged-in session."
    }
  ],
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "Your vugc_live_... API key."
      },
      "cookieAuth": {
        "type": "apiKey",
        "in": "cookie",
        "name": "session",
        "description": "A logged-in VerifyUGC web session cookie. Used by the on-site app, not by API-key integrations."
      }
    },
    "schemas": {
      "BatchCheckResult": {
        "type": "object",
        "description": "One row per submitted account, returned in input order.",
        "properties": {
          "provider": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "nullable": true
          },
          "banned": {
            "type": "boolean"
          },
          "high_risk": {
            "type": "boolean",
            "description": "Present and true when the account is flagged high-risk."
          },
          "watchlist": {
            "type": "boolean",
            "description": "Present and true when the account is on a watchlist."
          },
          "severity": {
            "type": "string",
            "enum": [
              "warn",
              "restrict",
              "ban"
            ],
            "description": "Present only on a hit."
          },
          "scope": {
            "type": "string",
            "enum": [
              "global",
              "vertical"
            ],
            "description": "Present only on a hit."
          },
          "reason_code": {
            "type": "string",
            "description": "Present only on a hit."
          },
          "error": {
            "type": "string",
            "description": "Present when the row could not be checked (e.g. `invalid_account`)."
          }
        }
      },
      "BlacklistEntry": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "severity": {
            "type": "string",
            "enum": [
              "warn",
              "restrict",
              "ban"
            ]
          },
          "scope": {
            "type": "string",
            "enum": [
              "global",
              "vertical"
            ]
          },
          "vertical": {
            "type": "string"
          },
          "reason_code": {
            "type": "string"
          },
          "summary": {
            "type": "string",
            "nullable": true
          },
          "issued_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the entry was issued (ISO 8601)."
          },
          "expires_at": {
            "type": "string",
            "nullable": true,
            "format": "date-time",
            "description": "When the entry expires (ISO 8601), or null if permanent."
          },
          "appealable": {
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "severity",
          "scope",
          "vertical",
          "reason_code",
          "summary",
          "issued_at",
          "expires_at",
          "appealable"
        ],
        "description": "Public-safe view of an active blacklist entry."
      },
      "BlacklistEntryPage": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/BlacklistEntry"
            }
          },
          "next_cursor": {
            "type": "string",
            "nullable": true,
            "description": "Opaque cursor for the next page (pass back as ?cursor=). Null on the last page."
          },
          "has_more": {
            "type": "boolean"
          }
        },
        "required": [
          "data",
          "next_cursor",
          "has_more"
        ],
        "description": "A cursor-paginated page of blacklist entries (incremental sync)."
      },
      "BlacklistHit": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "banned": {
            "type": "boolean"
          },
          "entry": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "string"
              },
              "severity": {
                "type": "string",
                "enum": [
                  "warn",
                  "restrict",
                  "ban"
                ]
              },
              "scope": {
                "type": "string",
                "enum": [
                  "global",
                  "vertical"
                ]
              },
              "vertical": {
                "type": "string"
              },
              "reason_code": {
                "type": "string"
              },
              "summary": {
                "type": "string",
                "nullable": true
              }
            }
          },
          "checked_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BlacklistResult": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string"
          },
          "id": {
            "type": "string"
          },
          "banned": {
            "type": "boolean"
          },
          "high_risk": {
            "type": "boolean"
          },
          "watchlist": {
            "type": "boolean"
          },
          "severity": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          },
          "reason_code": {
            "type": "string"
          },
          "summary": {
            "type": "string",
            "nullable": true
          },
          "appealable": {
            "type": "boolean"
          },
          "entry": {
            "allOf": [
              {
                "$ref": "#/components/schemas/BlacklistResultEntry"
              },
              {
                "nullable": true
              }
            ]
          },
          "checked_at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 UTC timestamp."
          }
        },
        "required": [
          "provider",
          "id",
          "banned",
          "checked_at"
        ],
        "description": "Keyed exact lookup: is a single platform account blacklisted?"
      },
      "BlacklistResultEntry": {
        "type": "object",
        "properties": {
          "severity": {
            "type": "string"
          },
          "scope": {
            "type": "string"
          },
          "reason_code": {
            "type": "string"
          },
          "summary": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "severity",
          "scope",
          "reason_code"
        ],
        "description": "The matching blacklist entry summary attached to a keyed check hit."
      },
      "Connection": {
        "type": "object",
        "properties": {
          "provider": {
            "type": "string"
          },
          "provider_username": {
            "type": "string",
            "nullable": true
          },
          "provider_url": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "verified_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CourseDetail": {
        "type": "object",
        "description": "Course detail with quiz questions. Option order is shuffled per request; each option carries its original index as `key`. Correct answers and explanations are never included here.",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "platform_tag": {
            "type": "string",
            "nullable": true
          },
          "difficulty": {
            "type": "string",
            "nullable": true
          },
          "pass_threshold": {
            "type": "integer"
          },
          "points": {
            "type": "integer"
          },
          "question_count": {
            "type": "integer"
          },
          "questions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "position": {
                  "type": "integer"
                },
                "question": {
                  "type": "string"
                },
                "options": {
                  "type": "array",
                  "items": {
                    "type": "object",
                    "properties": {
                      "key": {
                        "type": "integer",
                        "description": "Original option index — submit this as `answer_index`."
                      },
                      "text": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          },
          "completion": {
            "type": "object",
            "nullable": true,
            "properties": {
              "passed": {
                "type": "boolean"
              },
              "score": {
                "type": "integer"
              },
              "completed_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "CourseGrade": {
        "type": "object",
        "description": "Result of grading a course submission.",
        "properties": {
          "passed": {
            "type": "boolean"
          },
          "score": {
            "type": "integer",
            "description": "Percentage score."
          },
          "correct_count": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "pass_threshold": {
            "type": "integer"
          },
          "results": {
            "type": "array",
            "description": "Per-question outcome with the correct answer and explanation now revealed.",
            "items": {
              "type": "object"
            }
          },
          "trust_buff": {
            "type": "object",
            "properties": {
              "applied": {
                "type": "boolean"
              },
              "per_course": {
                "type": "integer"
              },
              "max_points": {
                "type": "integer"
              },
              "passed_count": {
                "type": "integer"
              },
              "earned_points": {
                "type": "integer"
              }
            }
          }
        }
      },
      "CourseSummary": {
        "type": "object",
        "description": "A course with the viewer's completion status. Status is `locked` when signed out, else `available` or `passed`.",
        "properties": {
          "slug": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "platform_tag": {
            "type": "string",
            "nullable": true
          },
          "difficulty": {
            "type": "string",
            "nullable": true
          },
          "pass_threshold": {
            "type": "integer",
            "description": "Percentage score required to pass."
          },
          "question_count": {
            "type": "integer"
          },
          "points": {
            "type": "integer",
            "description": "Trust points awarded for passing."
          },
          "status": {
            "type": "string",
            "enum": [
              "locked",
              "available",
              "passed"
            ]
          },
          "score": {
            "type": "integer",
            "nullable": true,
            "description": "The viewer's best score, when signed in and attempted."
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          }
        }
      },
      "CreatorProfile": {
        "type": "object",
        "properties": {
          "handle": {
            "type": "string"
          },
          "display_name": {
            "type": "string",
            "nullable": true
          },
          "verification_level": {
            "type": "integer"
          },
          "verification_label": {
            "type": "string"
          },
          "karma": {
            "type": "integer"
          },
          "trust_score": {
            "type": "integer",
            "description": "Composite Trust Score, 0-250."
          },
          "trust_band": {
            "$ref": "#/components/schemas/TrustBand"
          },
          "reviews": {
            "$ref": "#/components/schemas/ReviewsSummary"
          },
          "completed_deals": {
            "type": "integer"
          },
          "linked_accounts": {
            "type": "integer"
          },
          "blacklisted": {
            "type": "boolean"
          },
          "joined_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the creator joined (ISO 8601)."
          },
          "profile_url": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "handle",
          "display_name",
          "verification_level",
          "verification_label",
          "karma",
          "trust_score",
          "trust_band",
          "reviews",
          "completed_deals",
          "linked_accounts",
          "blacklisted",
          "joined_at",
          "profile_url"
        ],
        "description": "Public creator profile with headline Trust Score."
      },
      "DirectoryItem": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "handle": {
            "type": "string"
          },
          "display_name": {
            "type": "string",
            "nullable": true
          },
          "verification_level": {
            "type": "integer"
          },
          "karma": {
            "type": "integer"
          },
          "avatar_r2_key": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the creator joined (ISO 8601)."
          },
          "trust_score": {
            "type": "integer",
            "description": "Headline Trust Score, 0-250 (0 when never computed)."
          },
          "vouch_count": {
            "type": "integer"
          },
          "deal_count": {
            "type": "integer"
          },
          "platforms": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "match": {
            "type": "string",
            "description": "Server-side fuzzy-match haystack the row matched on."
          }
        },
        "required": [
          "id",
          "handle",
          "display_name",
          "verification_level",
          "karma",
          "avatar_r2_key",
          "created_at",
          "trust_score",
          "vouch_count",
          "deal_count",
          "platforms",
          "match"
        ],
        "description": "One public creator row in the directory feed."
      },
      "DirectoryPage": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DirectoryItem"
            }
          },
          "page": {
            "type": "integer",
            "description": "1-based page number."
          },
          "limit": {
            "type": "integer"
          },
          "page_size": {
            "type": "integer",
            "description": "Rows on this page (== limit unless the last page is short)."
          },
          "total": {
            "type": "integer",
            "description": "Total matching creators across all pages."
          },
          "total_pages": {
            "type": "integer"
          },
          "has_more": {
            "type": "boolean"
          },
          "sort": {
            "type": "string",
            "enum": [
              "newest",
              "trust",
              "vouches",
              "deals"
            ]
          }
        },
        "required": [
          "items",
          "page",
          "limit",
          "page_size",
          "total",
          "total_pages",
          "has_more",
          "sort"
        ],
        "description": "Offset/page-paginated directory results."
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "request_id": {
                "type": "string"
              }
            }
          }
        }
      },
      "PublicCheckHit": {
        "type": "object",
        "properties": {
          "platform": {
            "type": "string"
          },
          "username": {
            "type": "string",
            "nullable": true
          },
          "id": {
            "type": "string",
            "nullable": true
          },
          "banned": {
            "type": "boolean"
          },
          "high_risk": {
            "type": "boolean"
          },
          "watchlist": {
            "type": "boolean"
          },
          "severity": {
            "type": "string",
            "nullable": true
          },
          "reason_code": {
            "type": "string",
            "nullable": true
          },
          "summary": {
            "type": "string",
            "nullable": true
          },
          "source": {
            "type": "string",
            "nullable": true
          }
        },
        "required": [
          "platform",
          "username",
          "id",
          "banned",
          "high_risk",
          "watchlist",
          "severity",
          "reason_code",
          "summary"
        ],
        "description": "A single per-platform blacklist/watchlist hit. `watchlist:true` with `banned:false` is an unconfirmed external report, not a VerifyUGC ban."
      },
      "PublicCheckResult": {
        "type": "object",
        "properties": {
          "query": {
            "type": "string"
          },
          "found": {
            "type": "boolean"
          },
          "platforms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicCheckHit"
            }
          },
          "suggestions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "checked_at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 UTC timestamp."
          }
        },
        "required": [
          "query",
          "found",
          "platforms",
          "suggestions",
          "checked_at"
        ],
        "description": "Free, keyless unified blacklist search by username across every platform."
      },
      "PublicStats": {
        "type": "object",
        "description": "Cached social-proof counters for the marketing site.",
        "properties": {
          "creators_verified": {
            "type": "integer"
          },
          "servers_protected": {
            "type": "integer"
          },
          "entries_listed": {
            "type": "integer"
          },
          "deals_completed": {
            "type": "integer"
          },
          "cached": {
            "type": "boolean",
            "description": "True when served from the KV cache rather than freshly computed."
          }
        }
      },
      "PublicTrust": {
        "type": "object",
        "properties": {
          "handle": {
            "type": "string"
          },
          "found": {
            "type": "boolean"
          },
          "band": {
            "$ref": "#/components/schemas/TrustBand"
          },
          "tier": {
            "type": "string",
            "description": "Display label for the band, e.g. \"Good\"."
          },
          "tier_color": {
            "type": "string",
            "description": "Hex colour for the band."
          },
          "trust_score": {
            "type": "integer",
            "description": "Raw score (0-250). Only present for authenticated session callers."
          },
          "blacklisted": {
            "type": "boolean"
          },
          "checked_at": {
            "type": "string",
            "format": "date-time",
            "description": "ISO 8601 UTC timestamp."
          }
        },
        "required": [
          "handle",
          "found"
        ],
        "description": "Keyless Trust-tier lookup. When found is false only { handle, found } is returned."
      },
      "PublicVouch": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "from_username": {
            "type": "string",
            "description": "Handle of the creator who gave the vouch."
          },
          "from_display_name": {
            "type": "string",
            "nullable": true
          },
          "from_verification_level": {
            "type": "integer"
          },
          "from_avatar_url": {
            "type": "string",
            "nullable": true,
            "description": "Relative avatar path, or null when the voucher has no avatar."
          },
          "message": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the vouch was given (ISO 8601). Normalised from the epoch-ms store."
          }
        },
        "required": [
          "id",
          "from_username",
          "from_display_name",
          "from_verification_level",
          "from_avatar_url",
          "message",
          "created_at"
        ],
        "description": "A single received vouch on a creator's public profile."
      },
      "ReferralLeaderboard": {
        "type": "object",
        "description": "Public referral leaderboard. Privacy-safe: handle + count + badge only, never earnings.",
        "properties": {
          "period": {
            "type": "string",
            "enum": [
              "all",
              "month"
            ]
          },
          "leaders": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "rank": {
                  "type": "integer"
                },
                "handle": {
                  "type": "string"
                },
                "count": {
                  "type": "integer"
                },
                "badge": {
                  "type": "object",
                  "nullable": true,
                  "properties": {
                    "tier": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "ResolveResult": {
        "type": "object",
        "properties": {
          "found": {
            "type": "boolean"
          },
          "handle": {
            "type": "string"
          },
          "trust_score": {
            "type": "integer",
            "description": "Headline Trust Score (0-250) for the resolved creator."
          },
          "band": {
            "$ref": "#/components/schemas/TrustBand"
          },
          "blacklisted": {
            "type": "boolean"
          },
          "profile_url": {
            "type": "string",
            "format": "uri"
          }
        },
        "required": [
          "found"
        ],
        "description": "Maps a public linked platform account to its VerifyUGC creator. { found: false } when no public connection matches."
      },
      "ReviewsSummary": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer"
          },
          "average": {
            "type": "number",
            "nullable": true
          }
        },
        "required": [
          "count",
          "average"
        ],
        "description": "Aggregate review count and average rating."
      },
      "TrustBand": {
        "type": "string",
        "enum": [
          "banned",
          "terrible",
          "bad",
          "average",
          "good",
          "great",
          "excellent"
        ],
        "description": "Coarse Trust Score band."
      },
      "TrustBasis": {
        "type": "object",
        "properties": {
          "verification_level": {
            "type": "integer"
          },
          "verification_label": {
            "type": "string"
          },
          "account_age_days": {
            "type": "integer"
          },
          "linked_accounts": {
            "type": "integer"
          },
          "completed_deals": {
            "type": "integer"
          },
          "reviews": {
            "$ref": "#/components/schemas/ReviewsSummary"
          }
        },
        "required": [
          "verification_level",
          "verification_label",
          "account_age_days",
          "linked_accounts",
          "completed_deals",
          "reviews"
        ],
        "description": "Coarse public signals a Trust Score is computed from. No penalty internals."
      },
      "TrustBreakdown": {
        "type": "object",
        "properties": {
          "handle": {
            "type": "string"
          },
          "trust_score": {
            "type": "integer"
          },
          "band": {
            "$ref": "#/components/schemas/TrustBand"
          },
          "trend": {
            "$ref": "#/components/schemas/TrustTrend"
          },
          "blacklisted": {
            "type": "boolean"
          },
          "basis": {
            "$ref": "#/components/schemas/TrustBasis"
          },
          "computed_at": {
            "type": "string",
            "format": "date-time",
            "description": "When the score was computed (ISO 8601)."
          }
        },
        "required": [
          "handle",
          "trust_score",
          "band",
          "trend",
          "blacklisted",
          "basis",
          "computed_at"
        ],
        "description": "Composite Trust Score (0-250) plus the coarse public basis behind it."
      },
      "TrustTrend": {
        "type": "object",
        "properties": {
          "direction": {
            "type": "string",
            "enum": [
              "up",
              "down",
              "flat"
            ]
          },
          "delta": {
            "type": "integer"
          },
          "from": {
            "type": "integer",
            "nullable": true,
            "description": "Baseline score the delta is measured from; null if no history."
          },
          "window_days": {
            "type": "integer"
          }
        },
        "required": [
          "direction",
          "delta",
          "from",
          "window_days"
        ],
        "description": "Direction and magnitude of a creator's recent Trust Score movement."
      },
      "UsageStats": {
        "type": "object",
        "description": "Usage and rate-limit status for the calling API key.",
        "properties": {
          "key_id": {
            "type": "string"
          },
          "rate_limit_tier": {
            "type": "string",
            "enum": [
              "free",
              "verified",
              "partner"
            ]
          },
          "api_tier": {
            "type": "string",
            "enum": [
              "free",
              "pro",
              "max",
              "enterprise"
            ],
            "description": "The key owner's API tier, which drives the rate-limit ceiling."
          },
          "total_requests": {
            "type": "integer",
            "description": "All-time metered requests for this key (retained ~3 months)."
          },
          "requests_this_month": {
            "type": "integer",
            "description": "Metered requests in the current UTC month."
          },
          "rate_limit": {
            "type": "object",
            "properties": {
              "limit": {
                "type": "integer",
                "description": "Requests allowed per window for this key's tier."
              },
              "used": {
                "type": "integer"
              },
              "remaining": {
                "type": "integer"
              },
              "reset": {
                "type": "integer",
                "description": "Unix epoch seconds when the current window resets."
              },
              "window_seconds": {
                "type": "integer"
              }
            }
          },
          "by_endpoint": {
            "type": "array",
            "description": "Per-endpoint request counts, descending.",
            "items": {
              "type": "object",
              "properties": {
                "endpoint": {
                  "type": "string",
                  "description": "Method + route pattern, e.g. `GET /v1/blacklist/check`."
                },
                "count": {
                  "type": "integer"
                }
              }
            }
          }
        }
      },
      "Vertical": {
        "type": "string",
        "enum": [
          "roblox",
          "uefn",
          "minecraft",
          "all"
        ],
        "description": "Product vertical a record belongs to."
      },
      "VouchedPerson": {
        "type": "object",
        "properties": {
          "handle": {
            "type": "string"
          },
          "displayName": {
            "type": "string",
            "nullable": true
          },
          "avatarUrl": {
            "type": "string",
            "nullable": true
          },
          "trustScore": {
            "type": "integer",
            "nullable": true
          },
          "vouchedAt": {
            "type": "string",
            "format": "date-time",
            "description": "When the signed-in user vouched for this creator (ISO 8601)."
          }
        },
        "required": [
          "handle",
          "displayName",
          "avatarUrl",
          "trustScore",
          "vouchedAt"
        ],
        "description": "One creator the signed-in user has vouched FOR."
      },
      "VouchesGivenPage": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer"
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "vouches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/VouchedPerson"
            }
          }
        },
        "required": [
          "count",
          "limit",
          "offset",
          "vouches"
        ],
        "description": "Offset-paginated list of creators the signed-in user has vouched for."
      },
      "VouchesPage": {
        "type": "object",
        "properties": {
          "count": {
            "type": "integer",
            "description": "Total vouches the creator has received (not just this page)."
          },
          "limit": {
            "type": "integer"
          },
          "offset": {
            "type": "integer"
          },
          "vouches": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PublicVouch"
            }
          }
        },
        "required": [
          "count",
          "limit",
          "offset",
          "vouches"
        ],
        "description": "Offset-paginated list of vouches a creator has received."
      }
    },
    "parameters": {
      "cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "schema": {
          "type": "string"
        },
        "description": "Opaque pagination cursor from a previous response's `next_cursor`."
      },
      "limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "schema": {
          "type": "integer",
          "default": 50,
          "minimum": 1,
          "maximum": 100
        },
        "description": "Page size (1–100, default 50)."
      }
    }
  },
  "paths": {
    "/badge/{handle}": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Embeddable verification badge (SVG)",
        "description": "Server-rendered SVG trust badge for embedding via `<img src=\"https://verifyugc.dev/badge/@handle\">`. Keyless and CDN-cached (1h). Always returns 200 — unknown handles render a neutral \"Not Verified\" badge so a pasted embed never breaks. A trailing `.svg` on the handle is accepted.",
        "security": [],
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Creator handle. A leading @ and/or trailing .svg are stripped."
          },
          {
            "name": "theme",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "light",
                "dark"
              ],
              "default": "dark"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SVG badge",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          }
        }
      }
    },
    "/referrals/leaderboard": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Public referral leaderboard",
        "description": "Top referrers, ranked. Privacy-safe — handle, referral count and badge only, never earnings. Keyless and per-IP rate-limited.",
        "security": [],
        "parameters": [
          {
            "name": "period",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "all",
                "month"
              ],
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReferralLeaderboard"
                }
              }
            }
          }
        }
      }
    },
    "/v1/blacklist": {
      "get": {
        "tags": [
          "Blacklist"
        ],
        "summary": "List blacklist entries (cursor-paginated)",
        "description": "Returns a cursor-paginated list of active, public-safe blacklist entries. Page with `?cursor=&limit=`; the response carries `next_cursor` (pass it back to fetch the next page) and `has_more`. Use `?since=` for incremental sync — poll with the timestamp of your last sync to receive only newer entries.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "$ref": "#/components/parameters/cursor"
          },
          {
            "$ref": "#/components/parameters/limit"
          },
          {
            "name": "vertical",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "roblox",
                "uefn",
                "minecraft",
                "all"
              ]
            },
            "description": "Only entries for this vertical."
          },
          {
            "name": "since",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date-time"
            },
            "description": "Only entries issued strictly after this ISO-8601 timestamp (incremental sync)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlacklistEntryPage"
                }
              }
            }
          },
          "400": {
            "description": "Invalid `cursor`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unknown `vertical`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/blacklist/batch": {
      "post": {
        "tags": [
          "Blacklist"
        ],
        "summary": "Batch check up to 50 ids (paid API)",
        "description": "Requires Pro or higher. Accepts `{ items: [{provider, id}] }` (max 50) and returns a `results` array in input order. Distinct from `/check/batch` (which uses the `accounts` key and allows 100 on the base plan).",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "vertical": {
                    "type": "string",
                    "enum": [
                      "roblox",
                      "uefn",
                      "minecraft",
                      "all"
                    ]
                  },
                  "items": {
                    "type": "array",
                    "maxItems": 50,
                    "items": {
                      "type": "object",
                      "required": [
                        "provider",
                        "id"
                      ],
                      "properties": {
                        "provider": {
                          "type": "string"
                        },
                        "id": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BatchCheckResult"
                      }
                    },
                    "checked_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`items` missing or empty",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Pro or higher required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "More than 50 items",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/blacklist/check": {
      "get": {
        "tags": [
          "Blacklist"
        ],
        "summary": "Check a single account",
        "description": "Checks one account against the global blacklist. Both `provider` and `id` are required. To search an id across every platform at once without a key, use the free `GET /v1/public/blacklist/check` instead.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "provider",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "discord",
                "roblox",
                "epic",
                "minecraft",
                "youtube",
                "twitch",
                "twitter",
                "tiktok",
                "github"
              ]
            },
            "description": "Platform to scope the check to."
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Native platform user id to check."
          },
          {
            "name": "vertical",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "roblox",
                "uefn",
                "minecraft",
                "all"
              ],
              "default": "all"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/BlacklistHit"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "provider": {
                          "type": "string"
                        },
                        "id": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing `provider` or `id`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Unknown `vertical`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/blacklist/check/batch": {
      "post": {
        "tags": [
          "Blacklist"
        ],
        "summary": "Batch check up to 50 accounts (Pro+ or Partner)",
        "description": "Checks many accounts in one call. Send `{ accounts: [{provider, id}] }` (max 50); the response is a `results` array in input order. Requires a paid developer license (Pro or higher) or Partner tier — free keys get a 403. Use the single-item `GET /v1/blacklist/check` for unentitled keys.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "accounts"
                ],
                "properties": {
                  "vertical": {
                    "type": "string",
                    "enum": [
                      "roblox",
                      "uefn",
                      "minecraft",
                      "all"
                    ]
                  },
                  "accounts": {
                    "type": "array",
                    "maxItems": 50,
                    "items": {
                      "type": "object",
                      "required": [
                        "provider",
                        "id"
                      ],
                      "properties": {
                        "provider": {
                          "type": "string"
                        },
                        "id": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BatchCheckResult"
                      }
                    },
                    "checked_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "`accounts` missing or empty",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Requires a paid developer license (Pro+) or Partner tier",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "More than 50 accounts",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/blacklist/entries/{id}": {
      "get": {
        "tags": [
          "Blacklist"
        ],
        "summary": "Get a blacklist entry (public-safe fields)",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BlacklistEntry"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/courses": {
      "get": {
        "tags": [
          "Courses"
        ],
        "summary": "List creator-education courses",
        "description": "Every course with the viewer's completion status. Works signed-out (all come back `locked`). When a session cookie is present, each course is `available` or `passed` and carries the best score. Also returns the viewer's aggregate Trust-points earned from courses.",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "courses": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/CourseSummary"
                      }
                    },
                    "trust": {
                      "type": "object",
                      "properties": {
                        "signed_in": {
                          "type": "boolean"
                        },
                        "per_course": {
                          "type": "integer"
                        },
                        "max_points": {
                          "type": "integer"
                        },
                        "passed_count": {
                          "type": "integer"
                        },
                        "earned_points": {
                          "type": "integer"
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/courses/{slug}": {
      "get": {
        "tags": [
          "Courses"
        ],
        "summary": "Course detail with quiz questions",
        "description": "Course detail including quiz questions. Option order is shuffled per request; each option keeps its original index as `key` (submit that as `answer_index`). Correct answers and explanations are never sent here. Open endpoint; includes the viewer's completion when a session cookie is present.",
        "security": [],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CourseDetail"
                }
              }
            }
          },
          "404": {
            "description": "No such course",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/courses/{slug}/submit": {
      "post": {
        "tags": [
          "Courses"
        ],
        "summary": "Submit course answers for grading",
        "description": "Course quiz submissions are temporarily unavailable (disabled to prevent Trust-Score farming); this endpoint always responds 410. Requires a logged-in session (cookie auth) — not an API key. When re-enabled, `answer_index` is the ORIGINAL option index (the `key` from the detail payload), and a pass records the completion (best score kept, pass sticky) and recomputes the cached Trust Score.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "slug",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "answers"
                ],
                "properties": {
                  "answers": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "question_id",
                        "answer_index"
                      ],
                      "properties": {
                        "question_id": {
                          "type": "string"
                        },
                        "answer_index": {
                          "type": "integer",
                          "description": "The original option index (the `key` from course detail)."
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "401": {
            "description": "Not signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "410": {
            "description": "Course quiz submissions are temporarily unavailable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/me/tripwires": {
      "get": {
        "tags": [
          "Tripwires"
        ],
        "summary": "List the caller's armed tripwires with stats and prefs.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Armed wires, stat counters, and alert prefs."
          }
        }
      },
      "post": {
        "tags": [
          "Tripwires"
        ],
        "summary": "Arm a tripwire on a handle or Discord ID.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "who"
                ],
                "properties": {
                  "who": {
                    "type": "string",
                    "description": "@handle or a Discord snowflake"
                  },
                  "triggers": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "blacklist",
                        "flag",
                        "trust"
                      ]
                    }
                  },
                  "trust_threshold": {
                    "type": "integer",
                    "minimum": 0,
                    "maximum": 250
                  },
                  "duration_days": {
                    "type": "integer",
                    "nullable": true,
                    "description": "null ⇒ until disarmed"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "The armed wire."
          }
        }
      }
    },
    "/v1/me/tripwires/feed": {
      "get": {
        "tags": [
          "Tripwires"
        ],
        "summary": "Recent tripwire events (fires + clears) for the caller.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Newest-first event list."
          }
        }
      }
    },
    "/v1/me/tripwires/prefs": {
      "post": {
        "tags": [
          "Tripwires"
        ],
        "summary": "Update DM-routing / auto-watch prefs (KV-backed).",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "The updated prefs."
          }
        }
      }
    },
    "/v1/me/tripwires/{id}": {
      "delete": {
        "tags": [
          "Tripwires"
        ],
        "summary": "Disarm (delete) a wire the caller owns.",
        "security": [
          {
            "cookieAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Disarmed."
          },
          "404": {
            "description": "Not found or not owned."
          }
        }
      }
    },
    "/v1/me/usage": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Usage stats for the calling key",
        "description": "Returns the calling API key's total and current-month request counts, its live rate-limit status, and a per-endpoint breakdown. Authenticated by any valid API key — no specific scope required.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UsageStats"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/partner/stats": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Partner program stats (paid API)",
        "description": "Requires Pro or higher. Returns the calling key's current-month request count, today's daily-quota usage and remaining allowance, the number of creators currently watched via tripwires, and the webhook delivery success rate.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Pro or higher required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/public/blacklist/check": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Free, unauthenticated unified blacklist search (rate-limited)",
        "description": "Provider-less unified search: send a single query and it is checked against every supported platform at once. Powers the free public tool widget. No API key required. Per-IP rate-limited (~30/min, 200/day).",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The query to search — a username, handle, or native id. Matched across all platforms. (`id` is accepted as a legacy alias.)"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "query": {
                      "type": "string"
                    },
                    "vertical": {
                      "type": "string"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/BlacklistHit"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing `q`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Daily/burst limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/public/connections": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Public linked accounts for a creator (keyless)",
        "description": "Returns the creator's public, non-revoked linked platform accounts. Keyless. Powers connected-account pills in the extension badge.",
        "security": [],
        "parameters": [
          {
            "name": "handle",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Creator handle (without the leading @)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK — `connections` is empty when creator not found or has no public connections.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connections": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "provider": {
                            "type": "string"
                          },
                          "provider_username": {
                            "type": "string",
                            "nullable": true
                          },
                          "provider_url": {
                            "type": "string",
                            "nullable": true
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing `handle`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/public/creators": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Browse verified creators (search, filter, sort, paginate)",
        "description": "Keyless, rate-limited feed of verified creators powering the public directory. Supports free-text search, platform / verified / good-standing filters, sort, and page-based pagination. Also reachable at the legacy /v1/directory path.",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "Match on handle, display name, linked-account username, or verification level."
          },
          {
            "name": "platform",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "roblox",
                "uefn",
                "minecraft"
              ]
            },
            "description": "Only creators with a public verified account on this platform."
          },
          {
            "name": "verified",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            },
            "description": "`1` to restrict to Established+ creators (verification level >= 2)."
          },
          {
            "name": "standing",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "good"
              ]
            },
            "description": "`good` to restrict to creators in Good+ Standing (latest Trust Score >= 150)."
          },
          {
            "name": "sort",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "newest",
                "trust",
                "vouches",
                "deals"
              ]
            },
            "description": "Sort order (default `trust`)."
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "1-based page number (default 1)."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50
            },
            "description": "Results per page (default 24, max 50)."
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of verified creators. Supports free-text search, platform / verified / good-standing filters, sort, and page-based pagination."
          }
        }
      }
    },
    "/v1/public/resolve": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Resolve a public linked account to its creator",
        "description": "Maps a public linked platform account (provider + native id) to its VerifyUGC creator and Trust Score. Keyless. Privacy-gated: only connections the user marked public are resolvable. Powers inline extension badges.",
        "security": [],
        "parameters": [
          {
            "name": "provider",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Platform of the linked account, e.g. `roblox`."
          },
          {
            "name": "id",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Native platform user id."
          }
        ],
        "responses": {
          "200": {
            "description": "OK — `found` is false when no public connection matches.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "found": {
                      "type": "boolean"
                    },
                    "handle": {
                      "type": "string"
                    },
                    "trust_score": {
                      "type": "integer"
                    },
                    "band": {
                      "type": "string"
                    },
                    "blacklisted": {
                      "type": "boolean"
                    },
                    "profile_url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing `provider` or `id`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/public/trust": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Free public Trust tier lookup",
        "description": "Looks up a creator's public Trust tier (band + label + colour) by handle. Keyless. The raw numeric Trust Score is only included when the caller has a valid VerifyUGC session cookie.",
        "security": [],
        "parameters": [
          {
            "name": "handle",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Creator handle (without the leading @)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "handle": {
                      "type": "string"
                    },
                    "found": {
                      "type": "boolean"
                    },
                    "band": {
                      "type": "string"
                    },
                    "tier": {
                      "type": "string"
                    },
                    "tier_color": {
                      "type": "string"
                    },
                    "trust_score": {
                      "type": "integer",
                      "description": "Only present for authenticated (session) callers."
                    },
                    "blacklisted": {
                      "type": "boolean"
                    },
                    "checked_at": {
                      "type": "string",
                      "format": "date-time"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing `handle`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No such creator",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "handle": {
                      "type": "string"
                    },
                    "found": {
                      "type": "boolean"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/stats/public": {
      "get": {
        "tags": [
          "Public"
        ],
        "summary": "Public social-proof counters",
        "description": "Cached homepage counters (creators verified, servers protected, entries listed, deals completed). Keyless. KV-cached ~1h and edge-cacheable.",
        "security": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicStats"
                }
              }
            }
          }
        }
      }
    },
    "/v1/tools/link-check": {
      "post": {
        "tags": [
          "Public"
        ],
        "summary": "Check whether a link is a known fake-verification / phishing site",
        "description": "Free, per-IP rate-limited (10/min). Checks a pasted URL against Google Web Risk (the Safe Browsing threat lists) plus a maintained blocklist of known scam domains and a small set of gaming-scam lure patterns. Recognized official and reputable sites are answered from an allowlist without an external call. The link is sent to Google Web Risk for the reputation check, the verdict is cached briefly, and the checked link and its verdict are logged so we can improve the tool and the scam blocklist.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "The link to check (with or without a scheme)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string"
                    },
                    "safe": {
                      "type": "boolean"
                    },
                    "risk_level": {
                      "type": "string",
                      "enum": [
                        "safe",
                        "suspicious",
                        "dangerous"
                      ]
                    },
                    "reasons": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "official_url": {
                      "type": "string",
                      "format": "uri"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid `url`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/tools/similarity-check": {
      "post": {
        "tags": [
          "Public"
        ],
        "summary": "Check a work description for similarity against the prior-art registries",
        "description": "Free, keyless, per-IP rate-limited (5/min). Tokenizes a pasted work description and scores it against the descriptions already filed in the Asset Fingerprint Registry and the UEFN Map Registry using a basic word-overlap heuristic. Returns only matches above 40% word overlap. The description is never stored. This is a heuristic, not a legal plagiarism ruling.",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "description"
                ],
                "properties": {
                  "description": {
                    "type": "string",
                    "description": "The work description to check (asset name, description, style notes)."
                  },
                  "platform": {
                    "type": "string",
                    "description": "Which registries to search: 'roblox', 'uefn'/'fortnite', or 'all' (default)."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "matches": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "registrant_handle": {
                            "type": "string"
                          },
                          "similarity_score": {
                            "type": "integer"
                          },
                          "platform": {
                            "type": "string"
                          }
                        }
                      }
                    },
                    "total_checked": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Missing or invalid `description`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited"
          }
        }
      }
    },
    "/v1/users/{handle}": {
      "get": {
        "tags": [
          "Creators"
        ],
        "summary": "Public creator profile",
        "description": "Returns a creator's public profile including their headline Trust Score, verification level, review summary and linked-account count.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Creator handle (without the leading @)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CreatorProfile"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/users/{handle}/connections": {
      "get": {
        "tags": [
          "Creators"
        ],
        "summary": "Public linked accounts for a creator",
        "description": "Lists the creator's public, non-revoked linked platform accounts. Private connections are never returned.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "connections": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Connection"
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/v1/users/{handle}/trust": {
      "get": {
        "tags": [
          "Creators"
        ],
        "summary": "Creator Trust Score breakdown",
        "description": "The composite Trust Score (0–250) plus the coarse public basis behind it (verification, account age, linked accounts, completed deals, reviews) and a recent trend. Designed to be called before doing business. Penalty internals are never exposed.",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "handle",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TrustBreakdown"
                }
              }
            }
          },
          "401": {
            "description": "Missing/invalid key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Subscription required",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}
