TS
Tournament Suite
TS
Tournament Suite
Developer Documentation
Get StartedPaginationResponse CodesRate LimitsWebhooks
Overview

Webhooks

Register endpoints to receive real-time event notifications from TournamentSuite.

Webhooks let you receive notifications when events occur in your project — instead of polling the API repeatedly. When a subscribed event fires, TournamentSuite sends an HTTP POST to your endpoint with the event payload.

Set up a webhook

1. Register your endpoint

In your project's Settings → Developer → Webhooks, enter the URL of your endpoint and click Register. TournamentSuite will immediately send a verification request to confirm you own that endpoint.

Your endpoint must:

  • Be publicly reachable over HTTPS
  • Respond to the verification request with a 200 OK within 5 seconds
  • Echo back the challenge value from the verification payload
// Verification handler (Express example)
app.post('/webhooks/tournamentsuite', (req, res) => {
  if (req.body.type === 'webhook.verify') {
    return res.json({ challenge: req.body.challenge });
  }


2. Save the security token

After verification, TournamentSuite returns a signing secret. Store this secret securely — you will use it to verify the authenticity of every incoming webhook request.

3. Subscribe to events

Once registered, open the webhook details and select the events you want to receive. You can subscribe at the project level (all tournaments) or scope subscriptions to a specific tournament.

Verify webhook signatures

Every webhook request includes an X-TournamentSuite-Signature header. Verify it to ensure the payload came from TournamentSuite and was not tampered with:

import crypto from 'crypto';

function verifyWebhook(
  payload: string,
  signature: string,
  secret: string
): boolean



















Event payload format

{
  "id": "evt_01HXYZ",
  "type": "tournament.started",
  "createdAt": "2026-07-01T09:00:00.000Z",
  "projectId": "proj_abc123",
  "data": {
    "tournamentId": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Summer Open 2026"
  }
}

Available events

Tournament events

EventWhen it fires
tournament.createdA tournament is created
tournament.publishedA tournament is made public
tournament.startedA tournament begins
tournament.completedA tournament concludes
tournament.cancelledA tournament is cancelled

Participant events

EventWhen it fires
participant.registeredA player or team registers
participant.checked_inA participant checks in
participant.disqualifiedA participant is removed

Match events

EventWhen it fires
match.createdA match is scheduled
match.startedA match begins
match.score_reportedA result is submitted
match.completedA match result is confirmed
match.disputedA result is disputed

Circuit events

EventWhen it fires
circuit.season_startedA circuit season begins
circuit.season_endedA circuit season concludes
circuit.standings_updatedStandings change after a tournament

Retries

If your endpoint returns a non-2xx status or does not respond within 10 seconds, TournamentSuite retries delivery using exponential backoff over the next 24 hours. You can inspect failed deliveries in the webhook log inside your project dashboard.

Best practices

Always respond with 200 OK immediately, then process the event asynchronously. This avoids timeouts and duplicate retries caused by slow processing.

app.post('/webhooks/tournamentsuite', async (req, res) => {
  res.sendStatus(200); // acknowledge immediately

  // process in the background
  setImmediate(() 

Rate Limits

How API rate limits work on TournamentSuite and how to stay within them.

Authentication

How to authenticate requests to the TournamentSuite API using API keys or OAuth 2 access tokens.

On this page

Set up a webhook1. Register your endpoint2. Save the security token3. Subscribe to eventsVerify webhook signaturesEvent payload formatAvailable eventsTournament eventsParticipant eventsMatch eventsCircuit eventsRetriesBest practices
// handle real events below
res.sendStatus(200);
});
{
const expected = crypto
.createHmac('sha256', secret)
.update(payload, 'utf8')
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(`sha256=${expected}`)
);
}
app.post('/webhooks/tournamentsuite', express.raw({ type: 'application/json' }), (req, res) => {
const sig = req.headers['x-tournamentsuite-signature'] as string;
if (!verifyWebhook(req.body.toString(), sig, process.env.WEBHOOK_SECRET!)) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString());
// process event
res.sendStatus(200);
});
=>
handleEvent
(req.body));
});