{ "openapi": "3.0.3", "info": { "title": "Flavortown API", "version": "v1", "description": "You need an API key to use this! Go to your [account settings](https://flavortown.hackclub.com/kitchen?settings=1) to get one." }, "servers": [ { "url": "https://flavortown.hackclub.com/api/v1" } ], "security": [ { "bearerAuth": [] } ], "components": { "securitySchemes": { "bearerAuth": { "type": "http", "scheme": "bearer", "description": "Include your API key via `Authorization: Bearer YOUR_API_KEY`. You can find or regenerate your API key in your [account settings](https://flavortown.hackclub.com/kitchen?settings=1)." } }, "schemas": { "Pagination": { "type": "object", "properties": { "current_page": { "type": "integer" }, "total_pages": { "type": "integer" }, "total_count": { "type": "integer" }, "next_page": { "type": "integer", "nullable": true } } }, "Project": { "type": "object", "properties": { "id": { "type": "integer" }, "title": { "type": "string" }, "description": { "type": "string" }, "repo_url": { "type": "string" }, "demo_url": { "type": "string" }, "readme_url": { "type": "string" }, "ai_declaration": { "type": "string" }, "ship_status": { "type": "string" }, "devlog_ids": { "type": "array", "items": { "type": "integer" } }, "banner_url": { "type": "string", "nullable": true }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } }, "Comment": { "type": "object", "properties": { "id": { "type": "integer" }, "author": { "type": "object", "properties": { "id": { "type": "integer" }, "display_name": { "type": "string" }, "avatar": { "type": "string" } } }, "body": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } } }, "Devlog": { "type": "object", "properties": { "id": { "type": "integer" }, "body": { "type": "string" }, "comments_count": { "type": "integer" }, "duration_seconds": { "type": "integer" }, "likes_count": { "type": "integer" }, "scrapbook_url": { "type": "string" }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" }, "media": { "type": "array", "items": { "type": "object", "properties": { "url": { "type": "string" }, "content_type": { "type": "string" } } } }, "comments": { "type": "array", "items": { "$ref": "#/components/schemas/Comment" } } } }, "User": { "type": "object", "properties": { "id": { "type": "integer" }, "slack_id": { "type": "string" }, "display_name": { "type": "string" }, "avatar": { "type": "string" }, "project_ids": { "type": "array", "items": { "type": "integer" } }, "cookies": { "type": "integer", "nullable": true } } }, "UserDetail": { "allOf": [ { "$ref": "#/components/schemas/User" }, { "type": "object", "properties": { "vote_count": { "type": "integer" }, "like_count": { "type": "integer" }, "devlog_seconds_total": { "type": "integer" }, "devlog_seconds_today": { "type": "integer" } } } ] }, "RegionEnabled": { "type": "object", "properties": { "enabled_au": { "type": "boolean" }, "enabled_ca": { "type": "boolean" }, "enabled_eu": { "type": "boolean" }, "enabled_in": { "type": "boolean" }, "enabled_uk": { "type": "boolean" }, "enabled_us": { "type": "boolean" }, "enabled_xx": { "type": "boolean" } } }, "TicketCost": { "type": "object", "properties": { "base_cost": { "type": "number" }, "au": { "type": "number" }, "ca": { "type": "number" }, "eu": { "type": "number" }, "in": { "type": "number" }, "uk": { "type": "number" }, "us": { "type": "number" }, "xx": { "type": "number" } } }, "StoreItem": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "description": { "type": "string" }, "old_prices": { "type": "array", "items": {} }, "limited": { "type": "boolean" }, "stock": { "type": "integer" }, "type": { "type": "string" }, "show_in_carousel": { "type": "boolean" }, "accessory_tag": { "type": "string" }, "agh_contents": { "type": "string" }, "attached_shop_item_ids": { "type": "array", "items": {} }, "buyable_by_self": { "type": "boolean" }, "long_description": { "type": "string" }, "max_qty": { "type": "integer" }, "one_per_person_ever": { "type": "boolean" }, "sale_percentage": { "type": "integer" }, "image_url": { "type": "string" }, "enabled": { "$ref": "#/components/schemas/RegionEnabled" }, "ticket_cost": { "$ref": "#/components/schemas/TicketCost" } } }, "Error": { "type": "object", "properties": { "error": { "type": "string" } } }, "ValidationErrors": { "type": "object", "properties": { "errors": { "type": "array", "items": { "type": "string" } } } } }, "responses": { "Unauthorized": { "description": "Missing or invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Invalid API key" } } } }, "Forbidden": { "description": "Permission denied", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "NotFound": { "description": "Resource not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Resource not found" } } } }, "UnprocessableEntity": { "description": "Validation failed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ValidationErrors" } } } } } }, "paths": { "/projects": { "get": { "summary": "List projects", "tags": [ "Projects" ], "description": "Fetch a list of projects. Ratelimit: 5 reqs/min, 20 reqs/min if searching.", "operationId": "listProjects", "parameters": [ { "name": "page", "in": "query", "required": false, "schema": { "type": "integer" }, "description": "Page number for pagination" }, { "name": "query", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Search projects by title or description" } ], "responses": { "200": { "description": "A paginated list of projects", "content": { "application/json": { "schema": { "type": "object", "properties": { "projects": { "type": "array", "items": { "$ref": "#/components/schemas/Project" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" } } }, "post": { "summary": "Create a project", "tags": [ "Projects" ], "description": "Create a new project.", "operationId": "createProject", "parameters": [], "responses": { "201": { "description": "Project created", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "422": { "$ref": "#/components/responses/UnprocessableEntity" } }, "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": { "type": "object", "required": [ "title", "description" ], "properties": { "title": { "type": "string", "description": "Project title" }, "description": { "type": "string", "description": "Project description" }, "repo_url": { "type": "string", "description": "URL to the source code repository" }, "demo_url": { "type": "string", "description": "URL to the live demo" }, "readme_url": { "type": "string", "description": "URL to the README" }, "ai_declaration": { "type": "string", "description": "Declaration of AI tools used in this project" } } } } }, "required": true } } }, "/projects/{id}": { "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "get": { "summary": "Get a project", "tags": [ "Projects" ], "description": "Fetch a specific project by ID. Ratelimit: 30 reqs/min.", "operationId": "getProject", "responses": { "200": { "description": "A single project", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } } }, "patch": { "summary": "Update a project", "tags": [ "Projects" ], "description": "Update an existing project.", "operationId": "updateProject", "parameters": [], "responses": { "200": { "description": "Project updated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Project" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "403": { "$ref": "#/components/responses/Forbidden" }, "404": { "$ref": "#/components/responses/NotFound" }, "422": { "$ref": "#/components/responses/UnprocessableEntity" } }, "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": { "type": "object", "properties": { "title": { "type": "string", "description": "Project title" }, "description": { "type": "string", "description": "Project description" }, "repo_url": { "type": "string", "description": "URL to the source code repository" }, "demo_url": { "type": "string", "description": "URL to the live demo" }, "readme_url": { "type": "string", "description": "URL to the README" }, "ai_declaration": { "type": "string", "description": "Declaration of AI tools used in this project" } } } } }, "required": true } } }, "/projects/{project_id}/devlogs": { "get": { "summary": "List project devlogs", "tags": [ "Projects" ], "description": "Fetch all devlogs for a specific project.", "operationId": "listProjectDevlogs", "parameters": [ { "name": "project_id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "A paginated list of devlogs for the project", "content": { "application/json": { "schema": { "type": "object", "properties": { "devlogs": { "type": "array", "items": { "$ref": "#/components/schemas/Devlog" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } } } }, "/devlogs": { "get": { "summary": "List devlogs", "tags": [ "Devlogs" ], "description": "Fetch all devlogs across all projects.", "operationId": "listDevlogs", "parameters": [ { "name": "page", "in": "query", "required": false, "schema": { "type": "integer" }, "description": "Page number for pagination" } ], "responses": { "200": { "description": "A paginated list of devlogs", "content": { "application/json": { "schema": { "type": "object", "properties": { "devlogs": { "type": "array", "items": { "$ref": "#/components/schemas/Devlog" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" } } } }, "/devlogs/{id}": { "get": { "summary": "Get a devlog", "tags": [ "Devlogs" ], "description": "Fetch a devlog by ID.", "operationId": "getDevlog", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "A single devlog", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Devlog" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } } } }, "/store": { "get": { "summary": "List store items", "tags": [ "Store" ], "description": "Fetch a list of store items. Ratelimit: 5 reqs/min.", "operationId": "listStoreItems", "responses": { "200": { "description": "A list of store items", "content": { "application/json": { "schema": { "type": "array", "items": { "$ref": "#/components/schemas/StoreItem" } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" } } } }, "/store/{id}": { "get": { "summary": "Get a store item", "tags": [ "Store" ], "description": "Fetch a specific store item by ID. Ratelimit: 30 reqs/min.", "operationId": "getStoreItem", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "description": "A single store item", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StoreItem" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } } } }, "/users": { "get": { "summary": "List users", "tags": [ "Users" ], "description": "Fetch a list of users. Ratelimit: 5 reqs/min.", "operationId": "listUsers", "parameters": [ { "name": "page", "in": "query", "required": false, "schema": { "type": "integer" }, "description": "Page number for pagination" }, { "name": "query", "in": "query", "required": false, "schema": { "type": "string" }, "description": "Search users by display name or slack ID" } ], "responses": { "200": { "description": "A paginated list of users", "content": { "application/json": { "schema": { "type": "object", "properties": { "users": { "type": "array", "items": { "$ref": "#/components/schemas/User" } }, "pagination": { "$ref": "#/components/schemas/Pagination" } } } } } }, "401": { "$ref": "#/components/responses/Unauthorized" } } } }, "/users/{id}": { "get": { "summary": "Get a user", "tags": [ "Users" ], "description": "Fetch a specific user by ID. Use \"me\" as the ID to fetch the authenticated user.", "operationId": "getUser", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string" }, "description": "User ID or \"me\" for the authenticated user" } ], "responses": { "200": { "description": "A single user with additional stats", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserDetail" } } } }, "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" } } } } } }