Skip to main content

MATCH_CANCELLED

Triggered when a match is cancelled before completion.

Example Payload

{
"action": "MATCH_CANCELLED",
"queue": "valorant",
"channel": "1234567890123456789",
"guild": "9876543210987654321",
"teams": [
[
{
"name": "Player1#1234",
"id": "111222333444555666",
"mmr": 1500,
"role": "Duelist",
"team_num": 0,
"top_role_index": 0,
"ign": "PlayerIGN1",
"timestamp": 1707523200.0,
"pulled_from": null
}
],
[
{
"name": "Player3#9012",
"id": "333444555666777888",
"mmr": 1480,
"role": "Sentinel",
"team_num": 1,
"top_role_index": 2,
"ign": "PlayerIGN3",
"timestamp": 1707523300.0,
"pulled_from": null
}
]
]
}

Payload Fields

FieldTypeDescription
actionstringAlways "MATCH_CANCELLED"
queuestringThe name/identifier of the queue
channelstringDiscord channel ID where the event occurred
guildstringDiscord guild (server) ID
teamsPlayer[][]2D array of teams at the time of cancellation
info

If teams weren't created yet, the teams array may be empty or contain a single array with all players.

When This Event Fires

This webhook is sent when:

  • A moderator cancels the match using /cancel
  • A vote to cancel passes
  • Not enough players join the voice channel
  • System automatically cancels due to validation failure

Use Cases

  • Refund player entry fees or points
  • Log cancellation reasons and frequency
  • Notify players that match was cancelled
  • Clean up external match records
  • Track dodges and AFK cancellations
  • Analyze cancellation patterns

Implementation Example

def handle_match_cancelled(data):
queue_name = data['queue']
teams = data['teams']

# Get all players affected
all_players = []
for team in teams:
all_players.extend(team)

print(f"Match cancelled in {queue_name}")
print(f"{len(all_players)} players affected")

# Example: Refund entry costs
for player in all_players:
refund_player_entry(
player_id=player['id'],
queue=queue_name
)

# Example: Log cancellation
log_cancellation(
queue=queue_name,
player_ids=[p['id'] for p in all_players],
timestamp=time.time()
)

Handling Different Cancellation Stages

def process_cancellation(data):
teams = data['teams']

# Check if teams were created
if not teams or len(teams[0]) == 0:
print("Match cancelled before team creation")
return

# Check if any team assignments exist
has_teams = any(
player.get('team_num', -1) >= 0
for team in teams
for player in team
)

if has_teams:
print("Match cancelled after team creation")
else:
print("Match cancelled during validation")

Cancellation Analytics

Track cancellation patterns:

def analyze_cancellations(cancellation_data):
# Track cancellation frequency by queue
cancellations_by_queue = {}

for event in cancellation_data:
queue = event['queue']
cancellations_by_queue[queue] = \
cancellations_by_queue.get(queue, 0) + 1

# Find problematic queues
for queue, count in cancellations_by_queue.items():
if count > 10:
print(f"Warning: {queue} has {count} cancellations")

Distinguishing from Normal Completion

Unlike MATCH_COMPLETED, this event:

  • Does not include winning_team_index
  • Indicates no winner was determined
  • May be sent at various stages of match setup
  • Typically results in no MMR changes