Calculator API
Every ResearchForge calculator is also a JSON endpoint. Discover them, inspect their input schemas, and POST inputs to compute. The same pure function that runs on the React page runs on the server — you'll get identical results.
51
endpoints
51
compute modules
113
test cases
Endpoints
GET
/api/calculatorsCatalog every calculator with input schema and URLs.
Example
curl https://<your-host>/api/calculatorsResponse
{
"count": 29,
"calculators": [
{
"course_slug": "dynamics",
"calc_slug": "stopping-distance",
"title": "Stopping Distance",
"topic": "stopping-distance",
"test_status": "passing",
"test_count": 2,
"inputs": [ ... ],
"compute_url": "/api/calculators/dynamics/stopping-distance/compute",
"detail_url": "/api/calculators/dynamics/stopping-distance"
},
...
]
}GET
/api/calculators/[course]/[calc]Full metadata for one calculator — inputs, sample test cases, compute URL.
Example
curl https://<your-host>/api/calculators/dynamics/stopping-distanceResponse
{
"course_slug": "dynamics",
"calc_slug": "stopping-distance",
"title": "Stopping Distance",
"topic": "stopping-distance",
"test_status": "passing",
"test_count": 2,
"inputs": [
{ "name": "reaction_time", "label": "Reaction Time (s)", "type": "number", "default": 0.75 },
{ "name": "deceleration", "label": "Deceleration (ft/s²)", "type": "number", "default": 2 },
{ "name": "initial_speed", "label": "Initial Speed (ft/s)", "type": "number", "default": 44 }
],
"test_cases": [
{ "inputs": { "reaction_time": 0.75, "deceleration": 2, "initial_speed": 44 },
"expected": 517.0, "tolerance": 1e-06 }
],
"compute_url": "/api/calculators/dynamics/stopping-distance/compute"
}POST
/api/calculators/[course]/[calc]/computeRun the calculator with user-supplied inputs. Returns { ok, value, formula? }.
Example
curl -X POST https://<your-host>/api/calculators/dynamics/stopping-distance/compute \
-H "Content-Type: application/json" \
-d '{"inputs":{"reaction_time":0.75,"deceleration":2,"initial_speed":44}}'Response
{
"ok": true,
"value": 517,
"formula": "$ d_{total} = d_{reaction} + d_{stopping} = v_{0} * t_{reaction} + \\frac{v_{0}^{2}}{2 * a} $"
}Client examples
Same compute, multiple languages. Replace <your-host> with the URL the site is served from (e.g. localhost:3001).
JavaScript (fetch)
const r = await fetch("/api/calculators/dynamics/stopping-distance/compute", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
inputs: { reaction_time: 0.75, deceleration: 2, initial_speed: 44 },
}),
});
const data = await r.json();
console.log(data.value); // 517Python (requests)
import requests
r = requests.post(
"http://localhost:3001/api/calculators/dynamics/stopping-distance/compute",
json={"inputs": {"reaction_time": 0.75, "deceleration": 2, "initial_speed": 44}},
)
print(r.json()["value"]) # 517Python (httpx, async)
import httpx, asyncio
async def main():
async with httpx.AsyncClient() as c:
r = await c.post(
"http://localhost:3001/api/calculators/dynamics/stopping-distance/compute",
json={"inputs": {"reaction_time": 0.75, "deceleration": 2, "initial_speed": 44}},
)
print(r.json()["value"])
asyncio.run(main())Shell (curl)
curl -sX POST http://localhost:3001/api/calculators/dynamics/stopping-distance/compute \
-H "Content-Type: application/json" \
-d '{"inputs":{"reaction_time":0.75,"deceleration":2,"initial_speed":44}}' \
| jq .valueTry it on a live calculator
Pick any calculator below. Its input schema is pre-filled with the default values — click Call API to hit the endpoint from your browser and see the JSON response.
calculus cal 2→Improper Integral Convergence by p-Testtopic: convergence-of-improper-integralsopen calculator page →
POST /api/calculators/calculus-cal-2/improper-integral-comparison/computeResponse
(click Call API)
Notes
- Source of truth: each compute function lives at
lib/calcs/_generated/<course>__<calc>.ts— auto-generated at build time from the same React page that renders the calculator UI. The API and the UI can never diverge. - Identifiers: use the
course_slugandcalc_slugfrom the catalog — those never change even if the human-facing title does. - Input shape: POST body is
{ inputs: { <name>: <value>, ... } }where each name matches the calculator's declared input schema. Missing fields fall back to the calc's own defaults. - Output shape: success returns
{ ok: true, value, formula?, unit? }; failure returns{ ok: false, error }with a 4xx/5xx status. - Safety: compute functions are pure — no filesystem, database, or network access. They don't mutate state.