Ga naar hoofdinhoud
Developers Game SDK

Laten zien wat iemand speelt

Laat je game aan mssgs vertellen wat een speler doet. Vrienden zien "Speelt" onder de naam van de speler, openen de details en drukken op Meedoen om in dezelfde game te springen. Je game kan ook controleren of een speler lid is van jouw community.

Wat je kunt doen

  • Een speelstatus publicerenDe game, wat ze aan het doen zijn, hun rol en hoe vol de groep is.
  • Een Meedoen-knop toevoegenVrienden komen met één druk in dezelfde game, server of lobby.
  • Lidmaatschap controlerenVraag of een speler lid is van jouw community, en met welke rollen.
  • Desktop, browser of telefoonNative games gebruiken de lokale bridge; browser- en telefoongames lopen via je backend.

In de app

daniSpeelt Space Raiders
Space RaidersGespeeld door dani
Sector 7
In een raid
3 van 4 in de groep · al 12 min
Schutter

De status onder een naam, en de details die hij opent. De game publiceerde één JSON-blok; de rest doet de app.

Overzicht

De mssgs desktop-app draait een kleine lokale HTTP-bridge waar een game op dezelfde computer mee praat. Je game praat nooit met onze servers, ziet nooit een wachtwoord of token van het account, en kan nooit namens de speler iets posten. Hij praat met de kopie van mssgs waar de speler al is ingelogd, en die kopie bepaalt wat er wordt geantwoord.

Wat je ermee kunt:

  • Detecteren dat mssgs geïnstalleerd is en er iemand is ingelogd.
  • Uitlezen wie de speler is: user_guid, gebruikersnaam, avatar.
  • Vragen "zit deze speler in community X?" en welke rol ze daar hebben.
  • Een "Speelt …"-status publiceren met een Meedoen-knop voor anderen.
  • Een join-overdracht ontvangen wanneer iemand die knop indrukt.

Twee ingangen

Een native desktopgame praat met de lokale bridge; dat is wat de secties hierna beschrijven. Een game in een browser of op een telefoon kan die bridge niet bereiken. Daarvoor publiceert je eigen backend, voor spelers die hun mssgs-account hebben gekoppeld via een QR-code of een code van acht tekens: zie Browser- en telefoongames, met CozyCity als eerste voorbeeld. De speelstatus zelf is in beide gevallen hetzelfde blok.

Zo min mogelijk prijsgeven, standaard

De scopes zijn met opzet ongelijk. Wil je alleen weten of iemand lid is van jouw community, dan vraag je membership.query en noem je zelf de server_guid: je krijgt ja/nee plus hun rollen daar, en leert niets over de rest van hun communities. De volledige lijst zit achter een aparte, hogere scope die de speler los moet goedkeuren.

De client vinden

De bridge luistert alleen op 127.0.0.1, op de eerste vrije poort in een klein bereik. Probeer ze op volgorde tot er één antwoordt: 7440, 7441, 7442, 7443. Ontwikkelbuilds van mssgs luisteren op 7540–7543, zodat een testbuild nooit de aanroepen van een echte game beantwoordt.

GET http://127.0.0.1:7440/mssgs/v1/hello

Geen token nodig, en het antwoord zegt niets over de speler, alleen dat mssgs er is en of iemand is ingelogd.

Antwoord
{
  "product": "mssgs",
  "api": 1,
  "client": "desktop",
  "version": "14.2.20015",
  "platform": "darwin",
  "signed_in": true,
  "scopes": ["identity", "staff", "membership.query", "servers.list", "presence.write"]
}

Controleer product === "mssgs" en api voordat je verder gaat. Krijg je geen antwoord op alle vier de poorten, dan draait mssgs niet. Bied dan gewoon je normale ervaring aan in plaats van de speler te laten wachten.

Toestemming vragen

Alles behalve /hello vereist een token, en een token bestaat pas nadat de speler jouw game heeft goedgekeurd in een venster binnen de app. Vraag alleen de scopes die je echt gebruikt: de speler ziet ze allemaal los, met uitleg, en kan ze stuk voor stuk uitvinken.

1. Vraag toestemming
curl -X POST http://127.0.0.1:7440/mssgs/v1/authorize \
  -H "Content-Type: application/json" \
  -d '{
    "game_id": "com.acme.spacegame",
    "name": "Space Raiders",
    "scopes": ["identity", "membership.query", "presence.write"]
  }'

Je krijgt {"status":"pending","request_id":"…","poll_after_ms":1000} terug en de speler ziet het venster. Poll daarna tot hij antwoordt (de vraag verloopt na 3 minuten):

2. Poll op het antwoord
curl http://127.0.0.1:7440/mssgs/v1/authorize/<request_id>

# {"status":"approved","token":"…","scopes":["identity","presence.write"],"game_id":"com.acme.spacegame"}

Controleer altijd wat je écht hebt gekregen

De scopes in het antwoord kunnen korter zijn dan wat je vroeg: de speler mag er losse uitvinken. In het voorbeeld hierboven is membership.query geweigerd. Ga uit van wat er in het antwoord staat, niet van wat je hebt gevraagd, anders krijg je later een 403 MISSING_SCOPE die je niet had verwacht.

Bewaar het token en gebruik het als Authorization: Bearer <token>. Het blijft geldig over herstarts heen, dus een speler keurt jouw game één keer goed en niet elke sessie opnieuw. Vraag je later opnieuw autorisatie met scopes die al zijn verleend, dan krijg je meteen hetzelfde token terug zonder venster.

Scopes & privacy

De vijf scopes geven heel verschillende hoeveelheden weg. Dat is geen toeval: het is de hele opzet. Vraag van boven naar beneden zo min mogelijk.

Scope Wat het toestaat Wat de speler prijsgeeft
presence.write Tonen wat ze spelen Niets. Deze scope schrijft alleen en leest geen enkel accountgegeven.
identity Wie de speler is user_guid, gebruikersnaam, weergavenaam, avatar-URL.
staff Staff- / moderatorvlaggen Twee booleans, bovenop identity. Apart, omdat een game die een naam toont niet hoeft te weten dat de speler communities modereert.
membership.query Een community controleren die je al kent Voor een server_guid die jij noemt: ja/nee, de naam, en de rollen die de speler daar heeft. Niets over andere communities.
servers.list Alle communities waar ze in zitten De volledige lijst: guids, namen, iconen en rollen. Dit is de dure: vraag hem alleen als je hem echt nodig hebt.

De meeste games hebben er twee nodig

identity en presence.write dekken "wie ben je" en "laat zien wat je speelt", samen goed voor vrijwel elke integratie. Voeg membership.query toe als je een beloning wilt koppelen aan lidmaatschap van jouw community. servers.list heb je vrijwel nooit nodig, en de speler ziet hem in het rood.

Lidmaatschap checken

Dit is het alternatief voor "geef me de hele lijst". Jij noemt de server_guid van jouw eigen community (die je toch al kent) en krijgt alleen daarover antwoord.

Eén community
curl -H "Authorization: Bearer $TOKEN" \
  "http://127.0.0.1:7440/mssgs/v1/membership?server_guid=ca94ecc…f4g02"

# lid:
# {"server_guid":"ca94ecc…","member":true,"name":"Acme Fans","is_owner":false,
#  "roles":[{"guid":"0aa32…","name":"Pro"}]}

# geen lid, en verder niets:
# {"server_guid":"…","member":false}

Een "nee" is precies dat en niets meer. Je kunt tot 10 guids per aanroep meegeven (herhaal server_guid of gebruik komma's); dan krijg je een results-array terug. De @everyone-groep zit nooit in roles: die geldt voor iedereen en zegt dus niets.

Een speelstatus tonen

Eén PUT zet de "Speelt …"-regel onder de naam van de speler, overal waar hun communities ze zien.

PUT /mssgs/v1/activity
{
  "name":    "Space Raiders",
  "details": "Sector 7",
  "state":   "In a raid",
  "role":    "Gunner",
  "started_at": 1755859200000,
  "party":   { "size": 3, "max": 4, "kind": "party" },
  "join":    { "secret": "raid-42" }
}

Alleen name is verplicht. Het antwoord vertelt je hoe lang de status blijft staan en hoe vaak je moet heartbeaten:

Antwoord
{ "ok": true, "expires_in_ms": 90000, "heartbeat_every_ms": 30000 }

Heartbeat, of de status verdwijnt

Een status die 90 seconden geen teken van leven geeft, wordt vanzelf gewist. Dat is met opzet: crasht je game, dan blijft de speler niet uren "aan het spelen". Stuur elke 30 seconden een POST /mssgs/v1/activity/heartbeat, en DELETE /mssgs/v1/activity als je netjes afsluit.

Aantal spelers en rol

party.kind bepaalt welke zin er komt te staan, want dezelfde twee getallen betekenen niet hetzelfde. Een squad van vier is geen server met vier spelers erop.

kind Wordt getoond als Waarvoor
party (standaard)3 van 4 in de groepeen squad, crew of groep
server4/100 spelerseen game server (FiveM, een community-server)
lobby4/100 spelerseen lobby voor de match begint
match4/100 spelerseen lopende match of ronde

role (max 48 tekens) is waar de speler als speelt: een job, klasse of personage. Het krijgt een eigen veld in plaats van nog een zin in state, omdat het als label naast het aantal spelers wordt getoond.

details en state zijn elk maximaal 128 tekens, name maximaal 64. Regeleindes en stuurtekens worden eruit gehaald. Een icoon-URL wordt bewust niet ondersteund: die zou door elke client worden opgehaald die de regel toont, en dat maakt van een statusregel een baken dat elk lid van elke community van de speler bij jouw server meldt.

De Meedoen-knop

Zet een join-blok in je activiteit en anderen krijgen een Meedoen-knop naast de status. Er zijn twee manieren, en je kunt ze combineren.

1. Een secret (voor native games)

Zet {"join":{"secret":"raid-42"}}. Drukt iemand op Meedoen, dan wordt dat secret afgeleverd bij hun eigen kopie van jouw game, op hun eigen computer, herkend aan hetzelfde game_id. Er wordt geen URL geopend en geen schema-handler aangeroepen. Jouw game haalt het op met:

GET /mssgs/v1/events
{
  "events": [
    { "seq": 1, "type": "join", "secret": "raid-42",
      "from": { "user_guid": "62e377…", "username": "mssgs-test-1" } }
  ],
  "cursor": 1
}

Poll met ?since=<cursor> zodat je elk event één keer ziet. Draait de game van de drukker niet, dan wordt er niets afgeleverd; bied dan gerust ook een URL aan.

2. Een https-URL (voor webgames en lobby-links)

Zet {"join":{"url":"https://play.example.com/s/abc"}} en de knop opent die link. Alleen https wordt geaccepteerd. Een eigen schema (steam://, mygame://, file://) wordt geweigerd: dat blok komt op het scherm van elk lid terecht, en zo'n URL is een manier om op andermans computer een lokale handler aan te roepen met argumenten die jij hebt gekozen.

Alles in join is publiek

Het join-blok wordt uitgezonden naar iedereen die de status van de speler kan zien; dat is precies de bedoeling van een Meedoen-knop. Het is dus een lobbycode, geen inloggegeven. Zet er nooit iets in dat geheim moet blijven, en laat codes verlopen.

FiveM

FiveM heeft geen HTTP in de client-side Lua-runtime, dus een resource praat via NUI met de bridge: een CEF-view, en die stuurt een Origin mee. De bridge accepteert die origins expliciet: https://cfx-nui-<resource> en het oudere nui://<resource>. Gewone webpagina's blijven geweigerd, en een pagina op het open web kan die origin niet claimen; de browser zet hem zelf.

client.lua: vraag de NUI om te publiceren
-- De NUI-pagina doet het HTTP-werk; Lua stuurt alleen de gegevens.
CreateThread(function()
  while true do
    SendNUIMessage({
      action  = 'mssgs:publish',
      players = GetActivePlayers and #GetActivePlayers() or 0,
      maxPlayers = GetConvarInt('sv_maxclients', 100),
      job     = exports['qb-core'] and 'Police' or nil
    })
    Wait(30000) -- heartbeat: de status vervalt na 90 s
  end
end)
nui.js
const BASE = 'http://127.0.0.1:7440/mssgs/v1';   // probeer 7440-7443
let token = null;

async function authorize () {
  const res = await fetch(`${BASE}/authorize`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      game_id: 'fivem.lossantos.rp',
      name: 'Los Santos Roleplay',
      scopes: ['presence.write']          // meer heb je hier niet nodig
    })
  });
  const started = await res.json();
  if (started.status === 'approved') { return started.token; }

  // De speler ziet nu het toestemmingsvenster in mssgs.
  for (let i = 0; i < 180; i += 1) {
    await new Promise((r) => { setTimeout(r, 1000); });
    const poll = await (await fetch(`${BASE}/authorize/${started.request_id}`)).json();
    if (poll.status === 'approved') { return poll.token; }
    if (poll.status !== 'pending') { return null; }
  }
  return null;
}

window.addEventListener('message', async (event) => {
  if (event.data.action !== 'mssgs:publish') { return; }
  if (!token) { token = await authorize(); }
  if (!token) { return; }

  await fetch(`${BASE}/activity`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` },
    body: JSON.stringify({
      name: 'FiveM',
      details: 'Los Santos Roleplay',
      role: event.data.job,                       // "Police"
      party: { size: event.data.players, max: event.data.maxPlayers, kind: 'server' },
      join: { url: 'https://cfx.re/join/abc123' } // jullie cfx.re-link
    })
  });
});

Resultaat: Speelt FiveM · Los Santos Roleplay · 4/100 spelers · Police, met een Meedoen-knop die je cfx.re-link opent.

Vraag alleen presence.write

Voor een speelstatus heb je verder niets nodig: die scope leest helemaal niets. Wil je een in-game beloning koppelen aan lidmaatschap van jullie mssgs-community, voeg dan membership.query toe en noem je eigen server_guid; je komt dan nog steeds niets te weten over de andere communities van de speler.

Een server waar je op speelt is niet vanzelf te vertrouwen

Elke FiveM-server kan client-resources draaien, dus elke server waar iemand op komt kan om toestemming vragen. Dat is precies waarom er een venster tussen zit met de naam van de resource erin: de speler beslist, niet de server.

Browser- en telefoongames: koppelen via je backend

Een game in een browsertab of op een telefoon kan de bridge hierboven niet bereiken. Die draait op de desktop van de speler, en er staan drie muren tussen: de bridge weigert elk verzoek met een browser-Origin, Chrome zet een toestemmingsvraag voor een publieke pagina die 127.0.0.1 ophaalt en Safari weigert het helemaal, en een telefoon heeft überhaupt geen weg naar de loopback van een desktop.

Dus draait de richting om. Je eigen backend weet al wie er speelt, en vertelt dat aan mssgs, voor spelers die hun mssgs-account aan jouw game hebben gekoppeld. De koppeling wordt goedgekeurd in de mssgs-app, nooit in je game, en levert een koppeling op, nooit een sessie: niets hieronder kan iemand inloggen of namens de speler handelen. Je game-client ziet nooit een sleutel en praat nooit met mss.gs. De eerste game op deze weg is CozyCity, een stadsbouwer die als WebGL-pagina en als iPhone-app draait en geen desktopversie heeft; de voorbeelden hieronder zijn de zijne.

1. Registreer je game

Registreer de game op de registratiepagina van de Game SDK: je game_id (bijvoorbeeld com.deverence.cozycity), de naam en het icoon die de speler in het toestemmingsvenster ziet, en de hostnamen van je backend. Wij beoordelen hem daar, en na goedkeuring staat je backend-sleutel op dezelfde pagina klaar, één keer getoond; wij bewaren alleen een hash. De sleutel hoort op je server en nergens anders. Je kunt hem daar altijd vervangen; de oude blijft dan nog 24 uur geldig zodat een deploy kan rollen.

Registreer je game

De naam en het icoon in het venster komen altijd uit de registratie, nooit uit het verzoek. Anders kon een phishinglink een koppelvraag als elke willekeurige game vermommen. De hostnamen bepalen waar een join.url naartoe mag wijzen, zie verderop.

2. Koppel een speler

De speler kiest mssgs koppelen in jouw game. Je game vraagt het aan je backend, en je backend vraagt het aan ons:

POST /game-sdk/v1/link/start
curl -X POST https://ams1-gateway.mss.gs/game-sdk/v1/link/start \
  -H "Authorization: Bearer $BACKEND_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "player_ref": "player-8812", "player_name": "René\u2019s city" }'

# {"link_code":"K7PQ2XM4","device_code":"…","qr_url":"https://mss.gs/gl/K7PQ2XM4",
#  "deep_link":"mssgs://link-game/K7PQ2XM4","expires_in":600,"interval":5}

player_ref is jouw eigen, stabiele id voor die speler (maximaal 128 tekens), niet voor een sessie of een potje; player_name (maximaal 64) is wat het venster als "Speler: …" toont. Geef aan je game-client alleen link_code, qr_url en deep_link door. device_code is je eigen poll-handle en blijft op de server.

Je game toont dan drie dingen tegelijk, want de speler kan overal zitten:

  • De QR-code met qr_url. Een telefoon met mssgs opent hem rechtstreeks in het toestemmingsvenster van de app. Zonder de app landt hij op een pagina op mss.gs die de code toont en de download aanbiedt.
  • Een knop "Openen in mssgs" met deep_link, voor een desktopbrowser naast de desktop-app. Het is de enige externe URL die je game hoeft te openen.
  • De code zelf, in twee groepen van vier, om in te vullen onder Instellingen → Spelactiviteit → Game koppelen. Het alfabet heeft geen 0/O of 1/I, dus overtypen gaat zelden mis.

Wat de speler in mssgs te zien krijgt, in de app getekend uit de registratie:

CozyCity koppelen aan je mssgs-account?

CozyCity kan laten zien wat je speelt als je mssgs-status. Het ziet je berichten, je vrienden en je servers niet, en kan niet namens jou posten.
Speler: René's city · Koppelen / Niet nu

Ondertussen pollt je backend elke interval seconden (sneller geeft 429 SLOW_DOWN) tot de status omslaat. Een code werkt één keer en verloopt na tien minuten:

POST /game-sdk/v1/link/poll
curl -X POST https://ams1-gateway.mss.gs/game-sdk/v1/link/poll \
  -H "Authorization: Bearer $BACKEND_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "device_code": "…" }'

# {"status":"pending"}
# {"status":"denied"}      # de speler koos Niet nu
# {"status":"expired"}
# {"status":"linked","link_guid":"…","user":{"user_guid":"62e377…"}}

Bewaar link_guid bij je speler; dat is voortaan het adres om voor te publiceren. Het antwoord bevat alleen de user_guid; een username komt er alleen bij als je registratie de scope identity.link heeft, en meer dan dat is er niet. Een tweede goedkeuring voor dezelfde player_ref vervangt de eerdere koppeling, zodat één speler van je game één mssgs-account is. Hetzelfde mssgs-account mag wel aan meerdere games en aan meerdere player_refs van één game gekoppeld zijn (een gezins-iPad).

3. Publiceer de speelstatus

Hetzelfde blok als bij de bridge, met dezelfde regels en dezelfde limieten, alleen nu per koppeling en met je backend-sleutel:

PUT /game-sdk/v1/links/{link_guid}/activity
{
  "activity": {
    "name":       "CozyCity",
    "details":    "Lantern Hollow",
    "state":      "Day 12 · 34 residents",
    "started_at": 1788901000000,
    "party":      { "size": 6, "max": 40, "kind": "server" },
    "join":       { "url": "https://cozycity.net/game/?share=…" }
  }
}
Antwoorden
200 {"published":true,"changed":true}     # het blok is veranderd en uitgezonden
200 {"published":true,"changed":false}    # identiek aan wat er stond; alleen de TTL is ververst
204                                        # opgeslagen, maar de speler is nu niet online in mssgs
410 {"error":"LINK_REVOKED"}               # de speler heeft losgekoppeld: laat de koppeling los

Behandel 200 en 204 hetzelfde: opgeslagen. { "activity": null } wist het blok, stuur dat wanneer de speler stopt. Eén verschil met de bridge: de host van join.url moet één van je geregistreerde backends zijn (of een subdomein daarvan), anders 400 INVALID_PAYLOAD. Een backend kan dus geen Meedoen-knop op de status van een speler zetten die ergens heen leidt waar die speler nooit was.

Elke 60 seconden een heartbeat, TTL 120

Een gepubliceerde status leeft 120 seconden zonder nieuw bericht en verdwijnt daarna vanzelf. Stuur dus elke 60 seconden hetzelfde blok opnieuw; een ongewijzigd blok kost niets en ververst alleen de TTL. Valt je heartbeat weg, dan valt de regel "Speelt …" weg, en dat is precies de bedoeling.

Met honderden spelers online heartbeat je in één aanroep, tot 100 items per keer. Elk item krijgt zijn eigen status, dus één speler die in mssgs heeft losgekoppeld houdt de andere negenennegentig niet tegen:

POST /game-sdk/v1/activity/batch
{ "items": [ { "link_guid": "…", "activity": { "name": "CozyCity", "details": "Lantern Hollow" } },
             { "link_guid": "…", "activity": null } ] }

// → 200 { "results": [ { "link_guid": "…", "status": 200, "changed": false },
//                      { "link_guid": "…", "status": 410 } ] }

Hoe de status wordt getoond

  • Identiek aan een status van de bridge: Speelt CozyCity · Lantern Hollow · 6/40 spelers, met Meedoen als er een join.url is. Het blok krijgt server-side via: "backend" mee, zodat een client erbij kan zeggen "Gedeeld door de server van de game".
  • Alleen zolang de speler online is in mssgs. Is er geen mssgs-client open, dan is het account offline en blijft het offline; je backend kan iemand niet aanwezig laten lijken. Dat houdt deze route ook tegen als "is René aan zijn computer"-baken.
  • Voorrang: een spel in de app zelf > een game via de bridge > je backend. Gaat de speler in mssgs schaken terwijl je backend blijft heartbeaten, dan wint het schaken, niet wie het laatst schreef.

Loskoppelen

De speler ziet elke koppeling onder Instellingen → Spelactiviteit → Gekoppelde games, met je icoon en naam, de spelersnaam uit je game, wanneer er is gekoppeld en wanneer er voor het laatst is gepubliceerd, en een knop Loskoppelen. Daarna antwoordt je eerstvolgende publicatie 410 LINK_REVOKED; zo hoort je game het. Laat de link_guid los en bied "mssgs koppelen" opnieuw aan. Van jouw kant beëindig je een koppeling met DELETE /game-sdk/v1/links/{link_guid}.

Limieten

Per koppeling telt een wijziging hooguit elke 2 seconden; een ongewijzigde heartbeat is gratis. Per sleutel zijn er 600 verzoeken per minuut, waarbij batch-items los meetellen: 300 spelers elke 60 seconden heartbeaten kost 5 van de 600.

Endpoint-referentie: de bridge

Basis-URL http://127.0.0.1:<poort>. Alles behalve de eerste drie vereist Authorization: Bearer <token>.

Methode Pad Scope Wat het doet
GET /mssgs/v1/hello geen Is mssgs aanwezig, wat spreekt het, en is er iemand ingelogd. De enige route zonder token, en hij zegt niets over de speler.
POST /mssgs/v1/authorize geen Vraag de speler om toestemming. Opent een venster in de app en geeft een request_id terug om te pollen.
GET /mssgs/v1/authorize/:request_id geen pending, approved (met het token), denied of expired.
GET /mssgs/v1/me identity De ingelogde speler. Voegt is_staff / is_moderator alleen toe met de staff-scope.
GET /mssgs/v1/membership membership.query Lidmaatschap van de server_guid-waarden die je meegeeft (maximaal 10, herhaald of komma-gescheiden).
GET /mssgs/v1/servers servers.list Alle communities waar de speler in zit, met hun rollen. Directe berichten zitten er nooit bij.
PUT /mssgs/v1/activity presence.write Publiceer het "Speelt …"-blok. Geeft de TTL terug en hoe vaak je moet heartbeaten.
POST /mssgs/v1/activity/heartbeat presence.write Houd de gepubliceerde activiteit in leven zonder hem opnieuw te sturen.
DELETE /mssgs/v1/activity presence.write Wis hem meteen, voor een nette afsluiting.
GET /mssgs/v1/events presence.write Join-overdrachten bedoeld voor jouw game. Poll met ?since=<cursor>.
GET /mssgs/v1/session geen Wat dit token heeft: game_id, verleende scopes, en of er iemand is ingelogd.
DELETE /mssgs/v1/session geen Geef de toestemming terug. Zelfde effect als wanneer de speler hem intrekt in Instellingen.

Endpoint-referentie: gekoppelde backends

Basis-URL https://ams1-gateway.mss.gs. Elke route vereist Authorization: Bearer <backend-sleutel> en de scope activity.write op je registratie; antwoorden gaan uit met Cache-Control: no-store. Deze routes roep je aan vanaf je server, nooit vanuit de game-client.

Methode Pad Wat het doet
POST /game-sdk/v1/link/start Start een koppeling voor één van je spelers ({ player_ref, player_name? }). Geeft link_code, device_code, qr_url, deep_link, expires_in en interval terug.
POST /game-sdk/v1/link/poll { device_code } → pending, denied, expired, of linked met link_guid en user.
DELETE /game-sdk/v1/links/{link_guid} Beëindig een koppeling van jouw kant. De speler kan hetzelfde doen vanuit Instellingen.
PUT /game-sdk/v1/links/{link_guid}/activity Publiceer het "Speelt …"-blok voor één speler; { "activity": null } wist het.
POST /game-sdk/v1/activity/batch Hetzelfde, voor maximaal 100 spelers in één aanroep. Elk item antwoordt voor zich.

Foutcodes

Fouten komen terug als {"error":"CODE","message":"…"} met een passende HTTP-status.

Code Betekenis
401 UNAUTHORIZEDOntbrekend of onbekend token; autoriseer eerst.
403 MISSING_SCOPEDe speler heeft die toestemming niet gegeven. Mogelijk heeft hij hem uitgevinkt.
403 ORIGIN_NOT_ALLOWEDHet verzoek had een browser-Origin. Zie "Alleen native games" hieronder.
409 NOT_SIGNED_INmssgs draait, maar er is niemand ingelogd.
429 RATE_LIMITEDMeer dan 120 verzoeken per minuut van één game.
400 INVALID_GAME_IDgame_id mag alleen letters, cijfers, punt, streepje of underscore bevatten.
400 TOO_MANY_GUIDSMaximaal 10 server_guid-waarden per membership-aanroep.

Gekoppelde backends

De backend-routes gebruiken dezelfde vorm. In een batch komt de status per item terug in results, zodat één beëindigde koppeling nooit de hele aanroep laat mislukken.

Code Betekenis
401 INVALID_BACKEND_KEYOnbekende sleutel, of één die meer dan 24 uur geleden is vervangen.
403 SCOPE_NOT_GRANTEDJe registratie heeft de scope niet die deze route nodig heeft.
400 INVALID_PAYLOADOnleesbare body, meer dan 100 batch-items, of een join.url waarvan de host niet één van je geregistreerde backends is.
400 INVALID_ACTIVITYGeen bruikbare name over na normalisatie.
410 LINK_REVOKEDDe koppeling is beëindigd, aan één van beide kanten. Laat hem los en bied "mssgs koppelen" opnieuw aan.
429 SLOW_DOWNJe hebt link/poll sneller aangeroepen dan interval.
429 RATE_LIMITEDEen wijziging aan één koppeling binnen 2 seconden na de vorige, of meer dan 600 verzoeken per minuut op je sleutel.
503 LINK_STORE_UNAVAILABLETijdelijk, aan onze kant. Probeer het opnieuw bij je volgende heartbeat.

Beveiliging

Alleen native games

Verzoeken met de Origin van een webpagina worden geweigerd met 403 ORIGIN_NOT_ALLOWED. Een willekeurige webpagina die kan detecteren dat je mssgs draait en een toestemmingsvenster kan openen, is een fingerprint- en phishingoppervlak, geen functie. Een native game stuurt helemaal geen Origin en heeft hier dus geen last van, en de ingebouwde browser van een game wordt met naam toegelaten, zie FiveM. Bouw je een browser- of telefoongame, dan praat je niet met de bridge maar publiceert je eigen backend voor gekoppelde spelers, zie Browser- en telefoongames.

Wat de speler in handen houdt

  • De speler kan de bridge uitzetten in Instellingen → Spelactiviteit; daarna kan geen enkele game mssgs meer zien.
  • Elke goedgekeurde game staat daar met precies de rechten die hij heeft, wanneer hij voor het laatst actief was, en een Verwijderen-knop. Verwijderen werkt direct: het token is meteen dood.
  • Een gekoppelde browser- of telefoongame staat onder Gekoppelde games met een Loskoppelen-knop. Loskoppelen werkt ook direct: de eerstvolgende publicatie van die backend krijgt 410.
  • De bridge luistert alleen op 127.0.0.1 en nooit op het netwerk.
  • Directe berichten worden nooit prijsgegeven, ook niet met servers.list.
  • Er is per game een limiet van 120 verzoeken per minuut.

Goed burgerschap

  • Vraag scopes pas wanneer je ze nodig hebt, niet allemaal bij de eerste start.
  • Werkt zonder mssgs: de speler hoeft het niet te hebben.
  • Wis je status als het spelen stopt, in plaats van te wachten tot de TTL verloopt.
  • Behandel een geweigerde scope als een normale uitkomst, niet als een fout.

Verder bouwen