Developers

A read API for tournaments, signed webhooks and embeddable widgets for MAXIMUS VEGAS organisers and partners. Access is granted by an owner or administrator of an organising space in its “API, webhooks and widgets” section.

Access

API keys and webhook addresses are created in an organising space. A key sees only its own space's tournaments, drafts included; another space's tournament answers 404, the same as a missing one. Up to 10 active keys and 5 webhook addresses per space.

Authorisation and limits

Send the key in the Authorization header. At most 120 requests a minute per key: above it, 429 with a Retry-After header. A wrong, revoked or missing key gets 401. The API only reads data: a tournament cannot be changed through it.

curl -H "Authorization: Bearer mvk_…" https://www.maximus.vegas/api/v1/tournaments

Endpoints

  • GET /api/v1/organizationthe space the key belongs to
  • GET /api/v1/tournamentsthe space's tournaments: status, format, game, start, participants
  • GET /api/v1/tournaments/{slug}a tournament and its participants with places and seeds
  • GET /api/v1/tournaments/{slug}/matchesmatches: stage, round, sides, score, winner, time
  • GET /api/v1/tournaments/{slug}/standingsstandings: points table (round robin, Swiss), groups, leaderboard or final places
{ "data": [ { "slug": "autumn-cup", "name": "Autumn Cup", "game": "cs2", "status": "REGISTRATION_OPEN", "registered": 12, "max_participants": 16, "starts_at": "2026-10-12T16:00:00.000Z", "url": "https://www.maximus.vegas/ru/tournaments/autumn-cup" } ] }

Errors

An error is JSON with a code and a message; codes: unauthorized, rate_limited, not_found, method_not_allowed, unavailable.

{ "error": { "code": "not_found", "message": "No such resource for this key." } }

Webhooks

The portal sends a JSON POST to your HTTPS address. Answer 2xx within 5 seconds; redirects are not followed. A failure is retried after 1, 5, 30, 120, 360 minutes; after the sixth failed attempt it can be retried by hand. Addresses in private networks are refused.

Events

  • tournament.status_changedtournament status changed
  • registration.creatednew registration
  • registration.withdrawnregistration withdrawn
  • match.completedmatch completed
  • match.correctedmatch result corrected
  • pingtest event
{
  "id": "evt_1042",
  "type": "match.completed",
  "created_at": "2026-10-01T18:04:11.000Z",
  "data": {
    "tournament": { "id": "…", "slug": "autumn-cup", "name": "Autumn Cup", "game": "cs2", "format": "single_elimination", "status": "IN_PROGRESS", "url": "https://www.maximus.vegas/ru/tournaments/autumn-cup" },
    "match": { "id": "…", "round": 2, "position": 1, "status": "completed", "a_name": "Night Owls", "b_name": "Iron Wolves", "score_a": 2, "score_b": 1, "winner": "a" }
  }
}

Signature and replay protection

Every request is signed with the address's secret (shown once when created and when replaced). Verify the signature over the raw request body, reject a timestamp more than 5 minutes away and an event id you have already accepted: a replayed request is then refused. During a secret change the header may carry several v1= values.

MV-Webhook-Id: evt_1042
MV-Webhook-Timestamp: 1790877851
MV-Webhook-Signature: v1=<hex HMAC-SHA256(secret, "evt_1042.1790877851." + body)>
import { createHmac, timingSafeEqual } from "node:crypto";

const seen = new Set(); // keep accepted ids in a database in production

export function verifyWebhook(headers, rawBody, secret) {
  const id = headers["mv-webhook-id"];
  const ts = headers["mv-webhook-timestamp"];
  const sig = headers["mv-webhook-signature"];
  if (!id || !ts || !sig) return false;
  if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; // stale
  const expected = "v1=" + createHmac("sha256", secret).update(`${id}.${ts}.${rawBody}`).digest("hex");
  const ok = sig.split(" ").some((s) => s.length === expected.length && timingSafeEqual(Buffer.from(s), Buffer.from(expected)));
  if (!ok || seen.has(id)) return false; // forged or replayed
  seen.add(id);
  return true;
}

Widgets

A widget is a page for an iframe on your site: a tournament's bracket, registration and standings, and a space's calendar. Published tournaments are shown; links open the portal in a new tab; registration happens on the portal. The embed code is in the space's “API, webhooks and widgets” section.

<iframe src="https://www.maximus.vegas/embed/en/tournaments/{slug}/bracket" title="Bracket" width="100%" height="560" style="border:0" loading="lazy"></iframe>
/embed/en/tournaments/{slug}/registration
/embed/en/tournaments/{slug}/standings
/embed/en/organizer/{space}/calendar

Testing an integration

“Send a test event” sends a signed ping event to the chosen address — this checks the receiver and its signature check. For a full run, create a separate organising space: its draft and test tournaments are seen only by that space's key, and its events go only to its addresses.