{
 "openapi": "3.1.0",
 "info": {
  "title": "LFG Atlas public API",
  "version": "1.0.0",
  "description": "Free, keyless API for live LFG posts across 28 games. Docs: https://lfgatlas.pages.dev/developers/",
  "contact": {
   "url": "https://lfgatlas.pages.dev/contact.html"
  }
 },
 "servers": [
  {
   "url": "https://lfgatlas-bot.jonsimm36.workers.dev"
  }
 ],
 "paths": {
  "/api/games": {
   "get": {
    "operationId": "listGames",
    "summary": "List games",
    "responses": {
     "200": {
      "description": "Games"
     }
    }
   }
  },
  "/api/posts": {
   "get": {
    "operationId": "findPosts",
    "summary": "Find live LFG posts",
    "parameters": [
     {
      "in": "query",
      "required": false,
      "description": "Game slug or name (see /api/games)",
      "schema": {
       "type": "string"
      },
      "name": "game"
     },
     {
      "in": "query",
      "required": false,
      "description": "Post type",
      "schema": {
       "type": "string",
       "enum": [
        "lfg",
        "lfm",
        "server",
        "clan",
        "squad"
       ]
      },
      "name": "type"
     },
     {
      "in": "query",
      "required": false,
      "description": "Region, matched loosely (e.g. EU, NA East)",
      "schema": {
       "type": "string"
      },
      "name": "region"
     },
     {
      "in": "query",
      "required": false,
      "description": "Only players ready right now",
      "schema": {
       "type": "boolean"
      },
      "name": "ready_now"
     },
     {
      "in": "query",
      "required": false,
      "description": "Where it was posted",
      "schema": {
       "type": "string",
       "enum": [
        "atlas",
        "wildslfg",
        "shroudlfg"
       ]
      },
      "name": "source"
     },
     {
      "in": "query",
      "required": false,
      "description": "Only posts created after this ISO time",
      "schema": {
       "type": "string",
       "format": "date-time"
      },
      "name": "since"
     },
     {
      "in": "query",
      "required": false,
      "description": "Max results (1–100, default 50)",
      "schema": {
       "type": "integer",
       "minimum": 1,
       "maximum": 100
      },
      "name": "limit"
     }
    ],
    "responses": {
     "200": {
      "description": "Posts"
     }
    }
   },
   "post": {
    "operationId": "createPost",
    "summary": "Create a post for a player who asked you to",
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "$ref": "#/components/schemas/NewPost"
       }
      }
     }
    },
    "responses": {
     "201": {
      "description": "Created; includes private manage links for the player"
     },
     "400": {
      "description": "Rejected by the rules"
     },
     "429": {
      "description": "Rate limited (see Retry-After)"
     }
    }
   }
  },
  "/api/posts/{id}": {
   "get": {
    "operationId": "getPost",
    "summary": "Get one live post",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "responses": {
     "200": {
      "description": "Post"
     },
     "404": {
      "description": "Expired or removed"
     }
    }
   },
   "delete": {
    "operationId": "deletePost",
    "summary": "Delete a post you created",
    "parameters": [
     {
      "name": "id",
      "in": "path",
      "required": true,
      "schema": {
       "type": "string",
       "format": "uuid"
      }
     }
    ],
    "requestBody": {
     "required": true,
     "content": {
      "application/json": {
       "schema": {
        "type": "object",
        "required": [
         "edit_token"
        ],
        "properties": {
         "edit_token": {
          "type": "string",
          "format": "uuid"
         }
        }
       }
      }
     }
    },
    "responses": {
     "200": {
      "description": "Deleted"
     }
    }
   }
  },
  "/feed.xml": {
   "get": {
    "operationId": "rssFeed",
    "summary": "RSS 2.0 feed",
    "parameters": [
     {
      "in": "query",
      "required": false,
      "description": "Game slug (optional)",
      "schema": {
       "type": "string"
      },
      "name": "game"
     }
    ],
    "responses": {
     "200": {
      "description": "RSS",
      "content": {
       "application/rss+xml": {}
      }
     }
    }
   }
  },
  "/feed.atom": {
   "get": {
    "operationId": "atomFeed",
    "summary": "Atom feed",
    "parameters": [
     {
      "in": "query",
      "required": false,
      "description": "Game slug (optional)",
      "schema": {
       "type": "string"
      },
      "name": "game"
     }
    ],
    "responses": {
     "200": {
      "description": "Atom",
      "content": {
       "application/atom+xml": {}
      }
     }
    }
   }
  },
  "/feed.json": {
   "get": {
    "operationId": "jsonFeed",
    "summary": "JSON Feed 1.1",
    "parameters": [
     {
      "in": "query",
      "required": false,
      "description": "Game slug (optional)",
      "schema": {
       "type": "string"
      },
      "name": "game"
     }
    ],
    "responses": {
     "200": {
      "description": "JSON Feed"
     }
    }
   }
  },
  "/api/events": {
   "get": {
    "operationId": "clanEvents",
    "summary": "Upcoming and ongoing RuneScape clan events (ClanBingoBoard)",
    "responses": {
     "200": {
      "description": "Events"
     }
    }
   }
  }
 },
 "components": {
  "schemas": {
   "NewPost": {
    "type": "object",
    "required": [
     "game",
     "title",
     "region",
     "contact",
     "source",
     "consent"
    ],
    "additionalProperties": true,
    "properties": {
     "consent": {
      "type": "boolean",
      "const": true,
      "description": "true = the player behind this contact asked for this post. Never post other people's messages."
     },
     "source": {
      "type": "string",
      "pattern": "^[a-z0-9][a-z0-9_-]{1,31}$",
      "description": "Short name of your bot/app/site, e.g. myclan-bot (shown as the post's origin)"
     },
     "game": {
      "type": "string",
      "description": "Game slug from list_games / /api/games, e.g. cs2, valorant, osrs"
     },
     "type": {
      "type": "string",
      "enum": [
       "lfg",
       "lfm",
       "server",
       "clan",
       "squad"
      ],
      "default": "lfg",
      "description": "lfg = player wants a group; lfm = group needs players; server; clan; squad (regular group)"
     },
     "title": {
      "type": "string",
      "minLength": 3,
      "maxLength": 80,
      "description": "Short headline, no links"
     },
     "description": {
      "type": "string",
      "maxLength": 500,
      "description": "Details, no links"
     },
     "region": {
      "type": "string",
      "maxLength": 40,
      "description": "Region/server, ideally one from the game's regions list"
     },
     "platform": {
      "type": "string",
      "maxLength": 30
     },
     "mode": {
      "type": "string",
      "maxLength": 60,
      "description": "Activity/mode, ideally from the game's modes list"
     },
     "rank": {
      "type": "string",
      "maxLength": 40
     },
     "role": {
      "type": "string",
      "maxLength": 40
     },
     "language": {
      "type": "string",
      "maxLength": 20
     },
     "play_time": {
      "type": "string",
      "maxLength": 20
     },
     "play_style": {
      "type": "string",
      "maxLength": 24
     },
     "need": {
      "type": "integer",
      "minimum": 1,
      "maximum": 100,
      "description": "Players needed"
     },
     "have": {
      "type": "integer",
      "minimum": 0,
      "maximum": 500
     },
     "mic": {
      "type": "boolean"
     },
     "adult": {
      "type": "boolean",
      "description": "18+ only"
     },
     "ready_now": {
      "type": "boolean",
      "description": "Playing right now (lfg/lfm only, lasts 30 min–3 h)"
     },
     "party_code": {
      "type": "string",
      "maxLength": 24,
      "description": "Lobby/party code for ready_now posts"
     },
     "squad_days": {
      "type": "string",
      "maxLength": 40,
      "description": "Required for squad posts, e.g. Mon, Wed, Fri"
     },
     "squad_time": {
      "type": "string",
      "maxLength": 20
     },
     "squad_tz": {
      "type": "string",
      "maxLength": 20
     },
     "tags": {
      "type": "array",
      "maxItems": 6,
      "items": {
       "type": "string",
       "maxLength": 24
      }
     },
     "extra_games": {
      "type": "array",
      "maxItems": 3,
      "items": {
       "type": "string"
      }
     },
     "contact": {
      "type": "string",
      "description": "The player's OWN contact: discord.gg/xxxx invite, Discord username, or in-game name"
     },
     "contact_kind": {
      "type": "string",
      "enum": [
       "discord_invite",
       "discord_user",
       "ingame"
      ],
      "description": "Optional; guessed from contact if omitted"
     },
     "hours": {
      "type": "number",
      "description": "How long it stays up: lfg/lfm 1–24 (default 3), ready_now 0.5–3, server/clan up to 168, squad 24–168"
     }
    }
   }
  }
 }
}