{"openapi":"3.1.0","info":{"title":"SuperAwesomes offentlige API","version":"1.0.0","description":"Offentlige endpoints til netværket, servernes butiksintegration og Login med SuperAwesome via OAuth. Eksemplerne bruger opdigtede data. Kontroller både HTTP-status og svarets indhold; nogle ældre fejl bruger HTTP 200."},"servers":[{"url":"https://api.superawesome.dk"}],"tags":[{"name":"players","description":"Find spillere, offentlige profiler, teammedlemmer og ranglister."},{"name":"servers","description":"Udforsk servere, spillerantal, statistik og serverbutikker."},{"name":"information","description":"Netværkets status, spillerantal og fællesskabets regler."},{"name":"lobbies","description":"Butikker i Shoppylobby, item-tilbud og historiske markedspriser."},{"name":"store","description":"Forbind et serverplugin med køb, levering, betalinger og stemmer."},{"name":"oauth","description":"OAuth med spillervalg og scopes til profil, servere, Shoppy, reklamer, transporter, MCMMO, emerald-overførsler og køb i SA Store."}],"externalDocs":{"description":"Interaktiv dokumentation","url":"https://superawesome.dk/api-docs"},"components":{"securitySchemes":{"serverKey":{"type":"apiKey","in":"header","name":"Authorization","description":"Serverens API-nøgle som hele headerværdien. Sæt ikke Bearer foran. Brug kun nøglen fra serveren eller pluginet."},"oauthClient":{"type":"http","scheme":"basic","description":"Appens client ID og secret. URL-encode hver del før base64. Kun backend-kald. client_id og client_secret i request body understøttes som alternativ; brug aldrig begge metoder i samme kald."},"oauthPlayer":{"type":"oauth2","description":"Opaque Bearer access token for den Minecraft-spiller, brugeren valgte ved samtykke. Authorization Code kræver klient-secret og PKCE S256. Access tokens lever højst 15 minutter; den oprindelige adgang og refresh-token udløber efter 90 dage.","flows":{"authorizationCode":{"authorizationUrl":"https://api.superawesome.dk/oauth/authorize","tokenUrl":"https://api.superawesome.dk/oauth/token","refreshUrl":"https://api.superawesome.dk/oauth/token","scopes":{"player:profile":"Se dit UUID og brugernavn","player:balance":"Se din emerald-balance","servers:read":"Se dine servere","emeralds:transfer:request":"Anmode om overførsler af dine emeralds, som du godkender enkeltvis","store:purchases:request":"Anmode om køb i SA Store med dine emeralds, som du godkender enkeltvis","shoppy:plots:read":"Se dine Shoppy-plots","shoppy:chestshops:read":"Se dine chestshops og priser i Shoppy","advertisements:read":"Se dine reklamer, deres status og visninger","transporter:items:read":"Se dine items og antal i din transporter","mcmmo:read":"Se dine MCMMO-levels og erfaring"}}}}}},"paths":{"/players":{"get":{"operationId":"players-list","tags":["players"],"summary":"Spillerliste","description":"Den nuværende spillerliste er endnu ikke udfyldt og returnerer altid en tom liste. Brug søgning eller et direkte opslag for at finde en spiller.\n\nRuten understøtter ikke sideinddeling eller filtrering.\n\nSpillerruter returnerer Cache-Control: no-store.","security":[],"parameters":[],"responses":{"200":{"description":"En tom liste; dette endpoint tilbyder endnu ikke en oversigt over spillere.","content":{"application/json":{"examples":{"example1":{"summary":"En tom liste; dette endpoint tilbyder endnu ikke en oversigt over spillere.","value":[]}}}}}}}},"/players/staff":{"get":{"operationId":"players-staff","tags":["players"],"summary":"Teammedlemmer","description":"Hent brugernavn, UUID, rolle og synlig onlinestatus for teamets Minecraft-konti.\n\nOmfatter rollerne admin, seniormod, developer, mod, support og bygger. CONSOLE er udeladt.\n\nSkjult onlinestatus vises som offline. Cache-Control: no-store.\n\nRuten har ingen særskilt statuskode for en mislykket databaselæsning; svaret kan være null.","security":[],"parameters":[],"responses":{"200":{"description":"En liste over teammedlemmer.","content":{"application/json":{"examples":{"example1":{"summary":"En liste over teammedlemmer.","value":[{"username":"ExampleStaff","uuid":"22222222-2222-4222-8222-222222222222","role":"support","status":"offline"}]}}}}}}}},"/players/search":{"get":{"operationId":"players-search","tags":["players"],"summary":"Søg efter spillere","description":"Søg efter brugernavne eller slå et UUID op. Svaret indeholder op til otte spillere med deres rolle og synlige onlinestatus.\n\nBrugernavne matches på en del af navnet; UUID'er skal matche præcist. Et præcist brugernavnsmatch vises først, derefter sorteres efter status og brugernavn.\n\nSøgeteksten bruger LIKE-matching: % og _ fungerer som jokertegn.\n\nSkjult onlinestatus vises som status: offline og currentServer: null. Cache-Control: no-store.\n\nEt tomt resultat giver ikke 404 og kan også forekomme, hvis en databaselæsning mislykkes.","security":[],"parameters":[{"name":"query","in":"query","required":false,"description":"Søgetekst. Indledende og afsluttende blanktegn fjernes; længden skal derefter være 2–36 tegn. En ugyldig eller manglende query returnerer en tom liste.","schema":{"type":"string","examples":["Example"]}}],"responses":{"200":{"description":"Op til otte resultater. En manglende, for kort eller for lang query returnerer [].","content":{"application/json":{"examples":{"example1":{"summary":"Op til otte resultater. En manglende, for kort eller for lang query returnerer [].","value":[{"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","status":"online","currentServer":"Example-SMP"}]}}}}}}}},"/players/leaderboards":{"get":{"operationId":"players-leaderboards","tags":["players"],"summary":"Spillerranglister","description":"Hent ranglister for spilletid, spillerpoint, lobbypoint og vurderinger samt spilletid over de seneste 30, 90, 180 og 365 dage.\n\nvalue måles i sekunder for playtime, point for playerPoints/lobbyPoints og en vægtet score for ratings. rank starter ved 1.\n\nAlle perioder returneres under playtimePeriods; ruten accepterer ikke parametrene period eller limit.\n\nSpilletiden fra en enkelt session begrænses til syv dage. Kun en gyldig, aktuel og åben session kan fortsætte med at optjene spilletid.\n\nTotaler opdateres normalt hvert 300. sekund. Under en opdatering eller en midlertidig fejl kan svaret være op til 900 sekunder gammelt; tjek updatedAt.\n\nSkjulte spillere udelades ved hver forespørgsel, også når ranglistens totaler hentes fra cache. HTTP-svaret bruger Cache-Control: no-store.","security":[],"parameters":[],"responses":{"200":{"description":"Alle ranglister i et samlet svar med op til 100 spillere på hver rangliste.","content":{"application/json":{"examples":{"example1":{"summary":"Alle ranglister i et samlet svar med op til 100 spillere på hver rangliste.","value":{"updatedAt":"2026-10-01T10:00:00.000Z","refreshIntervalSeconds":300,"leaderboards":{"playtime":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":7200}],"playerPoints":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":20}],"lobbyPoints":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":5}],"ratings":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":4,"ratings":{"positive":4,"negative":0,"neutral":0,"total":4}}]},"playtimePeriods":{"30":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":7200}],"90":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":7200}],"180":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":7200}],"365":[{"rank":1,"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","value":7200}]}}}}}}},"503":{"description":"Ranglisterne kunne ikke hentes. Retry-After: 10 angiver ventetiden i sekunder før et nyt forsøg.","content":{"application/json":{"examples":{"example2":{"summary":"Ranglisterne kunne ikke hentes. Retry-After: 10 angiver ventetiden i sekunder før et nyt forsøg.","value":{"error":"Ranglisterne kunne ikke hentes. Prøv igen om lidt."}}}}}}}}},"/players/{lookup}/profile":{"get":{"operationId":"players-profile","tags":["players"],"summary":"Spillerprofil","description":"Hent en offentlig profil med rang, point, banstatus, spilletid, vurderinger, aktivitet, servere, badges og venner. lookup er et brugernavn eller UUID.\n\nactivity indeholder antal sessioner og spilletid pr. dag fra starten af dagen for 182 dage siden. favoriteServers og recentSessions indeholder hver op til otte resultater.\n\nSpilletid måles i sekunder, og hver session begrænses til syv dage. Den aktuelle loginStreak beregnes ud fra datoerne for i dag og i går i tidszonen Europe/Copenhagen.\n\nNår aktivitet er skjult, er activityVisible false og status offline, mens felterne for aktuel server og seneste aktivitet er null. Spilletid, votes og loginStreak nulstilles i svaret; aktivitet, favoritservere, seneste sessioner og boosts er tomme.\n\nBadges og venner kan stadig vises, men deres aktivitetsdatoer er null, når profilen skjuler aktivitet. Vennernes onlinestatus følger også deres egne valg om synlighed.\n\nfavoriteServers indeholder name, status, category, version, motdFavicon, sessions, playtimeSeconds og lastSeen. recentSessions indeholder name, type, joinedAt, leftAt og playtimeSeconds.\n\nownedServers indeholder name, status, category, version, created, descriptionLong, motdFavicon, players og maxPlayers. badges indeholder name, description, color, symbol, active og created.\n\nserverBoosts indeholder name og since. friends indeholder username, uuid, role, friendsSince, status og currentServer.\n\ncached er false; cachedAt er svartidspunktet. Spillerruter bruger Cache-Control: no-store. Profilruten har ikke en ensartet statuskode for databasefejl.","security":[],"parameters":[{"name":"lookup","in":"path","required":true,"description":"Brugernavn eller UUID. Indledende og afsluttende blanktegn fjernes; en tom værdi eller mere end 64 tegn afvises. Der kræves ikke et bestemt UUID-format.","schema":{"type":"string","examples":["ExamplePlayer"]}}],"responses":{"200":{"description":"En offentlig spillerprofil. Nogle felter kan være null, og aktivitet kan være skjult.","content":{"application/json":{"examples":{"example1":{"summary":"En offentlig spillerprofil. Nogle felter kan være null, og aktivitet kan være skjult.","value":{"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","rankLabel":null,"rankDisplayName":null,"rankColor":null,"vipDays":0,"proDays":0,"lobbyPoints":5,"playerPoints":20,"created":"2026-10-01T10:00:00.000Z","activityVisible":true,"lastJoined":"2026-10-01T10:00:00.000Z","lastSeen":"2026-10-01T10:00:00.000Z","status":"offline","currentServer":null,"banStatus":{"banned":false,"global":false,"lobby":false},"playtime":{"totalSeconds":0,"last7DaysSeconds":0,"last30DaysSeconds":0,"sessions":0,"serversPlayed":0,"averageSessionSeconds":0,"firstSession":null,"lastSession":null},"ratings":{"score":0,"total":0,"positive":0,"negative":0,"neutral":0},"votes":{"total":0,"last30Days":0},"loginStreak":{"current":0,"longest":0,"totalDays":0,"activeToday":false,"startedDate":null,"lastLoginDate":null},"activity":[],"favoriteServers":[],"recentSessions":[],"ownedServers":[],"badges":[],"serverBoosts":[],"friends":[],"cached":false,"cachedAt":"2026-10-01T10:00:00.000Z"}}}}}},"400":{"description":"lookup er tom eller længere end 64 tegn efter fjernelse af indledende og afsluttende blanktegn.","content":{"application/json":{"examples":{"example2":{"summary":"lookup er tom eller længere end 64 tegn efter fjernelse af indledende og afsluttende blanktegn.","value":{"error":"Ugyldig spiller"}}}}}},"404":{"description":"Ingen spiller matcher brugernavnet eller UUID'et.","content":{"application/json":{"examples":{"example3":{"summary":"Ingen spiller matcher brugernavnet eller UUID'et.","value":{"error":"Spilleren blev ikke fundet"}}}}}}}}},"/players/{lookup}":{"get":{"operationId":"players-lookup","tags":["players"],"summary":"Kort spilleropslag","description":"Slå en spiller op via brugernavn eller UUID. Med type=discord matches lookup i stedet med et Discord-ID, og svaret kan indeholde flere tilknyttede Minecraft-konti.\n\nEt opslag uden resultater returnerer HTTP 200 med {\"error\":\"Spilleren blev ikke fundet\"}, ikke HTTP 404. En mislykket datalæsning kan også returnere denne fejl.\n\nMed type=discord er et vellykket svar en liste af spillerobjekter uden cached og cachedAt. Eksempel: /players/123456789012345678?type=discord.\n\nrates indeholder username, uuid, role, points, type og created for hver spiller, der har givet en vurdering. rate er summen af point. lobbyAccess er en liste over lobbynavne.\n\nbadges indeholder name, color, symbol, active og created; serverBoosts indeholder name og since. servers viser ejede servere med name, status og version.\n\nHvis spilleren ikke ejer servere, kan servers indeholde et objekt med null-felter i stedet for en tom liste.\n\nSkjult onlinestatus vises som offline med null i lastSeen/currentServer. Boosts skjules, og aktivitetsdatoer i badges/vurderinger er null. Cache-Control: no-store.","security":[],"parameters":[{"name":"lookup","in":"path","required":true,"description":"Brugernavn eller UUID; med type=discord bruges et Discord-ID. Ruten validerer ikke særskilt længden eller UUID-formatet.","schema":{"type":"string","examples":["ExamplePlayer"]}},{"name":"type","in":"query","required":false,"description":"Kun den præcise værdi discord aktiverer Discord-opslag. Hvis feltet udelades eller har en anden værdi, bruger lookup brugernavn/UUID.","schema":{"type":"string","examples":["discord"]}}],"responses":{"200":{"description":"Et spillerobjekt ved et normalt opslag, en liste ved type=discord eller et fejlobjekt, hvis spilleren ikke findes.","content":{"application/json":{"examples":{"example1":{"summary":"Et spillerobjekt ved et normalt opslag, en liste ved type=discord eller et fejlobjekt, hvis spilleren ikke findes.","value":{"username":"ExamplePlayer","uuid":"11111111-1111-4111-8111-111111111111","role":"default","vipDays":0,"proDays":0,"lastSeen":"2026-10-01T10:00:00.000Z","discordID":null,"lobbyPoints":5,"playerPoints":20,"status":"offline","currentServer":null,"banned":false,"lobbyAccess":[],"rates":[],"badges":[],"serverBoosts":[],"servers":[{"name":"Example-SMP","status":"offline","version":"1.21.4"}],"rate":0,"cached":false,"cachedAt":"2026-10-01T10:00:00.000Z"}}}}}}}}},"/servers":{"get":{"operationId":"servers-list","tags":["servers"],"summary":"Find servere","description":"Pagineret serverliste med ejer, synlige online-spillere, MOTD og vurderinger. Sorteres med online-servere først, derefter spillerantal faldende og navn stigende.\n\nCache-Control: no-store. X-Has-More er teksten true/false og er eksponeret via CORS; næste side findes kun når den er true.\n\nvip, pro og whitelist er databaseflags (typisk 0/1). players og maxPlayers er tal; serverPoints og rate normaliseres til tal. rate er summen af +1 for positive og -2 for negative vurderinger.\n\ndescriptionLong, ejerfelter, MOTD-felter og playersData kan være null. playersData er ellers et array med username, uuid, vip og pro; rates er et array med username, uuid, role, points, type og created.\n\nAntallet af online-spillere og playersData udelader skjulte spillere (vanish) og spillere uden offentlig tilstedeværelse. Et lavt antal betyder derfor ikke nødvendigvis få faktiske spillere.\n\nquery bruges som SQL LIKE-mønster; % og _ kan også fungere som wildcards. Der returneres ikke et samlet antal sider.","security":[],"parameters":[{"name":"size","in":"query","required":false,"description":"Antal servere pr. side. Positive heltal over 100 begrænses til 100; ugyldige eller ikke-positive værdier bruger standarden. Standardværdi: 3.","schema":{"type":"integer","examples":[20]}},{"name":"page","in":"query","required":false,"description":"Sidenummer fra 1. Begrænses til 10.000; ugyldige værdier bruger standarden. Standardværdi: 1.","schema":{"type":"integer","examples":[1]}},{"name":"query","in":"query","required":false,"description":"Navnesøgning, trimmet og højst 100 tegn. Udeladt værdi matcher alle navne. Standardværdi: .","schema":{"type":"string","examples":["Eksempel"]}},{"name":"category","in":"query","required":false,"description":"Præcist kategorinavn, trimmet og højst 100 tegn. Tom værdi viser alle kategorier. Standardværdi: .","schema":{"type":"string","examples":["Survival"]}},{"name":"status","in":"query","required":false,"description":"Statusfilter. Andre værdier bruger online. Standardværdi: online.","schema":{"type":"string","enum":["online","offline","all"],"examples":["all"]}}],"responses":{"200":{"description":"Array af servere; [] når siden ikke har resultater.","content":{"application/json":{"examples":{"example1":{"summary":"Array af servere; [] når siden ikke har resultater.","value":[{"name":"EksempelSMP","version":"1.21.4","descriptionLong":"En hyggelig survival-server.","vip":1,"pro":0,"maxPlayers":50,"status":"online","serverOwner":"123e4567-e89b-42d3-a456-426614174000","serverOwnerName":"EksempelEjer","category":"Survival","whitelist":0,"players":1,"playersData":[{"username":"EksempelSpiller","uuid":"123e4567-e89b-42d3-a456-426614174001","vip":0,"pro":0}],"serverPoints":120,"rates":[{"username":"EksempelSpiller","uuid":"123e4567-e89b-42d3-a456-426614174001","role":"player","points":1,"type":"positive","created":"2026-10-01T12:00:00.000Z"}],"motdLine1":"§6EksempelSMP","motdLine2":"§aVelkommen!","motdFavicon":null,"rate":1}]}}}}}}}},"/servers/stats":{"get":{"operationId":"servers-stats-day","tags":["servers"],"summary":"Spillerhistorik for alle servere","description":"Målinger pr. minut fra det seneste døgn for servere med statistik og en tilknyttet ejer.\n\nIngen sti- eller forespørgselsparametre. Et tomt datasæt er []. players kan være [] ved manglende eller ulæselige ældre statistikdata.\n\nDette er den ældre samlede statistikform; brug /servers/stats/{serverName} for history, topPlayers og votes i et valgt tidsrum.","security":[],"parameters":[],"responses":{"200":{"description":"Array med serverName, serverOwnerUUID, serverOwner, maxPlayers og players. players knytter Unix-tidsstempler i sekunder til spillerantal.","content":{"application/json":{"examples":{"example1":{"summary":"Array med serverName, serverOwnerUUID, serverOwner, maxPlayers og players. players knytter Unix-tidsstempler i sekunder til spillerantal.","value":[{"serverName":"EksempelSMP","serverOwnerUUID":"123e4567-e89b-42d3-a456-426614174000","serverOwner":"EksempelEjer","maxPlayers":50,"players":{"1790856000":3,"1790856060":5}}]}}}}}}}},"/servers/stats/montly":{"get":{"operationId":"servers-stats-month","tags":["servers"],"summary":"30 dages spillerhistorik for alle servere","description":"Daglige playersOnline-målinger fra de seneste 30 dage. Den eksisterende URL staves montly.\n\nIngen forespørgselsparametre. Servere uden målinger/ejer er ikke med; players kan være [] ved ulæselige data.\n\nBrug /montly, ikke /monthly. Den faste montly-rute vælges før det dynamiske serverName-segment.","security":[],"parameters":[],"responses":{"200":{"description":"Samme objektform som døgnstatistikken; nøglerne i players er Unix-sekunder for de daglige målinger.","content":{"application/json":{"examples":{"example1":{"summary":"Samme objektform som døgnstatistikken; nøglerne i players er Unix-sekunder for de daglige målinger.","value":[{"serverName":"EksempelSMP","serverOwnerUUID":"123e4567-e89b-42d3-a456-426614174000","serverOwner":"EksempelEjer","maxPlayers":50,"players":{"1790769600":4,"1790856000":6}}]}}}}}}}},"/servers/stats/{serverName}":{"get":{"operationId":"servers-stats-detail","tags":["servers"],"summary":"Statistik for en server","description":"Spillerhistorik, de ti spillere med mest registreret spilletid og antal stemmer i et valgt tidsrum.\n\nhistory er kronologisk stigende. timestamp er Unix-sekunder, ikke millisekunder. Daglige players kan være et gennemsnit med decimaler; minutmålinger bruger samme antal til minPlayers/maxPlayers.\n\nmaxPlayers er serverens eksplicit gemte kapacitet eller 0; dette endpoint bruger ikke VIP/PRO-standardkapaciteten fra serverlisten.\n\ntopPlayers har username, uuid, sessions, playtimeSeconds og lastSeen. Kun sessioner startet inden for intervallet tælles, og hver session begrænses til højst syv dage. lastSeen viser seneste registrerede aktivitet, ikke om spilleren er online nu.\n\nCache-Control: public, max-age=60, stale-while-revalidate=240. API-processen kan genbruge samme serversvar for det valgte tidsrum i fem minutter.\n\nEn eksisterende server uden aktivitet returnerer tomme arrays og votes med 0; den samlede stats-router er monteret før /servers/{name}.","security":[],"parameters":[{"name":"serverName","in":"path","required":true,"description":"Serverens navn som et enkelt URL-kodet stisegment.","schema":{"type":"string","examples":["EksempelSMP"]}},{"name":"range","in":"query","required":false,"description":"24h bruger minutmålinger; 7d/30d bruger daglige målinger. Udeladt range bruger 30d. Standardværdi: 30d.","schema":{"type":"string","enum":["24h","7d","30d"],"examples":["7d"]}}],"responses":{"200":{"description":"serverName/range er tekststrenge, maxPlayers er et tal, history og topPlayers er arrays, og votes indeholder total og uniqueVoters.","content":{"application/json":{"examples":{"example1":{"summary":"serverName/range er tekststrenge, maxPlayers er et tal, history og topPlayers er arrays, og votes indeholder total og uniqueVoters.","value":{"serverName":"EksempelSMP","range":"7d","maxPlayers":50,"history":[{"timestamp":1790856000,"players":5.5,"minPlayers":1,"maxPlayers":10}],"topPlayers":[{"username":"EksempelSpiller","uuid":"123e4567-e89b-42d3-a456-426614174001","sessions":3,"playtimeSeconds":7200,"lastSeen":"2026-10-01T12:00:00.000Z"}],"votes":{"total":12,"uniqueVoters":8}}}}}}},"404":{"description":"Servernavnet findes ikke.","content":{"application/json":{"examples":{"example2":{"summary":"Servernavnet findes ikke.","value":{"error":"Server not found"}}}}}}}}},"/servers/{name}":{"get":{"operationId":"servers-detail","tags":["servers"],"summary":"Serverprofil","description":"En servers offentlige profil med ejer, spillere, vurderinger, boosts, stemmetal og links.\n\nManglende server returnerer {\"error\":\"Server not found.\"} med HTTP 200. Cache-Control: no-store.\n\nGrundfelter og datatyper følger serverlisten. Derudover: created/lastOnline er datostreng|null, websiteURL/discordURL string|null, stemmetal er tal, og serverBoosts er array|null med uuid, username og since.\n\ndailyVotes bruger database-dagen; weeklyVotes bruger den aktuelle database-uge/år; monthlyVotes er de seneste 30 dage. serverPoints dækker den seneste måned, mens totalVotes dækker alle stemmer.\n\nSpillerlisten respekterer samme offentlige tilstedeværelse/vanish-filtrering som serverlisten. MOTD kan indeholde Minecraft-formateringskoder.","security":[],"parameters":[{"name":"name","in":"path","required":true,"description":"Serverens navn. URL-kod navnet som et enkelt stisegment.","schema":{"type":"string","examples":["EksempelSMP"]}}],"responses":{"200":{"description":"Serverobjekt, eller et fejlobjekt med error når navnet ikke findes. Manglende server bruger HTTP 200.","content":{"application/json":{"examples":{"example1":{"summary":"Serverobjekt, eller et fejlobjekt med error når navnet ikke findes. Manglende server bruger HTTP 200.","value":{"name":"EksempelSMP","version":"1.21.4","descriptionLong":"En hyggelig survival-server.","vip":1,"pro":0,"maxPlayers":50,"status":"online","serverOwner":"123e4567-e89b-42d3-a456-426614174000","serverOwnerName":"EksempelEjer","category":"Survival","whitelist":0,"players":1,"playersData":[{"username":"EksempelSpiller","uuid":"123e4567-e89b-42d3-a456-426614174001","vip":0,"pro":0}],"serverPoints":120,"rates":[{"username":"EksempelSpiller","uuid":"123e4567-e89b-42d3-a456-426614174001","role":"player","points":1,"type":"positive","created":"2026-10-01T12:00:00.000Z"}],"motdLine1":"§6EksempelSMP","motdLine2":"§aVelkommen!","motdFavicon":null,"rate":1,"created":"2026-01-01T12:00:00.000Z","lastOnline":"2026-10-01T12:00:00.000Z","websiteURL":"https://example.com","discordURL":null,"serverBoosts":[{"uuid":"123e4567-e89b-42d3-a456-426614174001","username":"EksempelSpiller","since":"2026-10-01T12:00:00.000Z"}],"dailyVotes":2,"weeklyVotes":10,"monthlyVotes":35,"totalVotes":120}}}}}}}}},"/servers/{name}/favicon":{"get":{"operationId":"servers-favicon","tags":["servers"],"summary":"Serverikon","description":"Streamer serverens MOTD-favicon som PNG eller bruger det konfigurerede standardikon.\n\nManglende server: {\"error\":\"Server not found.\"}. Manglende ikon: {\"error\":\"No favicon found.\"}. Kontroller Content-Type før du fortolker svarindholdet.\n\nAPI-processen kan gemme standardikonet i sin cache i fem minutter; det er ikke en garanteret HTTP-cacheperiode for hele endpointet.","security":[],"parameters":[{"name":"name","in":"path","required":true,"description":"Serverens navn. URL-kod navnet som et enkelt stisegment.","schema":{"type":"string","examples":["EksempelSMP"]}}],"responses":{"200":{"description":"Binært PNG når serveren og et ikon findes.\n\nHTTP 200 med JSON-fejl når serveren eller både dens ikon og standardikon mangler.","content":{"image/png":{},"application/json":{"examples":{"example2":{"summary":"HTTP 200 med JSON-fejl når serveren eller både dens ikon og standardikon mangler.","value":{"error":"No favicon found."}}}}}}}}},"/servers/{name}/store":{"get":{"operationId":"servers-store","tags":["servers"],"summary":"Serverbutikkens katalog","description":"Kategorier, aktiverede produkter, EMS-prisoverslag og køberaktivitet, når offentlig visning er slået til. At læse kataloget gennemfører ikke et køb.\n\nUkendt server returnerer HTTP 200 med {\"error\":\"Server not found.\"}. Cache-Control: no-store, så købernes aktuelle privatlivsindstilling respekteres.\n\ncategories har uid/name/imageURL. products har uid/type/name/price/priceDKK/intervals/volumeDiscounts/description/duration/categoryUID/imageURL/automaticDiscount/priceQuote. Billed-URL og prisfelter kan være null; imageUID udelades fra JSON.\n\nProdukttype er eksempelvis standard, bulk, subscription eller upgrade. Abonnementets duration angiver antal dage; øvrige produkters duration kan være null.\n\nvolumeDiscounts er {minimumQuantity,discountPercent}[] og er [] for produkter der ikke er bulk. automaticDiscount er null eller {discountPercent,label}. priceQuote er null uden en gyldig EMS-pris.\n\npriceQuote har unitPrice, quantity, subtotal, discountPercent, discountAmount, total (tal), nextTier (rabattrin|null), discountSource (volume|automatic|code|null), discountLabel og discountCode (string|null). Bulk-overslaget bruger intervals; øvrige produkter bruger 1. Rabatter kombineres ikke: den største konkrete besparelse vælges.\n\nshowBuyers er boolean. false giver tomme topBuyers/recentBuyers. Ellers vises højst fem topkøbere og seks forskellige nylige købere blandt de seneste 30 køb. Kun accepterede EMS-ordrer medtages, udbetalinger udelades, og spillerne skal være offentligt synlige og ikke skjult via vanish.\n\nKatalogets prisoverslag inkluderer mængde- og automatiske rabatter, men ikke en brugerindtastet rabatkode.","security":[],"parameters":[{"name":"name","in":"path","required":true,"description":"Serverens navn. URL-kod navnet som et enkelt stisegment.","schema":{"type":"string","examples":["EksempelSMP"]}}],"responses":{"200":{"description":"Katalogobjekt eller {error} ved ukendt server. checkout.currency er EMS; produkternes price/priceDKK kan være database-decimalstrenge, men priceQuote bruger tal.","content":{"application/json":{"examples":{"example1":{"summary":"Katalogobjekt eller {error} ved ukendt server. checkout.currency er EMS; produkternes price/priceDKK kan være database-decimalstrenge, men priceQuote bruger tal.","value":{"checkout":{"version":1,"currency":"EMS","idempotency":true},"showBuyers":true,"topBuyers":[{"username":"EksempelSpiller","uuid":"123e4567-e89b-42d3-a456-426614174001","orders":4,"items":256,"spent":720,"spentCurrency":"EMS","lastPurchasedAt":"2026-10-01T12:00:00.000Z"}],"recentBuyers":[{"username":"EksempelSpiller","uuid":"123e4567-e89b-42d3-a456-426614174001","productName":"Diamanter","amount":180,"currency":"EMS","purchasedAt":"2026-10-01T12:00:00.000Z"}],"categories":[{"uid":"resources","name":"Ressourcer","imageURL":null}],"products":[{"uid":"diamonds","name":"Diamanter","type":"bulk","duration":null,"intervals":8,"price":"3.125","priceDKK":null,"volumeDiscounts":[{"minimumQuantity":64,"discountPercent":10},{"minimumQuantity":128,"discountPercent":15}],"description":"Diamanter til dine byggeprojekter.","categoryUID":"resources","imageURL":null,"automaticDiscount":null,"priceQuote":{"unitPrice":3.125,"quantity":8,"subtotal":25,"discountPercent":0,"discountAmount":0,"total":25,"nextTier":{"minimumQuantity":64,"discountPercent":10},"discountSource":null,"discountLabel":null,"discountCode":null}}]}}}}}},"503":{"description":"Kataloget kunne ikke hentes.","content":{"application/json":{"examples":{"example2":{"summary":"Kataloget kunne ikke hentes.","value":{"error":"Data kunne ikke hentes. Prøv igen."}}}}}}}}},"/information":{"get":{"operationId":"information-summary","tags":["information"],"summary":"Netværksinformation","description":"Hent netværkets aktive MOTD, favicon, antal online spillere og samlede antal tilslutninger til servere og lobbyer.\n\nOplysningerne opdateres normalt hvert minut. Hvis flere MOTD'er er aktive, kan en anden vælges ved næste opdatering.\n\nplayers er det samlede antal konti markeret som online, ikke antallet af offentligt synlige profiler.\n\ntotalJoins tæller registrerede tilslutninger til servere og lobbyer, ikke unikke spillere.\n\nip er null i den nuværende implementering. favicon, totalJoins, line1 og line2 starter som null; players starter ved 0.\n\nHvis en opdatering mislykkes, kan de tidligere oplysninger fortsat være tilgængelige. Svaret indeholder ikke et opdateringstidspunkt.","security":[],"parameters":[],"responses":{"200":{"description":"Et øjebliksbillede af netværksinformationen. Felter kan være null ved opstart, eller når data ikke er tilgængelige.","content":{"application/json":{"examples":{"example1":{"summary":"Et øjebliksbillede af netværksinformationen. Felter kan være null ved opstart, eller når data ikke er tilgængelige.","value":{"favicon":null,"ip":null,"players":12,"totalJoins":12000,"line1":"Velkommen til Example-netværket","line2":"Spil med dine venner"}}}}}}}}},"/information/rules":{"get":{"operationId":"information-rules","tags":["information"],"summary":"Netværkets regler","description":"Hent netværkets fælles regler som HTML i et JSON-objekt.\n\nReglerne hentes fra den fælles dokumentkilde og gemmes i cache i fem minutter efter en vellykket hentning.\n\nHvis hentningen mislykkes, indeholder svaret tidligere HTML eller html: null med HTTP 200. Fejl hos dokumentkilden har ingen særskilt statuskode.\n\nSvaret er application/json, selvom html-feltet indeholder et HTML-dokument.","security":[],"parameters":[],"responses":{"200":{"description":"html er en HTML-streng eller null, hvis reglerne endnu ikke er hentet.","content":{"application/json":{"examples":{"example1":{"summary":"html er en HTML-streng eller null, hvis reglerne endnu ikke er hentet.","value":{"html":"<html><body><h1>Eksempel på regler</h1><p>Vis respekt for andre spillere.</p></body></html>"}}}}}}}}},"/lobbies/shoppylobby/market":{"get":{"operationId":"lobbies-market","tags":["lobbies"],"summary":"Shoppylobbys butikker og tilbud","description":"Hent aktive, ejede AreaShop-regioner og deres ChestShop-tilbud. Ejeren er plot-ejeren fra AreaShop, uafhængigt af skiltets ejer. Tomme aktive plots har listings: [].\n\nIngen parametre kræves. Serveren er fast shoppylobby. Svaret omfatter begge handelsretninger; ruten har intet filter for item eller plot.\n\nB/buyPrice er prisen, spilleren betaler butikken. S/sellPrice er beløbet, butikken betaler spilleren. Prisen gælder amount items; divider nøjagtigt for at beregne prisen pr. item.\n\nPriser er decimalstrenge. null betyder, at handelsretningen ikke findes; 0 er et reelt tilbud. itemVariantKey er et fingeraftryk af itemet, ikke en billed-URL eller nødvendigvis itemId i historikruten.\n\nSOLD/RESELL og ikke-udløbne RENTED-regioner kan medtages. Kan ejerens UUID ikke kobles entydigt til en spiller, er playerID/username null, mens den gyldige ejer-UUID bevares.\n\nHTTP-svaret bruger Cache-Control: no-store. Backend genbruger normalt kataloget i 30 sekunder og kontrollerer udløb ved hvert kald. Spejlede data garanterer ikke, at varen er på lager.","security":[],"parameters":[],"responses":{"200":{"description":"Et katalog med server, hentetidspunkt og butikker.","content":{"application/json":{"examples":{"example1":{"summary":"Et katalog med server, hentetidspunkt og butikker.","value":{"server":"shoppylobby","fetchedAt":"2030-06-01T12:00:00.000Z","shops":[{"id":"3333333333333333333333333333333333333333333333333333333333333333","server":"shoppylobby","world":"world","regionName":"example_plot","regionType":"RENT","owner":{"playerID":42,"uuid":"00000000-0000-4000-8000-000000000001","username":"ExamplePlayer"},"expiresAt":"2030-06-10T12:00:00.000Z","min":{"x":0,"y":0,"z":0},"max":{"x":15,"y":255,"z":15},"syncedAt":"2030-06-01T11:00:00.000Z","listings":[{"id":"4444444444444444444444444444444444444444444444444444444444444444","server":"shoppylobby","world":"world","regionName":"example_plot","x":5,"y":64,"z":5,"item":"Coal","itemMaterial":"COAL","itemKey":"minecraft:coal","itemJson":{"schemaVersion":1,"id":"minecraft:coal","material":"COAL","iconKey":"coal","amount":64},"itemVariantKey":"2222222222222222222222222222222222222222222222222222222222222222","amount":64,"buyPrice":"8.00000000","sellPrice":"4.00000000","syncedAt":"2030-06-01T11:00:00.000Z"}]}]}}}}}},"503":{"description":"Markedet er midlertidigt utilgængeligt. Retry-After: 5.","content":{"application/json":{"examples":{"example2":{"summary":"Markedet er midlertidigt utilgængeligt. Retry-After: 5.","value":{"error":"Market temporarily unavailable"}}}}}}}}},"/lobbies/shoppylobby/market/items/{itemId}/history":{"get":{"operationId":"lobbies-market-item-history","tags":["lobbies"],"summary":"Et items bedste historiske priser","description":"Hent registrerede ændringer i den bedste pris for en præcis item-variant fra frontenden. buy følger laveste B-pris; sell følger højeste S-pris pr. item.\n\nKun direction og range accepteres som query-parametre; hver skal være en enkelt streng. Ukendte og gentagne parametre afvises.\n\nHistorikjobbet kontrollerer hver 6. time og gemmer første pris samt ændringer i enhedsprisen. Ejer- eller mængdeskift til samme enhedspris giver ikke et nyt punkt.\n\npoints kan være tomt. Første punkt kan være en tidligere måling lige før den valgte periode; dens recordedAt ændres ikke. from er null ved all.\n\nthrough går kun til sidste kendte historikopdatering. lastCheckedAt kan være null. Et bortfaldet tilbud er ikke et nul-prispunkt og dokumenterer ikke lager eller løbende tilgængelighed.\n\nprice/amount beskriver den oprindelige handel. numerator/denominator angiver den præcise enhedspris som heltalsstrenge; undgå floating-point ved sammenligning.\n\nDer returneres højst 2.001 punkter, inklusive en mulig måling før perioden. Store perioder udvælger første, sidste, laveste og højeste ændring i kronologiske grupper over hele perioden; sampled/totalChanges beskriver udvalget.\n\nHTTP: Cache-Control: no-store. Backend kan genbruge det samme historiksvar i 120 sekunder. Alle tidsfelter er UTC.","security":[],"parameters":[{"name":"itemId","in":"path","required":true,"description":"Præcis 64 hexadecimale tegn med små bogstaver: SHA-256 af frontendens semantiske item-identitet. Brug item-sidens id, ikke den rå itemVariantKey, material eller Minecraft-id.","schema":{"type":"string","examples":["1111111111111111111111111111111111111111111111111111111111111111"]}},{"name":"direction","in":"query","required":false,"description":"buy eller sell, set fra spillerens side. Standardværdi: buy.","schema":{"type":"string","examples":["sell"]}},{"name":"range","in":"query","required":false,"description":"1m, 3m eller all. Måneder er UTC-kalendermåneder; datoen begrænses til den valgte måneds sidste dag. Standardværdi: 1m.","schema":{"type":"string","examples":["1m"]}}],"responses":{"200":{"description":"Prishistorik med målegrænse og eventuelle registrerede prisændringer.","content":{"application/json":{"examples":{"example1":{"summary":"Prishistorik med målegrænse og eventuelle registrerede prisændringer.","value":{"server":"shoppylobby","itemId":"1111111111111111111111111111111111111111111111111111111111111111","direction":"sell","range":"1m","fetchedAt":"2030-06-01T12:30:00.000Z","from":"2030-05-01T12:30:00.000Z","through":"2030-06-01T12:00:00.000Z","lastCheckedAt":"2030-06-01T12:00:00.000Z","sampled":false,"totalChanges":1,"points":[{"recordedAt":"2030-06-01T06:00:00.000Z","price":"8.00000000","amount":64,"numerator":"1","denominator":"8","owner":{"playerID":42,"uuid":"00000000-0000-4000-8000-000000000001","username":"ExamplePlayer"},"world":"world","regionName":"example_plot"}]}}}}}},"400":{"description":"Ugyldigt id, query-navn, værdi eller gentaget/indlejret query-parameter.","content":{"application/json":{"examples":{"example2":{"summary":"Ugyldigt id, query-navn, værdi eller gentaget/indlejret query-parameter.","value":{"error":"Invalid market history request"}}}}}},"503":{"description":"Historikken er midlertidigt utilgængelig. Retry-After: 5.","content":{"application/json":{"examples":{"example3":{"summary":"Historikken er midlertidigt utilgængelig. Retry-After: 5.","value":{"error":"Market history temporarily unavailable"}}}}}}}}},"/storeapi/v2/purchases":{"get":{"operationId":"store-purchases","tags":["store"],"summary":"Hent og forny ventende køb","description":"Hent serverens ventende ordrer. Kaldet fornyer først abonnementer og kan derfor ændre data, selvom det bruger GET.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\namount er ordretotalen; product.price er total/quantity. Bevar totalens værdi uden unødig floating-point-afrunding.\n\nModtagerens uuid bruges til levering. Listen omfatter alle ventende ordrer for serveren; den har ingen parametre til sideinddeling eller datofiltrering.\n\nBrug kaldet fra serverintegrationen. Undgå browser/CDN-caching og automatiske linkvisninger: dette GET kan ændre saldi og abonnementsstatus.\n\nItems og kommandoer leveres af serverintegrationen; svaret bekræfter ikke i sig selv levering.\n\nÆndrer data: Kan oprette ventende abonnementsordrer, trække spillerens EMS til reserveret saldo (escrow) og nulstille fornyelsesmarkøren. Udløbne abonnementer og abonnementer, der ikke kan betales, kan blive annulleret.","security":[{"serverKey":[]}],"parameters":[],"responses":{"200":{"description":"Ventende køb for nøglens server; product er et JSON-objekt.\n\nIngen ventende køb eller manglende/ukendt nøgle.","content":{"application/json":{"examples":{"example1":{"summary":"Ventende køb for nøglens server; product er et JSON-objekt.","value":[{"id":"EXAMPLE_ORDER_UID","amount":"100.00","uuid":"00000000-0000-4000-8000-000000000001","product":{"type":"bulk","id":"example_product","name":"Eksempelpakke","price":25,"quantity":4,"duration":null}}]},"example2":{"summary":"Ingen ventende køb eller manglende/ukendt nøgle.","value":[]}}}}},"503":{"description":"Fornyelse mislykkedes.","content":{"application/json":{"examples":{"example3":{"summary":"Fornyelse mislykkedes.","value":{"error":"Unable to renew purchases. Please retry."}}}}}}},"x-side-effects":"Kan oprette ventende abonnementsordrer, trække spillerens EMS til reserveret saldo (escrow) og nulstille fornyelsesmarkøren. Udløbne abonnementer og abonnementer, der ikke kan betales, kan blive annulleret."},"put":{"operationId":"store-purchases-accept","tags":["store"],"summary":"Godkend et ventende køb","description":"Behandl en ventende EMS-ordre efter serverens levering. Ordren slås op og behandles under transaktionslåse.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\nFlere fejl returneres med HTTP 200 som JSON eller tekst. Kontroller svarindholdet, også når HTTP-status er 200.\n\nDer er intet idempotency-key-felt. Et allerede behandlet køb afvises med Purchase is not pending; en gentagelse returnerer ikke endnu en success-bekræftelse.\n\nRuten leverer ikke selv Minecraft-items. Den kan ikke behandle udbetalingsordrer (payout) eller DKK-betalinger.\n\nÆndrer data: Ændrer ordren til accepted, registrerer processed, frigiver den reserverede saldo til butiksejeren og eventuelle medejere og opdaterer abonnementets næste fornyelse, hvis købet er et abonnement.","security":[{"serverKey":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"example":{"purchase":"EXAMPLE_ORDER_UID"},"schema":{"type":"object","properties":{"purchase":{"type":"string","examples":["EXAMPLE_ORDER_UID"],"description":"Ordre-id'et fra feltet id i købslisten, 1–255 tegn. Det skal entydigt identificere en ventende EMS-ordre på nøglens server. Udbetalingsordrer (payout) kan ikke behandles her."}},"required":["purchase"]}}}},"responses":{"200":{"description":"Ordren blev behandlet.\n\nUgyldig nøgle, manglende purchase eller en ordre, der ikke kan behandles.\n\nAuthorization mangler.","content":{"text/html":{"examples":{"example1":{"summary":"Ordren blev behandlet.","value":"success"},"example4":{"summary":"Authorization mangler.","value":"Invalid api key"}}},"application/json":{"examples":{"example2":{"summary":"Ugyldig nøgle, manglende purchase eller en ordre, der ikke kan behandles.","value":{"error":"Purchase is not pending"}}}}}},"503":{"description":"Behandlingen kunne ikke afsluttes. Kontroller ordrestatus, før du prøver igen.","content":{"application/json":{"examples":{"example3":{"summary":"Behandlingen kunne ikke afsluttes. Kontroller ordrestatus, før du prøver igen.","value":{"error":"Unable to process purchase. Please retry."}}}}}}},"x-side-effects":"Ændrer ordren til accepted, registrerer processed, frigiver den reserverede saldo til butiksejeren og eventuelle medejere og opdaterer abonnementets næste fornyelse, hvis købet er et abonnement."}},"/storeapi/purchases/decline":{"put":{"operationId":"store-purchases-decline","tags":["store"],"summary":"Afvis og refunder et ventende køb","description":"Afvis en ventende EMS-ordre fra serveren. Den aktive afvisningsroute indeholder ikke /v2.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\nFlere fejl returneres med HTTP 200 som JSON eller tekst. Kontroller svarindholdet, også når HTTP-status er 200.\n\nTilbagebetalingen kommer fra den ventende ordres reserverede saldo. Udbetalingsordrer, DKK-ordrer og allerede behandlede ordrer afvises.\n\nBrug kun eksempel-id'er ved læsning af dokumentationen. Et rigtigt purchase-id påvirker en rigtig ordre og saldo.\n\nÆndrer data: Ændrer ordren til denied, registrerer grund og behandlingstidspunkt, returnerer den reserverede EMS til betaleren og annullerer et eventuelt tilknyttet abonnement.","security":[{"serverKey":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"example":{"purchase":"EXAMPLE_ORDER_UID","reason":"Eksempel: varen kunne ikke leveres"},"schema":{"type":"object","properties":{"purchase":{"type":"string","examples":["EXAMPLE_ORDER_UID"],"description":"Ordre-id'et fra feltet id i købslisten, 1–255 tegn. Det skal entydigt identificere en ventende EMS-ordre på nøglens server. Udbetalingsordrer (payout) kan ikke behandles her."},"reason":{"type":"string","examples":["Eksempel: varen kunne ikke leveres"],"description":"Valgfri afvisningsgrund. En ikke-tom streng gemmes; manglende værdi eller en værdi, der ikke er en streng, bliver null."}},"required":["purchase"]}}}},"responses":{"200":{"description":"Ordren blev behandlet.\n\nUgyldig nøgle, manglende purchase eller en ordre, der ikke kan behandles.\n\nAuthorization mangler.","content":{"text/html":{"examples":{"example1":{"summary":"Ordren blev behandlet.","value":"success"}}},"application/json":{"examples":{"example2":{"summary":"Ugyldig nøgle, manglende purchase eller en ordre, der ikke kan behandles.","value":{"error":"Purchase is not pending"}},"example4":{"summary":"Authorization mangler.","value":[]}}}}},"503":{"description":"Behandlingen kunne ikke afsluttes. Kontroller ordrestatus, før du prøver igen.","content":{"application/json":{"examples":{"example3":{"summary":"Behandlingen kunne ikke afsluttes. Kontroller ordrestatus, før du prøver igen.","value":{"error":"Unable to process purchase. Please retry."}}}}}}},"x-side-effects":"Ændrer ordren til denied, registrerer grund og behandlingstidspunkt, returnerer den reserverede EMS til betaleren og annullerer et eventuelt tilknyttet abonnement."}},"/storeapi/pay":{"post":{"operationId":"store-pay","tags":["store"],"summary":"Udbetal EMS fra serverejeren","description":"Overfør EMS fra serverejerens balance til en kendt spiller og opret en accepted payout-ordre med en logpost. Kaldet overfører penge.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\nFlere fejl returneres med HTTP 200 som JSON eller tekst. Kontroller svarindholdet, også når HTTP-status er 200.\n\nServerejerens aktive global/temp-ban blokerer udbetalingen; ejeren skal have tilstrækkelig saldo.\n\nRuten har ingen idempotency-key eller beskyttelse mod gentagne kald. Gentagelse af et vellykket kald kan overføre penge igen.\n\nJSON-indholdet i eksemplet er opdigtet. Udfør kun kaldet som en tilsigtet udbetaling fra en betroet serverintegration.\n\nÆndrer data: Opretter en udbetalingsordre og EMS-logpost, trækker beløbet fra serverejeren og lægger det til modtagerens balance.","security":[{"serverKey":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"example":{"target":"00000000-0000-4000-8000-000000000001","amount":10,"title":"Eksempeludbetaling","description":"Opdigtet eksempel uden rigtig udbetaling"},"schema":{"type":"object","properties":{"target":{"type":"string","examples":["00000000-0000-4000-8000-000000000001"],"description":"UUID-streng valideret af Zod; modtageren skal findes."},"amount":{"type":"number","examples":[10],"description":"EMS-beløb som JSON-tal. Send et positivt beløb; den eksisterende validator angiver ingen minimums- eller maksimumsværdi."},"title":{"type":"string","examples":["Eksempeludbetaling"],"description":"3–255 tegn. Titel på udbetalingsordren."},"description":{"type":"string","examples":["Opdigtet eksempel uden rigtig udbetaling"],"description":"3–255 tegn. Begrundelse på udbetalingsordren."}},"required":["target","amount","title","description"]}}}},"responses":{"200":{"description":"Udbetalingen blev gennemført.\n\nManglende nøgle; andre valideringsfejl returneres også som tekst.\n\nEjeren har utilstrækkelig saldo.","content":{"text/html":{"examples":{"example1":{"summary":"Udbetalingen blev gennemført.","value":"success"},"example2":{"summary":"Manglende nøgle; andre valideringsfejl returneres også som tekst.","value":"Invalid api key (1)"},"example3":{"summary":"Ejeren har utilstrækkelig saldo.","value":"Insufficent owner balance"}}}}}},"x-side-effects":"Opretter en udbetalingsordre og EMS-logpost, trækker beløbet fra serverejeren og lægger det til modtagerens balance."}},"/storeapi/v2/votes":{"get":{"operationId":"store-votes","tags":["store"],"summary":"Hent serverens ventende stemmer","description":"Hent ubehandlede stemmer for nøglens server inden for den aktuelle stemmeperiode.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\nDagens stemmer og stemmer fra den seneste time medtages. Dagsgrænsen følger databasens dato. Feltet date i svaret er et Unix-tidspunkt i millisekunder.\n\nDette GET markerer ikke stemmer som behandlet. Brug PUT /storeapi/v2/votes, efter serveren har givet belønningen.","security":[{"serverKey":[]}],"parameters":[],"responses":{"200":{"description":"Liste med stemme-id'er, spillere og tidspunkter.\n\nIngen resultater eller manglende/ukendt nøgle.","content":{"application/json":{"examples":{"example1":{"summary":"Liste med stemme-id'er, spillere og tidspunkter.","value":[{"id":"EXAMPLE_VOTE_UID","username":"ExamplePlayer","uuid":"00000000-0000-4000-8000-000000000001","date":1893499200000}]},"example2":{"summary":"Ingen resultater eller manglende/ukendt nøgle.","value":[]}}}}}}},"put":{"operationId":"store-votes-process","tags":["store"],"summary":"Marker stemmer som behandlet","description":"Sæt processed på stemme-id'er, der tilhører nøglens server. Endpointet giver ikke selv spilleren en belønning.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\nFlere fejl returneres med HTTP 200 som JSON eller tekst. Kontroller svarindholdet, også når HTTP-status er 200.\n\nVotes fra andre servere ændres ikke. Ukendte id'er kan stadig give success: true, fordi affectedRows ikke kontrolleres.\n\nÆndrer data: Sætter processed til det aktuelle tidspunkt på matchende stemmer på serveren. En gentagelse kan ændre processed-tidspunktet igen.","security":[{"serverKey":[]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"example":{"votes":["EXAMPLE_VOTE_UID"]},"schema":{"type":"object","properties":{"votes":{"type":"array","items":{},"examples":[["EXAMPLE_VOTE_UID"]],"description":"Ikke-tom liste af stemme-id'er. Send id-strenge; ruten kontrollerer arrayet og dets længde, men ikke hvert elements type."}},"required":["votes"]}}}},"responses":{"200":{"description":"Opdateringen blev udført; svaret angiver ikke antallet af resultater.\n\nBody, array eller nøgle er ugyldig.\n\nAuthorization mangler.","content":{"application/json":{"examples":{"example1":{"summary":"Opdateringen blev udført; svaret angiver ikke antallet af resultater.","value":{"success":true}},"example2":{"summary":"Body, array eller nøgle er ugyldig.","value":{"error":"Invalid parameters"}},"example3":{"summary":"Authorization mangler.","value":[]}}}}}},"x-side-effects":"Sætter processed til det aktuelle tidspunkt på matchende stemmer på serveren. En gentagelse kan ændre processed-tidspunktet igen."}},"/storeapi/v2/votes/players/{uuid}":{"get":{"operationId":"store-player-votes","tags":["store"],"summary":"Hent en spillers stemmer på serveren","description":"Hent alle kendte stemmer for spilleren og nøglens server, inklusive behandlede stemmer. Ruten har intet dagsfilter eller sideinddeling.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\ndate er et Unix-tidspunkt i millisekunder. Der er ingen garanteret sortering eller parameter til at afgrænse historikken.","security":[{"serverKey":[]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"Spillerens UUID. Spilleren skal findes. Disse stemmeruter slår UUID'et op uden særskilt kontrol af UUID-formatet.","schema":{"type":"string","examples":["00000000-0000-4000-8000-000000000001"]}}],"responses":{"200":{"description":"Stemmelisten.\n\nIngen resultater eller manglende/ukendt nøgle.\n\nSpilleren findes ikke.","content":{"application/json":{"examples":{"example1":{"summary":"Stemmelisten.","value":[{"id":"EXAMPLE_VOTE_UID","username":"ExamplePlayer","uuid":"00000000-0000-4000-8000-000000000001","date":1893499200000}]},"example2":{"summary":"Ingen resultater eller manglende/ukendt nøgle.","value":[]},"example3":{"summary":"Spilleren findes ikke.","value":{"error":"Invalid player"}}}}}}}}},"/storeapi/v2/votes/players/{uuid}/pending":{"get":{"operationId":"store-player-pending-vote","tags":["store"],"summary":"Find en spillers ventende stemme","description":"Hent en ubehandlet stemme for spilleren på serveren inden for den aktuelle stemmeperiode.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\nDagens stemmer og stemmer fra den seneste time medtages. Dagsgrænsen følger databasens dato. Feltet date i svaret er et Unix-tidspunkt i millisekunder.\n\nVed flere resultater returneres en stemme uden garanteret sortering. Svaret markerer den ikke som behandlet; en ukendt servernøgle kan give No pending votes.","security":[{"serverKey":[]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"Spillerens UUID. Spilleren skal findes. Disse stemmeruter slår UUID'et op uden særskilt kontrol af UUID-formatet.","schema":{"type":"string","examples":["00000000-0000-4000-8000-000000000001"]}}],"responses":{"200":{"description":"En matchende stemme.\n\nIngen matchende ventende stemme.\n\nSpilleren findes ikke.\n\nAuthorization mangler.","content":{"application/json":{"examples":{"example1":{"summary":"En matchende stemme.","value":{"id":"EXAMPLE_VOTE_UID","username":"ExamplePlayer","uuid":"00000000-0000-4000-8000-000000000001","date":1893499200000}},"example2":{"summary":"Ingen matchende ventende stemme.","value":{"error":"No pending votes"}},"example3":{"summary":"Spilleren findes ikke.","value":{"error":"Invalid player"}},"example4":{"summary":"Authorization mangler.","value":[]}}}}}}}},"/storeapi/v2/votes/players/{uuid}/hasvoted":{"get":{"operationId":"store-player-has-voted","tags":["store"],"summary":"Har spilleren stemt på serveren?","description":"Kontroller, om der findes en stemme i den aktuelle stemmeperiode. Behandlede stemmer tæller også med.\n\nAPI-nøglen bestemmer serveren. Disse ruter håndhæver ingen IP-begrænsning. Opbevar nøglen i serverkode.\n\nDagens stemmer og stemmer fra den seneste time medtages. Dagsgrænsen følger databasens dato. Feltet date i svaret er et Unix-tidspunkt i millisekunder.\n\nSvaret angiver ikke, om en belønning er leveret, eller om stemmen er behandlet.","security":[{"serverKey":[]}],"parameters":[{"name":"uuid","in":"path","required":true,"description":"Spillerens UUID. Spilleren skal findes. Disse stemmeruter slår UUID'et op uden særskilt kontrol af UUID-formatet.","schema":{"type":"string","examples":["00000000-0000-4000-8000-000000000001"]}}],"responses":{"200":{"description":"Stemmestatus.\n\nIngen matchende stemme eller ukendt nøgle.\n\nSpilleren findes ikke.\n\nAuthorization mangler.","content":{"application/json":{"examples":{"example1":{"summary":"Stemmestatus.","value":{"hasVoted":true}},"example2":{"summary":"Ingen matchende stemme eller ukendt nøgle.","value":{"hasVoted":false}},"example3":{"summary":"Spilleren findes ikke.","value":{"error":"Invalid player"}},"example4":{"summary":"Authorization mangler.","value":[]}}}}}}}},"/oauth/scopes":{"get":{"operationId":"oauth-scopes","tags":["oauth"],"summary":"Aktuelle OAuth-scopes","description":"Hent kataloget over rettigheder, som din app kan ansøge om, og brugeren kan give samtykke til.\n\nOpret appen i /dashboard/apps. Før produktionsgodkendelse kan kun app-ejeren give adgang til sine egne tilknyttede spillere. Nye scopes kræver app-godkendelse og nyt brugersamtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[],"parameters":[],"responses":{"200":{"description":"Scope-katalog med ID, kategori og brugerrettet beskrivelse.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"category":{"type":"string"},"description":{"type":"string"}},"required":["id","category","description"],"additionalProperties":false}},"examples":{"example1":{"summary":"Scope-katalog med ID, kategori og brugerrettet beskrivelse.","value":[{"id":"player:profile","category":"Profil","description":"Se dit UUID og brugernavn"},{"id":"player:balance","category":"Profil","description":"Se din emerald-balance"},{"id":"servers:read","category":"Servere","description":"Se dine servere"},{"id":"emeralds:transfer:request","category":"Emeralds","description":"Anmode om overførsler af dine emeralds, som du godkender enkeltvis"},{"id":"store:purchases:request","category":"SA Store","description":"Anmode om køb i SA Store med dine emeralds, som du godkender enkeltvis"},{"id":"shoppy:plots:read","category":"Shoppy","description":"Se dine Shoppy-plots"},{"id":"shoppy:chestshops:read","category":"Shoppy","description":"Se dine chestshops og priser i Shoppy"},{"id":"advertisements:read","category":"Reklamer","description":"Se dine reklamer, deres status og visninger"},{"id":"transporter:items:read","category":"Transporter","description":"Se dine items og antal i din transporter"},{"id":"mcmmo:read","category":"MCMMO","description":"Se dine MCMMO-levels og erfaring"}]}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/authorize":{"get":{"operationId":"oauth-authorize","tags":["oauth"],"summary":"Start Login med SuperAwesome","description":"Send brugeren hertil i browseren. API’et redirecter til SuperAwesomes samtykkeside, hvor brugeren logger ind, vælger Minecraft-spiller og ser de ønskede rettigheder.\n\nEfter godkendelse sendes code og state til den registrerede redirect_uri. Koden kan bruges én gang og udløber efter 60 sekunder. Ved afvisning sendes error=access_denied og state. Et forberedt samtykke udløber efter 10 minutter.\n\nRegistrerede redirects kræver HTTPS, uden fragment eller brugeroplysninger. HTTP er kun tilladt på localhost, 127.0.0.1 og [::1]. Der bruges præcist match, uden jokertegn.\n\nDette er OAuth 2.0 med fortrolige klienter og PKCE. Tokenudveksling kræver appens secret på backend. Der udstedes ikke et OpenID Connect ID-token.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[],"parameters":[{"name":"response_type","in":"query","required":true,"description":"Authorization Code er det understøttede flow.","schema":{"type":"string","enum":["code"],"examples":["code"]}},{"name":"client_id","in":"query","required":true,"description":"Din apps client ID.","schema":{"type":"string","examples":["DIT_CLIENT_ID"]}},{"name":"redirect_uri","in":"query","required":true,"description":"Skal matche en registreret redirect-URL præcist.","schema":{"type":"string","format":"uri","maxLength":2048,"examples":["https://example.com/oauth/callback"]}},{"name":"scope","in":"query","required":true,"description":"Et eller flere registrerede scopes adskilt med mellemrum. I produktion må kun appens godkendte scopes bruges.","schema":{"type":"string","maxLength":1024,"examples":["player:profile player:balance"]}},{"name":"state","in":"query","required":true,"description":"Tilfældig, sessionsbundet værdi. Gem den og kontrollér nøjagtig match på callback, også ved afvisning.","schema":{"type":"string","minLength":1,"maxLength":512}},{"name":"code_challenge","in":"query","required":true,"description":"base64url(SHA256(code_verifier)) uden padding. Gem verifier i brugerens session på backend.","schema":{"type":"string","minLength":43,"maxLength":43,"pattern":"^[A-Za-z0-9_-]{43}$"}},{"name":"code_challenge_method","in":"query","required":true,"description":"PKCE S256 er obligatorisk.","schema":{"type":"string","enum":["s256"],"examples":["S256"]}}],"responses":{"302":{"description":"Browseren sendes til SuperAwesomes samtykkeside. Query-parametrene følger med; klient, redirect og scopes valideres i flowet på siden.","content":{"text/html":{}},"headers":{"Location":{"description":"SuperAwesomes samtykkeside.","schema":{"type":"string","format":"uri"},"example":"https://superawesome.dk/oauth/authorize?response_type=code&client_id=DIT_CLIENT_ID"}}},"400":{"description":"Et query-parameter er ikke en enkelt tekstværdi, f.eks. fordi det gentages.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Et query-parameter er ikke en enkelt tekstværdi, f.eks. fordi det gentages.","value":{"error":"invalid_request"}}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/token":{"post":{"operationId":"oauth-token","tags":["oauth"],"summary":"Byt en kode eller forny tokens","description":"Byt callback-koden for access- og refresh-token, eller brug det seneste refresh-token til at rotere begge tokens. Udfør kaldet på appens backend.\n\nKlientgodkendelse er påkrævet: brug enten HTTP Basic eller client_id og client_secret sammen i request body.\n\nSend application/x-www-form-urlencoded. JSON understøttes også. HTTP Basic bruger base64 af URL-encoded client_id + ':' + URL-encoded client_secret; body-godkendelse er et alternativ.\n\nAccess tokens lever højst 900 sekunder. Refresh-token og adgang udløber 90 dage efter det oprindelige samtykke; rotation forlænger ikke perioden. expires_in kan være kortere tæt på dette udløb.\n\nGem det nye refresh-token atomisk og undgå samtidige refresh-kald. Gentag ikke blindt en forbrugt kode eller et refresh-token ved en netværksfejl; genbrug kan tilbagekalde adgangen.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.\n\nÆndrer data: Koden eller refresh-tokenet forbruges, og et nyt tokenpar udstedes. Genbrug af en allerede brugt kode eller refresh-token tilbagekalder hele adgangen.","security":[{"oauthClient":[]},{}],"parameters":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"examples":{"authorizationCode":{"summary":"Authorization Code med PKCE","value":{"grant_type":"authorization_code","code":"KODEN_FRA_CALLBACK","redirect_uri":"https://example.com/oauth/callback","code_verifier":"DIN_GEMTE_PKCE_VERIFIER_PAA_MINDST_43_TEGN_12345"}},"refreshToken":{"summary":"Rotation med seneste refresh-token","value":{"grant_type":"refresh_token","refresh_token":"DIT_SENESTE_REFRESH_TOKEN"}}},"schema":{"oneOf":[{"type":"object","properties":{"grant_type":{"const":"authorization_code","type":"string"},"code":{"type":"string","maxLength":128},"redirect_uri":{"type":"string","format":"uri"},"code_verifier":{"type":"string","minLength":43,"maxLength":128,"pattern":"^[A-Za-z0-9._~-]+$"},"client_id":{"type":"string","description":"Kun ved klientgodkendelse i body; send ikke samtidig HTTP Basic."},"client_secret":{"type":"string","description":"Kun ved klientgodkendelse i body; gem på backend."},"scope":{"type":"string","description":"Valgfrit. Hvis medtaget, skal scope-sættet være præcis det samme som den oprindelige adgang."}},"required":["grant_type","code","redirect_uri","code_verifier"],"additionalProperties":false,"dependentRequired":{"client_id":["client_secret"],"client_secret":["client_id"]}},{"type":"object","properties":{"grant_type":{"const":"refresh_token","type":"string"},"refresh_token":{"type":"string","maxLength":128},"client_id":{"type":"string","description":"Kun ved klientgodkendelse i body; send ikke samtidig HTTP Basic."},"client_secret":{"type":"string","description":"Kun ved klientgodkendelse i body; gem på backend."},"scope":{"type":"string","description":"Valgfrit. Hvis medtaget, skal scope-sættet være præcis det samme som den oprindelige adgang."}},"required":["grant_type","refresh_token"],"additionalProperties":false,"dependentRequired":{"client_id":["client_secret"],"client_secret":["client_id"]}}]}},"application/json":{"examples":{"authorizationCode":{"summary":"Authorization Code med PKCE","value":{"grant_type":"authorization_code","code":"KODEN_FRA_CALLBACK","redirect_uri":"https://example.com/oauth/callback","code_verifier":"DIN_GEMTE_PKCE_VERIFIER_PAA_MINDST_43_TEGN_12345"}},"refreshToken":{"summary":"Rotation med seneste refresh-token","value":{"grant_type":"refresh_token","refresh_token":"DIT_SENESTE_REFRESH_TOKEN"}}},"schema":{"oneOf":[{"type":"object","properties":{"grant_type":{"const":"authorization_code","type":"string"},"code":{"type":"string","maxLength":128},"redirect_uri":{"type":"string","format":"uri"},"code_verifier":{"type":"string","minLength":43,"maxLength":128,"pattern":"^[A-Za-z0-9._~-]+$"},"client_id":{"type":"string","description":"Kun ved klientgodkendelse i body; send ikke samtidig HTTP Basic."},"client_secret":{"type":"string","description":"Kun ved klientgodkendelse i body; gem på backend."},"scope":{"type":"string","description":"Valgfrit. Hvis medtaget, skal scope-sættet være præcis det samme som den oprindelige adgang."}},"required":["grant_type","code","redirect_uri","code_verifier"],"additionalProperties":false,"dependentRequired":{"client_id":["client_secret"],"client_secret":["client_id"]}},{"type":"object","properties":{"grant_type":{"const":"refresh_token","type":"string"},"refresh_token":{"type":"string","maxLength":128},"client_id":{"type":"string","description":"Kun ved klientgodkendelse i body; send ikke samtidig HTTP Basic."},"client_secret":{"type":"string","description":"Kun ved klientgodkendelse i body; gem på backend."},"scope":{"type":"string","description":"Valgfrit. Hvis medtaget, skal scope-sættet være præcis det samme som den oprindelige adgang."}},"required":["grant_type","refresh_token"],"additionalProperties":false,"dependentRequired":{"client_id":["client_secret"],"client_secret":["client_id"]}}]}}}},"responses":{"200":{"description":"Nye opaque tokens. expires_in er access-tokenets resterende levetid i sekunder; ingen ID-token.","content":{"application/json":{"schema":{"type":"object","properties":{"access_token":{"type":"string"},"refresh_token":{"type":"string"},"token_type":{"type":"string","const":"Bearer"},"expires_in":{"type":"integer","maximum":900},"scope":{"type":"string"}},"required":["access_token","refresh_token","token_type","expires_in","scope"],"additionalProperties":false},"examples":{"example1":{"summary":"Nye opaque tokens. expires_in er access-tokenets resterende levetid i sekunder; ingen ID-token.","value":{"access_token":"DIT_NYE_ACCESS_TOKEN","refresh_token":"DIT_NYE_REFRESH_TOKEN","token_type":"Bearer","expires_in":900,"scope":"player:profile player:balance"}}}}}},"400":{"description":"Client ID/secret er ugyldigt, appen er deaktiveret, eller Basic og body-godkendelse blandes.\n\nGrant type, kode eller refresh-token er ugyldigt, udløbet, allerede brugt eller tilhører en anden app. Forkert redirect_uri eller PKCE-verifier afvises også.\n\nEt scope er ukendt, eller scope-sættet er forskelligt fra den oprindelige adgang.\n\nAppen eller spillertilknytningen tillader ikke længere denne adgang.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Client ID/secret er ugyldigt, appen er deaktiveret, eller Basic og body-godkendelse blandes.","value":{"error":"invalid_client"}},"example3":{"summary":"Grant type, kode eller refresh-token er ugyldigt, udløbet, allerede brugt eller tilhører en anden app. Forkert redirect_uri eller PKCE-verifier afvises også.","value":{"error":"invalid_grant"}},"example4":{"summary":"Et scope er ukendt, eller scope-sættet er forskelligt fra den oprindelige adgang.","value":{"error":"invalid_scope"}},"example5":{"summary":"Appen eller spillertilknytningen tillader ikke længere denne adgang.","value":{"error":"access_denied"}}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example7":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}},"x-side-effects":"Koden eller refresh-tokenet forbruges, og et nyt tokenpar udstedes. Genbrug af en allerede brugt kode eller refresh-token tilbagekalder hele adgangen."}},"/oauth/revoke":{"post":{"operationId":"oauth-revoke","tags":["oauth"],"summary":"Tilbagekald en OAuth-adgang","description":"Tilbagekald hele adgangen, som appens token tilhører, inklusive tilknyttede access- og refresh-tokens.\n\nKlientgodkendelse er påkrævet: brug enten HTTP Basic eller client_id og client_secret sammen i request body.\n\nSend application/x-www-form-urlencoded; JSON understøttes også. Spilleren kan også tilbagekalde adgang i kontrolpanelet.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.\n\nÆndrer data: Tilbagekalder hele tokenets adgang, hvis det tilhører den godkendte app.","security":[{"oauthClient":[]},{}],"parameters":[],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"example":{"token":"DIT_ACCESS_ELLER_REFRESH_TOKEN"},"schema":{"type":"object","properties":{"token":{"type":"string"},"client_id":{"type":"string","description":"Kun ved klientgodkendelse i body; send ikke samtidig HTTP Basic."},"client_secret":{"type":"string","description":"Kun ved klientgodkendelse i body; gem på backend."}},"required":["token"],"additionalProperties":false,"dependentRequired":{"client_id":["client_secret"],"client_secret":["client_id"]}}},"application/json":{"example":{"token":"DIT_ACCESS_ELLER_REFRESH_TOKEN"},"schema":{"type":"object","properties":{"token":{"type":"string"},"client_id":{"type":"string","description":"Kun ved klientgodkendelse i body; send ikke samtidig HTTP Basic."},"client_secret":{"type":"string","description":"Kun ved klientgodkendelse i body; gem på backend."}},"required":["token"],"additionalProperties":false,"dependentRequired":{"client_id":["client_secret"],"client_secret":["client_id"]}}}}},"responses":{"200":{"description":"Tomt JSON-objekt. Ukendte eller andre apps' tokens giver også 200 uden at ændre deres adgang.","content":{"application/json":{"schema":{"type":"object","properties":{},"required":[],"additionalProperties":false},"examples":{"example1":{"summary":"Tomt JSON-objekt. Ukendte eller andre apps' tokens giver også 200 uden at ændre deres adgang.","value":{}}}}}},"400":{"description":"token mangler eller er ikke tekst.\n\nKlientgodkendelsen er ugyldig.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"token mangler eller er ikke tekst.","value":{"error":"invalid_request"}},"example3":{"summary":"Klientgodkendelsen er ugyldig.","value":{"error":"invalid_client"}}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}},"x-side-effects":"Tilbagekalder hele tokenets adgang, hvis det tilhører den godkendte app."}},"/oauth/v1/player/profile":{"get":{"operationId":"oauth-player-profile","tags":["oauth"],"summary":"Den valgte spillers profil","description":"Hent ID, UUID og brugernavn for den spiller, der gav appen adgang. Emerald-saldo medtages kun, hvis brugeren også gav player:balance.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["player:profile"]}],"parameters":[],"responses":{"200":{"description":"Profil med player:profile alene. balance er udeladt.\n\nProfil, når også player:balance er godkendt.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"uuid":{"type":"string","format":"uuid"},"username":{"type":"string"},"balance":{"type":["number","string","null"],"description":"Emerald-saldo. Kan være et tal eller decimaltekst; bevar præcisionen."}},"required":["id","uuid","username"],"additionalProperties":false},"examples":{"example1":{"summary":"Profil med player:profile alene. balance er udeladt.","value":{"id":"123","uuid":"11111111-1111-4111-8111-111111111111","username":"ExamplePlayer"}},"example2":{"summary":"Profil, når også player:balance er godkendt.","value":{"id":"123","uuid":"11111111-1111-4111-8111-111111111111","username":"ExamplePlayer","balance":1250}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/player/balance":{"get":{"operationId":"oauth-player-balance","tags":["oauth"],"summary":"Den valgte spillers emerald-saldo","description":"Hent emerald-saldoen for spilleren, som gav appen dette særskilte scope. Kaldet kan ikke ændre saldoen.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["player:balance"]}],"parameters":[],"responses":{"200":{"description":"Den valgte spillers balance.","content":{"application/json":{"schema":{"type":"object","properties":{"balance":{"type":["number","string","null"],"description":"Emerald-saldo. Kan være et tal eller decimaltekst; bevar præcisionen."}},"required":["balance"],"additionalProperties":false},"examples":{"example1":{"summary":"Den valgte spillers balance.","value":{"balance":1250}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/player/servers":{"get":{"operationId":"oauth-player-servers","tags":["oauth"],"summary":"Den valgte spillers serverliste","description":"Hent servere, som spilleren ejer eller er tilknyttet som subuser, med status, version og MOTD.\n\nDer returneres ingen servernøgler eller adgangsoplysninger. Listen omfatter både ejede servere og subuser-adgang; is_owner viser forskellen.\n\nKun limit og offset accepteres. Ukendte parametre, gentagne værdier, decimaler og værdier uden for intervallet giver invalid_request.\n\nhas_more viser, om der var flere resultater ved opslaget. Øg offset med limit for næste side. Datoer er ISO 8601 i UTC eller null; utilgængelige felter kan være null.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["servers:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Antal resultater pr. side, 1–100. Standardværdi: 50.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"examples":[50]}},{"name":"offset","in":"query","required":false,"description":"Antal resultater, der springes over, 0–100.000. Standardværdi: 0.","schema":{"type":"integer","minimum":0,"maximum":100000,"default":0,"examples":[0]}}],"responses":{"200":{"description":"En side af spillerens servere, sorteret efter server-ID.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"status":{"type":["string","null"]},"type":{"type":["string","null"]},"version":{"type":["string","null"]},"is_owner":{"type":"boolean"},"created_at":{"type":["string","null"],"format":"date-time"},"last_online_at":{"type":["string","null"],"format":"date-time"},"motd":{"type":"object","properties":{"line1":{"type":["string","null"]},"line2":{"type":["string","null"]}},"required":["line1","line2"],"additionalProperties":false}},"required":["id","name","status","type","version","is_owner","created_at","last_online_at","motd"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0,"maximum":100000},"has_more":{"type":"boolean"}},"required":["limit","offset","has_more"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false},"examples":{"example1":{"summary":"En side af spillerens servere, sorteret efter server-ID.","value":{"data":[{"id":"42","name":"Example-SMP","status":"online","type":"survival","version":"1.21.4","is_owner":true,"created_at":"2026-10-07T12:00:00.000Z","last_online_at":"2026-10-07T12:00:00.000Z","motd":{"line1":"Velkommen","line2":null}}],"pagination":{"limit":50,"offset":0,"has_more":false}}}}}}},"400":{"description":"Ugyldig sideinddeling eller ukendte query-parametre.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Ugyldig sideinddeling eller ukendte query-parametre.","value":{"error":"invalid_request"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/player/shoppy/plots":{"get":{"operationId":"oauth-shoppy-plots","tags":["oauth"],"summary":"Den valgte spillers Shoppy-plots","description":"Hent spillerens aktive plots i Shoppylobby med region, koordinater, ejerskabsstatus, pris og eventuelt lejeudløb.\n\nOmfatter SOLD og RESELL samt RENTED, hvor lejen ikke er udløbet. expires_at er kun udfyldt for leje; resell_price kun ved videresalg. Priser er decimaltekst eller null.\n\nKun limit og offset accepteres. Ukendte parametre, gentagne værdier, decimaler og værdier uden for intervallet giver invalid_request.\n\nhas_more viser, om der var flere resultater ved opslaget. Øg offset med limit for næste side. Datoer er ISO 8601 i UTC eller null; utilgængelige felter kan være null.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["shoppy:plots:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Antal resultater pr. side, 1–100. Standardværdi: 50.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"examples":[50]}},{"name":"offset","in":"query","required":false,"description":"Antal resultater, der springes over, 0–100.000. Standardværdi: 0.","schema":{"type":"integer","minimum":0,"maximum":100000,"default":0,"examples":[0]}}],"responses":{"200":{"description":"En side af aktive plots, sorteret efter world og region_name.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"server":{"type":"string","const":"shoppylobby"},"world":{"type":["string","null"]},"region_name":{"type":["string","null"]},"type":{"type":["string","null"]},"state":{"type":["string","null"]},"min":{"type":"object","properties":{"x":{"type":["integer","null"]},"y":{"type":["integer","null"]},"z":{"type":["integer","null"]}},"required":["x","y","z"],"additionalProperties":false},"max":{"type":"object","properties":{"x":{"type":["integer","null"]},"y":{"type":["integer","null"]},"z":{"type":["integer","null"]}},"required":["x","y","z"],"additionalProperties":false},"expires_at":{"type":["string","null"],"format":"date-time"},"price":{"type":["string","null"],"pattern":"^\\d{1,38}(?:\\.\\d{1,8})?$","description":"Decimaltal som tekst; bevar præcisionen. null, hvis prisen ikke er tilgængelig."},"rent_duration_ms":{"type":["integer","null"],"minimum":0},"reselling":{"type":"boolean"},"resell_price":{"type":["string","null"],"pattern":"^\\d{1,38}(?:\\.\\d{1,8})?$","description":"Decimaltal som tekst; bevar præcisionen. null, hvis prisen ikke er tilgængelig."},"synced_at":{"type":["string","null"],"format":"date-time"}},"required":["server","world","region_name","type","state","min","max","expires_at","price","rent_duration_ms","reselling","resell_price","synced_at"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0,"maximum":100000},"has_more":{"type":"boolean"}},"required":["limit","offset","has_more"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false},"examples":{"example1":{"summary":"En side af aktive plots, sorteret efter world og region_name.","value":{"data":[{"server":"shoppylobby","world":"world","region_name":"shop_12","type":"rent","state":"RENTED","min":{"x":10,"y":60,"z":10},"max":{"x":20,"y":80,"z":20},"expires_at":"2026-10-07T12:00:00.000Z","price":"100.00","rent_duration_ms":604800000,"reselling":false,"resell_price":null,"synced_at":"2026-10-07T12:00:00.000Z"}],"pagination":{"limit":50,"offset":0,"has_more":false}}}}}}},"400":{"description":"Ugyldig sideinddeling eller ukendte query-parametre.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Ugyldig sideinddeling eller ukendte query-parametre.","value":{"error":"invalid_request"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/player/shoppy/chestshops":{"get":{"operationId":"oauth-shoppy-chestshops","tags":["oauth"],"summary":"Den valgte spillers chestshops","description":"Hent chestshops, som den valgte spiller ejer, i aktive Shoppylobby-plots med item, placering og køb-/salgspriser.\n\nEjerskab følger chestshoppens skilt; spilleren behøver ikke eje plottet. Kun butikker i aktive plots medtages. Rå item-data, YAML og skiltlinjer returneres ikke.\n\nbuy_price og sell_price er decimaltekst eller null. null betyder, at en gyldig pris ikke er tilgængelig for den retning.\n\nKun limit og offset accepteres. Ukendte parametre, gentagne værdier, decimaler og værdier uden for intervallet giver invalid_request.\n\nhas_more viser, om der var flere resultater ved opslaget. Øg offset med limit for næste side. Datoer er ISO 8601 i UTC eller null; utilgængelige felter kan være null.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["shoppy:chestshops:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Antal resultater pr. side, 1–100. Standardværdi: 50.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"examples":[50]}},{"name":"offset","in":"query","required":false,"description":"Antal resultater, der springes over, 0–100.000. Standardværdi: 0.","schema":{"type":"integer","minimum":0,"maximum":100000,"default":0,"examples":[0]}}],"responses":{"200":{"description":"En side af chestshops, sorteret efter world, region og skiltets koordinater.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"server":{"type":"string","const":"shoppylobby"},"world":{"type":["string","null"]},"region_name":{"type":["string","null"]},"position":{"type":"object","properties":{"x":{"type":["integer","null"]},"y":{"type":["integer","null"]},"z":{"type":["integer","null"]}},"required":["x","y","z"],"additionalProperties":false},"item":{"type":["string","null"]},"item_material":{"type":["string","null"]},"item_key":{"type":["string","null"]},"item_json":{"type":["object","null"],"additionalProperties":true,"description":"Den tilgængelige versionerede item-visning; kan være null."},"amount":{"type":["integer","null"],"minimum":0},"buy_price":{"type":["string","null"],"pattern":"^\\d{1,38}(?:\\.\\d{1,8})?$","description":"Decimaltal som tekst; bevar præcisionen. null, hvis prisen ikke er tilgængelig."},"sell_price":{"type":["string","null"],"pattern":"^\\d{1,38}(?:\\.\\d{1,8})?$","description":"Decimaltal som tekst; bevar præcisionen. null, hvis prisen ikke er tilgængelig."},"admin_shop":{"type":"boolean"},"synced_at":{"type":["string","null"],"format":"date-time"}},"required":["server","world","region_name","position","item","item_material","item_key","item_json","amount","buy_price","sell_price","admin_shop","synced_at"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0,"maximum":100000},"has_more":{"type":"boolean"}},"required":["limit","offset","has_more"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false},"examples":{"example1":{"summary":"En side af chestshops, sorteret efter world, region og skiltets koordinater.","value":{"data":[{"server":"shoppylobby","world":"world","region_name":"shop_12","position":{"x":12,"y":64,"z":14},"item":"DIAMOND","item_material":"DIAMOND","item_key":"minecraft:diamond","item_json":null,"amount":1,"buy_price":"100.00","sell_price":"80.00","admin_shop":false,"synced_at":"2026-10-07T12:00:00.000Z"}],"pagination":{"limit":50,"offset":0,"has_more":false}}}}}}},"400":{"description":"Ugyldig sideinddeling eller ukendte query-parametre.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Ugyldig sideinddeling eller ukendte query-parametre.","value":{"error":"invalid_request"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/player/advertisements":{"get":{"operationId":"oauth-player-advertisements","tags":["oauth"],"summary":"Den valgte spillers reklamer","description":"Hent spillerens reklamer med tekst, kladdestatus, godkendelsesstatus, afvisningsårsag og visninger. API’et er skrivebeskyttet.\n\nremaining_views er max(0, total_views − views), eller null når tællerne ikke er tilgængelige. image indeholder kun ID, afvisningsårsag og datoer; ingen billedfil.\n\nKun limit og offset accepteres. Ukendte parametre, gentagne værdier, decimaler og værdier uden for intervallet giver invalid_request.\n\nhas_more viser, om der var flere resultater ved opslaget. Øg offset med limit for næste side. Datoer er ISO 8601 i UTC eller null; utilgængelige felter kan være null.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["advertisements:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Antal resultater pr. side, 1–100. Standardværdi: 50.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"examples":[50]}},{"name":"offset","in":"query","required":false,"description":"Antal resultater, der springes over, 0–100.000. Standardværdi: 0.","schema":{"type":"integer","minimum":0,"maximum":100000,"default":0,"examples":[0]}}],"responses":{"200":{"description":"En side af reklamer, nyeste først. Statusværdier returneres som tekst; image er metadata eller null.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":["string","null"]},"title":{"type":["string","null"]},"text":{"type":["string","null"]},"draft":{"type":"boolean"},"status":{"type":["string","null"]},"denial_reason":{"type":["string","null"]},"created_at":{"type":["string","null"],"format":"date-time"},"total_views":{"type":["integer","null"],"minimum":0},"views":{"type":["integer","null"],"minimum":0},"remaining_views":{"type":["integer","null"],"minimum":0},"server":{"type":"object","properties":{"name":{"type":["string","null"]},"status":{"type":["string","null"]}},"required":["name","status"],"additionalProperties":false},"image":{"anyOf":[{"type":"object","properties":{"id":{"type":["string","null"]},"denial_reason":{"type":["string","null"]},"created_at":{"type":["string","null"],"format":"date-time"},"last_viewed_at":{"type":["string","null"],"format":"date-time"}},"required":["id","denial_reason","created_at","last_viewed_at"],"additionalProperties":false},{"type":"null"}]}},"required":["id","title","text","draft","status","denial_reason","created_at","total_views","views","remaining_views","server","image"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0,"maximum":100000},"has_more":{"type":"boolean"}},"required":["limit","offset","has_more"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false},"examples":{"example1":{"summary":"En side af reklamer, nyeste først. Statusværdier returneres som tekst; image er metadata eller null.","value":{"data":[{"id":"33333333-3333-4333-8333-333333333333","title":"Spil på Example-SMP","text":"Kom og byg med os","draft":false,"status":"approved","denial_reason":null,"created_at":"2026-10-07T12:00:00.000Z","total_views":1000,"views":250,"remaining_views":750,"server":{"name":"Example-SMP","status":"online"},"image":null}],"pagination":{"limit":50,"offset":0,"has_more":false}}}}}}},"400":{"description":"Ugyldig sideinddeling eller ukendte query-parametre.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Ugyldig sideinddeling eller ukendte query-parametre.","value":{"error":"invalid_request"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/player/transporter/items":{"get":{"operationId":"oauth-transporter-items","tags":["oauth"],"summary":"Den valgte spillers transporter-items","description":"Hent items og antal i den valgte spillers transporter, sorteret efter material. Listen medtager kun positive gemte antal. Adgangen er skrivebeskyttet og gælder kun spilleren, der gav samtykke.\n\nHver række indeholder material og amount. amount er et positivt heltal inden for JavaScripts sikre heltalsinterval eller null, hvis den gemte værdi er ugyldig. Utilgængelige material-værdier vises som null. Kaldet viser spillerens beholdning og kan ikke flytte items.\n\nmaterial er det gemte item-ID, normalt med små bogstaver som diamond; ældre aliases bevares. amount tæller enkelte items, ikke stacks.\n\nBeholdningen caches i Redis i højst 30 sekunder fra observationen og kan derfor være op til 30 sekunder gammel. Sider caches særskilt for den valgte spiller, limit og offset. Hvis Redis er utilgængelig, hentes data fra databasen.\n\nToken, tilbagekaldelse, scopes og adgang til den valgte spiller kontrolleres ved hvert kald, også når data hentes fra cache. HTTP-svaret bruger fortsat Cache-Control: no-store. Der returneres ingen cache-tidsstempler.\n\nKun limit og offset accepteres. Ukendte parametre, gentagne værdier, decimaler og værdier uden for intervallet giver invalid_request.\n\nhas_more viser, om der var flere resultater ved opslaget. Øg offset med limit for næste side. Datoer er ISO 8601 i UTC eller null; utilgængelige felter kan være null.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["transporter:items:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Antal resultater pr. side, 1–100. Standardværdi: 50.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50,"examples":[50]}},{"name":"offset","in":"query","required":false,"description":"Antal resultater, der springes over, 0–100.000. Standardværdi: 0.","schema":{"type":"integer","minimum":0,"maximum":100000,"default":0,"examples":[0]}}],"responses":{"200":{"description":"En side af transporter-items med positive gemte antal, sorteret efter material.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"material":{"type":["string","null"],"maxLength":191},"amount":{"type":["integer","null"],"minimum":1,"maximum":9007199254740991}},"required":["material","amount"],"additionalProperties":false}},"pagination":{"type":"object","properties":{"limit":{"type":"integer","minimum":1,"maximum":100},"offset":{"type":"integer","minimum":0,"maximum":100000},"has_more":{"type":"boolean"}},"required":["limit","offset","has_more"],"additionalProperties":false}},"required":["data","pagination"],"additionalProperties":false},"examples":{"example1":{"summary":"En side af transporter-items med positive gemte antal, sorteret efter material.","value":{"data":[{"material":"diamond","amount":64}],"pagination":{"limit":50,"offset":0,"has_more":false}}}}}}},"400":{"description":"Ugyldig sideinddeling eller ukendte query-parametre.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Ugyldig sideinddeling eller ukendte query-parametre.","value":{"error":"invalid_request"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/player/mcmmo":{"get":{"operationId":"oauth-player-mcmmo","tags":["oauth"],"summary":"Den valgte spillers MCMMO","description":"Hent gemte MCMMO-levels og erfaring for den spiller, der gav appen adgang. API’et er skrivebeskyttet.\n\nskills indeholder gemte levels for 17 færdigheder samt det gemte total. experience indeholder gemt XP optjent på det nuværende level for de samme 17 færdigheder. total hentes fra den gemte værdi og beregnes ikke af API’et.\n\nHvis spillerens MCMMO-bruger mangler, er begge sektioner null. Hvis en skills- eller experience-datarække mangler, er den pågældende sektion null; manglende data erstattes ikke med nulværdier.\n\nEn feltværdi er et ikke-negativt sikkert heltal eller null, hvis den gemte værdi er ugyldig. Svaret indeholder kun skills og experience. Kaldet tager ingen query-parametre og har ingen sideinddeling.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["mcmmo:read"]}],"parameters":[],"responses":{"200":{"description":"Gemte levels i skills og gemt XP på færdighedens nuværende level i experience. Alle felter i en tilgængelig sektion medtages.\n\nDer findes ingen MCMMO-bruger for den valgte spiller. Hvis kun den ene datarække mangler, er kun den tilsvarende sektion null.","content":{"application/json":{"schema":{"type":"object","properties":{"skills":{"anyOf":[{"type":"object","properties":{"taming":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"mining":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"woodcutting":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"repair":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"unarmed":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"herbalism":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"excavation":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"archery":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"swords":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"axes":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"acrobatics":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"fishing":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"alchemy":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"crossbows":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"tridents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"maces":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"spears":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"total":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991}},"required":["taming","mining","woodcutting","repair","unarmed","herbalism","excavation","archery","swords","axes","acrobatics","fishing","alchemy","crossbows","tridents","maces","spears","total"],"additionalProperties":false},{"type":"null"}]},"experience":{"anyOf":[{"type":"object","properties":{"taming":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"mining":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"woodcutting":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"repair":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"unarmed":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"herbalism":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"excavation":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"archery":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"swords":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"axes":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"acrobatics":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"fishing":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"alchemy":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"crossbows":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"tridents":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"maces":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991},"spears":{"type":["integer","null"],"minimum":0,"maximum":9007199254740991}},"required":["taming","mining","woodcutting","repair","unarmed","herbalism","excavation","archery","swords","axes","acrobatics","fishing","alchemy","crossbows","tridents","maces","spears"],"additionalProperties":false},{"type":"null"}]}},"required":["skills","experience"],"additionalProperties":false},"examples":{"example1":{"summary":"Gemte levels i skills og gemt XP på færdighedens nuværende level i experience. Alle felter i en tilgængelig sektion medtages.","value":{"skills":{"taming":1,"mining":2,"woodcutting":3,"repair":4,"unarmed":5,"herbalism":6,"excavation":7,"archery":8,"swords":9,"axes":10,"acrobatics":11,"fishing":12,"alchemy":13,"crossbows":14,"tridents":15,"maces":16,"spears":17,"total":153},"experience":{"taming":100,"mining":200,"woodcutting":300,"repair":400,"unarmed":500,"herbalism":600,"excavation":700,"archery":800,"swords":900,"axes":1000,"acrobatics":1100,"fishing":1200,"alchemy":1300,"crossbows":1400,"tridents":1500,"maces":1600,"spears":1700}}},"example2":{"summary":"Der findes ingen MCMMO-bruger for den valgte spiller. Hvis kun den ene datarække mangler, er kun den tilsvarende sektion null.","value":{"skills":null,"experience":null}}}}}},"400":{"description":"Query-parametre accepteres ikke, heller ikke limit, offset eller en anden spiller.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Query-parametre accepteres ikke, heller ikke limit, offset eller en anden spiller.","value":{"error":"invalid_request"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example7":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/emerald-transfers":{"post":{"operationId":"oauth-emerald-transfer-create","tags":["oauth"],"summary":"Anmod om en emerald-overførsel","description":"Opret en anmodning om emeralds fra den valgte spiller til en anden spiller. Svaret giver et godkendelseslink; oprettelsen flytter ingen emeralds.\n\nSend JSON. Ved retry skal samme idempotency_key, modtager, beløb, trimmet beskrivelse og expires_in bruges. Svaret bevarer det oprindelige ID og udløb, også hvis anmodningen allerede er besluttet eller udløbet. Brug en ny nøgle til en ny betaling.\n\nAnmodningen gælder den præcise OAuth-adgang og valgte spiller. Den kan kun hentes med et aktuelt token for samme adgang; en ny login-adgang får ikke adgang til gamle anmodninger.\n\nexpiresAt er det tidligste af oprettelsestid + expires_in og adgangens oprindelige 90-dages udløb. En pending anmodning vises som expired efter udløb; approved og rejected bevarer deres status.\n\nRedirect spilleren til approval_url. Spilleren skal logge ind og godkende beløb, modtager og beskrivelse, før emeralds overføres. Status aflæses via GET; der er ingen callback-URL eller webhook for denne anmodning.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.\n\nÆndrer data: Opretter en betalingsanmodning. Emeralds flyttes først, når spilleren godkender den konkrete anmodning på SuperAwesome.","security":[{"oauthPlayer":["emeralds:transfer:request"]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"example":{"recipient_uuid":"22222222-2222-4222-8222-222222222222","amount":100,"description":"Betaling for en Shoppy-handel","expires_in":900,"idempotency_key":"order-2026-0001"},"schema":{"type":"object","properties":{"recipient_uuid":{"type":"string","format":"uuid","examples":["22222222-2222-4222-8222-222222222222"],"description":"Eksisterende Minecraft-spillers UUID med bindestreger. Skal være forskellig fra afsenderen."},"amount":{"oneOf":[{"type":"integer","minimum":1,"maximum":1000000000},{"type":"string","pattern":"^(?:[1-9][0-9]{0,8}|1000000000)$","description":"Højst 1.000.000.000."}],"description":"Positivt heltal, 1–1.000.000.000, som JSON-tal eller tekst. Ingen decimaler eller indledende nuller."},"description":{"type":"string","minLength":1,"maxLength":1000,"description":"Formålet, som spilleren skal godkende. 1–1.000 tegn; skal indeholde andet end blanktegn. Indledende/afsluttende blanktegn fjernes."},"expires_in":{"type":"integer","minimum":60,"maximum":86400,"description":"Ønsket levetid i sekunder, 60–86.400. Kan forkortes af adgangens udløb."},"idempotency_key":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9_-]{8,128}$","description":"8–128 tegn fra A–Z, a–z, 0–9, underscore og bindestreg. Identificerer én betaling inden for den præcise OAuth-adgang."}},"required":["recipient_uuid","amount","description","expires_in","idempotency_key"]}}}},"responses":{"200":{"description":"Ny anmodning eller den eksisterende anmodning ved et identisk retry. Beløb returneres som tekst.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"app":{"type":"object","properties":{"name":{"type":"string"},"logoUrl":{"type":"string","format":"uri"}},"required":["name","logoUrl"],"additionalProperties":false},"sender":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"username":{"type":"string"}},"required":["uuid","username"],"additionalProperties":false},"recipient":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"username":{"type":"string"}},"required":["uuid","username"],"additionalProperties":false},"amount":{"type":"string","pattern":"^[1-9][0-9]*$"},"description":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","approved","rejected","expired"]},"approval_url":{"type":"string","format":"uri"}},"required":["id","app","sender","recipient","amount","description","expiresAt","status","approval_url"],"additionalProperties":false},"examples":{"example1":{"summary":"Ny anmodning eller den eksisterende anmodning ved et identisk retry. Beløb returneres som tekst.","value":{"id":"EXAMPLE_TRANSFER_ID_REPLACE_WITH_RESPONSE_ID","app":{"name":"ExampleApp","logoUrl":"https://example.com/logo.png"},"sender":{"uuid":"11111111-1111-4111-8111-111111111111","username":"ExamplePlayer"},"recipient":{"uuid":"22222222-2222-4222-8222-222222222222","username":"ExampleRecipient"},"amount":"100","description":"Betaling for en Shoppy-handel","expiresAt":"2026-10-07T12:15:00.000Z","status":"pending","approval_url":"https://superawesome.dk/oauth/transfer/EXAMPLE_TRANSFER_ID_REPLACE_WITH_RESPONSE_ID"}}}}}},"400":{"description":"Ugyldigt indhold, ukendt/ikke-entydig modtager eller overførsel til samme spiller.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Ugyldigt indhold, ukendt/ikke-entydig modtager eller overførsel til samme spiller.","value":{"error":"invalid_request"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"409":{"description":"Nøglen er allerede brugt i denne adgang med en anden modtager, beløb, trimmet beskrivelse eller expires_in.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Nøglen er allerede brugt i denne adgang med en anden modtager, beløb, trimmet beskrivelse eller expires_in.","value":{"error":"idempotency_conflict"}}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example7":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}},"x-side-effects":"Opretter en betalingsanmodning. Emeralds flyttes først, når spilleren godkender den konkrete anmodning på SuperAwesome."}},"/oauth/v1/emerald-transfers/{id}":{"get":{"operationId":"oauth-emerald-transfer-status","tags":["oauth"],"summary":"Hent en emerald-anmodnings status","description":"Hent pending, approved, rejected eller expired for en anmodning fra den samme OAuth-adgang og spiller.\n\nEt udløbet eller tilbagekaldt OAuth-token giver 401, selvom anmodningen stadig findes. Godkendelsessiden kan afvise ved udløb, manglende saldo, spillerban eller modtagerens saldoloft; spilleren ser fejlen dér, og anmodningen godkendes ikke.\n\nAnmodningen gælder den præcise OAuth-adgang og valgte spiller. Den kan kun hentes med et aktuelt token for samme adgang; en ny login-adgang får ikke adgang til gamle anmodninger.\n\nexpiresAt er det tidligste af oprettelsestid + expires_in og adgangens oprindelige 90-dages udløb. En pending anmodning vises som expired efter udløb; approved og rejected bevarer deres status.\n\nRedirect spilleren til approval_url. Spilleren skal logge ind og godkende beløb, modtager og beskrivelse, før emeralds overføres. Status aflæses via GET; der er ingen callback-URL eller webhook for denne anmodning.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["emeralds:transfer:request"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Anmodningens ID fra oprettelsessvaret.","schema":{"type":"string","examples":["EXAMPLE_TRANSFER_ID_REPLACE_WITH_RESPONSE_ID"]}}],"responses":{"200":{"description":"Anmodningens aktuelle status og oprindelige oplysninger. approved betyder, at overførslen er gennemført.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"app":{"type":"object","properties":{"name":{"type":"string"},"logoUrl":{"type":"string","format":"uri"}},"required":["name","logoUrl"],"additionalProperties":false},"sender":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"username":{"type":"string"}},"required":["uuid","username"],"additionalProperties":false},"recipient":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"username":{"type":"string"}},"required":["uuid","username"],"additionalProperties":false},"amount":{"type":"string","pattern":"^[1-9][0-9]*$"},"description":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","approved","rejected","expired"]},"approval_url":{"type":"string","format":"uri"}},"required":["id","app","sender","recipient","amount","description","expiresAt","status","approval_url"],"additionalProperties":false},"examples":{"example1":{"summary":"Anmodningens aktuelle status og oprindelige oplysninger. approved betyder, at overførslen er gennemført.","value":{"id":"EXAMPLE_TRANSFER_ID_REPLACE_WITH_RESPONSE_ID","app":{"name":"ExampleApp","logoUrl":"https://example.com/logo.png"},"sender":{"uuid":"11111111-1111-4111-8111-111111111111","username":"ExamplePlayer"},"recipient":{"uuid":"22222222-2222-4222-8222-222222222222","username":"ExampleRecipient"},"amount":"100","description":"Betaling for en Shoppy-handel","expiresAt":"2026-10-07T12:15:00.000Z","status":"approved","approval_url":"https://superawesome.dk/oauth/transfer/EXAMPLE_TRANSFER_ID_REPLACE_WITH_RESPONSE_ID"}}}}}},"400":{"description":"En af de oprindelige spillere er ikke længere tilgængelig.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"En af de oprindelige spillere er ikke længere tilgængelig.","value":{"error":"access_denied"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"404":{"description":"Anmodningen findes ikke eller tilhører en anden OAuth-adgang.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Anmodningen findes ikke eller tilhører en anden OAuth-adgang.","value":{"error":"not_found"}}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example7":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}},"/oauth/v1/store-purchases":{"post":{"operationId":"oauth-store-purchase-create","tags":["oauth"],"summary":"Anmod om et køb i SA Store","description":"Opret en anmodning om et konkret produkt og antal med den valgte spillers emeralds. Svaret indeholder butikkens pris og et godkendelseslink. Oprettelsen reserverer ingen emeralds og opretter ingen ordre.\n\nSend JSON. Identiske retries returnerer 201 med oprindeligt ID og udløb samt aktuel quote, status og udløb, også efter godkendelse, afvisning eller udløb. Spillerens ændring af rabatkoden ændrer ikke den oprindelige payloads idempotens. En ændret payload med samme nøgle giver 409 idempotency_conflict. Brug en ny nøgle til et nyt køb.\n\nquote indeholder tal, ikke decimalstrenge. subtotal er unitPrice × quantity; discountAmount og total følger SA Stores prisberegning. discountSource er volume, automatic, code eller null; rabatter kombineres ikke. Saldo kontrolleres ved spillerens godkendelse, ikke ved oprettelsen.\n\nFind serverens navn og produktets uid, type og intervals i GET /servers/{name}/store. quantity er 1 for standard, subscription og upgrade. For bulk skal quantity følge produktets intervals og købsgrænser.\n\nDen valgte OAuth-spiller betaler og modtager produktet. Appen kan ikke vælge en anden betaler/modtager, en egen pris eller DKK. Prisen beregnes af SA Store med gældende mængde-, automatiske og eventuelle kode-rabatter.\n\nAnmodningen er knyttet til den præcise OAuth-adgang og valgte spiller. Et aktuelt token fra en anden adgang kan ikke læse den. expiresAt er det tidligste af oprettelse + expires_in og adgangens oprindelige 90-dages udløb.\n\nRedirect spilleren til approval_url. Spilleren kan indtaste eller fjerne en rabatkode og se en opdateret quote, før produkt, antal, pris og beskrivelse godkendes. Abonnementer viser periodens pris og automatiske fornyelse, som fortsætter indtil annullering i spillerens abonnementer.\n\ndiscountCode er den aktuelt valgte kode; quote.discountCode er den kode, som faktisk giver rabatten, eller null når en bedre mængde- eller automatisk rabat vælges. quote_revision stiger ved opdatering af pris eller kode. Et GET eller et identisk retry kan derfor vise spillerens seneste quote.\n\nVed godkendelse kontrolleres produkt, pris, rabatter, kontotilknytning, ban, saldo og købsgrænser igen. Produktvilkår, som er ændret, kræver en ny anmodning. En ændret pris kan spilleren opdatere og gennemse på godkendelsessiden. Den viste quote ændres ikke automatisk, og en ældre side kan ikke godkende en nyere quote.\n\napproved betyder, at en SA Store-ordre er oprettet og emeralds reserveret. order.state viser pending, accepted eller denied. accepted betyder, at serveren har accepteret ordren; det garanterer ikke i sig selv levering af items/kommandoer. SA Store håndterer afvisning og tilbagebetaling.\n\nStatus aflæses via GET; der er ingen callback eller webhook. En udløbet pending anmodning vises som expired. Godkendelse kan gentages uden en ekstra ordre eller ekstra debitering; den eksisterende ordre returneres.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.\n\nÆndrer data: Gemmer en anmodning og et prisoverslag. Spilleren skal godkende på SuperAwesome, før en ordre oprettes og emeralds reserveres.","security":[{"oauthPlayer":["store:purchases:request"]}],"parameters":[],"requestBody":{"required":true,"content":{"application/json":{"example":{"server_name":"EksempelSMP","product_uid":"diamonds","quantity":16,"description":"16 diamanter til dit byggeprojekt","expires_in":900,"idempotency_key":"store-order-2026-0001"},"schema":{"type":"object","properties":{"server_name":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[^\\x00-\\x1f\\x7f/\\\\?#:]+$","description":"Serverens navn fra kataloget, 1–64 tegn efter trimning. Kontroltegn, /, backslash, ?, # og : accepteres ikke. Idempotens ignorerer forskel på store og små bogstaver i servernavnet."},"product_uid":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[A-Za-z0-9_-]{1,255}$","description":"Produktets uid i serverens butik. 1–255 bogstaver, tal, underscore eller bindestreg."},"quantity":{"type":"integer","minimum":1,"maximum":1000000,"description":"JSON-heltal, 1–1.000.000. Bulk følger intervals; øvrige produkttyper kræver 1. En talstreng accepteres ikke."},"description":{"type":"string","minLength":1,"maxLength":1000,"description":"Formålet, som spilleren skal godkende. 1–1.000 tegn og ikke tom efter trimning."},"expires_in":{"type":"integer","minimum":60,"maximum":86400,"description":"Levetid i sekunder, 60–86.400, højst adgangens resterende levetid."},"idempotency_key":{"type":"string","minLength":8,"maxLength":128,"pattern":"^[A-Za-z0-9_-]{8,128}$","description":"8–128 bogstaver, tal, underscore eller bindestreg. Genbrug samme nøgle og samme indhold ved retry inden for samme OAuth-adgang."},"discount_code":{"type":"string","maxLength":20,"pattern":"^[A-Za-z0-9_-]{0,20}$","description":"Valgfri rabatkode: højst 20 bogstaver, tal, underscore eller bindestreg. Trimmes og normaliseres til store bogstaver; tom tekst svarer til ingen kode."}},"required":["server_name","product_uid","quantity","description","expires_in","idempotency_key"]}}}},"responses":{"201":{"description":"Ny anmodning eller identisk retry med oprindeligt ID og udløb samt aktuel quote. order er null indtil godkendelse.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"app":{"type":"object","properties":{"name":{"type":"string"},"logoUrl":{"type":"string","format":"uri"}},"required":["name","logoUrl"],"additionalProperties":false},"player":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"username":{"type":"string"}},"required":["uuid","username"],"additionalProperties":false},"server":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false},"product":{"type":"object","properties":{"uid":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["standard","bulk","subscription","upgrade"]},"duration":{"type":["integer","null"],"minimum":0,"description":"Produktets gemte periode i dage eller null. Abonnementer kræver en positiv periode."},"intervals":{"type":"integer","minimum":1}},"required":["uid","name","type","duration","intervals"],"additionalProperties":false},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"currency":{"type":"string","const":"EMS"},"discountCode":{"type":["string","null"],"description":"Aktuel kode valgt til anmodningen. Den kan være forskellig fra quote.discountCode, hvis en anden rabat er bedre."},"quote_revision":{"type":"integer","minimum":1,"description":"Versionen af den pris, spilleren skal godkende. Opdateres, når spilleren anvender eller fjerner en rabatkode eller opdaterer prisen."},"quote":{"type":"object","properties":{"unitPrice":{"type":"number","minimum":0,"maximum":1000000000000},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"subtotal":{"type":"number","minimum":0,"maximum":1000000000000},"discountPercent":{"type":"number","minimum":0,"maximum":100},"discountAmount":{"type":"number","minimum":0,"maximum":1000000000000},"total":{"type":"number","minimum":0,"maximum":1000000000000},"nextTier":{"anyOf":[{"type":"object","properties":{"minimumQuantity":{"type":"integer","minimum":1,"maximum":1000000},"discountPercent":{"type":"number","minimum":0,"maximum":100}},"required":["minimumQuantity","discountPercent"],"additionalProperties":false},{"type":"null"}]},"discountSource":{"type":["string","null"],"enum":["volume","automatic","code",null]},"discountLabel":{"type":["string","null"]},"discountCode":{"type":["string","null"]}},"required":["unitPrice","quantity","subtotal","discountPercent","discountAmount","total","nextTier","discountSource","discountLabel","discountCode"],"additionalProperties":false},"description":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","approved","rejected","expired"]},"approval_url":{"type":"string","format":"uri"},"order":{"anyOf":[{"type":"object","properties":{"uid":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","denied"]},"currency":{"type":"string","const":"EMS"},"amount":{"type":"number","minimum":0,"maximum":1000000000000},"quantity":{"type":"integer","minimum":1},"productName":{"type":"string"}},"required":["uid","state","currency","amount","quantity","productName"],"additionalProperties":false},{"type":"null"}]}},"required":["id","app","player","server","product","quantity","currency","discountCode","quote_revision","quote","description","expiresAt","status","approval_url","order"],"additionalProperties":false},"examples":{"example1":{"summary":"Ny anmodning eller identisk retry med oprindeligt ID og udløb samt aktuel quote. order er null indtil godkendelse.","value":{"id":"EXAMPLE_STORE_PURCHASE_ID_REPLACE_WITH_RESPONSE_ID","app":{"name":"ExampleApp","logoUrl":"https://example.com/logo.png"},"player":{"uuid":"11111111-1111-4111-8111-111111111111","username":"ExamplePlayer"},"server":{"name":"EksempelSMP"},"product":{"uid":"diamonds","name":"Diamanter","type":"bulk","duration":null,"intervals":8},"quantity":16,"currency":"EMS","discountCode":null,"quote_revision":1,"quote":{"unitPrice":3.125,"quantity":16,"subtotal":50,"discountPercent":10,"discountAmount":5,"total":45,"nextTier":null,"discountSource":"volume","discountLabel":"Mængderabat","discountCode":null},"description":"16 diamanter til dit byggeprojekt","expiresAt":"2026-10-07T12:15:00.000Z","status":"pending","approval_url":"https://superawesome.dk/oauth/store-purchase/EXAMPLE_STORE_PURCHASE_ID_REPLACE_WITH_RESPONSE_ID","order":null}}}}}},"400":{"description":"Ugyldige, manglende eller ukendte felter, talstrenge eller værdier uden for intervallerne.\n\nAntallet passer ikke til produktets type eller intervals.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Ugyldige, manglende eller ukendte felter, talstrenge eller værdier uden for intervallerne.","value":{"error":"invalid_request"}},"example3":{"summary":"Antallet passer ikke til produktets type eller intervals.","value":{"error":"invalid_quantity"}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example15":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Den valgte spiller er bannet.\n\nTokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"Den valgte spiller er bannet.","value":{"error":"payer_banned"}},"example16":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"404":{"description":"Serveren findes ikke.\n\nProduktet findes ikke eller er deaktiveret.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Serveren findes ikke.","value":{"error":"server_not_found"}},"example5":{"summary":"Produktet findes ikke eller er deaktiveret.","value":{"error":"product_unavailable"}}}}}},"409":{"description":"Nøglen er brugt i samme adgang med ændret server, produkt, antal, trimmet beskrivelse, expires_in eller normaliseret rabatkode.\n\nSpilleren har allerede dette abonnement.\n\nProduktets købsgrænse er nået.\n\nProduktet har ingen gyldig EMS-pris.\n\nProduktets type understøttes ikke.\n\nAbonnementets periode eller øvrige vilkår er ugyldige.\n\nPrisen kunne ikke beregnes.\n\nPrisen er ugyldig eller overstiger prisgrænsen.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example7":{"summary":"Nøglen er brugt i samme adgang med ændret server, produkt, antal, trimmet beskrivelse, expires_in eller normaliseret rabatkode.","value":{"error":"idempotency_conflict"}},"example8":{"summary":"Spilleren har allerede dette abonnement.","value":{"error":"subscription_exists"}},"example9":{"summary":"Produktets købsgrænse er nået.","value":{"error":"purchase_limit"}},"example10":{"summary":"Produktet har ingen gyldig EMS-pris.","value":{"error":"ems_price_unavailable"}},"example11":{"summary":"Produktets type understøttes ikke.","value":{"error":"product_type_unavailable"}},"example12":{"summary":"Abonnementets periode eller øvrige vilkår er ugyldige.","value":{"error":"invalid_subscription"}},"example13":{"summary":"Prisen kunne ikke beregnes.","value":{"error":"quote_unavailable"}},"example14":{"summary":"Prisen er ugyldig eller overstiger prisgrænsen.","value":{"error":"invalid_price"}}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example17":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example18":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}},"x-side-effects":"Gemmer en anmodning og et prisoverslag. Spilleren skal godkende på SuperAwesome, før en ordre oprettes og emeralds reserveres."}},"/oauth/v1/store-purchases/{id}":{"get":{"operationId":"oauth-store-purchase-status","tags":["oauth"],"summary":"Hent en SA Store-anmodnings status","description":"Hent anmodningens oprindelige produkt og antal, den aktuelle quote og rabatkode samt afgørelsen og den tilknyttede SA Store-ordres status.\n\nFind serverens navn og produktets uid, type og intervals i GET /servers/{name}/store. quantity er 1 for standard, subscription og upgrade. For bulk skal quantity følge produktets intervals og købsgrænser.\n\nDen valgte OAuth-spiller betaler og modtager produktet. Appen kan ikke vælge en anden betaler/modtager, en egen pris eller DKK. Prisen beregnes af SA Store med gældende mængde-, automatiske og eventuelle kode-rabatter.\n\nAnmodningen er knyttet til den præcise OAuth-adgang og valgte spiller. Et aktuelt token fra en anden adgang kan ikke læse den. expiresAt er det tidligste af oprettelse + expires_in og adgangens oprindelige 90-dages udløb.\n\nRedirect spilleren til approval_url. Spilleren kan indtaste eller fjerne en rabatkode og se en opdateret quote, før produkt, antal, pris og beskrivelse godkendes. Abonnementer viser periodens pris og automatiske fornyelse, som fortsætter indtil annullering i spillerens abonnementer.\n\ndiscountCode er den aktuelt valgte kode; quote.discountCode er den kode, som faktisk giver rabatten, eller null når en bedre mængde- eller automatisk rabat vælges. quote_revision stiger ved opdatering af pris eller kode. Et GET eller et identisk retry kan derfor vise spillerens seneste quote.\n\nVed godkendelse kontrolleres produkt, pris, rabatter, kontotilknytning, ban, saldo og købsgrænser igen. Produktvilkår, som er ændret, kræver en ny anmodning. En ændret pris kan spilleren opdatere og gennemse på godkendelsessiden. Den viste quote ændres ikke automatisk, og en ældre side kan ikke godkende en nyere quote.\n\napproved betyder, at en SA Store-ordre er oprettet og emeralds reserveret. order.state viser pending, accepted eller denied. accepted betyder, at serveren har accepteret ordren; det garanterer ikke i sig selv levering af items/kommandoer. SA Store håndterer afvisning og tilbagebetaling.\n\nStatus aflæses via GET; der er ingen callback eller webhook. En udløbet pending anmodning vises som expired. Godkendelse kan gentages uden en ekstra ordre eller ekstra debitering; den eksisterende ordre returneres.\n\nBrug et OAuth access token i Authorization: Bearer ACCESS_TOKEN. Tokenet gælder kun den Minecraft-spiller, brugeren valgte ved samtykke; der er intet player_id-parameter til at skifte spiller.\n\nAccess tokens lever højst 15 minutter. En adgang kan tilbagekaldes af spilleren eller ved ændret app-godkendelse, mistet kontotilknytning eller rotation af appens secret.\n\nEn godkendt app kan ansøge om flere scopes i /dashboard/apps. En sådan godkendelse bevarer eksisterende tokens med deres oprindelige rettigheder; nye scopes kræver et nyt OAuth-flow og spillerens samtykke.\n\nAlle OAuth-svar bruger Cache-Control: no-store. Maksimum er 120 OAuth-kald pr. IP i samme minut; ved 429 er Retry-After 60 sekunder.","security":[{"oauthPlayer":["store:purchases:request"]}],"parameters":[{"name":"id","in":"path","required":true,"description":"Anmodningens ID fra oprettelsessvaret.","schema":{"type":"string","examples":["EXAMPLE_STORE_PURCHASE_ID_REPLACE_WITH_RESPONSE_ID"]}}],"responses":{"200":{"description":"Aktuel status og quote. Her er købet godkendt, mens ordren afventer serverens behandling.","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"app":{"type":"object","properties":{"name":{"type":"string"},"logoUrl":{"type":"string","format":"uri"}},"required":["name","logoUrl"],"additionalProperties":false},"player":{"type":"object","properties":{"uuid":{"type":"string","format":"uuid"},"username":{"type":"string"}},"required":["uuid","username"],"additionalProperties":false},"server":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"],"additionalProperties":false},"product":{"type":"object","properties":{"uid":{"type":"string"},"name":{"type":"string"},"type":{"type":"string","enum":["standard","bulk","subscription","upgrade"]},"duration":{"type":["integer","null"],"minimum":0,"description":"Produktets gemte periode i dage eller null. Abonnementer kræver en positiv periode."},"intervals":{"type":"integer","minimum":1}},"required":["uid","name","type","duration","intervals"],"additionalProperties":false},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"currency":{"type":"string","const":"EMS"},"discountCode":{"type":["string","null"],"description":"Aktuel kode valgt til anmodningen. Den kan være forskellig fra quote.discountCode, hvis en anden rabat er bedre."},"quote_revision":{"type":"integer","minimum":1,"description":"Versionen af den pris, spilleren skal godkende. Opdateres, når spilleren anvender eller fjerner en rabatkode eller opdaterer prisen."},"quote":{"type":"object","properties":{"unitPrice":{"type":"number","minimum":0,"maximum":1000000000000},"quantity":{"type":"integer","minimum":1,"maximum":1000000},"subtotal":{"type":"number","minimum":0,"maximum":1000000000000},"discountPercent":{"type":"number","minimum":0,"maximum":100},"discountAmount":{"type":"number","minimum":0,"maximum":1000000000000},"total":{"type":"number","minimum":0,"maximum":1000000000000},"nextTier":{"anyOf":[{"type":"object","properties":{"minimumQuantity":{"type":"integer","minimum":1,"maximum":1000000},"discountPercent":{"type":"number","minimum":0,"maximum":100}},"required":["minimumQuantity","discountPercent"],"additionalProperties":false},{"type":"null"}]},"discountSource":{"type":["string","null"],"enum":["volume","automatic","code",null]},"discountLabel":{"type":["string","null"]},"discountCode":{"type":["string","null"]}},"required":["unitPrice","quantity","subtotal","discountPercent","discountAmount","total","nextTier","discountSource","discountLabel","discountCode"],"additionalProperties":false},"description":{"type":"string"},"expiresAt":{"type":"string","format":"date-time"},"status":{"type":"string","enum":["pending","approved","rejected","expired"]},"approval_url":{"type":"string","format":"uri"},"order":{"anyOf":[{"type":"object","properties":{"uid":{"type":"string"},"state":{"type":"string","enum":["pending","accepted","denied"]},"currency":{"type":"string","const":"EMS"},"amount":{"type":"number","minimum":0,"maximum":1000000000000},"quantity":{"type":"integer","minimum":1},"productName":{"type":"string"}},"required":["uid","state","currency","amount","quantity","productName"],"additionalProperties":false},{"type":"null"}]}},"required":["id","app","player","server","product","quantity","currency","discountCode","quote_revision","quote","description","expiresAt","status","approval_url","order"],"additionalProperties":false},"examples":{"example1":{"summary":"Aktuel status og quote. Her er købet godkendt, mens ordren afventer serverens behandling.","value":{"id":"EXAMPLE_STORE_PURCHASE_ID_REPLACE_WITH_RESPONSE_ID","app":{"name":"ExampleApp","logoUrl":"https://example.com/logo.png"},"player":{"uuid":"11111111-1111-4111-8111-111111111111","username":"ExamplePlayer"},"server":{"name":"EksempelSMP"},"product":{"uid":"diamonds","name":"Diamanter","type":"bulk","duration":null,"intervals":8},"quantity":16,"currency":"EMS","discountCode":null,"quote_revision":1,"quote":{"unitPrice":3.125,"quantity":16,"subtotal":50,"discountPercent":10,"discountAmount":5,"total":45,"nextTier":null,"discountSource":"volume","discountLabel":"Mængderabat","discountCode":null},"description":"16 diamanter til dit byggeprojekt","expiresAt":"2026-10-07T12:15:00.000Z","status":"approved","approval_url":"https://superawesome.dk/oauth/store-purchase/EXAMPLE_STORE_PURCHASE_ID_REPLACE_WITH_RESPONSE_ID","order":{"uid":"EXAMPLE_ORDER_UID","state":"pending","currency":"EMS","amount":45,"quantity":16,"productName":"Diamanter"}}}}}}},"401":{"description":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example3":{"summary":"Tokenet mangler, er ugyldigt, udløbet eller tilbagekaldt, eller adgangen til den valgte spiller er ophørt.","value":{"error":"invalid_token"}}}}},"headers":{"WWW-Authenticate":{"description":"Bearer-fejlen.","schema":{"type":"string"},"example":"Bearer error=\"invalid_token\""}}},"403":{"description":"Tokenet indeholder ikke det påkrævede scope.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example4":{"summary":"Tokenet indeholder ikke det påkrævede scope.","value":{"error":"insufficient_scope"}}}}},"headers":{"WWW-Authenticate":{"description":"Det nødvendige scope mangler.","schema":{"type":"string"},"example":"Bearer error=\"insufficient_scope\""}}},"404":{"description":"Anmodningen findes ikke eller tilhører en anden OAuth-adgang.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example2":{"summary":"Anmodningen findes ikke eller tilhører en anden OAuth-adgang.","value":{"error":"not_found"}}}}}},"429":{"description":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example5":{"summary":"Mere end 120 OAuth-forespørgsler fra samme IP i det aktuelle minut. Vent før retry.","value":{"error":"rate_limited"}}}}},"headers":{"Retry-After":{"description":"Ventetid i sekunder.","schema":{"type":"integer"},"example":60}}},"503":{"description":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"examples":{"example6":{"summary":"En midlertidig tjeneste- eller databasefejl. Prøv igen senere.","value":{"error":"temporarily_unavailable"}}}}}}}}}}}