Build exam study schedule
With Math weighted 3, Physics 2 and History 1, a 4-hour study day gives Math 2 hours, and over 10 days that is 20 of your 40 hours. Harder subjects get more time without starving the rest. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Days until exam
- 10
- Hours per day
- 4
- Subject count
- 3
- Difficulty sum
- 6
- Total study hours
- 40
When several subjects share one exam date, the hardest question is not how many hours you have, but how those hours should split across topics so the difficult courses get more practice without starving the easier ones. This exam study schedule builder accepts a list of subjects each with a relative difficulty weight, the number of days left until the exam, and a fixed daily study budget in hours. It returns hours per day and total hours for every subject using a transparent proportional rule: each subject receives a share of the daily budget equal to its difficulty divided by the sum of all difficulties. Zero days until the exam is rejected as invalid input, because there is no remaining study window to allocate.
How difficulty-weighted study hours are defined
Start with an honest list of subjects you still need to cover before the exam. For each subject assign a non-negative difficulty weight that reflects relative effort, not absolute letter grades: a three-weight math paper next to a one-weight history review means math should receive three times the daily minutes of history when both appear on the same list. Sum those weights into a single difficulty total.
Then take the hours you can realistically study each day and multiply by each subject share, where share equals that subject difficulty divided by the difficulty total. The product is hours per day for that subject. Multiply again by days until the exam to get total hours over the whole revision horizon.
When days until the exam is exactly zero there is no remaining calendar window, so the capability also fails with invalid input instead of returning a hollow zero schedule that a buggy planner might treat as success. Negative days, negative daily hours, empty subject lists, and missing names are likewise rejected. The tool does not invent spaced-repetition calendars, load live syllabus data, or convert between time zones; those are separate product intents with their own landings when coverage grows.
What you can do with it
Multi-subject revision weeks
Split a fixed daily study budget across Math, History, and Physics so harder papers receive proportionally more hours before a shared exam date.
FAQ
Can difficulty weights be zero for some subjects?
Yes for individual subjects, but the sum of all difficulty weights must be greater than zero. An all-zero list fails because proportional shares would divide by zero.
How are study hours split between subjects?
Each subject gets a share of your daily hours equal to its difficulty divided by the sum of all difficulties. That daily figure multiplied by the days left gives its total, so Math at 3 out of 6 takes half of every study day.
What happens if my exam is today?
Zero days left is rejected rather than returning an empty schedule, because there is no study window to divide. Fractional days are accepted, so half a day left still works.
Should the difficulty weight be my grade in the subject?
No. Use a weight for relative effort, not a letter grade. A weight of 3 next to a weight of 1 simply means the first subject gets three times as many minutes as the second on the same list.
Does it build a spaced-repetition calendar?
No. It returns hours per day and total hours for each subject from one proportional rule. It does not schedule review sessions on specific dates, load syllabus data or handle time zones.
Related tools
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/life/study-schedule-build \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"subjects":[{"name":"Math","difficulty":3},{"name":"History","difficulty":1},{"name":"Physics","difficulty":2}],"days_until_exam":10,"hours_per_day":4}'const res = await fetch("https://api.kit.forhosting.com/life/study-schedule-build", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"subjects": [
{
"name": "Math",
"difficulty": 3
},
{
"name": "History",
"difficulty": 1
},
{
"name": "Physics",
"difficulty": 2
}
],
"days_until_exam": 10,
"hours_per_day": 4
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/life/study-schedule-build",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"subjects": [
{
"name": "Math",
"difficulty": 3
},
{
"name": "History",
"difficulty": 1
},
{
"name": "Physics",
"difficulty": 2
}
],
"days_until_exam": 10,
"hours_per_day": 4
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/life/study-schedule-build", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"subjects":[{"name":"Math","difficulty":3},{"name":"History","difficulty":1},{"name":"Physics","difficulty":2}],"days_until_exam":10,"hours_per_day":4}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"subjects":[{"name":"Math","difficulty":3},{"name":"History","difficulty":1},{"name":"Physics","difficulty":2}],"days_until_exam":10,"hours_per_day":4}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/life/study-schedule-build", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"subjects": [
{
"name": "Math",
"difficulty": 3
},
{
"name": "History",
"difficulty": 1
},
{
"name": "Physics",
"difficulty": 2
}
],
"days_until_exam": 10,
"hours_per_day": 4
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "life.study_schedule_build",
"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.
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. |
Technical notes
How difficulty-weighted study hours are defined
When the difficulty total is zero the share formula divides by zero and the request fails with invalid input rather than inventing equal splits that you never asked for. The arithmetic is deterministic floating-point with stable rounding: identical inputs always produce identical JSON, with no wall-clock timestamps, random seeds, network calls, or model drift.
Input contract, response shape, and error behaviour
Classic check: Math weight three, History weight one, Physics weight two, ten days, four hours per day yields a difficulty sum of six, so Math receives two hours per day and twenty total, History receives two thirds of an hour per day, and Physics receives four thirds of an hour per day. POST a JSON body with three required fields. subjects is a non-empty array of objects, each with a non-empty name string and a finite non-negative difficulty number; optional aliases such as weight for difficulty are accepted by the solver when present. days_until_exam is a finite number strictly greater than zero representing whole or fractional days left before the exam; zero is the explicit hard failure described above. hours_per_day is a finite number greater than zero representing the total study budget for all subjects combined on a typical day. Missing fields, non-finite numbers, empty subject lists, zero or negative daily hours, negative difficulties, and a zero sum of difficulty weights fail with invalid_input and are not billed. On success the body echoes cleaned days_until_exam and hours_per_day, reports subject_count and difficulty_sum, returns total_study_hours as the product of daily budget and days, and provides a schedule array. Each schedule row includes index, name, difficulty, share as a unit fraction of the difficulty total, hours_per_day for that subject, and total_hours over the horizon. method is set to difficulty_proportional_study_hours and formula restates the two multiplications so tutors and auto-graders can cite the same expression. Pricing for successful API calls is the published base of $0.002 per item; validation failures do not consume prepaid balance.
Where an exam study schedule builder earns its keep
Secondary-school and university revision weeks constantly force students to split a fixed evening budget across four or five papers with uneven difficulty; a single trusted proportional oracle removes spreadsheet drift between roommates comparing plans. Tutoring platforms and exam-prep apps need a deterministic allocation they can show next to flashcards so learners see why hard subjects own more of the calendar. If you later need spaced-repetition day maps, calendar exports with time zones, or adaptive difficulty from past quiz scores, treat those as separate search intents and landings rather than overloading this build-exam-study-schedule page. Learning-management plugins and parent portals can call the API to prefill weekly hour targets without standing up a custom rules engine. Because this capability is a pure parse engine, API pricing is the published base of $0.002 per successful item and failed validation does not consume balance.
Integration use cases
Tutoring and exam-prep apps
Show learners a transparent hours-per-day table derived from difficulty weights, with the same numbers in the free widget and the paid API.
LMS and coach plan fixtures
Bulk-generate proportional schedules for cohorts and reject zero days until the exam with a hard invalid_input instead of a fake empty plan.
Technical questions
How are study hours allocated across subjects?
Each subject receives hours_per_day times (difficulty divided by the sum of all difficulties). Total hours for a subject equal that daily amount times days_until_exam.
What happens if days until the exam is zero?
The task fails with invalid_input. There is no remaining study window to allocate, so the API refuses a zero-day schedule rather than returning empty success.
What inputs are required?
A non-empty subjects array of {name, difficulty}, days_until_exam greater than zero, and hours_per_day greater than zero. Missing or non-finite values fail validation.
What does the exam study schedule builder cost?
The browser tool is free. API requests use prepaid KIT balance at $0.002 per successful call; invalid input is not billed.