Nerdulator> put something in

Free beta

API

Give Nerdulator something. It tells you what it could be, in recognition order, and what derives from it. The same answer every time, with no model anywhere in the path.

No key, no account, no rate card during beta. Version 1, behaviour 4b93e0722875.

Or install it

These call this same API, so anything it recognises, they recognise.

  • Chrome Select text on any page, right click, Nerdulate.
  • VS Code Inspect a selection without leaving the editor.
  • Open VSX The same extension for VSCodium, Cursor and Windsurf.

Try it

This calls the live endpoint. Click a relation to follow the graph.

Try:

Thirty seconds

curl https://nerdulator.com/api/v1/inspect \
  -H "Content-Type: application/json" \
  -d '{"input":"1066"}'
{
  "input": "1066",
  "deterministic": true,
  "readings": [
    { "rank": 1, "reading": "integer", "name": "Number", ... },
    { "rank": 2, "reading": "year",    "name": "Year",   ... },
    { "rank": 3, "reading": "colour",  "name": "Colour", ... }
  ],
  "api_version": "1",
  "behaviour_version": "4b93e0722875"
}

Prefer a typed client? /api/v1/openapi.json describes all of this, and every generator and API client reads it.

You never choose an interpretation. That is the point: 1066 honestly is a number, a year and a colour, and which one you meant is not something a parser can know, so all three come back and you pick.

Endpoints

POST /api/v1/inspect

Every reading of an input, in recognition order, each with its facts and relations. Body: {"input": "…"}, or {"input": {"type": "text", "value": "…"}}.

POST /api/v1/inspect/{reading}

One reading in full, once you know which you want. An input that is not that kind of thing returns an empty list, not an error.

GET /api/v1/objects/{reading}/{canonical}

A node you already know the identity of, which is what a relation hands you. The two segments are the halves of an object id: integer:1066 is /objects/integer/1066. A GET rather than a POST, because a POST cannot be cached by anything in between and traversal should be cheap.

GET /api/v1/readings

The vocabulary: every reading id and every typed relation name.

GET /api/v1/openapi.json

The machine-readable description. Point Postman, a client generator or Swagger UI at it. Generated from the same constants the code validates against, so it cannot drift: the reading ids in the spec are the reading ids the API accepts, because they are the same array.

GET /api/v1/health

Runs a real inspection rather than reporting that the process is up.

The response shape

Identical for every reading, whatever the engine underneath. A UUID, a chess square and a balanced chemical equation all come back the same way, so you write the loop once:

for (const reading of result.readings) {
  reading.reading      // stable id, e.g. "integer"
  reading.id           // "integer:1066", a stable object identity
  reading.rank         // recognition order, NOT a probability
  reading.match        // "exact" | "normalised" | "fallback"
  reading.canonical    // "1066", the object's name

  for (const fact of reading.facts) {
    fact.label         // human-readable, may be reworded
    fact.value         // always a string
    fact.value_type    // integer | decimal | quantity | date | boolean | string
    fact.value_number  // present when the value IS a number
    fact.value_unit    // present for a quantity: "g/mol"
    fact.approximate   // true when it is not exact
  }

  for (const rel of reading.relations) {
    rel.relation       // typed name, or null
    rel.target.id      // "integer:1067"
    GET("/v1/objects/" + rel.target.reading + "/" + rel.target.canonical)
  }
}

rank is recognition order, not a probability. There is no confidence score here and there never will be: recognition is regular expressions and lookup tables, so a percentage would be inventing a number nothing computed. Rank 1 is the recogniser with the strongest claim under a fixed rule, and the same input always gives the same order. Where you need something sharper, match says how the reading was reached: exact parsed the input as given, normalised matched only after rewriting or deslugging it, and fallback is the catch-all text reading.

What is contractual: id, reading, canonical, match, value_type, relation names and the envelope. What is not: fact label and note text, which is written for people and gets reworded when a page reads better for it. Key off ids, not prose.

What deterministic means here

Within one behaviour version, the same input returns byte-identical output. The version is the boundary, and it is the thing to pin: it covers the engines and the response shape together, so any change a byte comparison would notice moves it. That is checked rather than promised: 55 inputs are run through the real engines and hashed, and the digest is the behaviour_version on every response and in the X-Nerdulator-Behaviour-Version header. A date would not do: five deploys in one day can all be “2026.09” while the answers move underneath you.

The cost is that clock-dependent facts are excluded. A year page says “960 years ago” to a reader, and that cannot be in a reproducible response, so it is dropped and deterministic: true says so. Add ?volatile=true if you want them, and the flag flips to false.

Responses carry an ETag. Because the output is deterministic, a conditional request costs nothing until the behaviour version moves; worth honouring if you are inspecting the same values repeatedly.

Not knowing is an answer

{ "input": "flibbertigibbet", "readings": [ { "reading": "text", "fallback": true, … } ] }

Nothing recognised it, so the only reading is the catch-all text analysis, marked fallback: true. It is returned rather than hidden, because a character count is a real answer, and flagged rather than presented plainly, because it is not recognition. Filter on the flag if you only want confident readings. Either way it is a 200: “we looked and we do not know” is not an error.

Limits

Sustained rate5/second
Burst20
Per hour1,000
Max input10 KB

Per caller, no key needed. Every response carries X-RateLimit-Limit, -Remaining and -Reset, plus X-Quota-* for the hourly window; a refusal is a 429 with Retry-After.

A revalidated request is refunded. If you send an If-None-Match and get a 304, nothing was computed and the token goes back. Caching therefore costs you nothing against the limit, which is the point of counting here rather than at the proxy, since a proxy cannot tell the two apart.

Errors

{ "error": { "code": "invalid_request", "message": "…", "request_id": "req_…" } }
  • 400 invalid_request: malformed body or missing input
  • 404 unsupported_reading: unknown reading id
  • 405 method_not_allowed: inspect is POST
  • 413 input_too_large: over 10 KB
  • 429 rate_limited: too fast, or hourly quota spent
  • 504 timeout: exceeded the per-request budget
  • 500 internal_error: our fault

Beta terms

The API is free while in beta, with no key required. Responses are deterministic and strongly cacheable; clients should honour the ETag and cache successful responses where appropriate, which also costs nothing against the rate limit.

Results are deterministic and reproducible, produced by the same engines that serve nerdulator.com. No AI is used to generate any of them.

If usage-based pricing is introduced later, or the free allowance is materially reduced, there will be reasonable notice first. Keys and quotas will arrive if and when the traffic warrants them; nothing you build against version 1 will break without a version 2.

74 readings

Stable ids. Engine names are provenance, not contract; an engine is an internal grouping and may be reorganised; these will not be renamed under you.

base64Base64
beaufortBeaufort force
binary-textBinary as text
cardsPlaying cards
checksummed-idChecksummed identifier
chess-squareChessboard square
chessboardChessboard
chordChord
codepointUnicode code point
colourColour
constantPhysical constant
coordinateCoordinate
countryCountry
cronCron expression
currency-amountCurrency amount
darts-checkoutDarts checkout
dateDate
decadeDecade
decimalDecimal
diceDice notation
elementChemical element
email-addressEmail address
entropyEntropy
equationAlgebraic equation
expressionArithmetic expression
f-numberF-number
formulaChemical formula
fractionFraction
gas-markGas mark
http-statusHTTP status code
integerInteger
ip-addressIP address or network
iso-speedISO speed
isotopeIsotope
jwtJSON Web Token
key-signatureKey signature
knight-distanceKnight's distance
language-tagBCP 47 language tag
mac-addressMAC address
magic-squareMagic square
matrixMatrix
measurementMeasurement
media-typeMedia type
monthMonth
musical-noteMusical note
ohms-lawOhm's law
paper-sizePaper size
percentagePercentage
pointsPoints
polyhedronPolyhedron
portNetwork port
quantityDimensioned quantity
radixNumber in another base
ratioRatio
reactionChemical equation
regexRegular expression
resistorResistor
scaleMusical scale
screen-resolutionScreen resolution
semverSemantic version
sequenceSequence
shapeShape
solar-system-bodySolar system body
statisticsStatistics
textText
time-of-dayTime of day
timestampTimestamp
tyre-sizeTyre size
uncertaintyUncertainty
unix-timeUnix timestamp
urlURL
uuidUUID
wire-gaugeWire gauge
yearYear

37 typed relations

An edge with a fixed meaning gets a name. Every other edge is still returned and still traversable, with relation: null and its label; an honest null beats an invented name you might act on.

next-numberThe integer one greater.
previous-numberThe integer one less.
doubleTwice this value.
halfHalf this value.
squareThis value multiplied by itself.
cubeThis value raised to the third power.
negationThe additive inverse.
absolute-valueThe magnitude, without sign.
next-primeThe smallest prime greater than this value.
previous-primeThe largest prime less than this value.
reciprocalOne divided by this value.
same-value-asThe identical quantity, written another way.
same-bits-asThe identical bit pattern, read as another type.
as-integerThis object read as a plain integer.
as-hexadecimalThis object written in base 16.
as-fractionThis value as a ratio of integers.
bit-widthThe number of bits this object occupies.
part-ofA larger object this one belongs to.
componentA constituent part of this object.
network-ofThe network an address belongs to.
host-inAn address within this network.
element-ofA chemical element appearing in this formula.
species-inA chemical species taking part in this reaction.
date-partThe calendar date component of an instant.
time-partThe clock component of an instant.
year-ofThe year a date or month falls in.
month-ofThe month a date falls in.
nextThe following item in a natural sequence.
previousThe preceding item in a natural sequence.
neighbourA nearby item in the same sequence, in no particular direction.
first-day-ofThe first day of a month, year or decade.
last-day-ofThe last day of a month, year or decade.
decade-ofThe decade a year belongs to.
invertedThe colour with every channel complemented.
greyscaleThe same colour with its saturation removed.
complementThe colour opposite on the hue wheel.
antipodeThe point diametrically opposite on the globe.

Built on the same engines as the site itself. Nothing is calculated twice, and nothing here is API-specific.