Mobiili-API
Koko mobiili-API kulkee oman domainin kautta osoitteessa api.meidankesken.app. Reitit ovat JSON-pohjaisia ja tukevat CORS:ia – erillistä API-avainta ei tarvita.
Yhteys
BASE_URL = https://api.meidankesken.app/api/public
const res = await fetch(BASE_URL + "/auth/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password }),
});
const { access_token } = await res.json();
await fetch(BASE_URL + "/catalog"); // julkinen
await fetch(BASE_URL + "/game/session", { // vaatii tokenin
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer " + access_token,
},
body: JSON.stringify({ player_names: ["Anna"], deck_slug: "syvat-vedet" }),
});Kirjautumista vaativissa reiteissä lähetetään otsake Authorization: Bearer <access_token>.
Autentikointi
Rekisteröinti, kirjautuminen ja tokenin uusiminen saman domainin kautta.
POST /auth/signupJulkinen
Rekisteröi uusi pelaaja. Etunimi ja sukunimi ovat pakollisia.
Kutsu
{ "email": "pelaaja@example.com", "password": "salasana123", "first_name": "Anna", "last_name": "Virtanen" }Vastaus
{ "id": "uuid", "email": "pelaaja@example.com", "…": "…" }POST /auth/loginJulkinen
Kirjautuminen. Palauttaa access- ja refresh-tokenin.
Kutsu
{ "email": "pelaaja@example.com", "password": "salasana123" }Vastaus
{ "access_token": "…", "refresh_token": "…", "expires_in": 3600, "user": { "id": "uuid" } }POST /auth/refreshJulkinen
Uusi access token vanhentuneen tilalle.
Kutsu
{ "refresh_token": "…" }Vastaus
{ "access_token": "…", "refresh_token": "…" }POST /auth/logoutToken vaaditaan
Kirjaa käyttäjän ulos ja mitätöi istunnon.
Kutsu
{}Vastaus
204 No Content
GET /profileToken vaaditaan
Kirjautuneen pelaajan profiili nimitietoineen.
Vastaus
{ "id": "uuid", "first_name": "Anna", "last_name": "Virtanen", "display_name": "Anna Virtanen", "avatar_url": null }PATCH /profileToken vaaditaan
Päivittää etunimen, sukunimen tai avatarin. Näyttönimi päivittyy nimien mukana.
Kutsu
{ "first_name": "Anna", "last_name": "Virtanen" }Vastaus
{ "id": "uuid", "first_name": "Anna", "last_name": "Virtanen", "display_name": "Anna Virtanen" }Sisältö
Julkiset reitit – eivät vaadi kirjautumista.
GET /catalogJulkinen
Kaikki julkaistut kategoriat ja niiden korttipakat.
Vastaus
{
"categories": [
{
"id": "uuid", "slug": "parisuhde", "name": "Parisuhde",
"description": "…", "icon": "heart", "color": "#b4674d", "sort_order": 1,
"decks": [
{ "id": "uuid", "slug": "syvat-vedet", "name": "Syvät vedet",
"theme": "läheisyys", "difficulty": 3, "default_timer_seconds": 60 }
]
}
]
}GET /deck/{slug}Julkinen
Yksittäinen korttipakka ja sen kortit.
Kutsu
GET https://api.meidankesken.app/api/public/deck/syvat-vedet
Vastaus
{
"deck": { "id": "uuid", "slug": "syvat-vedet", "name": "Syvät vedet", "default_timer_seconds": 60 },
"cards": [
{ "id": "uuid", "content": "Mistä hetkestä muistat…",
"type": "question", "hint": null, "sort_order": 1 }
]
}Peli
Vaativat kirjautuneen käyttäjän bearer-tokenin. Data rajautuu omiin peleihin.
POST /game/sessionToken vaaditaan
Luo pelisession, sekoittaa kortit ja arpoo vuorojärjestyksen (ei kahta vuoroa peräkkäin samalle pelaajalle).
Kutsu
{
"player_names": ["Anna", "Mikko", "Sara"],
"deck_slug": "syvat-vedet", // tai deck_id
"timer_seconds": 45, // null = pakan oletus
"shuffle": true
}Vastaus
{
"session": { "id": "uuid", "started_at": "…", "timer_seconds": 45,
"player_names": ["Anna", "Mikko", "Sara"] },
"deck": { "id": "uuid", "name": "Syvät vedet" },
"cards": [ { "id": "uuid", "content": "…", "type": "question",
"sort_order": 3, "turn_player": "Mikko" } ],
"turn_order": ["Mikko", "Anna", "Sara", "…"]
}POST /game/playToken vaaditaan
Kirjaa kortin vastaukset. Lähetä kaikki kortin vastaajat kerralla player_names-listassa (skipped_players = ne jotka ohittivat). Vanha player_name-muoto toimii yhä.
Kutsu
{ "session_id": "uuid", "card_id": "uuid",
"player_names": ["Anna", "Mikko", "Sara"],
"skipped_players": ["Sara"] }Vastaus
{ "ok": true, "played_count": 7,
"cards_played": 7, "responses_count": 21 }POST /game/completeToken vaaditaan
Päättää session. Yhteenvedon played/answered/skipped lasketaan korttitasolla (ei kerraannu pelaajamäärällä); responses* kertoo yksittäiset vastaukset.
Kutsu
{ "session_id": "uuid" }Vastaus
{
"session": { "id": "uuid", "completed_at": "…" },
"summary": { "played": 12, "answered": 11, "skipped": 1,
"responses": 36, "responses_answered": 33, "responses_skipped": 3 }
}GET /game/sessionToken vaaditaan
Pelihistoria: 50 viimeisintä omaa sessiota.
Vastaus
[ { "id": "uuid", "player_names": ["Anna", "Mikko"],
"started_at": "…", "completed_at": "…",
"decks": { "name": "Syvät vedet", "slug": "syvat-vedet" } } ]AI-pelinjärjestäjä
Keskustelu, puheentunnistus ja kertojaääni samalta domainilta. Kaikki vaativat tokenin.
POST /chatToken vaaditaan
Striimaava keskustelu. mode: "host" = pakan valinta, "narrator" = kortin luku ja vuoron osoitus.
Kutsu
fetch("https://api.meidankesken.app/api/public/chat", {
method: "POST",
headers: {
"Authorization": "Bearer " + accessToken,
"Content-Type": "application/json",
},
body: JSON.stringify({ message: "Meitä on kolme, jotain kevyttä.", mode: "host" })
})Vastaus
data: {"delta":"Kuulostaa"}
data: {"delta":" hyvältä"}
data: [DONE]POST /speechToken vaaditaan
Muuttaa kertojan tekstin MP3-puheeksi. Kutsu reittiä, kun AI:n vastaus tai kortti halutaan lukea ääneen.
Kutsu
const res = await fetch("https://api.meidankesken.app/api/public/speech", {
method: "POST",
headers: {
"Authorization": "Bearer " + accessToken,
"Content-Type": "application/json",
},
body: JSON.stringify({ text: "On Annan vuoro.", format: "base64" })
});
const { audio_base64, mime_type } = await res.json();Vastaus
{ "audio_base64": "…", "mime_type": "audio/mpeg", "voice": "alloy" }POST /transcribeToken vaaditaan
Muuttaa mobiilisovelluksen äänitallenteen suomenkieliseksi tekstiksi. Lisää stream=true, niin teksti tulee heti osissa (text/event-stream). Nopein tulos: 16 kHz mono, lyhyet pätkät.
Kutsu
const form = new FormData();
form.append("file", audioBlob, "answer.wav");
form.append("language", "fi");
form.append("stream", "true"); // valinnainen, nopeuttaa näkyvää vastausta
const res = await fetch("https://api.meidankesken.app/api/public/transcribe", {
method: "POST",
headers: { "Authorization": "Bearer " + accessToken },
body: form
});
// stream=true → data: {"type":"transcript.text.delta","delta":"…"}
// ilman streamia → const { text } = await res.json();Vastaus
{ "text": "Tämä on minun vastaukseni.", "language": "fi" }Virhekoodit
| 400 | Virheellinen pyyntörunko |
| 401 | Puuttuva tai vanhentunut token |
| 403 | AI-pelinjärjestäjä pois käytöstä |
| 22023 | Virheellinen syöte (pelaajamäärä tai pakan tunniste) |
| P0002 | Resurssia ei löydy (pakka tai sessio) |
| P0003 | Pakassa ei ole julkaistuja kortteja |
| P0004 | Sessio on jo päättynyt |