{
	"openapi": "3.1.0",
	"info": {
		"title": "Featured Channels API",
		"version": "2.0.0",
		"description": "Control your featured channels from Nightbot, StreamElements, a Stream Deck, a script or any tool that can call a URL. Everything here uses your **command token**: the part after `/bot/` in the command link on the **Chatbot** tab of the extension settings. Keep it private; if it leaks, regenerate it there.",
		"contact": {
			"name": "FURiOUS",
			"url": "https://www.twitch.tv/furious"
		}
	},
	"servers": [
		{
			"url": "/",
			"description": "This server"
		}
	],
	"tags": [
		{
			"name": "Chatbot commands",
			"description": "Change the featured channels from chat or any tool. Replies are always plain text with status 200, because chatbots print them in chat."
		},
		{
			"name": "Overlay boxes",
			"description": "**Pro.** Read or replace the boxes placed over the video overlay, as a JSON array with each box's channel, position and size."
		}
	],
	"paths": {
		"/bot/{token}": {
			"get": {
				"tags": [
					"Chatbot commands"
				],
				"summary": "Show the current list",
				"description": "Same as `!featured` with nothing after it.",
				"operationId": "botList",
				"parameters": [
					{
						"$ref": "#/components/parameters/BotToken"
					}
				],
				"responses": {
					"200": {
						"$ref": "#/components/responses/ChatReply"
					}
				}
			}
		},
		"/bot/{token}/{command}": {
			"get": {
				"tags": [
					"Chatbot commands"
				],
				"summary": "Run a command",
				"description": "The command is the text a moderator typed after `!featured`, URL-encoded.\n\n| Command | Effect |\n|---|---|\n| `name1, name2, name3` | Replace the channel list (commas or spaces) |\n| `-` | Clear the channel list |\n| `team/teamname` | Set the Twitch Team (`team/-` removes it) |\n| `title=Text` | Set the title (max 60 characters) |\n| `subtitle=Text` | Set the subtitle (max 120 characters) |\n| `show` / `show 60` | **Pro:** show the video overlay to every viewer for 30 s, or 5–600 s |\n| `show on` | **Pro:** keep the overlay shown until `hide` |\n| `hide` | **Pro:** hide the overlay |\n\nChanges reach viewers instantly. With *Announce in chat* on, list changes are also posted in chat.",
				"operationId": "botCommand",
				"parameters": [
					{
						"$ref": "#/components/parameters/BotToken"
					},
					{
						"name": "command",
						"in": "path",
						"required": true,
						"description": "The command text (URL-encoded; `/` may be sent as `%2F`).",
						"schema": {
							"type": "string"
						},
						"examples": {
							"channels": {
								"summary": "Replace the list",
								"value": "aurora_plays, pixelpanda, nightowl_tv"
							},
							"clear": {
								"summary": "Clear the list",
								"value": "-"
							},
							"team": {
								"summary": "Set a team",
								"value": "team/speedrunners"
							},
							"title": {
								"summary": "Set the title",
								"value": "title=Raid train!"
							},
							"subtitle": {
								"summary": "Set the subtitle",
								"value": "subtitle=Go give them some love"
							},
							"show": {
								"summary": "Pro: show the overlay for 60 s",
								"value": "show 60"
							},
							"pin": {
								"summary": "Pro: keep the overlay shown",
								"value": "show on"
							},
							"hide": {
								"summary": "Pro: hide the overlay",
								"value": "hide"
							}
						}
					}
				],
				"responses": {
					"200": {
						"$ref": "#/components/responses/ChatReply"
					}
				}
			}
		},
		"/api/boxes/{token}": {
			"get": {
				"tags": [
					"Overlay boxes"
				],
				"summary": "Read the boxes",
				"description": "The boxes currently placed over the video overlay. Works for any channel; boxes only show to viewers with Pro.",
				"operationId": "boxesGet",
				"parameters": [
					{
						"$ref": "#/components/parameters/BotToken"
					}
				],
				"responses": {
					"200": {
						"$ref": "#/components/responses/Boxes"
					},
					"401": {
						"$ref": "#/components/responses/Error"
					}
				}
			},
			"put": {
				"tags": [
					"Overlay boxes"
				],
				"summary": "Replace the boxes",
				"description": "Replaces all boxes with the array you send (send `[]` to remove them). Positions and sizes are **percent of the video picture** (0–100): `x`/`y` is the box's top-left corner, `w`/`h` its width and height. Values are rounded to 0.1 and kept inside the video (minimum size 2). Up to 12 boxes. Viewers see the change instantly.\n\nBy default the overlay keeps showing what the settings say; add `mode` to switch between the channel list, the boxes or both.",
				"operationId": "boxesPut",
				"parameters": [
					{
						"$ref": "#/components/parameters/BotToken"
					},
					{
						"name": "mode",
						"in": "query",
						"description": "Also set what the overlay shows.",
						"schema": {
							"type": "string",
							"enum": [
								"list",
								"hotspots",
								"both"
							]
						},
						"example": "both"
					}
				],
				"requestBody": {
					"required": true,
					"content": {
						"application/json": {
							"schema": {
								"type": "array",
								"maxItems": 12,
								"items": {
									"$ref": "#/components/schemas/Box"
								}
							},
							"example": [
								{
									"login": "aurora_plays",
									"x": 5,
									"y": 10,
									"w": 20,
									"h": 20
								},
								{
									"login": "pixelpanda",
									"x": 75,
									"y": 10,
									"w": 20,
									"h": 20
								}
							]
						}
					}
				},
				"responses": {
					"200": {
						"$ref": "#/components/responses/Boxes"
					},
					"400": {
						"$ref": "#/components/responses/Error"
					},
					"401": {
						"$ref": "#/components/responses/Error"
					},
					"403": {
						"description": "The channel doesn't have Pro",
						"content": {
							"application/json": {
								"schema": {
									"type": "object",
									"properties": {
										"message": {
											"type": "string"
										},
										"subscribe_url": {
											"type": "string",
											"format": "uri"
										}
									}
								},
								"example": {
									"message": "Placed boxes are a Pro feature",
									"subscribe_url": "https://www.twitch.tv/subs/furious"
								}
							}
						}
					},
					"413": {
						"$ref": "#/components/responses/Error"
					}
				}
			}
		}
	},
	"components": {
		"parameters": {
			"BotToken": {
				"name": "token",
				"in": "path",
				"required": true,
				"description": "Your command token, from the Chatbot tab of the extension settings (the part after `/bot/` in your command link). Keep it private.",
				"schema": {
					"type": "string",
					"pattern": "^\\d+\\.[A-Za-z0-9_-]+$"
				}
			}
		},
		"responses": {
			"ChatReply": {
				"description": "A plain-text reply for the chatbot to print. Errors are replies too (invalid link, Pro needed, Twitch not responding).",
				"content": {
					"text/plain": {
						"schema": {
							"type": "string"
						},
						"examples": {
							"list": {
								"value": "Featured channels: twitch.tv/aurora_plays • twitch.tv/pixelpanda | team: speedrunners"
							},
							"updated": {
								"value": "Featured channels updated: aurora_plays, pixelpanda, nightowl_tv"
							},
							"show": {
								"value": "Featured channels overlay shown for 60 seconds."
							},
							"invalid": {
								"value": "Featured Channels: this command link is invalid. Copy a new one from the extension settings."
							}
						}
					}
				}
			},
			"Error": {
				"description": "Error (the reason is in `message`)",
				"content": {
					"application/json": {
						"schema": {
							"type": "object",
							"properties": {
								"message": {
									"type": "string"
								}
							}
						},
						"example": {
							"message": "Authorization failed"
						}
					}
				}
			},
			"Boxes": {
				"description": "The boxes now placed over the overlay",
				"content": {
					"application/json": {
						"schema": {
							"type": "object",
							"properties": {
								"boxes": {
									"type": "array",
									"items": {
										"$ref": "#/components/schemas/Box"
									}
								},
								"overlay_mode": {
									"type": "string",
									"enum": [
										"list",
										"hotspots",
										"both"
									],
									"description": "What the overlay shows: the channel list, the boxes, or both"
								},
								"max": {
									"type": "integer",
									"description": "Most boxes allowed"
								}
							}
						},
						"example": {
							"boxes": [
								{
									"login": "aurora_plays",
									"x": 5,
									"y": 10,
									"w": 20,
									"h": 20
								}
							],
							"overlay_mode": "both",
							"max": 12
						}
					}
				}
			}
		},
		"schemas": {
			"Box": {
				"type": "object",
				"required": [
					"login",
					"x",
					"y",
					"w",
					"h"
				],
				"properties": {
					"login": {
						"type": "string",
						"description": "The featured channel's Twitch login",
						"example": "aurora_plays"
					},
					"x": {
						"type": "number",
						"minimum": 0,
						"maximum": 98,
						"description": "Left edge, percent of the video width",
						"example": 5
					},
					"y": {
						"type": "number",
						"minimum": 0,
						"maximum": 98,
						"description": "Top edge, percent of the video height",
						"example": 10
					},
					"w": {
						"type": "number",
						"minimum": 2,
						"maximum": 100,
						"description": "Width, percent of the video width",
						"example": 20
					},
					"h": {
						"type": "number",
						"minimum": 2,
						"maximum": 100,
						"description": "Height, percent of the video height",
						"example": 20
					}
				}
			}
		}
	}
}
