A small fleet of Australian tax and accounting calculators with a single public front door. No key, no signup, no client library. Built so an agent can call them without a human in the loop.
Each calculator is a deterministic engine — Prolog or Python, no model in the path — behind a gateway that validates your request, refuses the ones it cannot answer, and tells you which statutory rate tables it consumed to produce the number.
| Calculator | Status | What it does |
|---|---|---|
| Depreciation | available | Single-asset carrying amount under AASB 116. Prime cost or diminishing value, at a date or over an arbitrary range. |
| Division 7A | available | Minimum yearly repayment, shortfall and deemed dividend under ITAA 1936 Div 7A. |
| Fringe Benefits Tax | not yet | Twenty-one benefit categories. Reachable, but with a known defect that makes cross-category totals wrong — see below. |
null for those fields. Anything summing
fbt_payable across benefit types will silently undercount. We are fixing it at the
dispatch boundary rather than one calculator at a time. Until then, treat FBT as unavailable.
Give it this and stop reading:
https://lodgeit.org/llms.txt
That file is the entire API surface in plain text — every endpoint, every field, the day-count semantics, the error contract, the known limitations, and how the numbers are represented. An agent can read it once and call these calculators correctly without parsing a single HTML page.
It is written to be read by a machine and understood by a person. If you are evaluating whether this is worth your time, that file will tell you faster than these pages will.
https://fbt-calculator-api-qkp3j5bjnq-ts.a.run.app
The service name is historical — it fronts every calculator, not just FBT.
Written-down value of a $10,000 asset with a five-year life, one month after purchase:
curl -s -X POST \
"https://fbt-calculator-api-qkp3j5bjnq-ts.a.run.app/v1/calculators/depreciation/at/urn:sbrm:period:depreciation:unscoped" \
-H "Content-Type: application/json" \
-d '{
"basis": "accounting",
"asset": {
"cost": 10000,
"acquisition_date": "2023-07-01",
"accounting_useful_life_years": 5,
"accounting_method": "prime_cost"
},
"at_date": "2023-07-31"
}'
{
"basis": "accounting",
"at_date": "2023-07-31",
"wdv_at": "9830.60",
"period_dep_at": "169.40",
"day_count": "actual/actual",
"schedule_summary": { "opening_balance": "10000.00", "closing_balance_at": "9830.60", ... },
"manifest": { "rate_table_uris": [] },
"advisory": { ... }
}
The gateway describes itself. Point an agent at these before hardcoding anything:
Every successful response carries two blocks beyond the calculation itself.
manifest.rate_table_uris lists the statutory rate tables the
calculation actually consumed, each with a SHA-256 of its contents. An empty list means the figure
was derived arithmetically from your inputs alone. This is emitted by the computation, not attached
by hand — if the list changes, the arithmetic changed.
advisory states what kind of figure you have been given and what
it is not. It varies by calculator: an AASB 116 carrying amount carries a warning against
using it in a tax return; a Division 7A figure carries the tax-agent framing. Read it — the
distinction is the point.
Status codes mean what they say. We treat this as a contract:
| Code | Meaning |
|---|---|
422 | Your request is malformed or incomplete. The body names the field. Do not retry unchanged. |
400 | Your request is well-formed but outside what this calculator will answer. The body carries a refusal_class. |
404 | Unknown calculator URN or a period URN this calculator does not accept. The body names what it does accept. |
5xx | Our fault. Retrying is reasonable. |
A 4xx from the engine behind the gateway is never reported to you as a 5xx. If you get a 5xx, something is genuinely wrong on our side.
These calculators refuse rather than guess. A Division 7A loan with a zero or negative
balance is not a loan, so it returns 400 instead of a compliance verdict. A pooled depreciating
asset is out of scope, so it returns 400 with pool_asset_out_of_t6_scope instead of a
number computed under the wrong rules.
If you are used to APIs that return something for everything, this will occasionally be inconvenient. It is deliberate. A refusal you can see beats a plausible number you cannot check.
None, none, and none. The services are capped at three instances each, so sustained heavy load will queue. If you need more than that, or you are building something that would break when we change a field name, get in touch first.
The most useful thing you can send us is a request and the response it produced, with the number you expected and where that expectation comes from. Two independent implementations disagreeing is how the last four defects in these calculators were found — including one where our engine was right and our own reasoning was wrong.