Source: https://gameye.com/custom-matchmaker-integration/

---
title: "Gameye Custom Matchmaker Integration — Any Language"
description: "Integrate any matchmaker with Gameye via REST API. No SDK required. POST /session returns host IP and port in 0.5 seconds."
---

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

Updated October 15, 2026

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 Developer Trial account** — [start a trial](https://trial.gameye.com/), no sales call required
- **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](https://admin.gameye.com) — image name, ports, networking mode, regions
- **Docker Hub webhook** set up so Gameye pulls new images automatically ([setup guide](https://gameye.com/docs/getting-started/1-docker-hub/))
- **Your matchmaker backend** capable of making HTTP POST/PUT/DELETE requests

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

Integration overview

- Clients ping available regions — matchmaker collects latency data
- Match found — matchmaker selects lowest-latency region
- Matchmaker calls `POST /session` — Gameye starts the server
- Gameye returns the server IP and port (~0.5s)
- Matchmaker delivers connection details to matched players
- Players connect — matchmaker calls `PUT /session/player/join`
- 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 — start a Developer Trial at [trial.gameye.com](https://trial.gameye.com/).

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.production-gameye.gameye.net/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.production-gameye.gameye.net/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.production-gameye.gameye.net/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

| Field | Required | Notes |
| --- | --- | --- |
| `image` | Yes | Your image/application name in Gameye |
| `location` | Yes | Region from `/available-location` |
| `version` | No | Docker image tag — controls which build is deployed |
| `env` | No | Key-value env vars injected at container start. Use to pass match config to the server |
| `ttl` | No | Auto-terminate after this duration. Format: `"90m"`, `"2h30m"`. Safety net against orphaned sessions |
| `id` | No | UUID4. 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.production-gameye.gameye.net/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.production-gameye.gameye.net/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.production-gameye.gameye.net/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.production-gameye.gameye.net/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

## Start your free trial today.

Sign up, push your Docker image, and make your first `POST /session` call — all before your next sprint ends.

[Start Building →](https://trial.gameye.com/)  [Full API reference →](https://gameye.com/docs/)

Further reading

- [All matchmaker integrations — Nakama, FlexMatch, Pragma, Photon](https://gameye.com/matchmaker-integrations/)
- [How Gameye orchestration works](https://gameye.com/how-it-works/)
- [AWS FlexMatch integration guide — STANDALONE mode](https://gameye.com/flexmatch-integration/)
- [Nakama Fleet Manager integration](https://gameye.com/nakama-integration/)
