← API-dokumentation

Login med SuperAwesome

OAuth 2.0 Authorization Code med obligatorisk PKCE S256 til apps med en sikker backend. Brugeren vælger selv, hvilken Minecraft-spiller appen må få adgang til.

1. Opret appen

Registrér navn, logo, beskrivelse, eksakte redirect-URL’er, ønskede scopes og en begrundelse i kontrolpanelet. Gem client ID og secret på appens backend. Før produktionsgodkendelse kan kun app-ejeren teste med sine egne tilknyttede spillere. Ansøg om produktionsadgang, før andre spillere kan bruge appen.

Redirects skal matche præcist og bruge HTTPS uden fragment eller brugeroplysninger. HTTP er kun tilladt på localhost, 127.0.0.1 og [::1] til udvikling. Der er ingen jokertegn.

2. Send brugeren til samtykke

Generér en tilfældig, sessionsbundet state og en PKCE-verifier på 43–128 tegn. Gem begge på backend. Challenge er base64url(SHA256(verifier)) uden padding. Scopes adskilles med mellemrum.

import { randomBytes, createHash } from "node:crypto";

const state = randomBytes(32).toString("base64url");
const verifier = randomBytes(32).toString("base64url");
const challenge = createHash("sha256").update(verifier).digest("base64url");

// Gem state og verifier i brugerens session på backend.
const url = new URL("https://api.superawesome.dk/oauth/authorize");
url.search = new URLSearchParams({
  response_type: "code",
  client_id: "DIT_CLIENT_ID",
  redirect_uri: "https://example.com/oauth/callback",
  scope: "player:profile player:balance",
  state,
  code_challenge: challenge,
  code_challenge_method: "S256",
}).toString();

// Redirect brugerens browser til url.toString().

Send brugerens browser til GET /oauth/authorize. På SuperAwesome logger brugeren ind, vælger én tilknyttet Minecraft-spiller og gennemgår appens rettigheder. Samtykkesiden har 10 minutters levetid.

Efter godkendelse modtager din registrerede callback code og state. Ved afvisning modtager den error=access_denied og state. Kontrollér, at state matcher sessionen, før du behandler svaret.

3. Byt koden på backend

Koden kan bruges én gang og udløber efter 60 sekunder. Send den gemte verifier og præcis samme redirect-URL til POST /oauth/token. Brug application/x-www-form-urlencoded og HTTP Basic med client ID og secret.

curl --request POST 'https://api.superawesome.dk/oauth/token' \
  --header 'Accept: application/json' \
  --user 'DIT_CLIENT_ID:DIT_CLIENT_SECRET' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=authorization_code' \
  --data-urlencode 'code=KODEN_FRA_CALLBACK' \
  --data-urlencode 'redirect_uri=https://example.com/oauth/callback' \
  --data-urlencode 'code_verifier=DIN_GEMTE_PKCE_VERIFIER_PAA_MINDST_43_TEGN_12345'

Basic-værdien er base64 af URL-encoded client ID, et kolon og URL-encoded secret. cURL-eksemplets pladsholdere og de udstedte client-oplysninger indeholder kun tegn, der ikke kræver ekstra encoding. JSON understøttes også. Som alternativ kan client_id og client_secret sendes i body; send aldrig samtidig Basic.

{
  "access_token": "DIT_NYE_ACCESS_TOKEN",
  "refresh_token": "DIT_NYE_REFRESH_TOKEN",
  "token_type": "Bearer",
  "expires_in": 900,
  "scope": "player:profile player:balance"
}

Tokens er opaque. Der udstedes ikke et OpenID Connect ID-token. Hent identiteten med profil-API’et. Det valgte spiller-ID, UUID og brugernavn findes i profilsvaret; brug UUID som Minecraft-identitet.

4. Kald API’erne for den valgte spiller

Brug Authorization: Bearer ACCESS_TOKEN. Tokenet er bundet til den spiller, brugeren valgte ved samtykke. Der er intet parameter til at skifte til en anden spiller; det kræver et nyt OAuth-flow og spillerens valg.

curl --request GET 'https://api.superawesome.dk/oauth/v1/player/profile' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer DIT_OAUTH_ACCESS_TOKEN'

Profilen indeholder id, uuid og username. balance udelades, medmindre tokenet også har player:balance. Saldo kan være et tal, decimaltekst eller null.

Listekald til servere, plots, chestshops, reklamer og transporter-items understøtter limit (1–100, standard 50) og offset (0–100.000, standard 0). Svaret er {data: [...], pagination: {limit, offset, has_more}}. Øg offset med limit til næste side, når has_more er sand. Ukendte query-parametre afvises. Priser returneres som decimaltekst eller null, og datoer som ISO 8601 i UTC eller null. De enkelte svarfelter og eksempler findes i endpoint-referencen og OpenAPI.

Serverlisten viser både ejede servere og subuser-adgang. Shoppy viser aktive plots og spillerens egne chestshops. Transporter-API’et viser items og antal for den valgte spiller, sorteret efter material, og medtager kun positive gemte antal. Antal er sikre positive heltal eller null ved ugyldige data. Beholdningen caches i Redis i højst 30 sekunder fra observationen og kan være op til 30 sekunder gammel. Sider caches særskilt pr. spiller, limit og offset; ved Redis-fejl hentes data fra databasen. Token, tilbagekaldelse, scopes og spillertilknytning kontrolleres på hvert kald, også ved cache-hit. HTTP-svaret er fortsat no-store og har ingen cache-tidsstempler. Profil, saldo, servere, Shoppy, reklamer og transporter-items er skrivebeskyttede.

Spillerens MCMMO

mcmmo:read giver skrivebeskyttet adgang til GET /oauth/v1/player/mcmmo for den valgte spiller. Kaldet tager ingen query-parametre og bruger ingen sideinddeling.

curl --request GET 'https://api.superawesome.dk/oauth/v1/player/mcmmo' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer DIT_OAUTH_ACCESS_TOKEN'

Svaret indeholder skills med de gemte levels for 17 færdigheder og det gemte total, samt experience med gemt XP optjent på hver færdigheds nuværende level. total er den gemte værdi. Hver værdi er et ikke-negativt sikkert heltal eller null ved ugyldige data.

Hvis spilleren ikke har en MCMMO-bruger, er skills og experience null. Mangler kun den ene datarække, er kun den tilsvarende sektion null. Manglende data erstattes ikke med nulværdier. Se endpoint-referencen for alle færdighedsnavne og svareksempler.

Scopes

Kataloget hentes fra GET /oauth/scopes. Ansøg kun om scopes, integrationen skal bruge. Nye scopes skal godkendes og kræver nyt brugersamtykke. Tokenfornyelse kan ikke ændre scopes; hvis scope medsendes ved fornyelse, skal sættet være præcis det samme som den oprindelige adgang.

Henter de aktuelle scopes…

Ansøg om flere scopes

Åbn din godkendte app under Apps og integrationer, og vælg Ansøg om flere scopes. Vælg de ekstra tilladelser, og forklar, hvad appen skal bruge hver af dem til. Du kan have én ansøgning under behandling ad gangen.

Appens eksisterende produktionsadgang fungerer, mens staff behandler ansøgningen, og hvis den bliver afvist. Staff kan godkende nogle eller alle de ansøgte scopes. Du kan se afgørelsen og begrundelsen på appen og ansøge igen senere.

Godkendte ekstra scopes føjes til appens eksisterende rettigheder. De eksisterende tokens beholder deres oprindelige scopes og udløb. Send spilleren gennem et nyt OAuth-flow med de nye scopes, så spilleren kan vælge Minecraft-spiller og give nyt samtykke. Tokenfornyelse giver aldrig automatisk flere rettigheder.

5. Forny og tilbagekald adgang

Access tokens lever højst 15 minutter. Send det seneste refresh-token til POST /oauth/token med samme klientgodkendelse for at få et nyt tokenpar.

curl --request POST 'https://api.superawesome.dk/oauth/token' \
  --header 'Accept: application/json' \
  --user 'DIT_CLIENT_ID:DIT_CLIENT_SECRET' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'grant_type=refresh_token' \
  --data-urlencode 'refresh_token=DIT_SENESTE_REFRESH_TOKEN'

Gem det nye refresh-token atomisk, og undgå samtidige refresh-kald. Genbrug af en allerede brugt kode eller refresh-token tilbagekalder hele adgangen. Gentag derfor ikke blindt et tokenkald, hvis netværket fejler efter udvekslingen.

Adgangen og refresh-tokenet udløber senest 90 dage efter det oprindelige samtykke. Rotation forlænger ikke perioden. expires_in angiver access-tokenets levetid og kan være kortere end 900 sekunder tæt på adgangens udløb. Start et nyt samtykkeflow, når adgangen er udløbet.

Tilbagekald via POST /oauth/revoke med et access- eller refresh-token. Det tilbagekalder hele den tilhørende adgang. Et ukendt token giver også 200 med {}.

curl --request POST 'https://api.superawesome.dk/oauth/revoke' \
  --header 'Accept: application/json' \
  --user 'DIT_CLIENT_ID:DIT_CLIENT_SECRET' \
  --header 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'token=DIT_ACCESS_ELLER_REFRESH_TOKEN'

Under Forbundne apps kan spilleren se appens adgang for hver Minecraft-spiller, de delte tilladelser og seneste registrerede vellykkede API-kald. Fjernes appen, tilbagekaldes alle dens adgange for spillerens konto, også access- og refresh-tokens. Fejlede kald og tokenfornyelse tæller ikke som API-brug; tidligere aktivitet kan ikke vises, før registreringen er startet. Appens secret-rotation og staffens almindelige ændringer af produktionsgodkendelsen tilbagekalder eksisterende adgange. Godkendelse af en særskilt ansøgning om ekstra scopes bevarer derimod tokens med deres oprindelige rettigheder. En ophørt kontotilknytning gør tokenet ubrugeligt.

Anmod om en emerald-overførsel

emeralds:transfer:request giver appen lov til at oprette en anmodning. Spilleren skal godkende hvert konkret beløb og hver modtager på SuperAwesome, før der sker en overførsel.

curl --request POST 'https://api.superawesome.dk/oauth/v1/emerald-transfers' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer DIT_OAUTH_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data-raw '{"recipient_uuid":"22222222-2222-4222-8222-222222222222","amount":100,"description":"Betaling for en Shoppy-handel","expires_in":900,"idempotency_key":"order-2026-0001"}'

Alle fem felter er påkrævede. Modtagerens UUID skal tilhøre en eksisterende spiller og være forskelligt fra afsenderens. Beløbet er et positivt heltal på højst 1.000.000.000. Beskrivelsen må være op til 1.000 tegn og må ikke være tom efter trimning. expires_in er et JSON-heltal på 60–86.400 sekunder.

idempotency_key er 8–128 tegn med bogstaver, tal, underscore eller bindestreg. Genbrug samme nøgle og indhold ved retry. Nøglen er knyttet til den præcise OAuth-adgang; en ny login-adgang har sit eget sæt nøgler. En ændret modtager, beløb, trimmet beskrivelse eller expires_in med samme nøgle giver 409 idempotency_conflict. Et identisk retry bevarer ID, status og oprindeligt udløb. Brug en ny nøgle til en ny betaling.

{
  "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"
}
  1. Oprettelsen returnerer 200 og approval_url. Den flytter ingen emeralds.
  2. Redirect spilleren til approval_url. Spilleren logger ind og godkender app, afsender, modtager, beløb og beskrivelse.
  3. Hent status med GET /oauth/v1/emerald-transfers/{id} og et aktuelt token fra samme OAuth-adgang. Der er ingen callback eller webhook for anmodningen.

Svaret bruger amount som tekst og expiresAt som dato. Udløbet er det tidligste af ønsket levetid og adgangens oprindelige udløb. Status er pending, approved, rejected eller expired. approved betyder, at overførslen er gennemført. En udløbet pending anmodning vises som expired; besluttede anmodninger bevarer status.

Godkendelsen kan afvises ved manglende saldo, udløb, spillerban eller modtagerens saldoloft. Spilleren ser fejlen på godkendelsessiden, og anmodningen bliver ikke godkendt. Appen kan kun se anmodninger fra samme adgang og spiller; et andet grant giver 404. Hvis OAuth-tokenet er udløbet eller tilbagekaldt, giver opslaget 401.

Anmod om et køb i SA Store

store:purchases:request giver appen lov til at anmode om et bestemt produkt og antal på en server. Den spiller, der gav OAuth-samtykke, både betaler og modtager produktet. Spilleren skal godkende det konkrete køb på SuperAwesome.

Find serverens navn og produktets uid, type og intervals i GET /servers/{name}/store. Bulk-produkter tillader et antal, som følger intervals. Standardprodukter, upgrades og abonnementer kræver antal 1. Kun betaling med EMS understøttes.

curl --request POST 'https://api.superawesome.dk/oauth/v1/store-purchases' \
  --header 'Accept: application/json' \
  --header 'Authorization: Bearer DIT_OAUTH_ACCESS_TOKEN' \
  --header 'Content-Type: application/json' \
  --data-raw '{"server_name":"EksempelSMP","product_uid":"diamonds","quantity":16,"description":"16 diamanter til dit byggeprojekt","expires_in":900,"idempotency_key":"store-order-2026-0001"}'

quantity er et JSON-heltal på 1–1.000.000. description, expires_in og idempotency_key følger de samme grænser som emerald-overførsler. Valgfri discount_code trimmes og normaliseres til store bogstaver. Appen kan ikke indsende en egen pris eller vælge en anden betaler eller modtager.

{
  "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
}
  1. Opret anmodningen med POST /oauth/v1/store-purchases. Svaret er 201 med SA Stores quote og approval_url. Der oprettes ingen ordre og reserveres ingen emeralds endnu.
  2. Send spilleren til approval_url. Siden viser app, spiller, server, produkt, antal, rabat, samlet pris, beskrivelse og udløb. Spilleren kan indtaste eller fjerne en rabatkode og se den nye total før godkendelsen. Abonnementer viser også periodens pris og automatisk fornyelse.
  3. Hent status med GET /oauth/v1/store-purchases/{id} og et aktuelt token fra samme OAuth-adgang.

Genbrug samme idempotensnøgle og samme indhold ved retry. Det bevarer oprindeligt ID og udløb og giver også 201 med den aktuelle quote. Spillerens valg af en anden kode ændrer ikke appens oprindelige payload. Ændret server, produkt, antal, trimmet beskrivelse, expires_in eller normaliseret rabatkode i appens payload giver 409 idempotency_conflict. Brug en ny nøgle til et nyt køb.

discountCode er den aktuelt valgte kode. quote.discountCode kan være null, hvis en anden rabat er bedre. quote_revision viser versionen af prisen; en ældre side kan ikke godkende en nyere quote. En ændring af kode eller pris flytter ikke emeralds og forlænger ikke anmodningens udløb.

Ved godkendelse kontrollerer SA Store produkt, vilkår, pris, rabatter, ban, saldo og købsgrænser igen. Spilleren kan opdatere en ændret pris og se den nye total på godkendelsessiden. Ændrede produktvilkår kræver en ny anmodning fra appen. En anmodning udløber senest sammen med den oprindelige OAuth-adgang.

approved betyder, at ordren er oprettet og emeralds reserveret. order.state viser pending, accepted eller denied. accepted betyder, at serveren har accepteret ordren, og garanterer ikke i sig selv levering af items eller kommandoer. SA Store håndterer afvisning og tilbagebetaling. Der er ingen callback eller webhook; appen læser status med GET.

Et abonnement fornyes automatisk med den viste periode, indtil spilleren annullerer det under sine abonnementer. Godkendelsessiden linker direkte til den valgte spillers abonnementer. Eksisterende apps skal ansøge om store:purchases:request, og spilleren skal give nyt samtykke, før det kan bruges.

Fejl og begrænsninger

OAuth-fejl er JSON med formen {"error":"invalid_token"}. Token- og klientfejl returneres i denne API som HTTP 400; de beskyttede ressourcer bruger 401 ved ugyldigt token og 403 ved manglende scope.

HTTPFejlHåndtering
400invalid_client, invalid_grant, invalid_scope, invalid_request, access_deniedKontrollér klientoplysninger, kode/verifier, scopes og felter. Se endpointets fejleksempler.
401invalid_tokenForny et udløbet access-token, hvis adgangen stadig er gyldig; ellers nyt login og samtykke.
403insufficient_scopeKaldet kræver et scope, som brugeren ikke har givet.
404 / 409not_found / idempotency_conflictKontrollér anmodningens ID/adgang eller idempotensnøglens oprindelige indhold.
429rate_limitedOAuth har et fælles maksimum på 120 kald pr. IP i samme minut. Vent Retry-After: 60 sekunder.
503temporarily_unavailablePrøv igen senere. Brug samme idempotensnøgle ved retry af en emerald-anmodning.

Alle OAuth-svar bruger Cache-Control: no-store. Tokens bruges kun på de dedikerede /oauth/v1-API’er; de er ikke servernøgler til Butiks-API’et.