Core concepts

The handful of ideas that make Numeratica different — read these once and the rest of the API is obvious.

On this page: Authentication · Determinism & result_id · Seeds · Error model · Versioning · Idempotency · Not advice · Rate limits

Authentication & API keys

Every /v1 endpoint requires an API key; health probes (/readyz) and self-serve signup (/v1/signup) are public. Get a free key in seconds — no card. Send the key as a bearer token, or in the X-API-Key header — both are accepted:

# either of these:
-H "Authorization: Bearer nmr_sk_test_xxx"
-H "X-API-Key: nmr_sk_test_xxx"
Keep keys server-side. A key in client-side JavaScript or a public repo is compromised — treat it like a password and rotate immediately if exposed. Separate test and live keys are on the roadmap.

Determinism & result_id

Numeratica calculations are pure functions. Every response carries an engine_version and a result_id, and the same inputs always produce the same answer and the same id — byte for byte.

The result_id is a content hash:

result_id = "<prefix>_" + sha256( canonical_json({ params, engine }) )[:16 hex]
# e.g.  mc_5445a80e48d88d60   (prefix "mc" = Monte Carlo)

Seeds

Stochastic engines (such as the retirement Monte Carlo) draw random paths. To make a run exactly reproducible, pass a seed:

Error model

Errors share one envelope — a stable machine-readable code plus a human message:

{
  "error": {
    "code": "missing_field",
    "message": "field \"current_age\" is required"
  }
}
CodeHTTPWhen
unauthorized401Missing or invalid API key.
invalid_json400Body isn't valid JSON, or contains an unknown field.
missing_field400A required field is absent (the message names it).
invalid_params400A value is out of its allowed range or internally inconsistent.
too_many_simulations400A simulation count exceeds the engine's cap.
no_solution400A root-finder couldn't converge for the given inputs.
method_not_allowed405Wrong HTTP method (calc endpoints are POST).
rate_limited429Over your per-minute budget — see Rate limits.
deadline_exceeded503The calculation hit its 25-second compute deadline.
internal_error500An unexpected server error (should be rare; please report).

Validation is strict and specific: unknown JSON fields are rejected (so typos surface immediately), and missing_field / invalid_params name the exact problem. Input caps keep every call bounded, so deadline_exceeded should never appear in normal use.

Versioning & deprecation

There are two version surfaces:

That makes engine changes detectable, not silent: watch engine_version (or a changed result_id for known inputs) to know exactly when an engine moved. A formal deprecation-notice policy lands with the changelog.

Idempotency

Because calculation POSTs are pure and side-effect-free, they are inherently idempotent: sending the same body twice returns the same result and the same result_id, and changes nothing on our side. Retry freely after a network error — no idempotency key required. (Stateful operations like billing, when they arrive, will use explicit idempotency keys.)

Informational, not financial advice

Every response includes a disclaimer. Numeratica returns calculation-engine output — it is not financial, tax, or investment advice, and it does not account for an individual's full circumstances. You are responsible for how results are presented to end users and for any advice layered on top.

"disclaimer": "Calculation engine output for informational purposes only; not financial advice."

Rate limits & quotas

Each API key has a per-minute request budget (a token bucket). Full keys get 200 requests/minute; free keys get 15/minute. Exceed it and the API returns 429 rate_limited with a Retry-After header (in seconds):

HTTP/1.1 429 Too Many Requests
Retry-After: 1

{ "error": { "code": "rate_limited", "message": "rate limit exceeded; retry after 1s" } }

Next