D&D Encounter Difficulty Calculator and XP Budget
Build a fifth-edition combat encounter around a party instead of relying on guesswork.
Run — free
Enter one level for every player character and one challenge rating for every monster. The calculator totals the monsters' listed XP, applies the standard multiplier for enemy numbers and party size, builds the party's easy, medium, hard, and deadly XP thresholds, and reports the resulting difficulty. It is a quick planning baseline for game masters preparing a session or checking an encounter during play.
Describe the whole party and monster group
Add one entry to player levels for every character who will participate. Repeating a level is intentional: four third-level characters should be entered as 3, 3, 3, and 3. The number of entries determines party size, so there is no separate count that can fall out of sync. Then add one challenge rating for every hostile creature in the encounter. Fractional ratings use decimal values: CR 1/8 is 0.125, CR 1/4 is 0.25, and CR 1/2 is 0.5. CR 0 and whole-number ratings through CR 30 are also supported. Include monsters that are expected to take meaningful actions in the same battle, but do not include hazards, neutral creatures, or reinforcements that are unlikely to appear. If the fight has distinct waves with time to recover or reposition, calculating each wave separately often gives a more useful planning signal than treating every creature as present at once. The tool requires at least one player character because encounter thresholds cannot be built without a party.
Understand the XP budget calculation
Each character level has four published XP thresholds: easy, medium, hard, and deadly. The calculator adds those values across the party, which naturally supports mixed-level groups. It also converts every monster challenge rating to its listed XP value and sums those values as base monster XP. A group of monsters is more dangerous than the same XP concentrated in one creature because it receives more turns and can pressure more targets, so the standard method applies a multiplier based on the number of monsters. That multiplier is shifted one step higher for parties with fewer than three characters and one step lower for parties with six or more characters. The adjusted encounter XP is used only to classify difficulty; base monster XP remains the amount relevant to ordinary XP awards. The result includes both numbers, the chosen multiplier, and all four party thresholds so you can see exactly why the classification was selected rather than receiving an unexplained label. Values below the party's medium threshold are reported as easy, keeping the requested result within the four standard planning categories.
Use difficulty as a planning aid, not a promise
An XP budget is a consistent starting point, but it cannot model every tactical detail. Terrain, surprise, range, cover, monster synergy, character optimization, depleted resources, magic items, and player experience can all move the real challenge substantially. A deadly label means the adjusted XP reaches the deadly threshold; it does not mean a character must die, and an easy label does not guarantee that poor luck cannot create danger. Pay special attention to creatures whose abilities bypass normal hit-point pressure, to a single monster that can defeat a low-level character in one hit, and to encounters where one side controls a narrow battlefield. The method also becomes less predictive when many weak creatures inflate the multiplier even though they cannot meaningfully threaten the party. Use the returned thresholds to tune the roster: remove a monster, lower a challenge rating, or split enemies into separate waves, then calculate again. For an adventuring day, consider the party's other encounters and opportunities to rest rather than judging this fight in isolation.
What you can do with it
Prepare a session
Check a planned monster roster against the exact levels and size of the party before play begins.
Tune a mixed-level party encounter
Combine the individual thresholds of characters at different levels instead of estimating from an average level.
Compare encounter variants
Add or remove monsters and compare adjusted XP, multipliers, and classifications before choosing a final lineup.
FAQ
Which D&D rules does this calculator use?
It uses the standard fifth-edition encounter-building XP thresholds, monster XP values, and multipliers commonly associated with the 2014 core rules.
How do I enter fractional challenge ratings?
Enter CR 1/8 as 0.125, CR 1/4 as 0.25, and CR 1/2 as 0.5.
Why are base XP and adjusted XP different?
Base XP is the sum of the monsters' XP values. Adjusted XP applies the encounter multiplier and is used for difficulty classification, not as the ordinary XP award.
How is party size handled?
The number of player-level entries is the party size. Parties smaller than three shift the monster multiplier up one step; parties of six or more shift it down one step.
Can an encounter below the easy threshold be reported?
The output stays within the requested four classifications, so any adjusted XP below the medium threshold is classified as easy.
How much does an API calculation cost?
Each API request costs $0.002. The same deterministic calculation can also run in the browser.
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/game/dnd-encounter-difficulty-calc \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"player_levels":[3,3,3,3],"monster_challenge_ratings":[1,1]}'const res = await fetch("https://api.kit.forhosting.com/game/dnd-encounter-difficulty-calc", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"player_levels": [
3,
3,
3,
3
],
"monster_challenge_ratings": [
1,
1
]
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/game/dnd-encounter-difficulty-calc",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"player_levels": [
3,
3,
3,
3
],
"monster_challenge_ratings": [
1,
1
]
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/game/dnd-encounter-difficulty-calc", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"player_levels":[3,3,3,3],"monster_challenge_ratings":[1,1]}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"player_levels":[3,3,3,3],"monster_challenge_ratings":[1,1]}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/game/dnd-encounter-difficulty-calc", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"player_levels": [
3,
3,
3,
3
],
"monster_challenge_ratings": [
1,
1
]
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "game.dnd_encounter_difficulty_calc",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Limits
max_players | 20 |
max_monsters | 50 |
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |