every model spec’d & versioned · Concordance-tested changelog →

Documentation

Integrate financial math that shows its work — in minutes

No API keys, no signup, no SDK required. Two surfaces — a REST API for products and an MCP server for AI assistants — over the same 61 Concordance-tested models. Three of them are free to call with attribution; the rest come with a paid plan — see pricing.

Watch the film — Anatomy of an Answer, 3½ minutes

Anatomy of an Answer · 3:21One real API response walked field by field — spec version, sentinels, sourced constants — ending on the SHA-256 any auditor can recompute.

Last reviewed

Quickstart (REST)

Three endpoints per model: the JSON contract (GET /api/v1/models/{model}), the full specification (…/spec), and execution (POST /api/v1/models/{model}). Discover models at GET /api/v1/models.

curl -s https://worthune.com/api/v1/models/relocation \
  -X POST -H 'content-type: application/json' \
  -d '{
    "currentSalary": 95000,
    "newSalary": 108000,
    "currentMonthlyExpenses": 4200,
    "newMonthlyExpenses": 4900,
    "movingCosts": 6000,
    "currentSavings": 40000,
    "annualReturn": 0.07,
    "yearsHorizon": 10
  }'

Or from JavaScript:

const res = await fetch(
  "https://worthune.com/api/v1/models/relocation",
  {
    method: "POST",
    headers: { "content-type": "application/json" },
    body: JSON.stringify(inputs), // per the model's contract
  },
);
const result = await res.json();
if (result.ok) {
  console.log(result.outputs.breakEvenMonths);
  console.log(result.specVersion, result.assumptions);
}
Where do I pastethe API key?There isn't one.…what's the catch?Also none.
the longest step of our onboarding: disbelief

SDKs — JavaScript and Python

Thin official wrappers over the same REST API. Zero dependencies in both, so adding one does not pull a tree into your build. Nothing here is available only through an SDK — every call above works with fetch or curl if you would rather not add a dependency at all.

npm i worthune        # JavaScript / TypeScript
pip install worthune   # Python

JavaScript:

import { Worthune, verifyRecord } from "worthune";

const wy = new Worthune();

const result = await wy.run("relocation", inputs);
if (result.ok) {
  console.log(result.outputs.breakEvenMonths);
  console.log(result.specVersion, result.assumptions);
  // Recompute the decision record's digest from the response itself.
  console.log(await verifyRecord(result));
} else {
  console.error(result.errors); // field-level, not a thrown exception
}

Python:

from worthune import Worthune, verify_record

wy = Worthune()

result = wy.run("relocation", inputs)
if result["ok"]:
    print(result["outputs"]["breakEvenMonths"])
    print(result["specVersion"], result["assumptions"])
    print(verify_record(result))
else:
    print(result["errors"])  # field-level, not a raised exception

Both expose the same surface: listModels, getContract, getSpec, run, listEvals, getEvalDataset, and getFacts — snake_case in Python, camelCase in JavaScript.

Two behaviors worth knowing. A validation failure comes back as ok: false with field-level errors rather than as a thrown exception, because a rejected input is an answer and not a crash; network and server faults do throw. And verifyRecord recomputes the decision record’s digest from the response you were handed, locally — it asks us for nothing, so it still means something if we are the party you are checking.

Source: github.com/CapsteraSupport/worthune-sdk.

MCP setup (AI assistants)

Streamable-HTTP endpoint: https://worthune.com/api/mcp/mcp — listed in the official MCP registry as com.worthune/models. Twenty tools; six need no key. The tools that operate on stored households take your wk_ key either once, as an Authorization: Bearer header on the connection (recommended — the key never enters the transcript; clients that support headers, such as Claude Code and Cursor, configure it that way), or per call as the api_key argument (on a connection that sent a bearer, the bearer is the identity and the argument is ignored). Roles apply exactly as on REST, and any tool result that is not an answer is an MCP error (isError: true) whose JSON body names the reason, so an agent never mistakes an error for a result.

The response envelope

Every successful run returns the same shape — designed so a caller (human or AI) can show its work:

Validation & errors

Inputs are validated against the spec's domains at the boundary. Out-of-domain values are rejected, never clamped — engine behavior outside a spec's domain is undocumented, and a silently adjusted answer is worse than an error. All fields are required; unknown fields are rejected.

HTTP 400
{
  "ok": false,
  "model": "relocation",
  "errors": [
    { "field": "newSalary", "message": "must be between 30000 and 300000" },
    { "field": "yearsHorizon", "message": "required" }
  ]
}

Unknown models return 404. Malformed JSON returns 400 with a single error message.

Conventions

Embeds — a working calculator in one script tag

Drop a calculator into your page. Prefill inputs with data-input-* attributes; the frame links its published spec and carries its own disclaimer and attribution line. Calculator embeds are free for every model. The household widgets (tenant tokens, below) render under your brand, and Growth can drop their attribution line through the tenant config.

<div data-worthune-embed="relocation"
     data-height="720"
     data-input-currentSavings="40000"></div>
<script async src="https://worthune.com/embed.js"></script>

The household engine

Want to build the integration before you buy? A sandbox key arrives by email and opens everything below on up to five stored households for thirty days — the same key works over REST, MCP and both SDKs, and Launch keeps the organization and its households when you move up.

One versioned document per client — members, accounts by tax wrapper, incomes, liabilities, expenses — and every computation the platform runs on it. The engine page at /household describes it whole, and /demo runs it live on a labeled fictional household.

Running it needs no key. The routes below operate on a STORED household and take a key — a sandbox key within its limits, or a paid plan's — because storage is what a plan buys. The computation itself is free and always will be — there is no run meter:

What a paid key adds is the household as something we keep:

White-label — tenant branding & embed tokens (Growth)

Eval datasets & the facts API

Grading — send us your copilot’s answers

The service form of the eval datasets: POST your own answers (from an LLM, an agent, or your own engine) and get each one graded against the production engine at the Concordance harness tolerances. Up to 500 cases per request; the three sample models grade without a key, the rest with a key (sandbox or paid).

curl -s https://worthune.com/api/v1/grade/emergency-fund \
  -X POST -H 'content-type: application/json' \
  -d '{
    "cases": [{
      "inputs": { "monthlyExpenses": 4000, "targetMonths": 6,
                  "currentSavings": 8000, "monthlySavings": 500,
                  "savingsAccountRate": 0.04 },
      "answer": { "targetAmount": 24000, "monthsToGoal": 29 }
    }]
  }'
# → { "ok": true, "passed": ..., "failed": ..., "passRate": ..., "cases": [...] }

Each case comes back pass / fail (with per-key diffs) / invalid-inputs, plus a batch pass rate. A tolerance override is accepted but clamped — never looser than 1e-2 relative, never tighter than the harness itself.

Verification — check a claim before you state it

The guardrail form of grading, shaped for one moment: an assistant is about to tell a user a number. POST the model inputs and the claims the assistant wants to make; each claim comes back verified / violated / out-of-scope, with the engine’s computed value as proof and the run’s decision record tying the verdict to a spec version. Claims support == (at tolerance) and < <= > >= (with the same tolerance as grace at the boundary). Up to 50 claims per request; same key boundary as running the model. MCP assistants get the identical check as the verify_claim tool.

curl -s https://worthune.com/api/v1/verify/emergency-fund \
  -X POST -H 'content-type: application/json' \
  -d '{
    "inputs": { "monthlyExpenses": 4000, "targetMonths": 6,
                "currentSavings": 8000, "monthlySavings": 500,
                "savingsAccountRate": 0.04 },
    "claims": [
      { "path": "targetAmount", "value": 24000 },
      { "path": "monthsToGoal", "op": "<=", "value": 30 }
    ]
  }'
# → { "ok": true, "verdict": "verified", "claims": [...], "record": {...} }

Out-of-scope is a deliberate verdict, not an error: it means the model doesn’t compute the claimed quantity, so we don’t rule on it. Separately, anyone holding a stored response can check its decision record — digest integrity, no key, nothing stored — at /proof/record or POST /api/v1/records/verify.

Computation reports — a run as a document

POST /api/v1/models/{model}/report takes the same JSON inputs as a run and returns a print-ready HTML document instead of an envelope: the inputs, the outputs with sentinel annotations at full precision, the assumptions in force, the sourced constants consumed, and the decision record — including the exact verification payload it hashes, so the file verifies itself: anyone holding only the document can recompute the digest or paste the payload at /proof/record. Print to PDF to archive. Same key boundary as running the model; errors come back as JSON. The report documents a computation — it is not advice, and it does not by itself satisfy any regulatory obligation (it says so on its face).

curl -s https://worthune.com/api/v1/models/emergency-fund/report \
  -X POST -H 'content-type: application/json' \
  -d '{ "monthlyExpenses": 4000, "targetMonths": 6, "currentSavings": 8000,
        "monthlySavings": 500, "savingsAccountRate": 0.04 }' \
  -o emergency-fund-report.html
# → a standalone, self-verifiable document; print to PDF to archive

Model reference

Each page shows the model's input contract and a live request/response pair generated from the real engine: