Matchmaker Integration

Gameye + your matchmaker

Gameye's Session API is matchmaker-agnostic. Any backend that can make an HTTP request can allocate a dedicated game server in under 0.5 seconds — no SDK required.

REST API Any language No SDK required

If your studio runs a custom matchmaking backend — whether that's an internal lobby service, your own queue system, or any backend that can make HTTP requests — you don't need a native Gameye plugin. The Session API is a straightforward REST interface: one endpoint to start a server, one to stop it, and two to track players. Your matchmaker calls them over HTTP with a Bearer token. That's the entire integration surface.

This guide covers the full lifecycle: prerequisites, region selection, session creation, delivering connection details to players, join/leave tracking, and shutdown. Code examples are shown in curl; the same calls work in any language or HTTP library.

Prerequisites checklist
  • Gameye sandbox accountrequest access, provisioned within 24 hours
  • API token — provided with your sandbox account
  • Docker image of your game server pushed to Docker Hub (Team or Large plan for private repos)
  • Application configured in the Gameye Admin Panel — image name, ports, networking mode, regions
  • Docker Hub webhook set up so Gameye pulls new images automatically (setup guide)
  • Your matchmaker backend capable of making HTTP POST/PUT/DELETE requests

API URLs: sandbox is api.sandbox-gameye.gameye.net, production is api.gameye.io. Examples below use api.gameye.io — swap in the sandbox URL during integration testing.

Integration overview
  1. Clients ping available regions — matchmaker collects latency data
  2. Match found — matchmaker selects lowest-latency region
  3. Matchmaker calls POST /session — Gameye starts the server
  4. Gameye returns the server IP and port (~0.5s)
  5. Matchmaker delivers connection details to matched players
  6. Players connect — matchmaker calls PUT /session/player/join
  7. Match ends — game server or matchmaker calls DELETE /session/{id}

Authentication

All API calls require a Bearer token in the Authorization header. Your token is provisioned during onboarding — request sandbox access at /get-access/.

All requests
Authorization: Bearer YOUR_API_TOKEN

Keep tokens in environment variables. Never hardcode them in client-side code or commit them to source control.


Step 1 — Select a region

Call GET /available-location/{image} to get a list of regions where your image is deployed, along with a pingable IP per region. Have game clients ping those IPs before queueing and report their latency to your matchmaker. Your matchmaker uses the lowest-latency common region when calling POST /session.

curl
curl https://api.gameye.io/available-location/your-image \
  -H "Authorization: Bearer YOUR_API_TOKEN"
Response
{
  "locations": [
    { "location": "eu-west-1",     "host": "185.x.x.1" },
    { "location": "eu-central-1",  "host": "185.x.x.2" },
    { "location": "us-east-1",     "host": "104.x.x.1" },
    { "location": "us-west-1",     "host": "104.x.x.2" },
    { "location": "ap-southeast-1","host": "103.x.x.1" }
  ]
}
Availability changes. Don't cache this list. Request it fresh per match — a location that was available an hour ago may be at capacity now.

Step 2 — Create a session

Once your matchmaker has a region and a set of matched players, call POST /session. Gameye starts the container and returns a host IP and port within ~0.5 seconds.

curl — minimal request
curl -X POST https://api.gameye.io/session \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "image":    "your-image",
  "location": "eu-west-1"
}'
curl — with match config injected as env vars
curl -X POST https://api.gameye.io/session \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "image":    "your-image",
  "location": "eu-west-1",
  "version":  "1.4.2",
  "ttl":      "2h",
  "env": {
    "MAP":         "dust2",
    "GAME_MODE":   "ranked",
    "PLAYER_IDS":  "player_a,player_b,player_c,player_d"
  }
}'
Response — 201 Created
{
  "id":    "550e8400-e29b-41d4-a716-446655440000",
  "host":  "185.12.34.56",
  "ports": [
    { "type": "udp", "container": 7777, "host": 27015 }
  ]
}

Key request fields

FieldRequiredNotes
imageYesYour image/application name in Gameye
locationYesRegion from /available-location
versionNoDocker image tag — controls which build is deployed
envNoKey-value env vars injected at container start. Use to pass match config to the server
ttlNoAuto-terminate after this duration. Format: "90m", "2h30m". Safety net against orphaned sessions
idNoUUID4. Auto-generated if omitted. Specify your own to correlate with your internal match ID

Step 3 — Deliver connection details to players

The POST /session response gives you everything players need to connect: a host IP and one or more ports. Your matchmaker delivers these to each matched player's client through whatever channel you already use — WebSocket push, polling, or a lobby state update.

Pseudocode
// On match found:
const session = await gameye.createSession({ image, location, env })

// Deliver to each player in the match:
for (const playerId of matchedPlayers) {
  await notifyPlayer(playerId, {
    host: session.host,
    port: session.ports[0].host,
    sessionId: session.id,
  })
}

Step 4 — Track players (optional but recommended)

Call PUT /session/player/join when players connect to the server and DELETE /session/player/leave when they disconnect. This gives you live player counts via GET /session and lets you query for sessions with open slots when implementing backfill.

Join
curl -X PUT https://api.gameye.io/session/player/join \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "session": "550e8400-...", "players": ["player_a", "player_b"] }'
Leave
curl -X DELETE https://api.gameye.io/session/player/leave \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "players": ["player_a"] }'

To find sessions with available capacity for backfill, use the playerCount filter on GET /session:

Query sessions with fewer than 10 players
curl "https://api.gameye.io/session?playerCount[lt]=10&image=your-image" \
  -H "Authorization: Bearer YOUR_API_TOKEN"

Step 5 — Stop the session

Sessions can be terminated by your matchmaker, your game server, or automatically via ttl. Gameye sends SIGTERM to the container, giving your server process a chance to flush match state before shutdown.

Terminate a session
curl -X DELETE https://api.gameye.io/session/550e8400-e29b-41d4-a716-446655440000 \
  -H "Authorization: Bearer YOUR_API_TOKEN"

A 204 No Content response confirms the termination request was accepted.


Error handling

401
Unauthorized — token missing, expired, or incorrect. Check your Authorization header.
404
Not found — image name or location doesn't exist in your Gameye organisation. Verify both against /available-location.
409
Conflict — a session with your supplied id already exists. Use a fresh UUID4 per session, or omit id entirely.
420
Capacity limit — too many sessions started in a short window. Retry with exponential backoff after ~60 seconds. For sustained high launch rates, contact Gameye to adjust your rate limit.
422
Invalid data — malformed request body. Check field names and types against this guide.

Frequently asked questions

How do I pass match configuration to my game server?

Use the env field in POST /session. Whatever key-value pairs you include are injected as environment variables when the container starts. Your server reads them on startup — map name, game mode, player IDs, tick rate, whatever your server needs.

Can I run multiple game modes or maps from the same image?

Yes — use env to pass the mode or map at session creation time. You don't need separate images per configuration. You can also use the args field to pass command-line arguments to the server process if that fits your server's startup model better.

What's the right TTL to set?

Set ttl to the longest a match could reasonably run, plus a buffer — something like "2h" for a session-based game, or "90m" for a round-limited competitive mode. TTL is a safety net for sessions that don't terminate cleanly. Your game server should still call DELETE /session on a normal match end rather than relying on TTL.

My matchmaker isn't in the list of native integrations. Does that matter?

No. Native integrations (Nakama, FlexMatch, Pragma, Photon) provide a packaged connector that handles the API calls for you. With a custom matchmaker you make those calls directly — it's the same underlying API with slightly more code on your side. For most teams it's a few hundred lines to wire up.

Can I verify a new image version is deployed before starting sessions with it?

Yes. Call GET /tag/{region}/{image}/{version} and check the exists boolean. Poll this after a new image push to confirm the version has propagated to your target region before routing live traffic to it.

How do I get match logs and artifacts after a session ends?

Use GET /artifacts?session={id}&path=/path/to/file to download logs, replay files, or any other file your server writes. Artifacts are available after the session terminates and until the container is removed from the host. For live log streaming during a session, use GET /logs?id={id}&follow=true.

Get started

Sandbox access in 24 hours.

Request your API token, push your Docker image, and make your first POST /session call — all before your next sprint ends.