Overtime pay calculator API
Overtime and night pay under Vietnam’s Labour Code: 150/200/300%, night +30% +20%, holiday work, monthly and yearly caps, PIT-exempt part from 2026.
Send the monthly_salary (pay for normal hours, without overtime, bonuses and unrelated allowances) or the hourly_wage, and the hours: simple totals (workday_ot_hours, weekly_off_ot_hours, holiday_ot_hours, the *_night_ot_hours and regular night_hours) or dated entries (the day type is taken from the public-holiday calendar when not given). The API applies Bộ luật Lao động 2019 Điều 98 and Nghị định 145/2020/NĐ-CP Điều 55–57: 150% on working days, 200% on the weekly day off, 300% on holidays, +30% for night work (22:00–06:00), and for overtime at night +20% of the day-time rate of that day (so 200% / 210% / 270% / 390%). Daily-paid workers (daily_paid=true) also get the holiday’s own pay.
Caps are checked (≤ 50% of normal daily hours on a working day, 12 h on a day off, 40 h a month, 200 or 300 h a year with ytd_ot_hours) and the PIT-exempt part is split out: until 2025 only the premium above normal pay was exempt; from tax year 2026 the whole overtime and night pay within the legal limits is exempt (Luật Thuế TNCN 109/2025, Nghị định 253/2026/NĐ-CP Điều 26), and pay for hours above the caps is taxable.
Parameters
| Name | In | Type | Required | Default | |
|---|---|---|---|---|---|
monthly_salary | query|body | number | no | Salary for normal hours (or hourly_wage). | |
working_days_per_month | query|body | number | no | 26 | Normal working days used to get the hourly wage. |
hours_per_day | query|body | number | no | 8 | Normal hours per day. |
workday_ot_hours | query|body | number | no | Overtime on working days (also weekly_off_ot_hours, holiday_ot_hours, workday_night_ot_hours, weekly_off_night_ot_hours, holiday_night_ot_hours, night_hours). | |
entries | body | array | no | Per day: [{"date":"2026-09-02","ot_hours":4,"ot_night_hours":0,"night_hours":0,"type":"holiday"}]. | |
ytd_ot_hours | query|body | number | no | Overtime hours already worked this year. | |
annual_cap | query|body | number | no | 200 | 200 or 300. |
daily_paid | query|body | boolean | no | Daily-paid worker (adds the holiday’s own pay). | |
tax_year | query|body | number | no | Tax year for the PIT split (default from the dates or this year). |
Example
curl -X POST "https://apibox.io.vn/v1/vn-overtime" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"monthly_salary":10400000,"workday_ot_hours":20,"weekly_off_ot_hours":8,"holiday_night_ot_hours":2,"tax_year":2026}'const res = await fetch('https://apibox.io.vn/v1/vn-overtime', {
method: 'POST',
headers: {
Authorization: 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({
"monthly_salary": 10400000,
"workday_ot_hours": 20,
"weekly_off_ot_hours": 8,
"holiday_night_ot_hours": 2,
"tax_year": 2026
}),
});
const data = await res.json();
console.log(data);import requests
res = requests.post(
"https://apibox.io.vn/v1/vn-overtime",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"monthly_salary": 10400000, "workday_ot_hours": 20, "weekly_off_ot_hours": 8, "holiday_night_ot_hours": 2, "tax_year": 2026},
timeout=30,
)
print(res.json())<?php
$ch = curl_init('https://apibox.io.vn/v1/vn-overtime');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => '{"monthly_salary":10400000,"workday_ot_hours":20,"weekly_off_ot_hours":8,"holiday_night_ot_hours":2,"tax_year":2026}',
]);
$response = curl_exec($ch);
print_r(json_decode($response, true));Response
{
"hourly_wage": 50000,
"hourly_basis": "monthly_salary / (26 days × 8 h)",
"lines": [
{
"date": null,
"type": "workday",
"kind": "overtime",
"hours": 20,
"percent": 150,
"pay": 1500000,
"normal_pay": 1000000,
"premium": 500000
},
{
"date": null,
"type": "weekly_off",
"kind": "overtime",
"hours": 8,
"percent": 200,
"pay": 800000,
"normal_pay": 400000,
"premium": 400000
},
{
"date": null,
"type": "holiday",
"kind": "night_overtime",
"hours": 2,
"percent": 390,
"pay": 390000,
"normal_pay": 100000,
"premium": 290000
}
],
"totals": {
"overtime_hours": 30,
"night_hours": 0,
"pay": 2690000,
"overtime_pay": 2690000,
"night_work_pay": 0,
"premium_above_normal": 1190000
},
"caps": {
"daily_workday_hours": 4,
"daily_day_off_hours": 12,
"monthly": 40,
"annual": 200,
"ytd_before": 0,
"excess_hours": 0,
"compliant": true
},
"pit": {
"tax_year": 2026,
"rule": "whole_pay_within_limits",
"exempt": 2690000,
"taxable": 0
},
"warnings": [],
"legal": [
"Bộ luật Lao động 45/2019/QH14 Điều 98, 106, 107",
"Nghị định 145/2020/NĐ-CP Điều 55–61",
"Luật Thuế TNCN 109/2025/QH15 Điều 4 khoản 8; Nghị định 253/2026/NĐ-CP Điều 26"
],
"reviewed": "2026-11-11"
}
Use cases
- Compute overtime lines in payroll software
- Show workers what they earn for working on Tết
- Flag overtime above the legal caps before payroll
- Split PIT-exempt overtime for the 2026 tax rules
FAQ
Where does 390% (or 490%) for night work on Tết come from?
300% holiday overtime + 30% night premium + 20% × 300% day-time holiday rate = 390%. A daily-paid worker also gets the holiday’s own pay, which the press quotes as 490%.
Is overtime pay taxed in 2026?
From tax year 2026 the whole overtime and night-work pay is PIT-exempt when it respects labour-law conditions and caps; pay for hours above the caps is taxable. Until 2025 only the premium part was exempt.
What are the overtime caps?
40 hours a month and 200 hours a year (300 in listed sectors such as textiles, electronics, utilities and urgent work), 50% of normal daily hours on a working day and 12 hours on a day off or holiday.
Related APIs
JSON Validator
Check JSON syntax with exact line and column of errors, and validate data against a JSON Schema (draft 4, 7, 2019-09 or 2020-12).
{ }JSON Formatter
Pretty print JSON with 0-8 spaces or tabs, minify it, or sort object keys recursively. Syntax errors are reported with line and column.
CSVCSV to JSON
Convert CSV into an array of JSON objects using the header row, with delimiter auto-detection, number and boolean typing, and row-level errors.