AnvilJSON utilities

Free · keyless · no logs

Small, honest JSON utilities for scripts, spreadsheets and side projects.

IDs, passwords, time zones, date differences, countdowns, unit conversions, cron schedules, bank holidays, working days, HTTP status codes, hashes, slugs and colour contrast. One GET away, with CORS on, no sign-up and no tracking.

$ curl https://api.oddlathe.com/v1/uuid?version=7
{
 "version": 7,
 "uuids": [
  "019a4b1e-7c2f-7d10-9f3a-2b6c1e8d4a51"
 ]
}
Try it live. Every endpoint below has a form. Change the values, press Send request and the real response appears underneath. Responses are pretty-printed; add compact to the query string for one line.

Identifiers

GET

/v1/uuid

#

Random UUIDs (v4) or time-ordered UUIDs (v7).

v7 UUIDs put a millisecond timestamp in the first 48 bits, so they sort by creation time and index well in databases. v4 is 122 random bits.

GET

/v1/ulid

#

ULIDs: sortable, 26-character IDs.

48-bit millisecond time + 80 random bits in Crockford base32. Lexicographically sortable and URL-safe.

GET

/v1/nanoid

#

Short URL-safe random IDs (21 chars, 126 bits).

Random

GET

/v1/password

#

Strong random passwords with entropy estimate.

Generated with the operating system's cryptographic random source. Every chosen character set is guaranteed to appear. Nothing is stored; responses are marked no-store. For anything important, generating locally is still best.

GET

/v1/random

#

Random integers, coin flips or dice rolls.

Uses a cryptographically secure generator, so results are unpredictable and unbiased.

Time

GET

/v1/time

#

Current time (or any moment) in a time zone, with next DST change.

Includes UTC offset, abbreviation, whether daylight saving is in force, ISO week and the next offset change (if the zone has one in the next two years).

GET

/v1/time/convert

#

Convert a local time between time zones.

A time with no offset is read as wall-clock time in 'from'. Times that don't exist (the hour skipped when clocks go forward) are flagged.

GET

/v1/timezones

#

All IANA time zone names with their current offset.

GET

/v1/cron/next

#

When will a cron schedule run next?.

Supports lists, ranges, steps, month and weekday names, 7 as Sunday, and the classic rule that when both day-of-month and day-of-week are restricted, either one matching is enough. Local times skipped by a DST change are left out; repeated times run once.

GET

/v1/cron/explain

#

Explain a cron schedule in plain English, with next runs.

Sibling of /v1/cron/next and of Tooltern's cron explainer: breaks each field down, writes one plain-English sentence, lists the next runs (DST-aware) and warns when day-of-month and day-of-week are ORed. Lists, ranges, steps, month/weekday names, 7 as Sunday, and @hourly/@daily/@weekly/@monthly/@yearly. Pure parsing; nothing is stored.

GET

/v1/date/diff

#

Age, duration and ISO week maths between two dates.

Difference between two moments: signed Y/M/D/H/M/S breakdown, total seconds, ISO 8601 duration, calendar age (decimal years + Y/M/D), ISO week numbers, weekdays, and whether the span crosses a daylight-saving change when a time zone is given. Accepts dates, datetimes, Unix timestamps or 'now'. Pure parsing; nothing is stored.

GET

/v1/countdown

#

Days until a date: sleeps, weekdays vs weekend days, time left, progress.

How long until (or since) a date, counted the ways people actually count: calendar days, sleeps (midnights passed in the chosen zone), weekdays (Mon–Fri) and weekend days among the days ahead, whole 24-hour days, inclusive days and days/hours/minutes left. Optional start gives a progress fraction and nights done/left; a clock-based day/night phase is included for each end. Named events cover Christmas, New Year, next Monday/Friday/Saturday, end of month and Halloween. Pure maths; nothing is stored.

Calendar

GET

/v1/holidays

#

Public / bank holidays for a year.

Calculated from the published rules (Easter by the Gregorian computus, 'first Monday' rules, substitute days) plus known one-off UK and Irish proclamations. Future one-off holidays appear only once announced, so check the official source for legal deadlines.

GET

/v1/holidays.ics

#

Subscribe to bank holidays in any calendar app (iCalendar feed).

Returns text/calendar (RFC 5545) with one all-day event per holiday, stable UIDs and a daily refresh hint. Paste the URL into Google Calendar (From URL), Apple Calendar (New Calendar Subscription) or Outlook (Subscribe from web). Same rules as /v1/holidays.

GET

/v1/holidays/next

#

The next few holidays from today (or a date).

GET

/v1/workdays

#

Count working days between two dates, or add working days to a date.

Working days are Monday to Friday, minus the region's public holidays when a region is given. Both ends of a range are included.

Convert

GET

/v1/units

#

Convert length, mass, temperature, data-size or data-rate units.

Convert a number between common units of length, mass, temperature or digital data size. Length uses metres as the base (m, km, cm, mm, mi, yd, ft, in, nmi). Mass uses kilograms (kg, g, mg, lb, oz, t for the metric tonne). Temperature accepts C, F and K with proper offset formulae. Data sizes distinguish SI (KB/MB/GB/TB = 1000) from IEC binary (KiB/MiB/GiB/TiB = 1024). Data rates convert between bits and bytes per second (Mbps, MB/s, MiB/s…; lower-case b = bits). Optional category disambiguates. Pure maths; nothing is stored.

GET

/v1/percent

#

Percentage calculator: of, is, change, apply, reverse.

Five percentage questions: what is X% of Y, X is what % of Y, percent change from A to B, apply ±% to a value, or recover the original before a % change. Pure maths; nothing is stored.

GET

/v1/battery

#

Power bank maths: charges after losses, size needed, flight rule, multi-gadget plan.

How many real charges a power bank gives once conversion losses (about a third, as heat) are counted. mAh is converted to Wh at the cell voltage, so bank and phone numbers become comparable. Also returns the bank size for N charges, the airline 100 Wh / 160 Wh rule and a rough refill time. mode=plan checks a whole list of gadgets from one bank (in list order or shared evenly) and says which one it runs out on and what size bank the list needs. Pure maths; nothing is stored.

GET

/v1/stream-data

#

Streaming data use: GB per hour, monthly allowance planner, film size, hours from GB.

How much mobile data streaming uses, with typical rounded figures (1 Mbps for an hour is 0.45 GB). mode=plan checks a month of habits against an allowance: GB a day, whether it lasts, the day it runs out, a safe daily budget and the single biggest saving from dropping one quality rung. Pass day and used for a mid-month check. mode=size gives a film or episode's size, mode=hours how long a number of GB lasts, mode=activities the whole ladder. Pure maths; nothing is stored.

GET

/v1/video-size

#

Video file size: MB for a length, what fits in free space, bitrate and ffmpeg commands for a target size.

How big a video is from a recording setting (or bitrate) and length: MB = Mbps x seconds / 8, with GiB as Windows shows it, whether it fits one FAT32 file and a typical 25 MB email limit. mode=fits says how many minutes of each setting fit in free space, mode=target gives the video bitrate (with 3% headroom), a sensible resolution and two-pass ffmpeg commands to land under a size limit, and mode=presets lists the typical rates. Pure maths; nothing is stored.

GET

/v1/input-lag

#

Input lag: ms from button press to picture, split into six parts, with the biggest fixes ranked.

How long it takes from pressing a button to seeing it on screen, using rounded typical figures: waiting for the next polling report, the trip over a cable or wireless, waiting for the game to read input, the game making the picture (1.5 to 3 frames), waiting for the screen's refresh and the screen's own processing. Returns typical, luckiest and unluckiest totals, frames late at 60 fps, a five-band verdict and the best single change per setting ranked by milliseconds saved. mode=compare puts two setups side by side (B uses b_ parameters) and mode=options lists every choice. Same model as the Tooltern input lag calculator. Pure maths; nothing is stored.

GET

/v1/broadband-need

#

Broadband speed needed: busiest-moment Mb/s down and up, plan tier, does your plan cope, download times.

How much broadband speed a household needs: adds up rounded typical Mb/s for everything happening at the busiest moment (4K and HD streams, video calls, online games, live streaming, cloud cameras, browsing, music), multiplies by headroom for Wi-Fi and busy evenings, and suggests the smallest common plan tier (30 to 2000 Mb/s) and upload tier that cover it. Pass plan_down / plan_up for a Plenty / Tight at busy times / Not enough verdict per direction. Also times a big download at your plan and 50 to 1000 Mb/s, in theory and at a realistic 70%. mode=download is just the time table; mode=options lists every figure. Same model as the Tooltern broadband speed calculator. Pure maths; nothing is stored.

Text

GET

/v1/lorem

#

Lorem ipsum placeholder text: paragraphs, sentences or words.

Placeholder text for mock-ups and fixtures. Ask for paragraphs, sentences or words; optionally start with the classic Lorem ipsum opener, wrap in HTML <p> tags, and pass a seed for a repeatable sample. Pure generation; nothing is stored.

GET

/v1/hash

#

Hash a short text (MD5, SHA-1, SHA-2, SHA-3, BLAKE2b).

Text travels in the URL, so don't hash secrets here. Use Tooltern's in-browser hash tool for anything private.

GET

/v1/slug

#

Turn a title into a clean URL slug.

Accents are folded to plain letters (é → e), apostrophes dropped, everything else that isn't a letter or digit becomes the separator.

Design

GET

/v1/qr.svg

#

QR code as SVG (usable as an <img src>).

Encode text into a QR code and return image/svg+xml. Same generator as Tooltern's /api/qr and /qr-code page. Text travels in the URL — don't put secrets here. Nothing is stored or logged.

GET

/v1/qr

#

QR code as JSON wrapping the SVG string.

Same QR as /v1/qr.svg, but the SVG is a string inside JSON — handy for scripts that already speak JSON. Prefer /v1/qr.svg when you can use it as an image URL.

GET

/v1/color

#

Colour formats (hex, RGB, HSL, OKLCH) and WCAG contrast.

Contrast uses the WCAG 2 relative-luminance formula; AA needs 4.5:1 for body text and 3:1 for large text, AAA needs 7:1 and 4.5:1.

Web

GET

/v1/http-status

#

Look up any HTTP status code: meaning, causes, fixes and retry advice.

Covers every registered code plus the non-standard ones people actually meet (nginx 444/499 and Cloudflare 520–526). Prefer GET /v1/http-status/404 or ?code=404. Each answer includes phrase, category, plain summary, when_you_see_it, what_to_do, related codes, retry advice and default cacheability.

GET

/v1/url/inspect

#

Link X-ray: who really owns a link, and its warning signs.

Finds the registrable domain (the real owner) with the full Public Suffix List, decodes international names, and lists warning signs with a severity: @ tricks, disguised IP addresses, look-alike letters from other alphabets, digits for letters, official words dressed up in front, redirect parameters, double file endings and more. Pure text analysis: the link is never fetched, resolved or stored.

GET

/v1/csp/parse

#

CSP header explainer: grade a Content-Security-Policy and check what it blocks.

Reads a Content-Security-Policy the way current browsers do: every directive explained in plain words, a grade (strong / okay / weak), findings with severity (unquoted keywords, missing semicolons, 'unsafe-inline', wildcards, missing object-src / base-uri / frame-ancestors, meta-tag traps), and an optional check that applies the fallback chains (script-src-elem → script-src → default-src, worker-src → child-src → …) plus nonce/hash/'strict-dynamic' rules. Pure text analysis: nothing is fetched or stored. Pass hash= to get 'sha256-…' / 'sha384-…' sources for an inline snippet.

GET

/v1/frame/check

#

Clickjacking headers: who may embed this page in a frame?.

Reads X-Frame-Options and CSP frame-ancestors the way current browsers do: every value explained in plain words, a grade (protected / okay / needs_work), findings (missing defence, ALLOW-FROM ignored, meta frame-ancestors ignored, broad *, CSP overrides XFO), and an optional check that answers whether a given parent may embed the page. Modern rule: when both headers are present, frame-ancestors wins. Pure text analysis: nothing is fetched or stored.

GET

/v1/text/inspect

#

Text X-ray: code points, graphemes, UTF-8/16 lengths and invisible characters.

X-rays a short string the way Unicode sees it: grapheme clusters vs code points vs UTF-8 bytes vs JavaScript string.length (UTF-16 units), every character named and labelled (emoji, zero-width joiner, skin tone, flag letter, control…), and findings for bidirectional overrides, invisible characters, look-alike letters from other alphabets, mixed scripts and characters that need 4-byte UTF-8. Optional form= returns a normalised copy; mojibake=1 previews the classic Windows-1252 misread. Pure text analysis: nothing is fetched or stored.

Meta

GET

/v1/status

#

Is this API healthy? Version, uptime and today's request count.