{"openapi":"3.1.0","info":{"title":"UTP Connect API","version":"1","description":"Read your park from outside the game — its rides, its shows, its riders and their on-ride photos — and start a show or play a track from your own website, bot or tools.\n\n**Where it lives.** Every park hosts its own instance — the site its guests open on their phones — and the API is at that address, followed by `/api/v1`. The instance also serves this document, at `/api/v1/openapi.json`, to import into Postman, Insomnia or a code generator.\n\n**Keys.** Create a key in **Administration → Settings → API** and send it with every request, as `Authorization: Bearer utp_…`. It is shown once. A *Read* key reads; a *Read and write* key can also start shows and play audio. Keep keys on a server, never in a web page anybody can open. A park holds 20 keys at most.\n\n**Limits.** 120 requests a minute per key; every answer says how many are left in `RateLimit-Remaining`. Past that, a 429 says when to try again in `Retry-After`.\n\n**Errors** come as `{ \"error\": \"code\", \"message\": \"…\" }`: test the code, show the message.\n\n**Webhooks.** To hear about laps, photos, emergency stops, shows and the server coming and going, rather than ask: add a webhook in **Administration → Settings → API**. See *Webhooks* below. A Discord channel's webhook link is sent a message for the channel instead of the envelope described there: no program needed in between."},"servers":[{"url":"https://{host}","description":"Your park's instance","variables":{"host":{"default":"connect.your-park.com","description":"The address your guests open."}}}],"security":[{"apiKey":[]}],"tags":[{"name":"Park","description":"Everything live, in one call."},{"name":"Rides","description":"Your rides, and how each stands."},{"name":"Shows","description":"The sequences of **Administration → Sequences**."},{"name":"Stats","description":"Laps, counted as the train stops back in the station."},{"name":"Photos","description":"On-ride photos, and the pages their QR codes open."},{"name":"Audio","description":"Tracks on a player's phone."}],"paths":{"/api/v1/park/live":{"get":{"tags":["Park"],"operationId":"getParkLive","summary":"The park, live","description":"Every ride and show as they are right now, in one call: what a status page needs. Asking more than once every five seconds tells you nothing new.","responses":{"200":{"description":"The park now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ParkLive"},"example":{"park":{"name":"Wonder Park","serverOnline":true,"guestsListening":42,"timeZone":"Europe/Paris"},"rides":[{"id":4,"name":"Lost Bearings","type":"coaster","availability":"open","status":"operating","phase":"running","manoeuvre":null,"operator":{"uuid":"b14e77d0-2c9a-4e6f-8d31-5f0c9a2e7b18","name":"MrPopcorn"},"guestsInStation":9,"trainInStation":false,"lapsToday":318},{"id":9,"name":"Temple Drop","type":"coaster","availability":"open","status":"down","phase":"idle","manoeuvre":null,"operator":{"uuid":"e9d0c3a4-71f2-4b8e-a6c5-0d2f8b4e1c97","name":"LunaRides"},"guestsInStation":4,"trainInStation":true,"lapsToday":96},{"id":7,"name":"Wild Detour","type":"flat","availability":"maintenance","status":"operating","phase":"idle","manoeuvre":null,"operator":null,"guestsInStation":0,"trainInStation":true,"lapsToday":141}],"shows":[{"id":3,"name":"Maya Night","region":"maya-plaza","location":"Maya Plaza","music":{"title":"Maya Night","author":"Wonder Park Orchestra"},"duration":312.5,"running":true,"startedAt":"2026-10-11T20:15:00.000Z","position":14.2,"schedule":[{"days":["monday","tuesday","wednesday","thursday","friday"],"time":"19:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true},{"days":["saturday","sunday"],"time":"21:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true}],"nextRunAt":"2026-10-12T17:00:00.000Z"}],"updatedAt":"2026-10-11T20:15:14.200Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}},"/api/v1/rides":{"get":{"tags":["Rides"],"operationId":"listRides","summary":"Every ride, live","description":"Sorted by name. A ride is `closed` while the Minecraft server is not connected.","responses":{"200":{"description":"The rides.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Ride"}},"example":[{"id":4,"name":"Lost Bearings","type":"coaster","availability":"open","status":"operating","phase":"running","manoeuvre":null,"operator":{"uuid":"b14e77d0-2c9a-4e6f-8d31-5f0c9a2e7b18","name":"MrPopcorn"},"guestsInStation":9,"trainInStation":false,"lapsToday":318},{"id":9,"name":"Temple Drop","type":"coaster","availability":"open","status":"down","phase":"idle","manoeuvre":null,"operator":{"uuid":"e9d0c3a4-71f2-4b8e-a6c5-0d2f8b4e1c97","name":"LunaRides"},"guestsInStation":4,"trainInStation":true,"lapsToday":96},{"id":7,"name":"Wild Detour","type":"flat","availability":"maintenance","status":"operating","phase":"idle","manoeuvre":null,"operator":null,"guestsInStation":0,"trainInStation":true,"lapsToday":141}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}},"/api/v1/rides/{rideId}":{"get":{"tags":["Rides"],"operationId":"getRide","summary":"One ride, live","parameters":[{"name":"rideId","in":"path","required":true,"schema":{"type":"integer"},"example":4,"description":"The ride's number, as `/utp ride list` shows it."}],"responses":{"200":{"description":"The ride now.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ride"},"example":{"id":4,"name":"Lost Bearings","type":"coaster","availability":"open","status":"operating","phase":"running","manoeuvre":null,"operator":{"uuid":"b14e77d0-2c9a-4e6f-8d31-5f0c9a2e7b18","name":"MrPopcorn"},"guestsInStation":9,"trainInStation":false,"lapsToday":318}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}},"/api/v1/rides/{rideId}/availability":{"post":{"tags":["Rides"],"operationId":"setRideAvailability","summary":"Open or close a ride","parameters":[{"name":"rideId","in":"path","required":true,"schema":{"type":"integer"},"example":4,"description":"The ride's number, as `/utp ride list` shows it."}],"description":"What `/utp ride availability <id> <state>` does in game. Closed — `closed`, `maintenance` or `broken`, which say why — no guest boards, guests already seated are let off, the operator leaves the post and nobody may take it; trains out on their lap come back and let their riders off. Under `maintenance`, staff allowed to test the ride may take the post again, ride it and send it round; those laps are not counted. The ride's commands for opening and closing run. Kept by the park, so it holds through a restart, and applied as soon as the Minecraft server is connected. Setting what the ride already is changes nothing and sends no webhook.\n\nNeeds a key with **Read and write** access.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailabilitySet"},"example":{"availability":"maintenance"}}}},"responses":{"200":{"description":"The ride, as it now stands.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Ride"},"example":{"id":4,"name":"Lost Bearings","type":"coaster","availability":"maintenance","status":"operating","phase":"running","manoeuvre":null,"operator":{"uuid":"b14e77d0-2c9a-4e6f-8d31-5f0c9a2e7b18","name":"MrPopcorn"},"guestsInStation":9,"trainInStation":false,"lapsToday":318}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ReadOnlyKey"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/Invalid"},"429":{"$ref":"#/components/responses/RateLimited"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}},"/api/v1/shows":{"get":{"tags":["Shows"],"operationId":"listShows","summary":"Every show","description":"The sequences of **Administration → Sequences**, whether each is running, and when each next starts on its schedule.","responses":{"200":{"description":"The shows.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Show"}},"example":[{"id":3,"name":"Maya Night","region":"maya-plaza","location":"Maya Plaza","music":{"title":"Maya Night","author":"Wonder Park Orchestra"},"duration":312.5,"running":true,"startedAt":"2026-10-11T20:15:00.000Z","position":14.2,"schedule":[{"days":["monday","tuesday","wednesday","thursday","friday"],"time":"19:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true},{"days":["saturday","sunday"],"time":"21:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true}],"nextRunAt":"2026-10-12T17:00:00.000Z"}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/shows/{showId}/start":{"post":{"tags":["Shows"],"operationId":"startShow","summary":"Start a show","parameters":[{"name":"showId","in":"path","required":true,"schema":{"type":"integer"},"example":3,"description":"The show's number, as `/utp sequence list` shows it."}],"description":"What `/utp sequence start <id> [from]` does in the console: the commands run, and the guests in the show's region hear its music.\n\nNeeds a key with **Read and write** access.","requestBody":{"required":false,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShowStart"},"example":{"from":"1:30"}}}},"responses":{"200":{"description":"The show, now running.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Show"},"example":{"id":3,"name":"Maya Night","region":"maya-plaza","location":"Maya Plaza","music":{"title":"Maya Night","author":"Wonder Park Orchestra"},"duration":312.5,"running":true,"startedAt":"2026-10-11T20:15:00.000Z","position":90,"schedule":[{"days":["monday","tuesday","wednesday","thursday","friday"],"time":"19:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true},{"days":["saturday","sunday"],"time":"21:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true}],"nextRunAt":"2026-10-12T17:00:00.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ReadOnlyKey"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"It is already running: stop it first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"already_running","message":"Maya Night is already running. Stop it first."}}}},"422":{"$ref":"#/components/responses/Invalid"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ServerOffline"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}},"/api/v1/shows/{showId}/stop":{"post":{"tags":["Shows"],"operationId":"stopShow","summary":"Stop a show","parameters":[{"name":"showId","in":"path","required":true,"schema":{"type":"integer"},"example":3,"description":"The show's number, as `/utp sequence list` shows it."}],"description":"What `/utp sequence stop <id>` does. Stopping a show that is not running is not an error.\n\nNeeds a key with **Read and write** access.","responses":{"200":{"description":"The show, stopped.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Show"},"example":{"id":3,"name":"Maya Night","region":"maya-plaza","location":"Maya Plaza","music":{"title":"Maya Night","author":"Wonder Park Orchestra"},"duration":312.5,"running":false,"startedAt":null,"position":null,"schedule":[{"days":["monday","tuesday","wednesday","thursday","friday"],"time":"19:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true},{"days":["saturday","sunday"],"time":"21:00","timeZone":"Europe/Paris","from":null,"until":null,"enabled":true}],"nextRunAt":"2026-10-12T17:00:00.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ReadOnlyKey"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ServerOffline"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}},"/api/v1/stats/rides":{"get":{"tags":["Stats"],"operationId":"rideStats","summary":"Laps per ride","parameters":[{"name":"period","in":"query","schema":{"type":"string","enum":["day","week","month","all"],"default":"day"},"description":"`day` is today, `week` the last seven days and `month` the last thirty, today included — days in UTC."}],"description":"The most ridden first. A ride since removed keeps the laps ridden on it.","responses":{"200":{"description":"The rides, busiest first.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/RideStats"}},"example":[{"rideId":4,"name":"Lost Bearings","laps":318,"riders":187},{"rideId":7,"name":"Wild Detour","laps":141,"riders":102}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/Invalid"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/stats/top-riders":{"get":{"tags":["Stats"],"operationId":"topRiders","summary":"Top riders","description":"The players with the most laps, on one ride or on the whole park — the list a leaderboard in the park shows.","parameters":[{"name":"rideId","in":"query","schema":{"type":"integer"},"description":"One ride's riders. The whole park if left out."},{"name":"period","in":"query","schema":{"type":"string","enum":["day","week","month","all"],"default":"day"},"description":"`day` is today, `week` the last seven days and `month` the last thirty, today included — days in UTC."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}}],"responses":{"200":{"description":"Most laps first.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TopRider"}},"example":[{"rank":1,"player":{"uuid":"3f8a2c1e-6b47-4d1a-9c2e-1a7b5e0d9f42","name":"Kaelith"},"laps":64},{"rank":2,"player":{"uuid":"e9d0c3a4-71f2-4b8e-a6c5-0d2f8b4e1c97","name":"LunaRides"},"laps":51}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/Invalid"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/players/{player}":{"get":{"tags":["Stats"],"operationId":"getPlayer","summary":"A player's laps","parameters":[{"name":"player","in":"path","required":true,"schema":{"type":"string"},"example":"Kaelith","description":"A UUID, or the name the player was last seen with."}],"responses":{"200":{"description":"The player.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlayerProfile"},"example":{"uuid":"3f8a2c1e-6b47-4d1a-9c2e-1a7b5e0d9f42","name":"Kaelith","lastSeen":"2026-10-11T19:52:08.000Z","listening":true,"totalLaps":76,"rides":[{"rideId":4,"name":"Lost Bearings","laps":64,"rank":1},{"rideId":7,"name":"Wild Detour","laps":12,"rank":8}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/photos":{"get":{"tags":["Photos"],"operationId":"listPhotos","summary":"The latest on-ride photos","description":"Photos still within the retention set in the administration, newest first.","parameters":[{"name":"rideId","in":"query","schema":{"type":"integer"},"description":"One ride's photos."},{"name":"since","in":"query","schema":{"type":"string","format":"date-time"},"description":"Only photos taken after this instant. Pass the last `takenAt` you saw to get only new ones."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":50,"default":20}}],"responses":{"200":{"description":"Newest first.","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Photo"}},"example":[{"id":"01K7AXM5Q3Z8C1V2B3N4M5P6Q7","rideId":4,"rideName":"Lost Bearings","takenAt":"2026-10-11T20:11:47.000Z","riders":[{"uuid":"3f8a2c1e-6b47-4d1a-9c2e-1a7b5e0d9f42","name":"Kaelith"},{"uuid":"b14e77d0-2c9a-4e6f-8d31-5f0c9a2e7b18","name":"MrPopcorn"}],"pageUrl":"https://connect.your-park.com/p/9F2A71C0DE","frames":["https://connect.your-park.com/api/p/9F2A71C0DE/0","https://connect.your-park.com/api/p/9F2A71C0DE/1"]}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"422":{"$ref":"#/components/responses/Invalid"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/audio/play":{"post":{"tags":["Audio"],"operationId":"playAudio","summary":"Play a track for a player","description":"What `/utp audio send` does: the track plays once on the player's phone. Nothing plays if their page is not open — `listening` says so. Their region's music comes back when they next cross a border.\n\nNeeds a key with **Read and write** access.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioPlay"},"example":{"player":"Kaelith","url":"https://music.your-park.com/welcome.mp3","volume":80}}}},"responses":{"200":{"description":"Sent to the player.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioSent"},"example":{"player":{"uuid":"3f8a2c1e-6b47-4d1a-9c2e-1a7b5e0d9f42","name":"Kaelith"},"listening":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ReadOnlyKey"},"404":{"description":"The player is not on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"not_online","message":"Kaelith is not on the server."}}}},"422":{"$ref":"#/components/responses/Invalid"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ServerOffline"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}},"/api/v1/audio/stop":{"post":{"tags":["Audio"],"operationId":"stopAudio","summary":"Stop the audio of a player","description":"What `/utp audio stop` does.\n\nNeeds a key with **Read and write** access.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioStop"},"example":{"player":"Kaelith"}}}},"responses":{"200":{"description":"Stopped.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AudioSent"},"example":{"player":{"uuid":"3f8a2c1e-6b47-4d1a-9c2e-1a7b5e0d9f42","name":"Kaelith"},"listening":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/ReadOnlyKey"},"404":{"description":"The player is not on the server.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"not_online","message":"Kaelith is not on the server."}}}},"422":{"$ref":"#/components/responses/Invalid"},"429":{"$ref":"#/components/responses/RateLimited"},"503":{"$ref":"#/components/responses/ServerOffline"},"504":{"$ref":"#/components/responses/ServerTimeout"}}}}},"webhooks":{"ride.lap.completed":{"post":{"summary":"A lap is over","description":"Sent as the train stops back in the station — or at the ride's unload platform — before anybody is let out: one message per lap, with everybody aboard.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"ride.lap.completed"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/LapCompleted"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"ride.lap.completed","timestamp":"2026-10-11T20:11:49.000Z","data":{"rideId":4,"rideName":"Lost Bearings","riders":[{"uuid":"3f8a2c1e-6b47-4d1a-9c2e-1a7b5e0d9f42","name":"Kaelith"},{"uuid":"b14e77d0-2c9a-4e6f-8d31-5f0c9a2e7b18","name":"MrPopcorn"}]}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"ride.photo.taken":{"post":{"summary":"An on-ride photo was taken","description":"Sent once the lap is stored, a few seconds after the shutter. The links work at once: the pictures are drawn when first opened.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"ride.photo.taken"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/Photo"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"ride.photo.taken","timestamp":"2026-10-11T20:11:49.000Z","data":{"id":"01K7AXM5Q3Z8C1V2B3N4M5P6Q7","rideId":4,"rideName":"Lost Bearings","takenAt":"2026-10-11T20:11:47.000Z","riders":[{"uuid":"3f8a2c1e-6b47-4d1a-9c2e-1a7b5e0d9f42","name":"Kaelith"},{"uuid":"b14e77d0-2c9a-4e6f-8d31-5f0c9a2e7b18","name":"MrPopcorn"}],"pageUrl":"https://connect.your-park.com/p/9F2A71C0DE","frames":["https://connect.your-park.com/api/p/9F2A71C0DE/0","https://connect.your-park.com/api/p/9F2A71C0DE/1"]}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"ride.stopped":{"post":{"summary":"A ride is stopped","description":"An emergency stop: pressed by an operator, or engaged by the ride itself when a transfer manoeuvre did not take effect.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"ride.stopped"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/RideStopped"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"ride.stopped","timestamp":"2026-10-11T20:11:49.000Z","data":{"rideId":9,"rideName":"Temple Drop","by":{"uuid":"e9d0c3a4-71f2-4b8e-a6c5-0d2f8b4e1c97","name":"LunaRides"}}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"ride.resumed":{"post":{"summary":"A stopped ride runs again","description":"The emergency stop was released.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"ride.resumed"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/RideResumed"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"ride.resumed","timestamp":"2026-10-11T20:11:49.000Z","data":{"rideId":9,"rideName":"Temple Drop","by":{"uuid":"e9d0c3a4-71f2-4b8e-a6c5-0d2f8b4e1c97","name":"LunaRides"}}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"ride.availability.changed":{"post":{"summary":"A ride opens or closes","description":"Its availability was changed: in game with `/utp ride availability`, in the administration, or through this API. Not sent when it was set to what it already was.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"ride.availability.changed"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/RideAvailabilityChanged"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"ride.availability.changed","timestamp":"2026-10-11T20:11:49.000Z","data":{"rideId":7,"rideName":"Wild Detour","availability":"maintenance","previous":"open","by":{"uuid":"e9d0c3a4-71f2-4b8e-a6c5-0d2f8b4e1c97","name":"LunaRides"}}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"show.upcoming":{"post":{"summary":"A show starts in thirty minutes","description":"Sent thirty minutes before a show starts on its schedule — or as soon as the Minecraft server connects, if it came back later than that. Not sent while the server is offline. The show itself starts only if somebody is online at the time: see `show.skipped`.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"show.upcoming"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/ShowUpcoming"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"show.upcoming","timestamp":"2026-10-11T20:11:49.000Z","data":{"showId":3,"showName":"Maya Night","showLocation":"Maya Plaza","startsAt":"2026-10-12T17:00:00.000Z"}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"show.started":{"post":{"summary":"A show started","description":"Sent when a show starts from the beginning on its schedule, from the administration, or through this API. A show started in game — a console command, a ride's cue — is not reported, nor one started part-way through, which is a rehearsal.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"show.started"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/ShowStarted"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"show.started","timestamp":"2026-10-11T20:11:49.000Z","data":{"showId":3,"showName":"Maya Night","showLocation":"Maya Plaza","trigger":"schedule","scheduledFor":"2026-10-12T17:00:00.000Z"}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"show.skipped":{"post":{"summary":"A scheduled show did not start","description":"Sent when a show's scheduled time comes and it does not start: nobody was online, it was still running, or the Minecraft server was not there.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"show.skipped"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/ShowSkipped"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"show.skipped","timestamp":"2026-10-11T20:11:49.000Z","data":{"showId":3,"showName":"Maya Night","showLocation":"Maya Plaza","scheduledFor":"2026-10-12T17:00:00.000Z","reason":"nobody_online"}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"server.online":{"post":{"summary":"The Minecraft server is connected","description":"Sent when the server comes back after `server.offline`, and when the instance itself has restarted.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"server.online"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/ServerOnline"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"server.online","timestamp":"2026-10-11T20:11:49.000Z","data":{}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"server.offline":{"post":{"summary":"The Minecraft server is gone","description":"Sent when the server stops, or when nothing has been heard from it for twenty seconds.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"server.offline"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/ServerOffline"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"server.offline","timestamp":"2026-10-11T20:11:49.000Z","data":{"reason":"stopping"}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}},"webhook.test":{"post":{"summary":"A test","description":"Sent by the **Send a test** button in the administration, to this webhook alone.","parameters":[{"name":"webhook-id","in":"header","required":true,"schema":{"type":"string"},"example":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","description":"The message's identifier, the same on every retry: use it to ignore a message you already have."},{"name":"webhook-timestamp","in":"header","required":true,"schema":{"type":"integer"},"example":1791749509,"description":"When this attempt was sent, in Unix seconds. Refuse a message more than five minutes old."},{"name":"webhook-signature","in":"header","required":true,"schema":{"type":"string"},"example":"v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=","description":"`v1,` and the HMAC-SHA256, in base64, of `webhook-id.webhook-timestamp.body` with your webhook's secret — the part after `whsec_`, decoded from base64."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["id","type","timestamp","data"],"properties":{"id":{"type":"string","description":"The same as `webhook-id`."},"type":{"const":"webhook.test"},"timestamp":{"type":"string","format":"date-time","description":"When it happened."},"data":{"$ref":"#/components/schemas/WebhookTest"}}},"example":{"id":"msg_01K7AXM5Q3Z8C1V2B3N4M5P6Q7","type":"webhook.test","timestamp":"2026-10-11T20:11:49.000Z","data":{"message":"This is a test from your park's administration."}}}}},"responses":{"200":{"description":"Any 2xx says it arrived. Anything else, or no answer within ten seconds, is tried again: four more times over the next hour."}}}}},"components":{"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"utp_…","description":"A key from **Administration → Settings → API**."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string","description":"A stable code to test against: `unauthorized`, `not_found`, `already_running`…"},"message":{"type":"string","description":"A sentence for a human."}},"required":["error","message"]},"Player":{"type":"object","properties":{"uuid":{"type":"string","description":"The player's Minecraft UUID."},"name":{"type":"string","description":"The name they were last seen with."}},"required":["uuid","name"]},"RideStatus":{"type":"string","enum":["operating","down","closed"],"description":"`operating`: running as usual. `down`: stopped by an emergency stop, until somebody releases it. `closed`: the Minecraft server is not connected, or the ride is not set up in the world. Treat any other value as unknown: more may come."},"RideAvailability":{"type":"string","enum":["open","closed","maintenance","broken"],"description":"Whether the ride takes guests, as its owner set it. `open`. `closed`, `maintenance` and `broken` all close it to guests — no guest boards, nobody takes the operator's post — and say why; under `maintenance`, staff allowed to test the ride may still ride it and run it from its post, and those laps are not counted. Kept while the Minecraft server is offline."},"RidePhase":{"type":"string","enum":["idle","dispatching","running","unloading","transfer"],"description":"Where the ride is in its cycle. `idle`: waiting in the station. `dispatching`: counting down, gates and restraints closing. `running`: the train is out. `unloading`: back, guests getting off. `transfer`: the transfer table is being worked."},"Ride":{"type":"object","properties":{"id":{"type":"integer","description":"The ride's number, as `/utp ride list` shows it."},"name":{"type":"string"},"type":{"type":"string","enum":["coaster","flat"]},"availability":{"$ref":"#/components/schemas/RideAvailability"},"status":{"$ref":"#/components/schemas/RideStatus"},"phase":{"anyOf":[{"$ref":"#/components/schemas/RidePhase"},{"type":"null"}],"description":"Null while the ride is `closed`."},"manoeuvre":{"anyOf":[{"type":"string","enum":["restart","hand-back","respawn"]},{"type":"null"}],"description":"The ride working itself, or null: `restart` brings its trains out of storage, `respawn` puts its one train back in place — a coaster's in its station, a flat ride's seats — and `hand-back` takes over from an operator who left."},"operator":{"anyOf":[{"$ref":"#/components/schemas/Player"},{"type":"null"}],"description":"Who holds the operator's post, or null when the ride runs by itself."},"guestsInStation":{"anyOf":[{"type":"integer"},{"type":"null"}],"description":"Players standing in the station's region right now: the nearest thing to a queue. Null while `closed`."},"trainInStation":{"description":"Null while `closed`.","type":["boolean","null"]},"lapsToday":{"type":"integer","description":"Laps ridden today (UTC), every rider counted."}},"required":["id","name","type","availability","status","phase","manoeuvre","operator","guestsInStation","trainInStation","lapsToday"]},"ShowSchedule":{"type":"object","properties":{"days":{"type":"array","items":{"type":"string","enum":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]},"description":"The days of the week it starts on."},"time":{"type":"string","description":"`HH:MM`, on the park's clocks: `19:00` in `timeZone`."},"timeZone":{"type":"string","description":"The park's time zone, by its IANA name: `Europe/Paris`."},"from":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"The first day it runs, or null."},"until":{"anyOf":[{"type":"string","format":"date"},{"type":"null"}],"description":"The last day it runs, or null. The same as `from` for a single day."},"enabled":{"type":"boolean","description":"False for a time switched off in the administration: kept, but it starts nothing."}},"required":["days","time","timeZone","from","until","enabled"]},"Show":{"type":"object","properties":{"id":{"type":"integer","description":"The show's number, as `/utp sequence list` shows it."},"name":{"type":"string"},"region":{"description":"The WorldGuard region its music is heard in, or null.","type":["string","null"]},"location":{"description":"Where guests find it, as the owner wrote it: `Main Lake`. Null for a show kept off the guests' schedule.","type":["string","null"]},"music":{"anyOf":[{"type":"object","properties":{"title":{"type":"string"},"author":{"type":["string","null"]}},"required":["title","author"]},{"type":"null"}],"description":"The track it plays to, or null for a show without music."},"duration":{"description":"In seconds: the music's length or the last cue, whichever ends later.","type":["number","null"]},"running":{"type":"boolean"},"startedAt":{"anyOf":[{"type":"string","format":"date-time","description":"An instant, in ISO 8601, UTC."},{"type":"null"}],"description":"When the run under way started, or null."},"position":{"description":"Seconds into the show, while it runs.","type":["number","null"]},"schedule":{"type":"array","items":{"$ref":"#/components/schemas/ShowSchedule"},"description":"When it starts by itself, as set in **Administration → Sequences**. Empty for a show started by hand."},"nextRunAt":{"anyOf":[{"type":"string","format":"date-time","description":"An instant, in ISO 8601, UTC."},{"type":"null"}],"description":"When it next starts on its schedule, or null. It starts only if somebody is online then."}},"required":["id","name","region","location","music","duration","running","startedAt","position","schedule","nextRunAt"]},"ParkLive":{"type":"object","properties":{"park":{"type":"object","properties":{"name":{"type":"string","description":"Your park's name, from the administration."},"serverOnline":{"type":"boolean","description":"Whether the Minecraft server is connected."},"guestsListening":{"type":"integer","description":"Players with their audio page open."},"timeZone":{"description":"The park's time zone, which the shows' schedules are written in. Null until a show is scheduled.","type":["string","null"]}},"required":["name","serverOnline","guestsListening","timeZone"]},"rides":{"type":"array","items":{"$ref":"#/components/schemas/Ride"}},"shows":{"type":"array","items":{"$ref":"#/components/schemas/Show"}},"updatedAt":{"type":"string","format":"date-time","description":"An instant, in ISO 8601, UTC."}},"required":["park","rides","shows","updatedAt"]},"RideStats":{"type":"object","properties":{"rideId":{"type":"integer"},"name":{"type":"string","description":"The ride's name, or `Ride #n` for a ride since removed."},"laps":{"type":"integer"},"riders":{"type":"integer","description":"Different players."}},"required":["rideId","name","laps","riders"]},"TopRider":{"type":"object","properties":{"rank":{"type":"integer","description":"First is 1. Players level on laps share a rank."},"player":{"$ref":"#/components/schemas/Player"},"laps":{"type":"integer"}},"required":["rank","player","laps"]},"PlayerProfile":{"type":"object","properties":{"uuid":{"type":"string"},"name":{"type":"string"},"lastSeen":{"anyOf":[{"type":"string","format":"date-time","description":"An instant, in ISO 8601, UTC."},{"type":"null"}],"description":"When the server last reported them online."},"listening":{"type":"boolean","description":"Their audio page is open right now."},"totalLaps":{"type":"integer"},"rides":{"type":"array","items":{"type":"object","properties":{"rideId":{"type":"integer"},"name":{"type":"string"},"laps":{"type":"integer"},"rank":{"type":"integer","description":"Where they stand on that ride's leaderboard."}},"required":["rideId","name","laps","rank"]}}},"required":["uuid","name","lastSeen","listening","totalLaps","rides"]},"Photo":{"type":"object","properties":{"id":{"type":"string"},"rideId":{"type":"integer"},"rideName":{"type":"string"},"takenAt":{"type":"string","format":"date-time","description":"An instant, in ISO 8601, UTC."},"riders":{"type":"array","items":{"$ref":"#/components/schemas/Player"}},"pageUrl":{"description":"The page the photo wall's QR code opens. Anyone with the link sees it, until the photo expires.","type":["string","null"]},"frames":{"type":"array","items":{"type":"string"},"description":"The pictures, one per group of rows, as images anyone with the link can load."}},"required":["id","rideId","rideName","takenAt","riders","pageUrl","frames"]},"AudioSent":{"type":"object","properties":{"player":{"$ref":"#/components/schemas/Player"},"listening":{"type":"boolean","description":"Whether their page is open. If it is not, nothing plays."}},"required":["player","listening"]},"ShowStart":{"type":"object","properties":{"from":{"description":"Where to start: seconds (`90`) or minutes and seconds (`\"1:30\"`, `\"1:30.250\"`). The beginning if left out.","anyOf":[{"type":"number","minimum":0},{"type":"string","pattern":"^\\d+(:\\d{1,2})?(\\.\\d{1,3})?$"}]}}},"AudioPlay":{"type":"object","properties":{"player":{"type":"string","minLength":1,"maxLength":36,"description":"A player's name or UUID."},"url":{"type":"string","maxLength":500,"format":"uri","description":"An MP3, OGG or M4A file anyone can download."},"volume":{"description":"From 0 to 100. Left as it is if not given.","type":"integer","minimum":0,"maximum":100}},"required":["player","url"]},"AudioStop":{"type":"object","properties":{"player":{"type":"string","minLength":1,"maxLength":36,"description":"A player's name or UUID."}},"required":["player"]},"AvailabilitySet":{"type":"object","properties":{"availability":{"$ref":"#/components/schemas/RideAvailability"}},"required":["availability"]},"LapCompleted":{"type":"object","properties":{"rideId":{"type":"integer"},"rideName":{"type":"string"},"riders":{"type":"array","items":{"$ref":"#/components/schemas/Player"},"description":"Everybody aboard for the lap."}},"required":["rideId","rideName","riders"]},"RideStopped":{"type":"object","properties":{"rideId":{"type":"integer"},"rideName":{"type":"string"},"by":{"anyOf":[{"$ref":"#/components/schemas/Player"},{"type":"null"}],"description":"The operator who pressed it, or null when the ride stopped itself."}},"required":["rideId","rideName","by"]},"RideResumed":{"type":"object","properties":{"rideId":{"type":"integer"},"rideName":{"type":"string"},"by":{"anyOf":[{"$ref":"#/components/schemas/Player"},{"type":"null"}],"description":"The operator who released it, or null."}},"required":["rideId","rideName","by"]},"RideAvailabilityChanged":{"type":"object","properties":{"rideId":{"type":"integer"},"rideName":{"type":"string"},"availability":{"$ref":"#/components/schemas/RideAvailability"},"previous":{"description":"How it stood before.","$ref":"#/components/schemas/RideAvailability"},"by":{"anyOf":[{"$ref":"#/components/schemas/Player"},{"type":"null"}],"description":"The player who changed it, in game or in the administration; null from the server's console or through this API."}},"required":["rideId","rideName","availability","previous","by"]},"ShowUpcoming":{"type":"object","properties":{"showId":{"type":"integer"},"showName":{"type":"string"},"showLocation":{"description":"Where guests find it, or null.","type":["string","null"]},"startsAt":{"type":"string","format":"date-time","description":"When it starts, on its schedule."}},"required":["showId","showName","showLocation","startsAt"]},"ShowStarted":{"type":"object","properties":{"showId":{"type":"integer"},"showName":{"type":"string"},"showLocation":{"description":"Where guests find it, or null.","type":["string","null"]},"trigger":{"type":"string","enum":["schedule","admin","api"],"description":"`schedule`: on its schedule. `admin`: from the administration. `api`: through this API."},"scheduledFor":{"anyOf":[{"type":"string","format":"date-time","description":"An instant, in ISO 8601, UTC."},{"type":"null"}],"description":"The time it was scheduled for, when `trigger` is `schedule`."}},"required":["showId","showName","showLocation","trigger","scheduledFor"]},"ShowSkipped":{"type":"object","properties":{"showId":{"type":"integer"},"showName":{"type":"string"},"showLocation":{"description":"Where guests find it, or null.","type":["string","null"]},"scheduledFor":{"type":"string","format":"date-time","description":"The time it was scheduled for."},"reason":{"type":"string","enum":["nobody_online","already_running","server_offline","not_ready","no_answer"],"description":"`nobody_online`: nobody was on the Minecraft server. `already_running`: it was still running from an earlier start. `server_offline`: the Minecraft server was not connected. `not_ready`: the server did not have the show yet. `no_answer`: the server did not answer."}},"required":["showId","showName","showLocation","scheduledFor","reason"]},"ServerOnline":{"type":"object","properties":{}},"ServerOffline":{"type":"object","properties":{"reason":{"type":"string","enum":["stopping","lost"],"description":"`stopping`: the server shut down cleanly. `lost`: nothing heard from it for twenty seconds."}},"required":["reason"]},"WebhookTest":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}},"responses":{"Unauthorized":{"description":"No key, or a key that does not exist (any more).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"unauthorized","message":"Missing or invalid API key. Create one in Administration → Settings → API, and send it as Authorization: Bearer <key>."}}}},"ReadOnlyKey":{"description":"The key can only read.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"forbidden","message":"This key can only read. Create a key with Read and write access to do this."}}}},"NotFound":{"description":"Nothing with that number or name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"not_found","message":"There is no ride 12."}}}},"Invalid":{"description":"A parameter or a field is not right; the message says which.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"invalid","message":"limit: Too big: expected number to be <=100"}}}},"RateLimited":{"description":"More than 120 requests in a minute with this key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"rate_limited","message":"Too many requests. Try again in 12 seconds."}}},"headers":{"Retry-After":{"schema":{"type":"integer"},"description":"Seconds to wait."}}},"ServerOffline":{"description":"The Minecraft server is not connected, so nothing can be done in the game.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"server_offline","message":"The Minecraft server is not connected."}}}},"ServerTimeout":{"description":"The Minecraft server is connected but did not answer within five seconds.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"server_timeout","message":"The Minecraft server did not answer."}}}}}}}