lodgeit labs

Deterministic tax and accounting calculators, over HTTP

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.

What's live

CalculatorStatusWhat 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 available Taxable value of a fringe benefit under FBTAA 1986, across nineteen benefit-category calculators — car (statutory formula and operating cost), loan, debt waiver, expense payment, property, residual, housing, LAFHA, board, entertainment and car parking. Full list via discovery.
Fano classifier available Trial-balance line classifier for the LodgeiT chart of accounts. Send ledger lines with entity type and section; get an SBRM code with accepted_fact or draft_fact (candidates shown). Rules first, model second; a draft is the engine refusing to guess. No key; rate-limited.
Hire Purchase available Amortisation schedule for a hire purchase, chattel mortgage or equipment loan: nominal monthly period basis, in arrears or in advance, monthly frequency, with an optional balloon that replaces or adds to the instalment on its row. Internal balances are unrounded; output rounds to cents. The residual is reported against the stated rate and never forced to zero. Monthly frequency only; other frequencies are refused.

Publish your own

These are the calculators we wrote. The constellation is meant to hold the ones we didn't — any deterministic tax or accounting engine that describes itself, refuses what it cannot answer, names what it consumed, and returns money as exact decimals. If you build bounded tax or accounting tools, read the standard and the invitation — you host it, we point at it, and it lands on this page and in llms.txt the same week it clears conformance.

Working with an agent?

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.

Base URL

https://fbt-calculator-api-qkp3j5bjnq-ts.a.run.app

The service name is historical — it fronts every calculator, not just FBT.

This host will change. A stable custom domain is coming; until then you are calling the underlying Cloud Run URL directly. Put the base URL in configuration rather than in your code, and re-check this page before assuming it still resolves.

Thirty seconds

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": { ... }
}

Discovery

The gateway describes itself. Point an agent at these before hardcoding anything:

GET /v1/calculators
Every calculator, its URN, its input schema reference, and the period URNs it accepts.
GET /v1/modules
The modules (fbt, div7a, depreciation), each with its statutes, election groups, and its calculators in registry order. Filter the calculator listing to one with GET /v1/calculators?module=.
GET /openapi.json
Full OpenAPI 3 document for every route.
GET /v1/rates/{period_uri}
The statutory rate tables registered for a period, each with a content hash.
GET /healthz
Liveness.

How the responses are shaped

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.

Errors

Status codes mean what they say. We treat this as a contract:

CodeMeaning
422Your request is malformed or incomplete. The body names the field. Do not retry unchanged.
400Your request is well-formed but outside what this calculator will answer. The body carries a refusal_class.
404Unknown calculator URN or a period URN this calculator does not accept. The body names what it does accept.
5xxOur 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.

Refusals are a feature

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.

What this is not

Rate limits, cost, keys

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.

Telling us it's wrong

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.

github.com/lodgeit-labs