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:
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}'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())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:
{ "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:
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"])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.
Start the session with the format, the teams and, if you want, the map pool:
jsonPOST /api/actions/veto_start { "boFormat": "bo3", "teamA": { "name": "Vitality" }, "teamB": { "name": "NAVI" }, "mapPool": ["ancient", "anubis", "dust2", "inferno", "mirage", "nuke", "train"] }Send each map with
veto_select. MyHUD knows whose turn it is and whether the step is a ban or a pick:jsonPOST /api/actions/veto_select { "map": "nuke" }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:
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"])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:
| Command | Effect |
|---|---|
veto_undo | Cancels the last ban or pick. Also works after the veto is complete. |
veto_status | Tells whose turn it is, the type of the next step and the maps that are left. |
veto_cancel | Stops 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:
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:
| Payload | Effect |
|---|---|
{ "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.
