POST /v1/calculate/:calcId

Runs a calculator's math server-side and returns the result — no widget, no rendering, just the number.

Every calculator's logic is a plain function — calcId just picks which one. Some calculators export several genuinely distinct functions (e.g. investment has 7 — end amount, required contribution, required years, etc. — with no single "the" one), so a request also names which exported function to call. Same account and quota as POST /v1/widget/verify — Free's 100-call trial, Base's 1,000/mo, Extra's 10,000/mo, off the same usage counter. Rate limited to 30 requests/minute per IP.

1. Look up what a calculator exports

curl https://exactcalcs.com/v1/calculate/bmi/functions
{ "calcId": "bmi", "functions": ["adultBmiCategory", "calcBmi"] }

GET /v1/calculate (no calcId) returns this same list for all 67 calculators in one call — useful for building a picker instead of hardcoding IDs.

2. Call it

curl -X POST https://exactcalcs.com/v1/calculate/bmi \
  -H "Content-Type: application/json" \
  -d '{
    "apiKey": "sk_live_...",
    "fn": "calcBmi",
    "args": [{ "heightCm": 175, "weightKg": 70 }]
  }'
FieldTypeNotes
apiKeystring, requiredFrom your dashboard.
fnstring, requiredOne of the names from GET /v1/calculate/:calcId/functions.
argsarray, optionalPositional arguments, in the order the function declares them — usually one input object (as above), sometimes several plain values (e.g. [120, 80] for a two-number function like blood pressure). Check the calculator's own page in this repo's apps/web/src/calculators/<calcId>/calc.ts for the exact shape, or just try the function and read the error — a wrong shape usually surfaces as NaN/undefined in the result rather than a thrown error.

Response — success

{ "result": { "bmi": 22.86, "bmiPrime": 0.91, "ponderalIndex": 13.06, "category": "Normal" } }

result is exactly whatever the function returns — a number, an object, whatever that calculator's own return type is. There's no unwrapping or normalizing across calculators.

Response — error

{ "error": "Unknown calcId: not-a-real-calc" }

Some calculators (Framingham CVD, KFRE, PBCG, ...) throw a machine-readable error string for out-of-range input — those pass through as the error field with a 400, not a 500. See Errors & rate limits for the shared apiKey/quota errors (invalid key, trial expired, quota exceeded).

Interactive docs

Every route above is also documented as an OpenAPI spec with a try-it-out UI at exactcalcs.com/v1/docs.