API

Documentation of a closed endpoint: compute calls return 403. The OpenAPI spec stays public.

A server-side port of the three exact-arithmetic tools -- same BigInt/fraction discipline, never floats. It runs on native BigInt at Cloudflare's edge, because this site is served entirely by a Cloudflare Worker (see Privacy). Until 7 August 2026 this paragraph said a PHP+BCMath port was “kept in sync as a fallback”. It was not, and the detail matters: the file exists in our repository, nothing routes to it, and it was last changed on 3 August — two days before the amplification fix in KSI-2026-002. So it still caps the reply at a flat 1,000 trajectory steps, which is the exact defect that incident is about, and it has no authentication of any kind. A fallback nobody can reach is not a fallback; one carrying a fixed bug and no key would have been worse than none. It is described here rather than quietly deleted because this page asserted its existence for days. Every response is JSON, and every response now carries its own real measured compute time (see "Performance, measured" below) rather than a speed claim you'd have to take on faith. Every endpoint is rate-limited at the edge (Cloudflare), independent of and stricter than the general site limit.

Basics

Base URL, format, limits

Base URLhttps://kodamaseclabs.com/api
FormatJSON in, JSON out (application/json)
AuthClosed — a client code we issue directly; nothing to read the docsThis row said “none” until 5 August 2026, then “a free key” until 7 August, and both are now wrong: the compute actions return 403 to everyone, checked before the key is looked up. This page and /openapi.json still need nothing, because reading what an endpoint does should never need permission.
Version1.2.0, unversioned URL by designDeliberately not /api/v1/...: there are three small, stable endpoints here, not a product with a deprecation cycle. If that ever changes, a real v2 path would be introduced alongside this one, not silently swapped in -- said explicitly rather than left for you to guess. The bump to 1.1.0 was the spec catching up with the key requirement; 1.2.0 is it catching up with the closure. Neither changed an endpoint.
Machine-readable spec/openapi.json (OpenAPI 3.1)Hand-written, and reconciled against the Worker by a check that runs before every deploy: the actions it documents, the security scheme, and the status codes it can return are compared with the deployed Worker and its access gate. That check exists because this file did drift — until 7 August 2026 it described a PHP+BCMath service, declared itself unauthenticated, and offered a 501 bcmath not enabled that no Worker can return. Importing it into Postman produced a client that got 401 on every call. Import it now and the Bearer field is there.
Rate limit20 requests / 60s per IP, enforced at the edgeSeparate from and stricter than the site-wide limit (120/60s). Exceeding it returns HTTP 429 with a Retry-After header. This is enforced, not a courtesy nudge like the client-side counter on the free tools -- these endpoints run real computation on our server, so unlike the in-browser tools there is real load to protect.
CORSOpen (Access-Control-Allow-Origin: *) -- it's public, read-only-in-effect data and computation, safe to call from any origin.
Performance, measured

Not a speed claim — a number every response actually carries

Every JSON response includes its own real computeTimeMs (and the same number again in a standard Server-Timing header, which Chrome/Firefox DevTools' Network panel already understands natively) — timed around the actual arithmetic only, not request parsing or JSON serialization, so it answers one question: how long did the exact-arithmetic engine itself take for this exact input. Nothing here is a marketing number; run the curl examples above yourself and read it straight off the response.

exact, 1/7 to 2000 digits (max allowed)~1msNative BigInt at the edge (Cloudflare Workers) -- median of 5 runs.
collatz, 1000-digit start (max allowed, hits the 5000-step cap)~20msWorst-case input size, not a typical one -- collatz(27) alone measures 0ms.
primality, 400-digit composite (max allowed), all 12 witnesses~7msprimality(97) alone measures ~5ms -- most of that is fixed overhead, not the arithmetic.

Why there is no second set of numbers here

This section used to compare two implementations: the Worker's native BigInt against a PHP+BCMath port, the second measuring meaningfully slower because BCMath does arbitrary-precision arithmetic on decimal strings where BigInt uses the CPU's own machine words. The comparison was sound arithmetic and a false premise — the PHP path was never live and stopped tracking the Worker on 3 August 2026 — so quoting it here invited you to compare a number we serve against a number nobody could get. One number, from the path that actually answered, is the accurate version.

Terms

Who can use this, for what

Educational / research useNot over HTTP any more — but every one of these tools still runs in your browserCoursework, papers, personal projects, classroom demos: this row said “no key needed”, then “free, but a key”, and now the endpoint is closed to the public altogether. What that costs you is less than it sounds — the identical fraction engine, parser and Miller–Rabin run client-side at /tools with no key, no limit and no request leaving your machine. The docs on this page and the OpenAPI description stay open to everyone.
Commercial useContact us first: @KodamaSecLabsKodamaSEC Labs Ltd is a non-commercial research lab and is not currently operating a commercial licensing programme -- said plainly here rather than left ambiguous. If that's still true when you ask, we'll tell you so directly.
POST /api?action=exact

Exact arithmetic calculator

Same engine as the calculator in the Observatory's free tools: fraction arithmetic all the way through, exact repeating decimals, exact continued fractions. + - * / and parentheses. Never a float, in the browser or here.

Bodyexpression (string, required), digits (int, 10–2000, default 300), cfTerms (int, 3–100, default 25)
curl example
curl -X POST https://kodamaseclabs.com/api?action=exact \
  -H "Content-Type: application/json" \
  -d '{"expression":"0.1 + 0.2"}'

→ {"input":"0.1 + 0.2","numerator":"3","denominator":"10","fraction":"3/10", ..., "computeTimeMs":1}
Response fieldTypeNotes
inputstringEcho of the parsed expression.
numerator, denominatorstringExact integers, as strings (arbitrary precision, not a JS/JSON number).
fractionstring"numerator/denominator", already reduced.
decimalobjectStructured, not a single rounded string: {sign, intPart, nonRepeating, repeating, terminating} -- repeating is "" when terminating is true.
continuedFractionarray of stringsContinued-fraction terms, e.g. ["3","7","16"] for 355/113.
continuedFractionTruncatedbooleantrue if cfTerms was hit before the expansion finished.
computeTimeMsintegerReal measured server-side time for this exact request, in milliseconds -- see "Performance, measured" below.
POST /api?action=collatz

Collatz trajectory

Any positive whole number, exact arbitrary-precision arithmetic (native BigInt, on the only path there is), up to 1000 digits. Trajectory capped at 5000 accelerated steps server-side same as the browser tool; the JSON response itself is capped to the first 1000 steps, and further limited so the reply stays a sensible size — each step carries two full decimal numbers, so the step budget scales down as those numbers grow (a 1000-digit start returns about 32 steps, not 1000). Either way stepsTruncated tells you (see stepsTruncated) to keep replies a sane size.

Bodystart (string, required -- positive whole number, up to 1000 digits)
curl example
curl -X POST https://kodamaseclabs.com/api?action=collatz \
  -H "Content-Type: application/json" \
  -d '{"start":"27"}'

→ {"input":"27","stepCount":41,"reachedOne":true,"maxJumpV2":5, ..., "computeTimeMs":0}
Response fieldTypeNotes
inputstringEcho of start.
stepCountintegerCompressed steps taken (each combines a Collatz step with dividing out every factor of 2).
reachedOnebooleanfalse only if the 5000-step server-side cap was hit before reaching 1.
maxJumpV2integerLargest single-step 2-adic valuation k seen in this trajectory.
stepsarray of objectsEach entry {from, to, k}, strings/integer. Truncated to the first 1000, and fewer when the numbers are large -- see stepsTruncated.
stepsTruncatedbooleantrue if the trajectory is longer than the 1000 entries returned.
computeTimeMsintegerReal measured server-side time for this exact request, in milliseconds -- see "Performance, measured" below.
POST /api?action=primality

Miller–Rabin primality trace

Same fixed 12-base Miller–Rabin as the browser tool, with an explicit confidence statement attached — proven zero false positives below 3.3×10²⁴ (Sorenson & Webster, 2015), a strong empirical claim above that, never a bare "yes" or "no". Up to 400 digits.

Bodynumber (string, required -- positive whole number, up to 400 digits), witnesses (int, 1–12, default 12)
curl example
curl -X POST https://kodamaseclabs.com/api?action=primality \
  -H "Content-Type: application/json" \
  -d '{"number":"97"}'

→ {"input":"97","composite":false,"reason":"passed all 12 witnesses tested -- proven prime, not probabilistic: n is below the bound (Sorenson & Webster, 2015) where these exact 12 bases are known to have zero false positives", ..., "computeTimeMs":5}
Response fieldTypeNotes
inputstringEcho of number.
compositebooleanfalse means "passed every witness tested," not "proven prime" -- see reason for the exact bound.
reasonstringPlain-language explanation, including the false-positive bound where relevant -- never a bare yes/no.
roundsarray of objectsOne entry per witness actually tested: {witness, passed, powers} -- powers is the intermediate modular-exponentiation trace for that round.
computeTimeMsintegerReal measured server-side time for this exact request, in milliseconds -- see "Performance, measured" below.
Errors

Status codes

400Bad input -- missing field, invalid expression, not a positive whole number, over a size limit. {"error": "..."} explains what.
404Unknown action.
405Compute endpoints (exact/collatz/primality) require POST.
429Rate limit exceeded -- see Retry-After.
501Removed on 7 August 2026: no deployed code can produce it. It described a missing PHP extension on a site that is a Worker. It had already been taken out of /openapi.json for the same reason, and stayed on this page for two days after — the two now agree, and a checker keeps them agreeing.
every error, same shape
HTTP/1.1 400 Bad Request
Content-Type: application/json

{"error": "Missing "expression"."}
Stated plainly

What's new here, and how it was verified

The exact-arithmetic endpoints are a server-side port of the same algorithm already running in your browser in the free tools -- same fraction engine, same recursive-descent parser (never eval), same Miller–Rabin square-and-multiply. This paragraph said “PHP + BCMath” until 7 August 2026, which stopped being true when the site moved to a Cloudflare Worker and native BigInt; the same wrong claim was in the OpenAPI file and is corrected there too. It was actually run and checked, not just reasoned about: real execution against the same reference cases used throughout this site (0.1+0.2=3/10, 355/113's continued fraction, Collatz(27), Miller–Rabin cross-checked against independent trial division for every n from 2 to 2999), plus a numeric-value comparison against the browser engine on the same inputs, plus real HTTP requests against these exact endpoints. If a result here ever disagrees with what the free tools give you for the same input, that's a real bug worth reporting -- please do.

There is no longer a form here

Closed on 7 August 2026. There was an application form on this page until that date: one dropdown, one checkbox, an optional client code, and a proof-of-work your browser solved before a key was issued. It is gone, and so is the endpoint behind it — ?action=apply returns 403 before it looks at anything you send. We are not leaving a form that would take your input and refuse it.

Why it went. That form was the only thing on this site that stored anything resembling a contact detail. It never took a name or an email, but it stored a keyed hash of a handle, and a stable identifier derived from something of yours is still a stable identifier. With the compute endpoints closed there was nothing left for it to be for, so it was removed rather than kept collecting for a service nobody can call. What that means for the data protection notice is written out at /privacy, section B0.

Who can call it now. Auditors and experts engaged and paid by KodamaSEC Labs Ltd, using a client code issued to them directly. There is no self-service path to that and no queue to join, and we would rather say so than run an application form whose answer is always no.

What did not close. Everything on this site that computes does it in your own browser and is untouched: the exact-arithmetic tools, The Notebook, Labs and Factory. None of them has ever called this API. The documentation on this page and /openapi.json also stay open, because reading what an endpoint does should not require permission even when calling it does.

If you hold a key issued before 7 August 2026: it no longer computes anything, and you can still see what is recorded against it and ask for it to be erased. List what you hold.

Limits, and the request that produced them

Every limit below exists because a specific request made it necessary, and the numbers are the measured ones rather than round figures chosen to sound careful.

The request: on 5 August 2026, during an audit of this endpoint, we sent POST /api?action=collatz with a start value of 1000 nines — the largest input the documented limit allows.

The cause, stated plainly because it is the useful part: the response cap counted steps, not bytes. Each step carries from and to as full decimal strings, so a thousand steps is a few kilobytes for a ten-digit start and two megabytes for a thousand-digit one. The limit was right for what someone types into the demo and wrong for what someone sends deliberately.

What changed: the step budget now scales with the size of the numbers involved — about 64,000 digits of trajectory in total. Ordinary inputs still return the full 1000 steps; a 1000-digit start returns about 32. stepsTruncated tells you either way. That exact request no longer produces that response, and it is documented here rather than quietly patched, because an endpoint that reports its own limits is easier to trust than one that just has them.

A monthly ceiling as well. This API is free but not open: it needs a key, and the key carries a shared daily allowance, so its cost is bounded twice over — once per applicant and once for the whole site. It is capped at an estimated €40 of compute per calendar month; past that it returns 503 with the spend so far and resets on the 1st. That estimate comes from a stated model — Cloudflare’s published unit prices for requests, CPU-milliseconds and KV operations — and it is our own arithmetic, not a bill from anyone. The browser tools at /tools and the exhibits at /kodama-house are unaffected by it: they compute on your machine and cost us nothing at all.