MENU navbar-image

Introduction

This documentation aims to provide all the information you need to work with our API.

<aside><strong>Id-formater:</strong> Rum- og match-id'er er <strong>ULID-strenge</strong> (26 tegn, fx <code>01jf5g8h3k2m4n6p8r0s2t4v6x</code>) — aldrig heltal. Bruger-id'er er heltal. Rum kan desuden findes via deres 6-tegns joinkode.</aside>

<aside>As you scroll, you'll see code examples for working with the API in different programming languages in the dark area to the right (or as part of the content on mobile).
You can switch the language used with the tabs at the top right (or from the nav menu at the top left on mobile).</aside>

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {YOUR_AUTH_KEY}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Du får et token fra POST /api/v1/auth/apple/token eller POST /api/v1/auth/facebook/token.

Endpoints

Authenticate the request for channel access.

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/broadcasting/auth" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/broadcasting/auth"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/broadcasting/auth

POST api/v1/broadcasting/auth

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Opret konto med brugernavn og adgangskode.

requires authentication

Alternativ til social login. Returnerer et Sanctum-token for enheden.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/auth/register" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"username\": \"b\",
    \"password\": \"|]|{+-\",
    \"email\": \"justina.gaylord@example.org\",
    \"platform\": \"ios\",
    \"device_name\": \"i\",
    \"os_version\": \"k\",
    \"app_version\": \"h\",
    \"push_token\": \"w\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/auth/register"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "username": "b",
    "password": "|]|{+-",
    "email": "justina.gaylord@example.org",
    "platform": "ios",
    "device_name": "i",
    "os_version": "k",
    "app_version": "h",
    "push_token": "w"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/auth/register

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

username   string  optional    

Must match the regex /^[A-Za-z0-9_.-]+$/. Must be at least 3 characters. Must not be greater than 30 characters. Example: b

password   string     

Example: |]|{+-

email   string     

Must be a valid email address. Must not be greater than 255 characters. Example: justina.gaylord@example.org

platform   string     

Example: ios

Must be one of:
  • ios
  • android
device_name   string  optional    

Must not be greater than 255 characters. Example: i

os_version   string  optional    

Must not be greater than 40 characters. Example: k

app_version   string  optional    

Must not be greater than 50 characters. Example: h

push_token   string  optional    

Must not be greater than 512 characters. Example: w

Log ind med e-mail og adgangskode.

requires authentication

username tages fortsat imod for konti oprettet, før e-mailen blev nøglen (Kasper 2026-09-16) — de har måske ingen adresse endnu.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/auth/login" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"gbailey@example.net\",
    \"username\": \"architecto\",
    \"password\": \"|]|{+-\",
    \"platform\": \"android\",
    \"device_name\": \"v\",
    \"os_version\": \"d\",
    \"app_version\": \"l\",
    \"push_token\": \"j\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/auth/login"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "gbailey@example.net",
    "username": "architecto",
    "password": "|]|{+-",
    "platform": "android",
    "device_name": "v",
    "os_version": "d",
    "app_version": "l",
    "push_token": "j"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/auth/login

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string  optional    

This field is required when username is not present. Example: gbailey@example.net

username   string  optional    

This field is required when email is not present. Example: architecto

password   string     

Example: |]|{+-

platform   string     

Example: android

Must be one of:
  • ios
  • android
device_name   string  optional    

Must not be greater than 255 characters. Example: v

os_version   string  optional    

Must not be greater than 40 characters. Example: d

app_version   string  optional    

Must not be greater than 50 characters. Example: l

push_token   string  optional    

Must not be greater than 512 characters. Example: j

Log ind med Apple.

requires authentication

Verificerer et identityToken fra native Sign in with Apple og returnerer et Sanctum-token for enheden. Sendes en gyldig Bearer-token med, kobles Apple-kontoen til den eksisterende bruger.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/auth/apple/token" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"identity_token\": \"architecto\",
    \"name\": \"n\",
    \"platform\": \"ios\",
    \"device_name\": \"g\",
    \"os_version\": \"z\",
    \"app_version\": \"m\",
    \"push_token\": \"i\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/auth/apple/token"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "identity_token": "architecto",
    "name": "n",
    "platform": "ios",
    "device_name": "g",
    "os_version": "z",
    "app_version": "m",
    "push_token": "i"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/auth/apple/token

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

identity_token   string     

Example: architecto

name   string  optional    

Must not be greater than 255 characters. Example: n

platform   string     

Example: ios

Must be one of:
  • ios
  • android
device_name   string  optional    

Must not be greater than 255 characters. Example: g

os_version   string  optional    

Must not be greater than 40 characters. Example: z

app_version   string  optional    

Must not be greater than 50 characters. Example: m

push_token   string  optional    

Must not be greater than 512 characters. Example: i

Log ind med Facebook.

requires authentication

Verificerer et accessToken fra Facebook Login SDK og returnerer et Sanctum-token for enheden. Sendes en gyldig Bearer-token med, kobles Facebook-kontoen til den eksisterende bruger.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/auth/facebook/token" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"access_token\": \"architecto\",
    \"platform\": \"ios\",
    \"device_name\": \"n\",
    \"os_version\": \"g\",
    \"app_version\": \"z\",
    \"push_token\": \"m\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/auth/facebook/token"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "access_token": "architecto",
    "platform": "ios",
    "device_name": "n",
    "os_version": "g",
    "app_version": "z",
    "push_token": "m"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/auth/facebook/token

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

access_token   string     

Example: architecto

platform   string     

Example: ios

Must be one of:
  • ios
  • android
device_name   string  optional    

Must not be greater than 255 characters. Example: n

os_version   string  optional    

Must not be greater than 40 characters. Example: g

app_version   string  optional    

Must not be greater than 50 characters. Example: z

push_token   string  optional    

Must not be greater than 512 characters. Example: m

Anmod om nulstilling af adgangskode.

Sender en e-mail med nulstillingslink til konti med e-mail. Svaret er altid det samme, så det ikke afslører, om kontoen findes.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/auth/forgot-password" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"gbailey@example.net\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/auth/forgot-password"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "gbailey@example.net"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/auth/forgot-password

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

email   string     

Must be a valid email address. Example: gbailey@example.net

Nulstil adgangskode.

Bruger token fra nulstillings-e-mailen. Alle enhedens tokens tilbagekaldes, så gamle logins ikke overlever et kompromitteret kodeord.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/auth/reset-password" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"token\": \"architecto\",
    \"email\": \"zbailey@example.net\",
    \"password\": \"|]|{+-\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/auth/reset-password"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "token": "architecto",
    "email": "zbailey@example.net",
    "password": "|]|{+-"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/auth/reset-password

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

token   string     

Example: architecto

email   string     

Must be a valid email address. Example: zbailey@example.net

password   string     

Example: |]|{+-

Understøttede sprog.

Sprogkoder med aktuel version, så appen kan afgøre om dens cachede sprogfil er forældet. Spillet udledes af appens User-Agent (f.eks. Cucumber/1.2.0 (ios) matcher spillet med app-navnet Cucumber); ?game= kan bruges som eksplicit override.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/languages" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/languages"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 60
x-ratelimit-remaining: 59
access-control-allow-origin: *
 

{
    "languages": [
        {
            "locale": "da",
            "version": 195
        },
        {
            "locale": "en",
            "version": 194
        }
    ]
}
 

Request      

GET api/v1/languages

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Hent sprogfil.

Alle oversættelser for et sprog: fælles strenge plus spillets egne (spilspecifikke overskriver fælles ved samme nøgle). Spillet udledes af appens User-Agent, ?game= kan override. Sendes ?version= med, og den matcher den aktuelle version, returneres 304 Not Modified, så appen kan beholde sin cache.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/languages/sr_BA" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/languages/sr_BA"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404):

Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 60
x-ratelimit-remaining: 58
access-control-allow-origin: *
 

{
    "message": ""
}
 

Request      

GET api/v1/languages/{locale}

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

locale   string     

Example: sr_BA

App-konfiguration og feature flags.

Kill-switches, som appen skal respektere uden en ny release. Login- flag er kun sande, når både featuren er slået til OG serverens credentials er konfigureret.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/config" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/config"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 60
x-ratelimit-remaining: 57
access-control-allow-origin: *
 

{
    "online_enabled": null,
    "matchmaking_enabled": true,
    "apple_login_enabled": true,
    "facebook_login_enabled": true,
    "minimum_app_version": "",
    "sound_enabled": null,
    "haptics_enabled": null,
    "hints_enabled": null,
    "auto_sort_enabled": null,
    "deck_designs": null,
    "support_email": null,
    "seats": null,
    "legal_urls": null
}
 

Request      

GET api/v1/config

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Rapportér en klientfejl.

requires authentication

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/client-errors" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"message\": \"Undefined method\",
    \"exception\": \"BadMethodCallException\",
    \"file\": \"app\\/Livewire\\/Lobby.php\",
    \"line\": 42,
    \"trace\": \"architecto\",
    \"screen\": \"lobby\",
    \"platform\": \"ios\",
    \"app_version\": \"0.1.0\",
    \"app_build\": \"49\",
    \"match_log\": \"d\",
    \"match_id\": \"l\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/client-errors"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "message": "Undefined method",
    "exception": "BadMethodCallException",
    "file": "app\/Livewire\/Lobby.php",
    "line": 42,
    "trace": "architecto",
    "screen": "lobby",
    "platform": "ios",
    "app_version": "0.1.0",
    "app_build": "49",
    "match_log": "d",
    "match_id": "l"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/client-errors

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

message   string     

Fejlbeskeden. Example: Undefined method

exception   string  optional    

Undtagelsens klasse. Example: BadMethodCallException

file   string  optional    

Filen fejlen skete i. Example: app/Livewire/Lobby.php

line   integer  optional    

Linjenummeret. Example: 42

trace   string  optional    

Stakspor, højst 8000 tegn. Example: architecto

screen   string  optional    

Skærmen brugeren var på. Example: lobby

platform   string  optional    

ios eller android. Example: ios

app_version   string  optional    

Example: 0.1.0

app_build   string  optional    

Example: 49

match_log   string  optional    

Kun for LOKALE partier: gzip+base64 af en engine-matchlog. Se SubmittedMatchLog for hvorfor online-matcher afvises. Must not be greater than 90000 characters. Example: d

match_id   string  optional    

Online: kun id'et. Loggen bygger vi selv af vores egne data. Must not be greater than 40 characters. Example: l

Facebook data deletion callback.

requires authentication

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/facebook/data-deletion" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/facebook/data-deletion"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/facebook/data-deletion

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Status for en sletteanmodning.

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/facebook/data-deletion/architecto" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/facebook/data-deletion/architecto"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (404):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": ""
}
 

Request      

GET api/v1/facebook/data-deletion/{code}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

code   string     

Example: architecto

Log ud.

requires authentication

Tilbagekalder enhedens token og fjerner enheden.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/auth/logout" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/auth/logout"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/auth/logout

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Registrér eller ryd enhedens push-token.

requires authentication

iOS beder først om push-tilladelse efter login, og FCM roterer tokens løbende — derfor kan tokenet opdateres når som helst i en session. Opdaterer præcis den enhed, Bearer-tokenet hører til, så brugerens øvrige enheder ikke berøres. Send push_token: null for at rydde det, når brugeren afviser eller trækker tilladelsen tilbage. Idempotent.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/devices/push-token" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"push_token\": \"b\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/devices/push-token"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "push_token": "b"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (204):

Empty response
 

Request      

POST api/v1/devices/push-token

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

push_token   string  optional    

Must not be greater than 512 characters. Example: b

Hent min profil.

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/me" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/me"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/me

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Slet min konto.

requires authentication

Tilbagekalder alle tokens med det samme og anonymiserer kontoen i baggrunden. Endelig sletning sker efter 30 dage.

Example request:
curl --request DELETE \
    "http://localhost:8000/api/v1/me" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/me"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request      

DELETE api/v1/me

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Upload profilbillede.

requires authentication

Multipart/form-data med feltet avatar. Billedet beskæres til et kvadrat og skaleres ned til 256x256 JPEG på serveren — send originalen, ikke en nedskaleret udgave.

HEIC accepteres, hvis serveren kan læse det; kan den ikke, svarer endpointet 422 med en besked, der kan vises til spilleren, i stedet for at fejle tavst.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/me/avatar" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: multipart/form-data" \
    --header "Accept: application/json" \
    --form "avatar=@/private/var/folders/cl/d5kzxjfn4_n4bbc7mfrp5qmc0000gn/T/phpakd6tkfi0kthfbLWZRh" 
const url = new URL(
    "http://localhost:8000/api/v1/me/avatar"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "multipart/form-data",
    "Accept": "application/json",
};

const body = new FormData();
body.append('avatar', document.querySelector('input[name="avatar"]').files[0]);

fetch(url, {
    method: "POST",
    headers,
    body,
}).then(response => response.json());

Request      

POST api/v1/me/avatar

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: multipart/form-data

Accept        

Example: application/json

Body Parameters

avatar   file     

Billedfil: jpeg, png, webp, heic eller heif. Maks 10 MB. Example: /private/var/folders/cl/d5kzxjfn4_n4bbc7mfrp5qmc0000gn/T/phpakd6tkfi0kthfbLWZRh

Fjern profilbillede.

requires authentication

Brugeren falder tilbage på sin avatar_id (de indbyggede tegninger).

Example request:
curl --request DELETE \
    "http://localhost:8000/api/v1/me/avatar" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/me/avatar"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request      

DELETE api/v1/me/avatar

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Hent venner.

requires authentication

Accepterede venskaber samt afventende anmodninger i begge retninger.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/friends" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/friends"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/friends

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Send venneanmodning via brugernavn.

requires authentication

Bruges af invitationslinks og QR-koder, hvor afsenderen kun kender modtagerens brugernavn. Gør præcis det samme som store(): findes der en afventende anmodning den anden vej, accepteres den.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/friends/by-username/kortkasper" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/friends/by-username/kortkasper"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/friends/by-username/{username}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

username   string     

Modtagerens brugernavn. Example: kortkasper

Send eller acceptér venneanmodning.

requires authentication

Findes der en afventende anmodning fra den anden bruger, accepteres den; ellers sendes en ny anmodning.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/friends/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/friends/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/friends/{user_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

user_id   integer     

The ID of the user. Example: 1

Fjern ven eller anmodning.

requires authentication

Example request:
curl --request DELETE \
    "http://localhost:8000/api/v1/friends/1" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/friends/1"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request      

DELETE api/v1/friends/{user_id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

user_id   integer     

The ID of the user. Example: 1

Synkronisér lokal statistik.

requires authentication

Gæsteprofilens singleplayer-statistik knyttes til kontoen. Idempotent: tællere er monotone, så der tages max af eksisterende og indsendt værdi per nøgle — et gentaget kald ændrer intet.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/stats/sync" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"game_id\": \"b\",
    \"stats\": [
        39
    ]
}"
const url = new URL(
    "http://localhost:8000/api/v1/stats/sync"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "game_id": "b",
    "stats": [
        39
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/stats/sync

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

game_id   string     

Must not be greater than 50 characters. Example: b

stats   integer[]  optional    

Must be at least 0.

Hent min statistik.

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/stats/me" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/stats/me"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/stats/me

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Åbne offentlige rum.

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/rooms" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/rooms

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Opret rum.

requires authentication

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"game_id\": \"b\",
    \"seats\": 3,
    \"rule_set\": [
        \"architecto\"
    ],
    \"visibility\": \"private\",
    \"mode\": \"async\",
    \"turn_timer_seconds\": 11,
    \"target_score\": 67
}"
const url = new URL(
    "http://localhost:8000/api/v1/rooms"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "game_id": "b",
    "seats": 3,
    "rule_set": [
        "architecto"
    ],
    "visibility": "private",
    "mode": "async",
    "turn_timer_seconds": 11,
    "target_score": 67
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/rooms

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

game_id   string     

Must not be greater than 50 characters. Example: b

seats   integer     

Must be between 2 and 8. Example: 3

rule_set   string[]     
visibility   string  optional    

Example: private

Must be one of:
  • private
  • public
mode   string  optional    

Example: async

Must be one of:
  • realtime
  • async
turn_timer_seconds   integer  optional    

Must be between 10 and 86400. Example: 11

target_score   integer  optional    

Must be at least 1. Example: 67

Find rum via 6-tegns kode.

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/rooms/code/architecto" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/code/architecto"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/rooms/code/{code}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

code   string     

The code. Example: architecto

Hent rum.

requires authentication

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/rooms/architecto" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/rooms/{id}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Tag plads i rummet.

requires authentication

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms/architecto/join" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/join"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/rooms/{room_id}/join

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Forlad rummet.

requires authentication

Forlader værten rummet, lukkes det.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms/architecto/leave" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/leave"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/rooms/{room_id}/leave

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Sæt klar-status.

requires authentication

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms/architecto/ready" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/ready"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/rooms/{room_id}/ready

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Spark en spiller (kun vært).

requires authentication

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms/architecto/kick" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/kick"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/rooms/{room_id}/kick

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Inviter en ven til rummet.

requires authentication

Vennen får et push med et deeplink til SPØRGE-skærmen — en uopfordret invitation må ikke sætte nogen ved et bord uden at spørge (Kaspers ønske 2026-09-16).

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms/architecto/invite" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"user_id\": 7
}"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/invite"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "user_id": 7
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/rooms/{room_id}/invite

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn). Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Body Parameters

user_id   integer     

Vennens bruger-id fra vennelisten. Example: 7

Udfyld tomme pladser med AI (kun vært).

requires authentication

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms/architecto/fill-ai" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"level\": 2,
    \"seat\": 2
}"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/fill-ai"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "level": 2,
    "seat": 2
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/rooms/{room_id}/fill-ai

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Body Parameters

level   integer  optional    

AI-styrke 1-3: 1 = let (begynder), 2 = normal, 3 = svær. Udelades feltet, bruges spillets standard (pt. 2). Example: 2

seat   integer  optional    

Udfyld KUN denne plads (0-baseret). Udelades feltet, fyldes alle tomme pladser. Example: 2

Ændr indstillinger (kun vært, kun før start).

requires authentication

Example request:
curl --request PATCH \
    "http://localhost:8000/api/v1/rooms/architecto/settings" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"rule_set\": [
        \"architecto\"
    ],
    \"mode\": \"realtime\",
    \"turn_timer_seconds\": 11,
    \"target_score\": 67
}"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/settings"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "rule_set": [
        "architecto"
    ],
    "mode": "realtime",
    "turn_timer_seconds": 11,
    "target_score": 67
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

PATCH api/v1/rooms/{room_id}/settings

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Body Parameters

rule_set   string[]     
mode   string  optional    

Example: realtime

Must be one of:
  • realtime
  • async
turn_timer_seconds   integer  optional    

Must be between 10 and 86400. Example: 11

target_score   integer  optional    

Must be at least 1. Example: 67

Start matchen (kun vært).

requires authentication

Kræver at alle pladser er fyldt (menneske eller AI), og at alle andre spillere er klar.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/rooms/architecto/start" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/rooms/architecto/start"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request      

POST api/v1/rooms/{room_id}/start

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

room_id   string     

The ID of the room. Example: architecto

room   string     

Rummets id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Hent min PlayerView (resync).

requires authentication

Returnerer spillerens egen visning, seneste seq og alle events for spillerens plads efter after_seq. Bruges efter genforbindelse.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/matches/architecto/view" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/matches/architecto/view"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/matches/{match_id}/view

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

match_id   string     

The ID of the match. Example: architecto

match   string     

Matchens id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Send en handling.

requires authentication

Idempotent via klient-genereret action_id: en gentaget request udføres ikke to gange.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/matches/architecto/actions" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"action_id\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
    \"seat\": 84,
    \"payload\": []
}"
const url = new URL(
    "http://localhost:8000/api/v1/matches/architecto/actions"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "action_id": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
    "seat": 84,
    "payload": []
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/matches/{match_id}/actions

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

match_id   string     

The ID of the match. Example: architecto

match   string     

Matchens id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Body Parameters

action_id   string     

Must be a valid UUID. Example: 6ff8f7f6-1eb3-3525-be4a-3932c805afed

seat   integer     

Must be at least 0. Example: 84

payload   object     

Hent replay (efter afslutning).

requires authentication

Kun offentlige events — private hænder afsløres ikke.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/matches/architecto/replay" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/matches/architecto/replay"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/matches/{match_id}/replay

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

match_id   string     

The ID of the match. Example: architecto

match   string     

Matchens id — en ULID-streng (26 tegn), IKKE et heltal. Example: 01jf5g8h3k2m4n6p8r0s2t4v6x

Stil dig i kø.

requires authentication

Matcher spillere i samme spil og pladstal efter rating; båndet udvides med ventetiden. Køen udløber efter 120 sekunder.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/matchmaking" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"game_id\": \"b\",
    \"seats\": 3
}"
const url = new URL(
    "http://localhost:8000/api/v1/matchmaking"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "game_id": "b",
    "seats": 3
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/matchmaking

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

game_id   string     

Must not be greater than 50 characters. Example: b

seats   integer  optional    

Must be between 2 and 8. Example: 3

Forlad køen.

requires authentication

Example request:
curl --request DELETE \
    "http://localhost:8000/api/v1/matchmaking" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/matchmaking"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request      

DELETE api/v1/matchmaking

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Kø-status (polling-fallback).

requires authentication

Returnerer den seneste billet — status matched indeholder match_id, som klienten skal navigere til.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/matchmaking" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/matchmaking"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/matchmaking

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Leaderboard for et spil.

requires authentication

Top-50 efter rating (åben sæson) plus din egen placering. Cachet i 60 sekunder.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/leaderboards/architecto" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/leaderboards/architecto"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (401):

Show headers
cache-control: no-cache, private
content-type: application/json
access-control-allow-origin: *
 

{
    "message": "Unauthenticated."
}
 

Request      

GET api/v1/leaderboards/{game}

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

game   string     

Example: architecto

Rapportér en spiller.

requires authentication

Send reason med spillerens egne ord (3-1000 tegn) — de faste kategorier er væk. comment tages stadig imod for ældre builds.

Indberetninger behandles i administrationen.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/reports" \
    --header "Authorization: Bearer {YOUR_AUTH_KEY}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"user_id\": 12,
    \"seat\": 2,
    \"match_id\": \"architecto\",
    \"reason\": \"Skrev grimme ting i chatten\",
    \"comment\": \"z\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/reports"
);

const headers = {
    "Authorization": "Bearer {YOUR_AUTH_KEY}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "user_id": 12,
    "seat": 2,
    "match_id": "architecto",
    "reason": "Skrev grimme ting i chatten",
    "comment": "z"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request      

POST api/v1/reports

Headers

Authorization        

Example: Bearer {YOUR_AUTH_KEY}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

user_id   integer  optional    

Den anmeldte bruger. Example: 12

seat   integer  optional    

Pladsen i matchen, hvis brugeren ikke kendes. Example: 2

match_id   string  optional    

Matchens id, påkrævet sammen med seat. Example: architecto

reason   string     

Spillerens egen beskrivelse. Example: Skrev grimme ting i chatten

comment   string  optional    

Must not be greater than 1000 characters. Example: z

Juridisk og hjælp

Teksten kommer som HTML uden ramme: overskrifter, afsnit, lister og tabeller. Appen bestemmer selv typografien.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/legal/privacy?locale=da&game=agurk" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/legal/privacy"
);

const params = {
    "locale": "da",
    "game": "agurk",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 60
x-ratelimit-remaining: 56
access-control-allow-origin: *
 

{
    "data": {
        "document": "privacy",
        "title": "Privatlivspolitik",
        "locale": "da",
        "updated_at": "2026-09-15",
        "url": "http://localhost:8000/privacy/agurk/da",
        "html": "<h1>Privatlivspolitik</h1>\n    <p class=\"updated\">Senest opdateret 15. september 2026</p>\n\n    <p>\n        Denne politik beskriver, hvordan Focusweb behandler personoplysninger i\n        vores kortspils-app <strong>Agurk</strong> og den tilhørende\n        onlinetjeneste. Vi er dataansvarlige for behandlingen.\n    </p>\n\n    <h2>Kort fortalt</h2>\n    <ul>\n        <li>Du kan spille mod computeren <strong>uden</strong> at oprette en konto. Så forlader intet din telefon.</li>\n        <li>Konto kræves kun for at spille online mod andre.</li>\n        <li>Vi sælger ikke dine oplysninger og bruger dem ikke til annoncering eller profilering.</li>\n        <li>Du kan når som helst slette din konto i appen.</li>\n    </ul>\n\n    <h2>Hvilke oplysninger behandler vi?</h2>\n\n    <table>\n        <tr>\n            <th>Kontooplysninger</th>\n            <td>Brugernavn, visningsnavn, valgt avatar, sprog og, hvis du oplyser den, e-mailadresse.\n                Adgangskoder gemmes altid krypteret (hashet) og kan ikke læses af os.</td>\n        </tr>\n        <tr>\n            <th>Social login</th>\n            <td>Logger du ind med Apple eller Facebook, modtager vi et bruger-id fra udbyderen samt\n                navn og e-mail, hvis du deler dem. Vælger du Apples \"skjul min e-mail\", ser vi kun\n                den anonyme videresendelsesadresse.</td>\n        </tr>\n        <tr>\n            <th>Enheder</th>\n            <td>Platform (iOS/Android), enhedsnavn, appversion, tidspunkt for seneste aktivitet og, hvis du tillader\n                notifikationer, et push-token.</td>\n        </tr>\n        <tr>\n            <th>Spildata</th>\n            <td>Rum, spillede kort, handlinger, resultater, point, rating og statistik. Vi gemmer et\n                fuldt hændelseslog per parti, så spil kan genoptages, genafspilles og fejlsøges, og\n                så snyd kan undersøges.</td>\n        </tr>\n        <tr>\n            <th>Venner og indberetninger</th>\n            <td>Venneanmodninger og blokeringer. Indberetter du en spiller, gemmer vi din\n                indberetning, den berørte konto og din eventuelle kommentar.</td>\n        </tr>\n        <tr>\n            <th>Teknisk data</th>\n            <td>Fejlrapporter og serverlogfiler (bl.a. IP-adresse og tidspunkt) i forbindelse med\n                drift og fejlretning.</td>\n        </tr>\n    </table>\n\n    <p>\n        Vi indsamler <strong>ikke</strong> placeringsdata, kontakter, billeder eller reklame-id'er,\n        og vi bruger ikke sporingsteknologi på tværs af apps eller websteder.\n    </p>\n\n    <h2>Hvorfor behandler vi dem?</h2>\n    <ul>\n        <li><strong>For at levere spillet</strong> (opfyldelse af aftale): konto, login, onlinepartier, venner, rating og statistik.</li>\n        <li><strong>For at holde spillet fair og trygt</strong> (legitim interesse): hændelseslog mod snyd, indberetninger, filter mod stødende navne.</li>\n        <li><strong>For at drifte og forbedre tjenesten</strong> (legitim interesse): fejlrapporter og driftslogfiler.</li>\n        <li><strong>Notifikationer</strong> (samtykke): \"det er din tur\" og \"match fundet\" sendes kun, hvis du har accepteret notifikationer. Du kan altid slå dem fra igen i enhedens indstillinger.</li>\n    </ul>\n\n    <h2>Hvem deler vi med?</h2>\n    <p>Vi videregiver ikke oplysninger til andre end de databehandlere, der er nødvendige for at drive tjenesten:</p>\n    <ul>\n        <li><strong>Vores hostingleverandør</strong> (servere og database i EU).</li>\n        <li><strong>Google (Firebase Cloud Messaging)</strong>: udelukkende push-tokenet og selve notifikationen, når du har accepteret notifikationer.</li>\n        <li><strong>Sentry</strong>: fejlrapporter, når noget går galt i appen eller på serveren.</li>\n        <li><strong>Apple og Facebook</strong>: kun hvis du selv vælger at logge ind med dem.</li>\n    </ul>\n    <p>Andre spillere kan se dit visningsnavn, din avatar, dit spil i partiet og din placering på ranglisten. De ser aldrig din e-mail eller dine kort på hånden.</p>\n\n    <h2>Hvor længe gemmer vi data?</h2>\n    <ul>\n        <li><strong>Konto og spildata:</strong> så længe din konto findes.</li>\n        <li><strong>Efter sletning:</strong> kontoen anonymiseres straks og fjernes endeligt senest <strong>30 dage</strong> efter. Afsluttede partier kan bestå i anonymiseret form, så modspillernes historik og rangliste fortsat giver mening.</li>\n        <li><strong>Fejlrapporter og logfiler:</strong> slettes løbende og typisk inden for 90 dage.</li>\n    </ul>\n\n    <h2>Dine rettigheder</h2>\n    <p>\n        Du har ret til indsigt i, berigtigelse af og sletning af dine oplysninger, til at begrænse\n        eller gøre indsigelse mod behandlingen og til dataportabilitet.\n    </p>\n    <ul>\n        <li><strong>Slet din konto</strong> direkte i appen under din profil. Det sletter alt som beskrevet ovenfor.</li>\n        <li><strong>Indsigt eller kopi af dine data</strong>: skriv til <a href=\"mailto:kasper@focusweb.dk\">kasper@focusweb.dk</a>.</li>\n        <li>Har du logget ind med Facebook, kan du også bede om sletning via Facebooks indstillinger; vi modtager anmodningen automatisk.</li>\n    </ul>\n    <p>\n        Du kan klage til <a href=\"https://www.datatilsynet.dk\" rel=\"noreferrer\">Datatilsynet</a>,\n        hvis du mener, vi behandler dine oplysninger forkert.\n    </p>\n\n    <h2>Børn</h2>\n    <p>\n        Tjenesten henvender sig ikke til børn under 13 år, og vi indsamler ikke bevidst oplysninger\n        om dem. Bliver vi opmærksomme på en sådan konto, sletter vi den.\n    </p>\n\n    <h2>Sikkerhed</h2>\n    <p>\n        Al trafik mellem app og server er krypteret (HTTPS). Adgangskoder hashes, og tokens fra\n        Apple og Facebook gemmes krypteret. Adgang til administrationen kræver to-faktor-godkendelse.\n    </p>\n\n    <h2>Ændringer</h2>\n    <p>\n        Vi opdaterer politikken, når tjenesten ændrer sig. Væsentlige ændringer varsles i appen.\n        Datoen øverst viser, hvornår politikken sidst blev ændret.\n    </p>\n\n    <h2>Kontakt</h2>\n    <p>\n        Focusweb, <a href=\"mailto:kasper@focusweb.dk\">kasper@focusweb.dk</a>\n    </p>"
    }
}
 

Hent ofte stillede spørgsmål.

Spillets egne spørgsmål plus de fælles, i den rækkefølge de vises, og kun dem der er skrevet på det valgte sprog.

Example request:
curl --request GET \
    --get "http://localhost:8000/api/v1/faq?locale=da&game=agurk" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
const url = new URL(
    "http://localhost:8000/api/v1/faq"
);

const params = {
    "locale": "da",
    "game": "agurk",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):

Show headers
cache-control: no-cache, private
content-type: application/json
x-ratelimit-limit: 60
x-ratelimit-remaining: 55
access-control-allow-origin: *
 

{
    "data": [
        {
            "id": 1,
            "question": "Skal jeg oprette en konto for at spille?",
            "answer": "Nej. Du kan spille mod computeren uden konto, det virker også uden internet.\n\nEn konto er kun nødvendig, hvis du vil spille online mod andre.",
            "shared": true
        },
        {
            "id": 2,
            "question": "Hvordan spiller jeg mod en ven?",
            "answer": "Opret et rum under \"Spil online\" og del den 6-tegns kode, appen viser. Din ven vælger \"Deltag\" og indtaster koden.\n\nMangler I spillere, kan værten fylde de tomme pladser med computerspillere.",
            "shared": true
        },
        {
            "id": 3,
            "question": "Hvad sker der, hvis jeg mister forbindelsen midt i et spil?",
            "answer": "Kom tilbage i appen, så genoptager du spillet, hvor det var, serveren gemmer hele partiet.\n\nNår det er din tur, har du en tidsgrænse. Overskrides den to gange i træk, overtager computeren din plads, så de andre kan spille videre. Du får pladsen tilbage, så snart du selv spiller et kort igen.",
            "shared": true
        },
        {
            "id": 4,
            "question": "Hvorfor får jeg ikke notifikationer?",
            "answer": "Notifikationer kræver, at du har givet appen lov. Tjek din enheds indstillinger under appens navn.\n\nDe sendes kun, når appen ikke er åben, er du i gang med spillet, ser du turen direkte på skærmen.",
            "shared": true
        },
        {
            "id": 5,
            "question": "Hvordan ændrer jeg mit navn eller min avatar?",
            "answer": "Åbn din profil i appen. Visningsnavnet er det, andre spillere ser, det skal være pænt og må ikke være stødende.",
            "shared": true
        },
        {
            "id": 6,
            "question": "Hvordan sletter jeg min konto?",
            "answer": "Du sletter din konto i appen under din profil. Vi anonymiserer den straks og fjerner den endeligt senest 30 dage efter.\n\nAfsluttede partier kan bestå i anonym form, så modspillernes historik stadig giver mening.",
            "shared": true
        },
        {
            "id": 7,
            "question": "En spiller opfører sig dårligt, hvad gør jeg?",
            "answer": "Brug indberetningsfunktionen i appen. Vi gennemgår alle indberetninger manuelt og kan kræve navneskift, suspendere eller lukke konti.",
            "shared": true
        },
        {
            "id": 8,
            "question": "Koster spillet noget?",
            "answer": "Nej. Spillet er gratis, og der er hverken køb i appen, abonnementer eller reklamer.",
            "shared": true
        }
    ],
    "meta": {
        "locale": "da",
        "support_url": "http://localhost:8000/support/agurk/da"
    }
}
 

Request      

GET api/v1/faq

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

locale   string  optional    

da eller en. Example: da

game   string  optional    

Spillets slug, hvis User-Agent ikke siger det. Example: agurk

Send en henvendelse til support.

Kræver ikke login: en spiller, der ikke kan komme ind, er netop en af dem, der skal kunne skrive. Er der et token med, knyttes henvendelsen til kontoen.

Example request:
curl --request POST \
    "http://localhost:8000/api/v1/support-requests" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"b\",
    \"email\": \"zbailey@example.net\",
    \"subject\": \"i\",
    \"message\": \"y\",
    \"locale\": \"da\"
}"
const url = new URL(
    "http://localhost:8000/api/v1/support-requests"
);

const headers = {
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "b",
    "email": "zbailey@example.net",
    "subject": "i",
    "message": "y",
    "locale": "da"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (201):


{
    "data": {
        "reference": "S00042"
    }
}
 

Request      

POST api/v1/support-requests

Headers

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

name   string     

Must not be greater than 100 characters. Example: b

email   string     

Must be a valid email address. Must not be greater than 255 characters. Example: zbailey@example.net

subject   string     

Must not be greater than 150 characters. Example: i

message   string     

Must be at least 10 characters. Must not be greater than 5000 characters. Example: y

locale   string  optional    

Example: da

Must be one of:
  • da
  • en