Custom games

Create a customs session, add signed-up players, then dispatch: Zyron's bot pool friends each player in Fortnite and enters the match key in their party — no key ever posted in chat.

All paths are relative to https://api.zyron.pro/api/v1/guilds/:guildId.

How it works

A customs session represents one custom-game lobby: a host, a match key, and a list of signed-up players. The key is never shared publicly — when you dispatch, Zyron's bot pool delivers it to each player inside Fortnite. Players must have a linked Epic account so the bots know whom to friend.

Config

GET/guilds/:guildId/customs/config
PATCH/guilds/:guildId/customs/config

Guild-wide customs settings. PATCH is a partial update and returns the full config.

FieldTypeDescription
hostRoleIdsstring[]Roles allowed to host customs from Discord.
cooldownMinutesnumberMinimum minutes between sessions per host.
minAccountAgeDaysnumberMinimum Discord account age for players to sign up.
requiredRoleIdsstring[]Roles a player must have to sign up (empty = anyone).
defaultChannelIdstringDefault channel for session announcements.
maxActiveSessionsnumberHow many sessions may be live at once.
json
{
  "hostRoleIds": ["987654321098765432"],
  "cooldownMinutes": 30,
  "minAccountAgeDays": 7,
  "requiredRoleIds": [],
  "defaultChannelId": "333333333333333333",
  "maxActiveSessions": 2
}

Presets

GET/guilds/:guildId/customs/presets
POST/guilds/:guildId/customs/presets
PATCH/guilds/:guildId/customs/presets/:presetId
DELETE/guilds/:guildId/customs/presets/:presetId

Presets are saved session templates (title, game mode, region, playlist, team size, signup cap, and lifecycle messages including missedSignup for post-dispatch late sign-ups). Pass a presetId when creating a session to prefill it — explicit body fields override preset values. POST returns 201 with the created preset.

List sessions

GET/guilds/:guildId/customs/sessions
FieldTypeDescription
statusstringQuery parameter — filter by status, e.g. open, dispatched, cancelled.
pagenumberQuery parameter — 1-based page number.
limitnumberQuery parameter — results per page.

Create a session

POST/guilds/:guildId/customs/sessions
FieldTypeDescription
hostDiscordIdrequiredstringThe Discord member hosting the match. They are DM'd as host with the session details and key.
titlestringDisplay title for the session.
gameModerequiredstringGame mode, e.g. Battle Royale or Zero Build.
regionstringServer region, e.g. EU, NAC.
playliststringPlaylist / island identifier.
teamSizenumberPlayers per team (1 = solos).
channelIdstringAnnouncement channel. Defaults to the config's defaultChannelId.
signupCapnumberMaximum number of signed-up players.
presetIdstringPrefill from a preset; explicit fields override it.
curl -X POST https://api.zyron.pro/api/v1/guilds/123456789012345678/customs/sessions \
  -H "Authorization: Bearer zyr_your_guild_key" \
  -H "Content-Type: application/json" \
  -d '{
    "hostDiscordId": "222222222222222222",
    "title": "Friday Night Customs",
    "gameMode": "Battle Royale",
    "region": "EU",
    "teamSize": 2,
    "signupCap": 100
  }'

Returns 201 Created:

json
{
  "session": {
    "sessionId": "cs_9f2c1ab34d",
    "title": "Friday Night Customs",
    "gameMode": "Battle Royale",
    "region": "EU",
    "teamSize": 2,
    "signupCap": 100,
    "status": "open",
    "hostDiscordId": "222222222222222222",
    "players": [],
    "createdAt": "2026-07-10T17:00:12.000Z"
  },
  "key": "duos-eu-4821"
}

The key is returned once

Get session & key

GET/guilds/:guildId/customs/sessions/:sessionId

Returns the session with its status and player list — without the key.

GET/guilds/:guildId/customs/sessions/:sessionId/key

Returns { "key": "duos-eu-4821" }. Treat this endpoint as sensitive — anyone with the key can join the match.

Players

POST/guilds/:guildId/customs/sessions/:sessionId/players

Adds a player to the session — call this when someone signs up in your own bot. The player must have a linked Epic account; otherwise the request fails with 409 conflict and a message explaining the reason (no link, blocklisted, account too new, already signed up, or the cap is reached).

Sign-ups normally require status open. When the session's messages.missedSignup stage is enabled ("keep sign-up open after dispatch"), the endpoint also accepts sign-ups while the session is closed, dispatching or ready — the key is then delivered to the late player immediately. Once the game is started or cancelled the endpoint returns 409 again.

FieldTypeDescription
discordIdrequiredstringThe Discord member signing up.
memberRoleIdsstring[]The member's role IDs, used to evaluate requiredRoleIds without a Discord lookup.
createdTimestampnumberThe member's Discord account creation time (ms), used to evaluate minAccountAgeDays.
curl -X POST https://api.zyron.pro/api/v1/guilds/123456789012345678/customs/sessions/cs_9f2c1ab34d/players \
  -H "Authorization: Bearer zyr_your_guild_key" \
  -H "Content-Type: application/json" \
  -d '{ "discordId": "555555555555555555" }'
DELETE/guilds/:guildId/customs/sessions/:sessionId/players/:discordId

Removes a player from the session (e.g. they un-signed-up).

Dispatch — deliver the key in-game

POST/guilds/:guildId/customs/sessions/:sessionId/dispatch

The key-distribution action. Zyron's bot pool friends each signed-up player in Fortnite and enters the match key in their party — players never see the key in Discord. Dispatch runs asynchronously; listen for the customs.dispatch.completed webhook to learn when it finishes and how many deliveries succeeded.

With the preset's messages.missedSignup stage enabled, dispatch also posts a "Missed sign up?" embed with a late sign-up button in the session channel — players who missed the window can still join and get a key until the game is started or cancelled (the button then deactivates).

bash
curl -X POST https://api.zyron.pro/api/v1/guilds/123456789012345678/customs/sessions/cs_9f2c1ab34d/dispatch \
  -H "Authorization: Bearer zyr_your_guild_key"

Cancel & retry

POST/guilds/:guildId/customs/sessions/:sessionId/cancel

Cancels the session and fires the customs.session.cancelled webhook.

POST/guilds/:guildId/customs/sessions/:sessionId/retry/:discordId

Retries key delivery for a single player whose dispatch failed (e.g. their friend request expired or their party was full).

Leaderboards & scoring

Custom games are scored automatically from replay uploads. When players run the Zyron Client during a hosted custom game, each replay is correlated to the session by the recorder's Epic id on the roster, and every game is scored (placement + eliminations against the session's point system) into a per-game result.

  • Per-lobby leaderboard — per-player standings aggregated across all games of one session, plus each game's full scoreboard and killfeed.
  • Server-wide ladder — an all-time, per-player leaderboard aggregating every custom game the server has hosted (points, wins, eliminations, games played).

Standings are per player

GET/guilds/:guildId/customs/leaderboard

The server-wide, all-time ladder for the guild (per player).

GET/guilds/:guildId/customs/sessions/:sessionId/leaderboard

The per-lobby leaderboard for one session, aggregated across its scored games. Public (no-auth) shareable pages also exist at zyron.pro/leaderboard/customs/<sessionId> and zyron.pro/leaderboard/customs/guild/<guildId>.

Build your own customs bot

The intended integration: your bot owns the Discord UX (signup buttons, embeds, reminders); Zyron owns Epic-side delivery. The flow:

  • 1. Create the session POST /customs/sessions with your host's hostDiscordId. Zyron DMs the host; you store sessionId (and the once-only key if you need it).
  • 2. Add players as they sign up — each time someone clicks your bot's signup button, call POST .../players. Surface any 409 message back to the user (e.g. "link your Epic account first").
  • 3. Dispatch — when the lobby is ready, call POST .../dispatch. Zyron's bots friend every player and enter the key in their parties.
  • 4. Listen for completion — handle the customs.dispatch.completed webhook (doneCount, failedCount, cause). Use POST .../retry/:discordId for any stragglers.

Verified links are the prerequisite