Skip to content

Repository files navigation

bir-taxes

Philippine BIR income tax computation for Python. The graduated tables are data; the computation is one small function over them.

No dependencies, typed, Decimal throughout. Python 3.9+.

pip install bir-taxes

Use

from birtax import compute_income_tax

result = compute_income_tax(1_000_000)

result.tax_due  # Decimal('152500.00')
result.marginal_rate  # Decimal('0.25')
result.effective_rate  # Decimal('0.1525')
print(result.explain())
Table:          Graduated income tax, 2023 onwards
Taxable income: PHP 1,000,000.00
Bracket:        800,000 to 2,000,000: 102,500 + 25% of the excess over 800,000
Computation:    102,500.00 + 25% x 200,000.00
Tax due:        PHP 152,500.00
Effective rate: 15.25%
Marginal rate:  25%

If you only want the number:

from birtax import tax_due

tax_due("1_250_000")  # Decimal('215000.00')
tax_due(300_000, year=2021)  # Decimal('10000.00') -- the 2018-2022 table

taxable_income is net of every deduction and exemption. This library applies a table and nothing else — it does not compute deductions, the ₱90,000 13th-month exclusion, SSS/PhilHealth/Pag-IBIG contributions, the 8% gross receipts option, or withholding per payroll period.

Command line

$ birtax 1,250,000
$ birtax --json 300000 1000000
$ birtax --year 2021 500000
$ birtax --table 2027-proposed --show-table

The tables

In force — taxable year 2023 onwards (and so, 2026)

RA 10963 (TRAIN), sec. 24(A)(2)(b). No change took effect for 2026.

Annual taxable income Tax due
Not over ₱250,000 None
Over ₱250,000 but not over ₱400,000 15% of the excess over ₱250,000
Over ₱400,000 but not over ₱800,000 ₱22,500 + 20% of the excess over ₱400,000
Over ₱800,000 but not over ₱2,000,000 ₱102,500 + 25% of the excess over ₱800,000
Over ₱2,000,000 but not over ₱8,000,000 ₱402,500 + 30% of the excess over ₱2,000,000
Over ₱8,000,000 ₱2,202,500 + 35% of the excess over ₱8,000,000

Superseded — taxable years 2018 to 2022

RA 10963 (TRAIN), sec. 24(A)(2)(a). Kept for amended returns and back-year audits, reachable as TABLE_2018_2022 or year=2018..2022.

Annual taxable income Tax due
Not over ₱250,000 None
Over ₱250,000 but not over ₱400,000 20% of the excess over ₱250,000
Over ₱400,000 but not over ₱800,000 ₱30,000 + 25% of the excess over ₱400,000
Over ₱800,000 but not over ₱2,000,000 ₱130,000 + 30% of the excess over ₱800,000
Over ₱2,000,000 but not over ₱8,000,000 ₱490,000 + 32% of the excess over ₱2,000,000
Over ₱8,000,000 ₱2,410,000 + 35% of the excess over ₱8,000,000

Not law — the ₱350,000 bills, proposed for 1 January 2027

Bills pending in both chambers (the "Expanded Income Tax Exemption Act of 2026") would lift the exempt ceiling from ₱250,000 to ₱350,000 and keep the 20/25/30/35% rates. It is not enacted: table_for_year will never return it, and you must opt in by name.

from birtax import TABLE_2027_PROPOSED, tax_due

tax_due(380_000, table=TABLE_2027_PROPOSED)  # Decimal('4500.00')
Annual taxable income Tax due
Not over ₱350,000 None
Over ₱350,000 but not over ₱400,000 15% of the excess over ₱350,000
Over ₱400,000 but not over ₱800,000 ₱22,500 + 20% of the excess over ₱400,000
Over ₱800,000 but not over ₱2,000,000 ₱102,500 + 25% of the excess over ₱800,000
Over ₱2,000,000 but not over ₱8,000,000 ₱402,500 + 30% of the excess over ₱2,000,000
Over ₱8,000,000 ₱2,202,500 + 35% of the excess over ₱8,000,000

This table has a cliff at ₱400,000. Moving the ceiling to ₱350,000 shrinks the 15% band to ₱50,000, which yields ₱7,500 — but the next row still starts at the old ₱22,500. Earning one more peso above ₱400,000 costs ₱15,000 in tax. The library encodes the draft as written rather than silently "fixing" it, and reports the gap:

TABLE_2027_PROPOSED.discontinuities()  # ((<400k row>, <800k row>, Decimal('15000')), )
TABLE_2023_ONWARDS.discontinuities()   # () -- enacted law is continuous

If the final law recomputes the fixed amounts instead, that ₱22,500 becomes ₱7,500 and the rest shift down with it. Build your own TaxTable until then.

Money and rounding

Amounts are Decimal. int, str, and Decimal are exact; float is converted through its repr, so 0.1 means one tenth — but prefer strings for centavo-precise input. Results round half-up to centavos, as BIR forms do; pass rounding=None for full precision or rounding=PESO for whole pesos.

Custom tables

from birtax import Bracket, TaxTable, tax_due

local = TaxTable(
    name="Some future table",
    brackets=(
        Bracket(0, 350_000, 0, "0"),
        Bracket(350_000, 400_000, 0, "0.15"),
        Bracket(400_000, None, 7_500, "0.20"),
    ),
)
tax_due(500_000, table=local)

TaxTable refuses gaps, overlaps, a first bracket that does not start at zero, and a last bracket that is not open-ended — a mistyped table fails at import, not in a payslip.

Accuracy

Every expected figure in the test suite is hand-computed from the published table, never captured from this library's output. Tables cite their statute in .authority.

This is not tax advice. Verify against the BIR issuance that applies to you.

Contributing

See CONTRIBUTING.md. New tables are welcome — cite the law, add hand-computed cases, and never delete a superseded table.

License

MIT.

About

Philippine BIR income tax computation for Python: the graduated tables as data, and one function over them.

Topics

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages