Skip to content

Veto ​

You can put a veto on the HUD in three ways:

  • Import it from a FACEIT room or an HLTV match.
  • Run it step by step: each ban or pick appears live on the overlay.
  • Send it in one go, when your script already knows all the steps.

All veto commands need the main MyHUD window to be open and signed in.

Import from FACEIT or HLTV ​

Send import_match_veto with the match URL:

bash
curl -X POST http://127.0.0.1:44555/api/actions/import_match_veto \
  -H 'Content-Type: application/json' \
  -d '{"url":"https://www.hltv.org/matches/2370000/vitality-vs-navi","show":true}'
python
import requests

res = requests.post(
    "http://127.0.0.1:44555/api/actions/import_match_veto",
    json={"url": "https://www.hltv.org/matches/2370000/vitality-vs-navi", "show": True},
    timeout=40,
)
print(res.json())
ts
const res = await fetch('http://127.0.0.1:44555/api/actions/import_match_veto', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'https://www.hltv.org/matches/2370000/vitality-vs-navi', show: true }),
});
console.log(await res.json());

For FACEIT, you can also send the match id instead of the URL:

json
{ "faceitMatchId": "1-abcdef12-3456-7890-abcd-ef1234567890", "show": true }

MyHUD then does the same as the Apply button of the veto page:

  • it fills the series maps with the picks and the decider;
  • it shows the veto on the open pages, including OBS browser sources.

With "show": true, it also opens the veto panel on the HUD. To only read the veto without changing anything, send "apply": false.

The import can take up to 20 seconds.

Wait for the veto ​

Before the teams finish the veto, MyHUD answers 409 conflict. A script can retry until it gets 200:

python
import time

import requests

IMPORT_URL = "http://127.0.0.1:44555/api/actions/import_match_veto"


def import_veto(match_id):
    while True:
        res = requests.post(IMPORT_URL, json={"faceitMatchId": match_id, "show": True}, timeout=40)
        body = res.json()
        if res.status_code == 200:
            return body["result"]
        if res.status_code != 409:
            raise RuntimeError(f"{body['error']}: {body['message']}")
        time.sleep(10)  # no veto yet


result = import_veto("1-abcdef12-3456-7890-abcd-ef1234567890")
print(result["teamA"]["name"], "vs", result["teamB"]["name"])
ts
const IMPORT_URL = 'http://127.0.0.1:44555/api/actions/import_match_veto';

async function importVeto(faceitMatchId: string) {
  while (true) {
    const res = await fetch(IMPORT_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ faceitMatchId, show: true }),
    });
    const body = await res.json();
    if (res.status === 200) return body.result;
    if (res.status !== 409) throw new Error(`${body.error}: ${body.message}`);
    await new Promise((resolve) => setTimeout(resolve, 10_000)); // no veto yet
  }
}

const result = await importVeto('1-abcdef12-3456-7890-abcd-ef1234567890');
console.log(result.teamA.name, 'vs', result.teamB.name);

Do not retry faster than every few seconds: each attempt loads the FACEIT room.

Run a veto step by step ​

Use this for an offline match or when your own tool runs the veto.

  1. Start the session with the format, the teams and, if you want, the map pool:

    json
    POST /api/actions/veto_start
    {
      "boFormat": "bo3",
      "teamA": { "name": "Vitality" },
      "teamB": { "name": "NAVI" },
      "mapPool": ["ancient", "anubis", "dust2", "inferno", "mirage", "nuke", "train"]
    }
  2. Send each map with veto_select. MyHUD knows whose turn it is and whether the step is a ban or a pick:

    json
    POST /api/actions/veto_select
    { "map": "nuke" }
  3. Continue until the veto is complete. MyHUD sets the decider itself.

Each step appears on the overlay at once. When the veto is complete, MyHUD fills the series maps.

The same veto as a script, with the myhud helper from Get started:

python
myhud("veto_start", {
    "boFormat": "bo3",
    "teamA": {"name": "Vitality"},
    "teamB": {"name": "NAVI"},
    "mapPool": ["ancient", "anubis", "dust2", "inferno", "mirage", "nuke", "train"],
})

for map_name in ["nuke", "ancient", "mirage", "inferno", "anubis", "dust2"]:
    status = myhud("veto_select", {"map": map_name})
    print(status["steps"][-1])  # the step that was just played

decider = next(s for s in status["steps"] if s["type"] == "decider")
print("Decider:", decider["map"])
ts
type VetoStep = { type: 'ban' | 'pick' | 'decider'; team: 'A' | 'B' | null; map: string };
type VetoStatus = { complete: boolean; steps: VetoStep[] };

await myhud('veto_start', {
  boFormat: 'bo3',
  teamA: { name: 'Vitality' },
  teamB: { name: 'NAVI' },
  mapPool: ['ancient', 'anubis', 'dust2', 'inferno', 'mirage', 'nuke', 'train'],
});

let status!: VetoStatus;
for (const map of ['nuke', 'ancient', 'mirage', 'inferno', 'anubis', 'dust2']) {
  status = await myhud<VetoStatus>('veto_select', { map });
  console.log(status.steps.at(-1)); // the step that was just played
}

console.log('Decider:', status.steps.find((s) => s.type === 'decider')?.map);

Other commands:

CommandEffect
veto_undoCancels the last ban or pick. Also works after the veto is complete.
veto_statusTells whose turn it is, the type of the next step and the maps that are left.
veto_cancelStops the session and shows the veto that was there before.

The rules are the same as on the veto page:

  • BO1: bans until one map is left, which is the decider.
  • BO3: bans until 5 maps are left, then 2 picks, 2 bans and the decider.
  • BO5: bans until 5 maps are left, then 4 picks and the decider.
  • Team A bans first, unless you send "firstBanner": "B".

Map names can be mirage or de_mirage.

Send a complete veto ​

If your script already has all the steps, send them with veto_set:

json
POST /api/actions/veto_set
{
  "boFormat": "bo1",
  "teamA": { "name": "Vitality" },
  "teamB": { "name": "NAVI" },
  "steps": [
    { "type": "ban", "team": "A", "map": "nuke" },
    { "type": "ban", "team": "B", "map": "ancient" },
    { "type": "ban", "team": "A", "map": "anubis" },
    { "type": "ban", "team": "B", "map": "dust2" },
    { "type": "ban", "team": "A", "map": "inferno" },
    { "type": "ban", "team": "B", "map": "train" },
    { "type": "decider", "map": "mirage" }
  ]
}

MyHUD checks the steps against the rules. If they do not follow the rules, it answers 400 invalid_payload and changes nothing.

Reveal the veto step by step ​

If the veto page uses the progressive reveal, use veto_reveal to show the steps one by one, for example from a Stream Deck button:

PayloadEffect
{ "mode": "next" }Shows the next step.
{ "mode": "prev" }Hides the last step shown.
{ "mode": "all" }Shows all the steps.
{ "mode": "reset" }Hides all the steps.
{ "instant": true }Turns off the progressive reveal: all the steps are shown at once.

Clear the veto ​

reset_veto clears the veto and all the series maps.