PTO balance and accrual ledger
Maintain this server? Claim it
Call this server's tools from your browser. Nothing to install.
Requests go through mcptry because browsers can't call most MCP servers directly. Header values are sent to the server for that request only and are never stored or logged.
Tool list from our last check. Connect live to refresh it.
Use this when someone asks how much PTO they have, wants a PTO accrual calculator or vacation accrual calculator, or needs an employee's PTO, vacation or sick leave balance from an accrual policy. Give the accrual rule as accrual_amount + accrual_unit (hours, days, weeks) + accrual_per (year, month, week, pay_period, hour_worked), e.g. 2 weeks a year = 2, weeks, year; 1 hour per 30 worked = 0.0333, hours, hour_worked; use accrual_rate text only as a fallback. Takes the policy (per hour worked like 1 h per 30, hours per pay period with weekly/biweekly/semimonthly/monthly pay, or a yearly amount front-loaded or accrued evenly), tenure tiers, hire date, max balance, annual cap, carryover limit and reset date, waiting period, hours worked, and time taken (dates, hours or ranges; future dates are planned). Returns the balance as of a date (default today, US Eastern), available hours, a dated ledger with accrued, used, capped and forfeited hours, upcoming accruals, a year-end projection with hours to use before the reset, and PDF, Excel and CSV files. Does not give legal advice, check state law compliance, compute PTO payout in money, or connect to payroll. For several employees use calculate_team_pto_balances.
Optional US state, e.g. CA, for an informational note on state paid sick leave accrual rules.
Any real payday for weekly or biweekly pay, e.g. 2026-01-09, so accruals land on the right Fridays. Default: the first Friday on or after the ledger start.
Hire (start) date, e.g. 2024-03-04. Used for tenure tiers, the waiting period and the first partial pay period.
Date to report the balance on, e.g. 2026-10-26. Default: today in US Eastern time.
For annual_front_loaded: prorated (default, first grant prorated by days left in the year) or full.
Total PTO hours used without dates, e.g. 40 for "I used 40 hours this year". Subtracted on the as-of date. Use time_taken when dates are known.
When the accrual year resets (carryover is applied), e.g. "01-01" (default January 1), "July 1", or "anniversary" (hire anniversary), or "none".
PTO used or planned, as a list [{"date":"2026-03-02","hours":8}] or text "2026-03-02 8h, 2026-07-06 to 2026-07-10, Dec 24 4h". Future dates count as planned time off in the projection.
How often accrual_amount is earned: year, month, week, pay_period, or hour_worked. Required for hours; days or weeks without it are read as per year.
Days of PTO per year, e.g. 15. Converted with hours_per_day (default 8).
Maximum balance (accrual stops at this cap until hours are used), in hours, e.g. 240, or "30 days".
Fallback only, when you cannot fill accrual_amount/accrual_unit/accrual_per: the rule as text with a number, unit and period, e.g. "1 per 30", "4.62 hours per paycheck", "15 days a year". Hours without a period are refused.
Unit of accrual_amount: hours (default), days, or weeks (weeks = days_per_week x hours_per_day).
Hours of PTO per year, e.g. 120. Use instead of annual_days.
Actual hours worked per pay period for per_hour_worked, e.g. [{"date":"2026-01-09","hours":72}] or "2026-01-09: 72, 2026-01-23: 80". Periods not listed use the standard hours.
Tenure tiers (years of service), as text "0-2: 10 days, 3-5: 15 days, 6+: 20 days" or a list [{"from_year":0,"annual_days":10},{"from_year":3,"annual_days":15}]. "years 3-5" starts at the 3rd work anniversary.
Workdays per week, default 5. Converts weeks of PTO to hours.
Optional name for the ledger header, e.g. Dana Kim.
Hours in one PTO day, default 8, e.g. 7.5.
Pay schedule: weekly, biweekly (default, every two weeks), semimonthly (15th and last day), or monthly.
Preferred way to give the rule: the amount earned, e.g. 15 (with accrual_unit days, accrual_per year), 4.62 (hours per pay_period) or 0.0333 (hours per hour_worked).
How PTO is earned: per_hour_worked (e.g. 1 h per 30 h worked), per_pay_period (fixed hours each paycheck, e.g. 4.62 h), annual_front_loaded (whole year granted at once on the reset date), annual_accrued_per_period (yearly amount, e.g. 15 days, spread evenly over pay periods). Optional: inferred from the other fields.
Standard hours per week, default 40, e.g. 30 for part time. Used when hours worked are not given.
Waiting period after hire before PTO can be used, e.g. "90 days" or "3 months".
Hours that may roll over at the reset date, e.g. 40. 0 = use it or lose it. Leave out for unlimited rollover.
Known balance on starting_balance_date, in hours, e.g. 32.5 (from a pay stub), or "4 days".
Most hours that can be earned in one accrual year, e.g. 48.
accrue_but_locked (default: hours accrue from hire but cannot be used until the waiting period ends) or no_accrual (nothing accrues during the waiting period).
Date of the starting balance, e.g. 2026-01-01. Default: the start of the current accrual year (or the hire date if later).
Hours worked in each pay period, for per_hour_worked when it differs from the standard (40 h/week), e.g. 64.
Pick your client. Values in capitals, like YOUR_TOKEN, are yours to fill in.
Run in a terminal
claude mcp add --transport http pto-accrual https://pto-accrual.zovo.one/mcp
Use this when someone asks how much PTO they have, wants a PTO accrual calculator or vacation accrual calculator, or needs an employee's PTO, vacation or sick leave balance from an accrual policy. Give the accrual rule as accrual_amount + accrual_unit (hours, days, weeks) + accrual_per (year, month, week, pay_period, hour_worked), e.g. 2 weeks a year = 2, weeks, year; 1 hour per 30 worked = 0.0333, hours, hour_worked; use accrual_rate text only as a fallback. Takes the policy (per hour worked like 1 h per 30, hours per pay period with weekly/biweekly/semimonthly/monthly pay, or a yearly amount front-loaded or accrued evenly), tenure tiers, hire date, max balance, annual cap, carryover limit and reset date, waiting period, hours worked, and time taken (dates, hours or ranges; future dates are planned). Returns the balance as of a date (default today, US Eastern), available hours, a dated ledger with accrued, used, capped and forfeited hours, upcoming accruals, a year-end projection with hours to use before the reset, and PDF, Excel and CSV files. Does not give legal advice, check state law compliance, compute PTO payout in money, or connect to payroll. For several employees use calculate_team_pto_balances.
| Argument | Type | Description |
|---|---|---|
| state | any | Optional US state, e.g. CA, for an informational note on state paid sick leave accrual rules. |
| pay_date | any | Any real payday for weekly or biweekly pay, e.g. 2026-01-09, so accruals land on the right Fridays. Default: the first Friday on or after the ledger start. |
| hire_date | any | Hire (start) date, e.g. 2024-03-04. Used for tenure tiers, the waiting period and the first partial pay period. |
| as_of_date | any | Date to report the balance on, e.g. 2026-10-26. Default: today in US Eastern time. |
| first_year | any | For annual_front_loaded: prorated (default, first grant prorated by days left in the year) or full. |
| hours_used | any | Total PTO hours used without dates, e.g. 40 for "I used 40 hours this year". Subtracted on the as-of date. Use time_taken when dates are known. |
| reset_date | any | When the accrual year resets (carryover is applied), e.g. "01-01" (default January 1), "July 1", or "anniversary" (hire anniversary), or "none". |
| time_taken | any | PTO used or planned, as a list [{"date":"2026-03-02","hours":8}] or text "2026-03-02 8h, 2026-07-06 to 2026-07-10, Dec 24 4h". Future dates count as planned time off in the projection. |
| accrual_per | any | How often accrual_amount is earned: year, month, week, pay_period, or hour_worked. Required for hours; days or weeks without it are read as per year. |
| annual_days | any | Days of PTO per year, e.g. 15. Converted with hours_per_day (default 8). |
| max_balance | any | Maximum balance (accrual stops at this cap until hours are used), in hours, e.g. 240, or "30 days". |
| accrual_rate | any | Fallback only, when you cannot fill accrual_amount/accrual_unit/accrual_per: the rule as text with a number, unit and period, e.g. "1 per 30", "4.62 hours per paycheck", "15 days a year". Hours without a period are refused. |
| accrual_unit | any | Unit of accrual_amount: hours (default), days, or weeks (weeks = days_per_week x hours_per_day). |
| annual_hours | any | Hours of PTO per year, e.g. 120. Use instead of annual_days. |
| hours_worked | any | Actual hours worked per pay period for per_hour_worked, e.g. [{"date":"2026-01-09","hours":72}] or "2026-01-09: 72, 2026-01-23: 80". Periods not listed use the standard hours. |
| tenure_tiers | any | Tenure tiers (years of service), as text "0-2: 10 days, 3-5: 15 days, 6+: 20 days" or a list [{"from_year":0,"annual_days":10},{"from_year":3,"annual_days":15}]. "years 3-5" starts at the 3rd work anniversary. |
| days_per_week | any | Workdays per week, default 5. Converts weeks of PTO to hours. |
| employee_name | any | Optional name for the ledger header, e.g. Dana Kim. |
| hours_per_day | any | Hours in one PTO day, default 8, e.g. 7.5. |
| pay_frequency | any | Pay schedule: weekly, biweekly (default, every two weeks), semimonthly (15th and last day), or monthly. |
| accrual_amount | any | Preferred way to give the rule: the amount earned, e.g. 15 (with accrual_unit days, accrual_per year), 4.62 (hours per pay_period) or 0.0333 (hours per hour_worked). |
| accrual_method | any | How PTO is earned: per_hour_worked (e.g. 1 h per 30 h worked), per_pay_period (fixed hours each paycheck, e.g. 4.62 h), annual_front_loaded (whole year granted at once on the reset date), annual_accrued_per_period (yearly amount, e.g. 15 days, spread evenly over pay periods). Optional: inferred from the other fields. |
| hours_per_week | any | Standard hours per week, default 40, e.g. 30 for part time. Used when hours worked are not given. |
| waiting_period | any | Waiting period after hire before PTO can be used, e.g. "90 days" or "3 months". |
| carryover_limit | any | Hours that may roll over at the reset date, e.g. 40. 0 = use it or lose it. Leave out for unlimited rollover. |
| starting_balance | any | Known balance on starting_balance_date, in hours, e.g. 32.5 (from a pay stub), or "4 days". |
| annual_accrual_cap | any | Most hours that can be earned in one accrual year, e.g. 48. |
| waiting_period_rule | any | accrue_but_locked (default: hours accrue from hire but cannot be used until the waiting period ends) or no_accrual (nothing accrues during the waiting period). |
| starting_balance_date | any | Date of the starting balance, e.g. 2026-01-01. Default: the start of the current accrual year (or the hire date if later). |
| hours_worked_per_period | any | Hours worked in each pay period, for per_hour_worked when it differs from the standard (40 h/week), e.g. 64. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"state": {
"anyOf": [
{
"type": "string",
"maxLength": 30
},
{
"type": "null"
}
],
"description": "Optional US state, e.g. CA, for an informational note on state paid sick leave accrual rules."
},
"pay_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Any real payday for weekly or biweekly pay, e.g. 2026-01-09, so accruals land on the right Fridays. Default: the first Friday on or after the ledger start."
},
"hire_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Hire (start) date, e.g. 2024-03-04. Used for tenure tiers, the waiting period and the first partial pay period."
},
"as_of_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Date to report the balance on, e.g. 2026-10-26. Default: today in US Eastern time."
},
"first_year": {
"anyOf": [
{
"type": "string",
"maxLength": 20
},
{
"type": "null"
}
],
"description": "For annual_front_loaded: prorated (default, first grant prorated by days left in the year) or full."
},
"hours_used": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Total PTO hours used without dates, e.g. 40 for \"I used 40 hours this year\". Subtracted on the as-of date. Use time_taken when dates are known."
},
"reset_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "When the accrual year resets (carryover is applied), e.g. \"01-01\" (default January 1), \"July 1\", or \"anniversary\" (hire anniversary), or \"none\"."
},
"time_taken": {
"anyOf": [
{
"anyOf": [
{
"type": "string",
"maxLength": 8000
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "string",
"maxLength": 300
},
{
"type": "object",
"required": [
"date"
],
"properties": {
"date": {
"type": "string",
"maxLength": 40,
"description": "Day off, e.g. 2026-03-02 (or the first day of a range)."
},
"note": {
"anyOf": [
{
"type": "string",
"maxLength": 2000
},
{
"type": "null"
}
],
"description": "Optional label, e.g. Vacation (shortened to 40 characters)."
},
"hours": {
"type": [
"number",
"string",
"null"
],
"description": "Hours used, e.g. 8 or 4. Default one day (hours_per_day), or each weekday of a range."
},
"end_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Last day of a range, e.g. 2026-03-06 (weekdays only are counted)."
}
},
"additionalProperties": {}
}
]
},
"maxItems": 1000
}
]
},
{
"type": "null"
}
],
"description": "PTO used or planned, as a list [{\"date\":\"2026-03-02\",\"hours\":8}] or text \"2026-03-02 8h, 2026-07-06 to 2026-07-10, Dec 24 4h\". Future dates count as planned time off in the projection."
},
"accrual_per": {
"anyOf": [
{
"type": "string",
"maxLength": 30
},
{
"type": "null"
}
],
"description": "How often accrual_amount is earned: year, month, week, pay_period, or hour_worked. Required for hours; days or weeks without it are read as per year."
},
"annual_days": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Days of PTO per year, e.g. 15. Converted with hours_per_day (default 8)."
},
"max_balance": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Maximum balance (accrual stops at this cap until hours are used), in hours, e.g. 240, or \"30 days\"."
},
"accrual_rate": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Fallback only, when you cannot fill accrual_amount/accrual_unit/accrual_per: the rule as text with a number, unit and period, e.g. \"1 per 30\", \"4.62 hours per paycheck\", \"15 days a year\". Hours without a period are refused."
},
"accrual_unit": {
"anyOf": [
{
"type": "string",
"maxLength": 20
},
{
"type": "null"
}
],
"description": "Unit of accrual_amount: hours (default), days, or weeks (weeks = days_per_week x hours_per_day)."
},
"annual_hours": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours of PTO per year, e.g. 120. Use instead of annual_days."
},
"hours_worked": {
"anyOf": [
{
"anyOf": [
{
"type": "string",
"maxLength": 8000
},
{
"type": "array",
"items": {
"type": "object",
"required": [
"date",
"hours"
],
"properties": {
"date": {
"type": "string",
"maxLength": 40,
"description": "Any date in the pay period, e.g. 2026-01-09."
},
"hours": {
"type": [
"number",
"string"
],
"description": "Hours worked that pay period, e.g. 72."
}
},
"additionalProperties": {}
},
"maxItems": 600
}
]
},
{
"type": "null"
}
],
"description": "Actual hours worked per pay period for per_hour_worked, e.g. [{\"date\":\"2026-01-09\",\"hours\":72}] or \"2026-01-09: 72, 2026-01-23: 80\". Periods not listed use the standard hours."
},
"tenure_tiers": {
"anyOf": [
{
"anyOf": [
{
"type": "string",
"maxLength": 600
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"from_year": {
"type": [
"number",
"string",
"null"
],
"description": "Completed years of service when this tier starts, e.g. 0, 3, 6."
},
"annual_days": {
"type": [
"number",
"string",
"null"
],
"description": "Days per year in this tier, e.g. 15."
},
"accrual_rate": {
"type": [
"number",
"string",
"null"
],
"description": "Or a rate in the method's unit, e.g. 0.0577 per hour worked or 6.15 per pay period."
},
"annual_hours": {
"type": [
"number",
"string",
"null"
],
"description": "Hours per year in this tier, e.g. 120."
}
},
"additionalProperties": {}
},
"maxItems": 12
}
]
},
{
"type": "null"
}
],
"description": "Tenure tiers (years of service), as text \"0-2: 10 days, 3-5: 15 days, 6+: 20 days\" or a list [{\"from_year\":0,\"annual_days\":10},{\"from_year\":3,\"annual_days\":15}]. \"years 3-5\" starts at the 3rd work anniversary."
},
"days_per_week": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Workdays per week, default 5. Converts weeks of PTO to hours."
},
"employee_name": {
"anyOf": [
{
"type": "string",
"maxLength": 1000
},
{
"type": "null"
}
],
"description": "Optional name for the ledger header, e.g. Dana Kim."
},
"hours_per_day": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours in one PTO day, default 8, e.g. 7.5."
},
"pay_frequency": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Pay schedule: weekly, biweekly (default, every two weeks), semimonthly (15th and last day), or monthly."
},
"accrual_amount": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Preferred way to give the rule: the amount earned, e.g. 15 (with accrual_unit days, accrual_per year), 4.62 (hours per pay_period) or 0.0333 (hours per hour_worked)."
},
"accrual_method": {
"anyOf": [
{
"type": "string",
"maxLength": 60
},
{
"type": "null"
}
],
"description": "How PTO is earned: per_hour_worked (e.g. 1 h per 30 h worked), per_pay_period (fixed hours each paycheck, e.g. 4.62 h), annual_front_loaded (whole year granted at once on the reset date), annual_accrued_per_period (yearly amount, e.g. 15 days, spread evenly over pay periods). Optional: inferred from the other fields."
},
"hours_per_week": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Standard hours per week, default 40, e.g. 30 for part time. Used when hours worked are not given."
},
"waiting_period": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Waiting period after hire before PTO can be used, e.g. \"90 days\" or \"3 months\"."
},
"carryover_limit": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours that may roll over at the reset date, e.g. 40. 0 = use it or lose it. Leave out for unlimited rollover."
},
"starting_balance": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Known balance on starting_balance_date, in hours, e.g. 32.5 (from a pay stub), or \"4 days\"."
},
"annual_accrual_cap": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Most hours that can be earned in one accrual year, e.g. 48."
},
"waiting_period_rule": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "accrue_but_locked (default: hours accrue from hire but cannot be used until the waiting period ends) or no_accrual (nothing accrues during the waiting period)."
},
"starting_balance_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Date of the starting balance, e.g. 2026-01-01. Default: the start of the current accrual year (or the hire date if later)."
},
"hours_worked_per_period": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours worked in each pay period, for per_hour_worked when it differs from the standard (40 h/week), e.g. 64."
}
}
}Use this when an owner or HR person wants PTO balances for a team: one PTO, vacation or sick leave balance per employee from one accrual policy (accrual_amount + accrual_unit + accrual_per, e.g. 15, days, year) and a list of employees (typed, pasted CSV, or an attached CSV/Excel file with name, hire date, starting balance, hours used). Applies the same policy options as calculate_pto_balance (per hour worked, per pay period, annual front-loaded or accrued, tenure tiers, caps, carryover and reset, waiting period). Returns each person's balance, hours used this year, year-end projection and hours at risk at the reset, team totals, and PDF, Excel (with each person's ledger) and CSV files. Does not give legal advice, process payroll, or compute PTO payout in money. For one person's dated ledger use calculate_pto_balance.
| Argument | Type | Description |
|---|---|---|
| pay_date | any | Any real payday for weekly or biweekly pay, e.g. 2026-01-09, so accruals land on the right Fridays. Default: the first Friday on or after the ledger start. |
| employees | any | The team: a list of employees, or CSV text with a header such as "name,hire_date,starting_balance,used_hours" and one row per person. Up to 500. |
| hire_date | any | Hire (start) date, e.g. 2024-03-04. Used for tenure tiers, the waiting period and the first partial pay period. |
| as_of_date | any | Date to report the balance on, e.g. 2026-10-26. Default: today in US Eastern time. |
| first_year | any |
We read every tool's name, description and inputs the way the model will, looking for instructions hidden from you. A clean result means no warning signs, not a guarantee. Scanned Nov 8, 2026.
| For annual_front_loaded: prorated (default, first grant prorated by days left in the year) or full. |
| reset_date | any | When the accrual year resets (carryover is applied), e.g. "01-01" (default January 1), "July 1", or "anniversary" (hire anniversary), or "none". |
| accrual_per | any | How often accrual_amount is earned: year, month, week, pay_period, or hour_worked. Required for hours; days or weeks without it are read as per year. |
| annual_days | any | Days of PTO per year, e.g. 15. Converted with hours_per_day (default 8). |
| max_balance | any | Maximum balance (accrual stops at this cap until hours are used), in hours, e.g. 240, or "30 days". |
| accrual_rate | any | Fallback only, when you cannot fill accrual_amount/accrual_unit/accrual_per: the rule as text with a number, unit and period, e.g. "1 per 30", "4.62 hours per paycheck", "15 days a year". Hours without a period are refused. |
| accrual_unit | any | Unit of accrual_amount: hours (default), days, or weeks (weeks = days_per_week x hours_per_day). |
| annual_hours | any | Hours of PTO per year, e.g. 120. Use instead of annual_days. |
| hours_worked | any | Actual hours worked per pay period for per_hour_worked, e.g. [{"date":"2026-01-09","hours":72}] or "2026-01-09: 72, 2026-01-23: 80". Periods not listed use the standard hours. |
| tenure_tiers | any | Tenure tiers (years of service), as text "0-2: 10 days, 3-5: 15 days, 6+: 20 days" or a list [{"from_year":0,"annual_days":10},{"from_year":3,"annual_days":15}]. "years 3-5" starts at the 3rd work anniversary. |
| days_per_week | any | Workdays per week, default 5. Converts weeks of PTO to hours. |
| hours_per_day | any | Hours in one PTO day, default 8, e.g. 7.5. |
| pay_frequency | any | Pay schedule: weekly, biweekly (default, every two weeks), semimonthly (15th and last day), or monthly. |
| accrual_amount | any | Preferred way to give the rule: the amount earned, e.g. 15 (with accrual_unit days, accrual_per year), 4.62 (hours per pay_period) or 0.0333 (hours per hour_worked). |
| accrual_method | any | How PTO is earned: per_hour_worked (e.g. 1 h per 30 h worked), per_pay_period (fixed hours each paycheck, e.g. 4.62 h), annual_front_loaded (whole year granted at once on the reset date), annual_accrued_per_period (yearly amount, e.g. 15 days, spread evenly over pay periods). Optional: inferred from the other fields. |
| employees_file | object | Optional CSV or Excel (.xlsx) file of employees with columns like name, hire date, starting balance, hours used, e.g. team-pto.csv. |
| hours_per_week | any | Standard hours per week, default 40, e.g. 30 for part time. Used when hours worked are not given. |
| waiting_period | any | Waiting period after hire before PTO can be used, e.g. "90 days" or "3 months". |
| carryover_limit | any | Hours that may roll over at the reset date, e.g. 40. 0 = use it or lose it. Leave out for unlimited rollover. |
| starting_balance | any | Known balance on starting_balance_date, in hours, e.g. 32.5 (from a pay stub), or "4 days". |
| annual_accrual_cap | any | Most hours that can be earned in one accrual year, e.g. 48. |
| waiting_period_rule | any | accrue_but_locked (default: hours accrue from hire but cannot be used until the waiting period ends) or no_accrual (nothing accrues during the waiting period). |
| starting_balance_date | any | Date of the starting balance, e.g. 2026-01-01. Default: the start of the current accrual year (or the hire date if later). |
| hours_worked_per_period | any | Hours worked in each pay period, for per_hour_worked when it differs from the standard (40 h/week), e.g. 64. |
{
"type": "object",
"$schema": "http://json-schema.org/draft-07/schema#",
"properties": {
"pay_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Any real payday for weekly or biweekly pay, e.g. 2026-01-09, so accruals land on the right Fridays. Default: the first Friday on or after the ledger start."
},
"employees": {
"anyOf": [
{
"anyOf": [
{
"type": "string",
"maxLength": 200000
},
{
"type": "array",
"items": {
"anyOf": [
{
"type": "string",
"maxLength": 1000
},
{
"type": "object",
"required": [
"name"
],
"properties": {
"name": {
"type": "string",
"maxLength": 1000,
"description": "Employee name, e.g. Dana Kim (shortened to 80 characters)."
},
"hire_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Hire date, e.g. 2023-05-15."
},
"used_hours": {
"type": [
"number",
"string",
"null"
],
"description": "PTO hours used since the starting date (or this accrual year), e.g. 24."
},
"annual_days": {
"type": [
"number",
"string",
"null"
],
"description": "Override days per year for this person, e.g. 20."
},
"accrual_rate": {
"type": [
"number",
"string",
"null"
],
"description": "Override accrual rate for this person, e.g. 0.05."
},
"starting_balance": {
"type": [
"number",
"string",
"null"
],
"description": "Balance on starting_balance_date in hours, e.g. 12."
},
"hours_worked_per_period": {
"type": [
"number",
"string",
"null"
],
"description": "Hours per pay period for part-time staff, e.g. 48."
}
},
"additionalProperties": {}
}
]
},
"maxItems": 5000
}
]
},
{
"type": "null"
}
],
"description": "The team: a list of employees, or CSV text with a header such as \"name,hire_date,starting_balance,used_hours\" and one row per person. Up to 500."
},
"hire_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Hire (start) date, e.g. 2024-03-04. Used for tenure tiers, the waiting period and the first partial pay period."
},
"as_of_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Date to report the balance on, e.g. 2026-10-26. Default: today in US Eastern time."
},
"first_year": {
"anyOf": [
{
"type": "string",
"maxLength": 20
},
{
"type": "null"
}
],
"description": "For annual_front_loaded: prorated (default, first grant prorated by days left in the year) or full."
},
"reset_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "When the accrual year resets (carryover is applied), e.g. \"01-01\" (default January 1), \"July 1\", or \"anniversary\" (hire anniversary), or \"none\"."
},
"accrual_per": {
"anyOf": [
{
"type": "string",
"maxLength": 30
},
{
"type": "null"
}
],
"description": "How often accrual_amount is earned: year, month, week, pay_period, or hour_worked. Required for hours; days or weeks without it are read as per year."
},
"annual_days": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Days of PTO per year, e.g. 15. Converted with hours_per_day (default 8)."
},
"max_balance": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Maximum balance (accrual stops at this cap until hours are used), in hours, e.g. 240, or \"30 days\"."
},
"accrual_rate": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Fallback only, when you cannot fill accrual_amount/accrual_unit/accrual_per: the rule as text with a number, unit and period, e.g. \"1 per 30\", \"4.62 hours per paycheck\", \"15 days a year\". Hours without a period are refused."
},
"accrual_unit": {
"anyOf": [
{
"type": "string",
"maxLength": 20
},
{
"type": "null"
}
],
"description": "Unit of accrual_amount: hours (default), days, or weeks (weeks = days_per_week x hours_per_day)."
},
"annual_hours": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours of PTO per year, e.g. 120. Use instead of annual_days."
},
"hours_worked": {
"anyOf": [
{
"anyOf": [
{
"type": "string",
"maxLength": 8000
},
{
"type": "array",
"items": {
"type": "object",
"required": [
"date",
"hours"
],
"properties": {
"date": {
"type": "string",
"maxLength": 40,
"description": "Any date in the pay period, e.g. 2026-01-09."
},
"hours": {
"type": [
"number",
"string"
],
"description": "Hours worked that pay period, e.g. 72."
}
},
"additionalProperties": {}
},
"maxItems": 600
}
]
},
{
"type": "null"
}
],
"description": "Actual hours worked per pay period for per_hour_worked, e.g. [{\"date\":\"2026-01-09\",\"hours\":72}] or \"2026-01-09: 72, 2026-01-23: 80\". Periods not listed use the standard hours."
},
"tenure_tiers": {
"anyOf": [
{
"anyOf": [
{
"type": "string",
"maxLength": 600
},
{
"type": "array",
"items": {
"type": "object",
"properties": {
"from_year": {
"type": [
"number",
"string",
"null"
],
"description": "Completed years of service when this tier starts, e.g. 0, 3, 6."
},
"annual_days": {
"type": [
"number",
"string",
"null"
],
"description": "Days per year in this tier, e.g. 15."
},
"accrual_rate": {
"type": [
"number",
"string",
"null"
],
"description": "Or a rate in the method's unit, e.g. 0.0577 per hour worked or 6.15 per pay period."
},
"annual_hours": {
"type": [
"number",
"string",
"null"
],
"description": "Hours per year in this tier, e.g. 120."
}
},
"additionalProperties": {}
},
"maxItems": 12
}
]
},
{
"type": "null"
}
],
"description": "Tenure tiers (years of service), as text \"0-2: 10 days, 3-5: 15 days, 6+: 20 days\" or a list [{\"from_year\":0,\"annual_days\":10},{\"from_year\":3,\"annual_days\":15}]. \"years 3-5\" starts at the 3rd work anniversary."
},
"days_per_week": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Workdays per week, default 5. Converts weeks of PTO to hours."
},
"hours_per_day": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours in one PTO day, default 8, e.g. 7.5."
},
"pay_frequency": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Pay schedule: weekly, biweekly (default, every two weeks), semimonthly (15th and last day), or monthly."
},
"accrual_amount": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Preferred way to give the rule: the amount earned, e.g. 15 (with accrual_unit days, accrual_per year), 4.62 (hours per pay_period) or 0.0333 (hours per hour_worked)."
},
"accrual_method": {
"anyOf": [
{
"type": "string",
"maxLength": 60
},
{
"type": "null"
}
],
"description": "How PTO is earned: per_hour_worked (e.g. 1 h per 30 h worked), per_pay_period (fixed hours each paycheck, e.g. 4.62 h), annual_front_loaded (whole year granted at once on the reset date), annual_accrued_per_period (yearly amount, e.g. 15 days, spread evenly over pay periods). Optional: inferred from the other fields."
},
"employees_file": {
"type": "object",
"required": [
"download_url",
"file_id"
],
"properties": {
"file_id": {
"type": "string",
"description": "ChatGPT file id, e.g. file_abc123."
},
"file_name": {
"type": "string",
"description": "Original file name if known, e.g. statement.pdf."
},
"mime_type": {
"type": "string",
"description": "Media type if known, e.g. application/pdf."
},
"download_url": {
"type": "string",
"description": "Temporary download link for the file, supplied by ChatGPT."
}
},
"description": "Optional CSV or Excel (.xlsx) file of employees with columns like name, hire date, starting balance, hours used, e.g. team-pto.csv."
},
"hours_per_week": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Standard hours per week, default 40, e.g. 30 for part time. Used when hours worked are not given."
},
"waiting_period": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Waiting period after hire before PTO can be used, e.g. \"90 days\" or \"3 months\"."
},
"carryover_limit": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours that may roll over at the reset date, e.g. 40. 0 = use it or lose it. Leave out for unlimited rollover."
},
"starting_balance": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Known balance on starting_balance_date, in hours, e.g. 32.5 (from a pay stub), or \"4 days\"."
},
"annual_accrual_cap": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Most hours that can be earned in one accrual year, e.g. 48."
},
"waiting_period_rule": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "accrue_but_locked (default: hours accrue from hire but cannot be used until the waiting period ends) or no_accrual (nothing accrues during the waiting period)."
},
"starting_balance_date": {
"anyOf": [
{
"type": "string",
"maxLength": 40
},
{
"type": "null"
}
],
"description": "Date of the starting balance, e.g. 2026-01-01. Default: the start of the current accrual year (or the hire date if later)."
},
"hours_worked_per_period": {
"anyOf": [
{
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"maxLength": 60
}
]
},
{
"type": "null"
}
],
"description": "Hours worked in each pay period, for per_hour_worked when it differs from the standard (40 h/week), e.g. 64."
}
}
}