Duo Data Utilities: IBAN, VAT, ISIN Validation API

33 pay-per-call data utilities for agents: IBAN, ISIN, VAT/tax ID and GTIN validation, time zones and calendars, text, URL/JWT parsing, geo, chain primitives, reference tables. $0.05 per tool call via x402 (USDC on Base); no account or API key.

Hosted MCP Server

npx add-mcp 'https://api.duoleads.com/mcp'

Installs into Claude Code, Codex, Cursor and more

Documentation

Duo Data Utilities: documentation

Client libraries: duo-data-utilities on npm (TypeScript, pays per call with your own wallet) and GitHub (also a Python client and MCP configs).

How to call

Every route is paid per call over x402 v2: HTTP 402 plus USDC on Base (CAIP-2 eip155:8453). An unpaid request returns 402 with a base64 PAYMENT-REQUIRED header describing the price. Sign an EIP-3009 authorization for that amount and retry the same request with a base64 PAYMENT-SIGNATURE header; the 200 response carries a base64 PAYMENT-RESPONSE settlement receipt. Requests that are malformed (400), unknown (404), sent with the wrong method (405) or too large (413) are rejected before the paywall and are never charged.

Methods: every route is a GET with query parameters. It also accepts POST with the same parameters as a JSON object body (numbers and booleans may be JSON values), or the same query string with an empty body; price, checks and answer are the GET's.

Quick start

Try it from a terminal: npx agentcash try https://api.duoleads.com

Python (requests):

# pip install "x402[requests,evm]"
import os
from eth_account import Account
from x402 import x402ClientSync
from x402.http.clients import x402_requests
from x402.mechanisms.evm import EthAccountSigner
from x402.mechanisms.evm.exact.register import register_exact_evm_client
client = x402ClientSync()
register_exact_evm_client(client, EthAccountSigner(Account.from_key(os.environ["PRIVATE_KEY"])))  # a Base wallet holding USDC
session = x402_requests(client)  # pays the 402 and retries for you
r = session.get("https://api.duoleads.com/v1/id/iban?iban=NL91+ABNA+0417+1643+00", timeout=30)
print(r.status_code, r.json())

TypeScript (fetch):

// npm i @x402/fetch @x402/evm viem
import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
import { ExactEvmScheme } from "@x402/evm/exact/client";
import { privateKeyToAccount } from "viem/accounts";
const account = privateKeyToAccount(process.env.PRIVATE_KEY as \`0x${string}\`); // a Base wallet holding USDC
const pay = wrapFetchWithPayment(fetch, new x402Client().register("eip155:8453", new ExactEvmScheme(account)));
const res = await pay("https://api.duoleads.com/v1/id/iban?iban=NL91+ABNA+0417+1643+00", { signal: AbortSignal.timeout(30_000) });
process.stdout.write(\`${res.status} ${JSON.stringify(await res.json())}\n\`);

Most paid answers take 1-5 s, some up to about 20 s: give your HTTP client a timeout of at least 30 s. The payment settles only after the answer is ready, so a call that fails before that is never charged.

A bare URL without any parameters answers with the 402 (that is how discovery probes see the price); a request with missing or malformed parameters is a free 400 that says what would be accepted.

Every 200 response is {ok, route, version, data, meta}. Errors are {ok:false, error:{code, param, message, expected}} with codes MISSING_PARAM, INVALID_PARAM, UNSUPPORTED_VALUE (400), INPUT_TOO_LARGE (413), METHOD_NOT_ALLOWED (405), NOT_FOUND (404), PAYMENT_REQUIRED and PAYMENT_FAILED (402), INTERNAL (500), SERVICE_UNAVAILABLE (503, the payment facilitator was unreachable: retry after Retry-After). None of these is charged. Unknown query parameters are ignored.

Routes

Identifiers and check digits

GET | POST /v1/id/national R05 v1.0.0

VAT number format and checksum (no VIES lookup), tax ID and national ID validator: 23 countries. VAT, tax ID and national ID validator: check a national identity, tax or company registration number against its country's official checksum rule. Covers 23 countries including NL BSN, ES NIF/NIE/CIF, IT codice fiscale, FR SIREN/SIRET, DE Steuer-ID, BE/PL/CZ national numbers, SE/NO/DK/FI personal numbers, BR CPF/CNPJ, AU ABN/TFN, UK NINo, IE PPS, US NPI/EIN. Structure and check digit only, no registry lookup; the number is never stored (logs keep only its length and character types).

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, id, identifiers, validation, checksum.

ParameterTypeDescription
countrystring, requiredISO 3166-1 alpha-2 country code, case-insensitive. One of the 23 supported countries; the United Kingdom is accepted as UK or GB (the response echoes what you sent). Accepted: one of the 23 supported ISO 3166-1 alpha-2 codes.
kindstring, requiredIdentifier type for that country, e.g. bsn, nif, cf, cpf; vat picks the country's VAT number (NL btw, BE vat, DE ustid, FR tva, IT piva, PL nip, AT uid, CH uid, IE vat). Accepted: an identifier kind supported for the country, or vat.
valuestring, requiredThe identifier. Separators (space. - /) are stripped before checking. Accepted: at most 64 characters.

Output (data): valid (boolean), country, kind, normalised (string|null), formatted (string|null), reason (null | length | charset | checksum | structure | reserved_range: a number in a range the issuer reserves or never assigned, e.g. CA SIN starting 0 or 8, UK NINO prefixes BG GB KN NK NT TN ZZ, US EIN unassigned prefixes, NZ IRD outside 10,000,000-150,000,000), algorithm (e.g. elfproef-11, mod-97-10, luhn), derived (object of facts the number encodes, {} when none: birth_date (YYYY-MM-DD) and sex (M|F) for IT cf, SE personnummer, PL pesel, BE rrn, NO fodselsnummer, DK cpr, FI hetu, CZ rc and SK rc; birthplace_code for IT cf; century_assumed (boolean) for SE personnummer, true when a 10-digit form forced the century to be inferred; for BE, NO, DK, FI, CZ and SK the number itself fixes the century (BE by the check digits, NO by the individual number, DK by the sequence digit, FI by the century sign, CZ/SK by the digit count). birth_date is omitted when the encoded date is not a real date, and for NO FH-numbers). FR nir carries no day and no century, so its derived holds sex, birth_year_yy (2 digits), birth_month (1-12, or null for special codes) and department_code instead of birth_date. normalised is the number without separators (SE personnummer keeps a 12-digit input's century and a + sign).

Example: https://api.duoleads.com/v1/id/national?country=NL&kind=bsn&value=111222333 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/id/gs1 R12 v1.0.0

EAN/UPC barcode validator: GTIN, EAN-13, UPC-A (GTIN-12), GTIN-8/14, GLN and SSCC check digits. GTIN barcode validator: validate and convert GS1 identifiers: GTIN-8, GTIN-12 (UPC-A), GTIN-13 (EAN-13), GTIN-14, GLN and SSCC. Returns the check-digit verdict, the computed correct check digit, the GTIN-14 form with its indicator digit, and conversion between GTIN-8, -12, -13 and -14. No company-prefix split is returned: GS1's prefix-length table is no longer public data. Also computes a missing check digit from a partial code. Structure only, no product database.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, id, identifiers, validation, barcodes.

ParameterTypeDescription
openum, optional, default validatevalidate (default), checkdigit (compute the missing final digit) or convert. Accepted: validate, checkdigit, convert.
valuestring, requiredGS1 code, digits with optional spaces or hyphens. For op=checkdigit, omit the final digit. Accepted: 8, 12, 13, 14 or 18 digits.
toenum, optionalTarget format. Required when op=convert. Accepted: gtin8, gtin12, gtin13, gtin14.

Output (data): valid, type (gtin8|gtin12|gtin13|gtin14|gln|sscc|unknown), normalised, check_digit (the digit that should be there; string|null, null when the length is unsupported), check_digit_ok, gtin14 (zero-padded; string|null, null for sscc and unsupported lengths), indicator (string|null), reason (string|null), also_valid_as (present only for a gtin13, which is also a valid gln: [gln]; also after op=checkdigit and op=convert that produce a gtin13), converted (op=convert only: the value in the requested format; null when the input's check digit is wrong, in which case valid is false, reason is checksum and type and normalised are those of the input). The GS1 company-prefix boundary is not returned.

Example: https://api.duoleads.com/v1/id/gs1?value=5901234123457 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/id/security R21 v1.0.0

ISIN validator plus CUSIP, SEDOL and FIGI check-digit validation; builds an ISIN from an NSIN. ISIN validator plus CUSIP, SEDOL and FIGI check digits: validate the check digit of a financial security identifier (ISIN per ISO 6166). Returns the verdict, the computed correct check character, and for an ISIN the issuing country prefix and the embedded NSIN. Also builds an ISIN from a country code plus a 9-character NSIN. Format and checksum only, no security master lookup.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, id, identifiers, validation, finance.

ParameterTypeDescription
openum, optional, default validatevalidate (default) or build-isin. Accepted: validate, build-isin.
valuestring, optionalISIN, CUSIP, SEDOL or FIGI to validate. Required when op=validate. Accepted: an alphanumeric security identifier of at most 24 characters.
countrystring, optionalISO 3166-1 alpha-2 code or XS. Required when op=build-isin. Accepted: at most 16 characters.
nsinstring, optionalExactly 9 alphanumeric characters. Required when op=build-isin. Accepted: exactly 9 alphanumeric characters.

Output (data): validate: valid, type (isin|cusip|sedol|figi|unknown), normalised, check_char (string|null, null when the type is unknown), check_char_ok, country (ISIN only; string|null), nsin (ISIN only; string|null), reason (string|null, null when valid), algorithm (string|null, null when the type is unknown). build-isin: isin plus the same fields.

Example: https://api.duoleads.com/v1/id/security?value=US0378331005 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/id/iban R32 v1.0.0

IBAN validator: length, mod-97 check digits, bank/branch/account breakdown (89 countries). IBAN validator: validate an IBAN's length for its country, permitted character classes per field, and the ISO 7064 mod-97-10 check digits. Returns the verdict with a specific failure reason, the electronic and print formats, and the decomposed bank code, branch code and account number according to that country's registered layout. Covers the 89 countries of the SWIFT IBAN registry. Structure and checksum only, it does not confirm the account exists.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, id, identifiers, banking, validation.

ParameterTypeDescription
ibanstring, requiredThe IBAN. Spaces and non-breaking spaces are stripped; lowercase is accepted and uppercased. Accepted: an IBAN of at most 64 characters.

Output (data): valid (boolean), iban (electronic format, no spaces, uppercase), iban_print (grouped in fours), country (first two characters), check_digits, bban, parts ({bank, branch, account}, each string|null per the registry layout for the country; all null when the length, structure or country is wrong), length (actual), expected_length (registry length, null for an unknown country), reason (null | country_unknown | length | charset | structure | checksum, checked in that order), algorithm (always mod-97-10). A failed verdict is a 200, never a 400.

Example: https://api.duoleads.com/v1/id/iban?iban=NL91+ABNA+0417+1643+00 (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "iban-registry",
      "version": "ibantools 4.5.4, field layout schwifty 2026.7.3",
      "published": "2026-04-10",
      "attribution": "IBAN registry via ibantools (MIT); field offsets via schwifty (MIT); underlying data: SWIFT IBAN Registry, public",
      "license": "MIT"
    }
  ]
}

GET | POST /v1/id/iban-build R24 v1.0.0

IBAN generator: build an IBAN from country and BBAN or bank/branch/account, computing check digits. IBAN generator: construct an IBAN from a country code and the domestic account parts, computing the ISO 7064 mod-97-10 check digits. Takes a single BBAN string or named parts (bank code, branch code, account number); digit fields are left-padded with zeros to the country's registered widths. Returns the IBAN in electronic and print formats with its bank, branch and account parts. Covers the 89 SWIFT registry countries. Named parts work only where they span the whole BBAN; else pass the BBAN.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, id, identifiers, banking, checksum.

ParameterTypeDescription
countrystring, requiredISO 3166-1 alpha-2 country code in the SWIFT IBAN registry, case-insensitive. Accepted: an ISO 3166-1 alpha-2 code in the IBAN registry.
bbanstring, optionalThe whole domestic account number (BBAN), alphanumeric. Use this or bank plus account. Accepted: an alphanumeric BBAN of at most 34 characters.
bankstring, optionalBank code. Requires account. Accepted: a bank code of at most 16 characters.
branchstring, optionalBranch code, for countries whose layout has a branch field. Accepted: a branch code of at most 16 characters.
accountstring, optionalAccount number. Requires bank. Accepted: an account number of at most 32 characters.

Output (data): iban (electronic format, no spaces), iban_print (grouped in fours), country, check_digits, bban, parts ({bank, branch, account} as parsed by the registry layout, each string|null: null where the country's registry layout defines no such field, e.g. branch for most countries and all three for HN), length, valid (always true on success: a built IBAN is valid by construction). Named parts are accepted only for countries where bank, branch and account together cover the whole BBAN (56 of 89); for the others (e.g. FR, ES, IT, BE with national check digits) pass bban. Digit fields shorter than their width are left-padded with zeros; letter fields must be exact.

Example: https://api.duoleads.com/v1/id/iban-build?country=NL&bank=ABNA&account=0417164300 (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "iban-registry",
      "version": "ibantools 4.5.4, field layout schwifty 2026.7.3",
      "published": "2026-04-10",
      "attribution": "IBAN registry via ibantools (MIT); field offsets via schwifty (MIT); underlying data: SWIFT IBAN Registry, public",
      "license": "MIT"
    }
  ]
}

Dates, times and zones

GET | POST /v1/time/zone R29 v1.0.0

Timezone converter: instant to local time in an IANA time zone and back, with UTC offset and DST state. Timezone converter: convert an instant to wall-clock time in a named IANA time zone, or a wall-clock time in a zone back to an instant. Returns the local date and time, the UTC offset in ±HH:MM and seconds, the zone abbreviation, whether DST is in effect, the ISO week date, and the day of year. Handles the ambiguous and skipped local times at DST boundaries explicitly rather than guessing.

Price: $0.05 per call. Deterministic only when the query fixes the instant; otherwise it depends on the current time and is not cached. Tags: no-api-key, time, timezones.

ParameterTypeDescription
zonestring, requiredIANA time zone id, e.g. Europe/Amsterdam. Accepted: an IANA time zone id, e.g. Europe/Amsterdam.
instantstring, optionalRFC 3339 timestamp or integer Unix seconds/milliseconds. Defaults to now. Mutually exclusive with local. Accepted: RFC 3339 timestamp or integer epoch.
localstring, optionalWall-clock time YYYY-MM-DDTHH:MM[:SS] in zone, converted back to an instant. Mutually exclusive with instant. Accepted: YYYY-MM-DDTHH:MM[:SS].
ambiguousenum, optionalOnly with local: which instant a repeated local time maps to. Default earlier. Accepted: earlier, later, reject.

Output (data): zone, instant (RFC 3339 UTC), epoch_ms, local (YYYY-MM-DDTHH:MM:SS), offset (+HH:MM), offset_seconds, abbreviation, dst, weekday, iso_week {year, week, weekday}, day_of_year, ambiguity (null|repeated|skipped), resolution (null|the ambiguous mode applied), gap (true when a skipped local time was moved forward by the gap length). abbreviation is the runtime (Intl en-US) short name, e.g. GMT+2 or EDT.

Example: https://api.duoleads.com/v1/time/zone?zone=Europe%2FAmsterdam&instant=2026-10-25T00%3A30%3A00Z (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/time/dst R26 v1.0.0

DST transitions: next daylight-saving time changes for an IANA time zone. DST transitions: list the daylight-saving time changes for an IANA time zone over a date range: the exact instant of each shift, the offset before and after, and whether local clocks jump forward or back. Returns the current offset and DST state, and the next transition from a given instant. Zones without DST return an empty transition list rather than an error.

Price: $0.05 per call. Deterministic only when the query fixes the instant; otherwise it depends on the current time and is not cached. Tags: no-api-key, time, timezones, dst.

ParameterTypeDescription
zonestring, requiredIANA time zone id. Accepted: an IANA time zone id, e.g. Europe/Amsterdam.
fromstring, optionalStart of the range: RFC 3339 or YYYY-MM-DD. Default now. Accepted: RFC 3339 timestamp or YYYY-MM-DD.
yearsinteger, optional, default 2Length of the range in years, 1-10. Default 2. Accepted: integer 1-10.

Output (data): zone, observes_dst, current {offset, offset_seconds, abbreviation, dst}, next (first transition after from, or null), transitions [{at, local_before, local_after, offset_before, offset_after, delta_seconds, direction forward|back, abbreviation_before, abbreviation_after}].

Example: https://api.duoleads.com/v1/time/dst?zone=Europe%2FAmsterdam&from=2026-01-01&years=1 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/time/business-days R31 v1.0.0

Business days calculator: add or count working days with your weekend mask and holiday list. Business days calculator with a caller-supplied calendar: add or subtract N working days from a date, or count the working days between two dates. The weekend is a weekday mask (Friday-Saturday and Sunday-only weeks work) and holidays are an explicit date list, so nothing depends on a stale holiday table. Returns the result date, the day count and the skipped dates with reasons. The skipped list is capped at 1,000 entries (skipped_truncated flags it); skipped_total is always exact.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, time, calendar, business-days.

ParameterTypeDescription
openum, optional, default addadd (default) N business days to from, or count business days between from and to. Accepted: add, count.
fromdate, requiredStart date, YYYY-MM-DD. Accepted: a calendar date as YYYY-MM-DD.
daysinteger, optionalBusiness days to add, -3650 to 3650. Required when op=add. Accepted: integer between -3650 and 3650.
todate, optionalEnd date YYYY-MM-DD, may precede from. Required when op=count. Accepted: a calendar date as YYYY-MM-DD.
weekendstring, optional, default sat,sunComma-separated weekday names or ISO numbers. Default sat,sun. Empty string = no weekend. Accepted: comma-separated weekday names (mon..sun) or ISO numbers 1-7.
holidaysstring, optionalComma-separated YYYY-MM-DD holiday dates. Accepted: comma-separated YYYY-MM-DD dates, at most 2048 characters.
inclusiveenum, optional, default startFor op=count: start (default, half-open [from, to)), both or neither. Accepted: start, both, neither.

Output (data): add: result (YYYY-MM-DD), from, days, calendar_days_spanned, skipped [{date, reason weekend|holiday, weekday}] (first 1,000), skipped_total, skipped_truncated. count: business_days, calendar_days, weekend_days, holiday_days, holidays_matched, direction (forward|backward) (holidays on a weekend are reported as weekend, never as holiday). count is half-open [from, to) unless inclusive says otherwise; when to precedes from the same interval is counted backwards and business_days is still a non-negative count. skipped is in the order the dates were traversed and lists at most 1,000 entries; skipped_total is the full count and skipped_truncated is true when the list was cut (the cap only binds for days beyond roughly 1,400 working-day skips, e.g. days near 3,650 with a two-day weekend); result, calendar_days_spanned and skipped_total are always exact.

Example: https://api.duoleads.com/v1/time/business-days?from=2026-12-24&days=5&holidays=2026-12-25%2C2026-12-26%2C2027-01-01 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/time/rrule R19 v1.0.0

RRULE expander: RFC 5545 recurrence rule to concrete occurrence dates. RRULE expander: expand an RFC 5545 recurrence rule into concrete occurrence timestamps. Accepts an RRULE string with DTSTART, an IANA time zone, and optional EXDATE and RDATE lists, and returns up to 200 occurrences as both local wall-clock times and UTC instants. Supports FREQ, INTERVAL, COUNT, UNTIL, BYDAY, BYMONTHDAY, BYMONTH, BYSETPOS and WKST. Occurrences moved by a DST gap carry gap: true. Rules needing over 50,000 candidate evaluations are rejected.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, time, calendar, recurrence.

ParameterTypeDescription
rrulestring, requiredRFC 5545 RRULE, e.g. FREQ=MONTHLY;BYDAY=-1FR;COUNT=6. Accepted: at most 512 characters.
dtstartstring, requiredFirst occurrence, YYYY-MM-DDTHH:MM:SS local to zone. Accepted: YYYY-MM-DDTHH:MM:SS.
zonestring, requiredIANA time zone id. Accepted: an IANA time zone id, e.g. Europe/Amsterdam.
countinteger, optional, default 20Maximum occurrences to return, 1-200. Default 20. Accepted: integer 1-200.
afterstring, optionalRFC 3339 instant; skip occurrences before it. Accepted: RFC 3339 timestamp.
exdatestring, optionalComma-separated local datetimes to exclude. Accepted: at most 1024 characters.
rdatestring, optionalComma-separated local datetimes to add. Accepted: at most 1024 characters.

Output (data): occurrences [{local, instant, epoch_ms, offset, dst, gap (present, true, only when a DST gap shifted the occurrence forward)}], count, truncated, rule (the parsed rule: freq, interval (integer), wkst, and, when given, count, until, byday [], bymonthday [], bymonth [], bysetpos [], byhour [], byminute [], bysecond []), zone.

Example: https://api.duoleads.com/v1/time/rrule?rrule=FREQ%3DMONTHLY%3BBYDAY%3D-1FR%3BCOUNT%3D3&dtstart=2026-01-01T09%3A00%3A00&zone=Europe%2FAmsterdam (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/time/calendar R18 v1.0.0

Calendar converter: Gregorian to Hijri, Hebrew, Japanese era, Persian and more, plus Easter date. Calendar converter: convert a Gregorian date to other calendar systems: Islamic (both the tabular civil calendar and the Umm al-Qura variant), Hebrew, Japanese imperial era, Republic of China, Buddhist and Persian. Also computes Easter Sunday for a year in both the Gregorian and Julian reckonings. Uses the calendar support built into the runtime, with the algorithm named in every response.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, time, calendar.

ParameterTypeDescription
openum, optional, default convertconvert (default) a Gregorian date, or easter for a year. Accepted: convert, easter.
datedate, optionalGregorian date YYYY-MM-DD. Required when op=convert. Accepted: a calendar date as YYYY-MM-DD.
tostring, optionalComma-separated calendar ids: islamic, islamic-umalqura, hebrew, japanese, roc, buddhist, persian. Default all. Accepted: islamic, islamic-umalqura, hebrew, japanese, roc, buddhist, persian.
yearinteger, optionalYear for op=easter, 326-9999. Accepted: integer 326-9999.
riteenum, optional, default westernEaster reckoning: western (default) or eastern. Accepted: western, eastern.

Output (data): convert: gregorian, calendars {<id>: {year, month, month_name, day, era, formatted, algorithm}}, and unavailable {<id>: reason} when no to was given and a calendar is undefined for the date. Gregorian input covers years 1-9999 (proleptic Gregorian, so month and month_name always agree with the date given); every field is computed for the whole range, never clamped. A calendar that is undefined for the date is rejected with 400 INVALID_PARAM on date when named in to, and listed in unavailable when to is omitted: japanese before Meiji 1 (1868-10-23) and islamic-umalqura outside its published table (1300-1600 AH, 1882-11-12 to 2174-11-25). islamic and persian are proleptic before their epoch (year 0 and negative years, as ICU computes them). easter: year, rite, date (always the Gregorian date), gregorian_date, julian_date (eastern rite only: the date in the Julian calendar), algorithm (anonymous-gregorian|meeus-julian). islamic is the tabular civil calendar; Hebrew months are numbered from Tishri = 1.

Example: https://api.duoleads.com/v1/time/calendar?date=2026-09-28&to=islamic%2Chebrew%2Cjapanese (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

Text and Unicode

GET | POST /v1/text/slug R06 v1.0.0

Slug generator: Unicode-aware URL slug with transliteration. Slug generator: turn arbitrary text into a URL-safe slug. Decomposes accents, transliterates German umlauts, Scandinavian and Turkish letters, the ligatures that lose meaning under plain NFD, and Cyrillic (Russian, Ukrainian, Belarusian, Bulgarian, Serbian, Macedonian; language from lang or inferred from the letters). Lowercases, collapses separators, truncates on a word boundary. Returns the slug plus what was removed.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, text, unicode, slug.

ParameterTypeDescription
textstring, requiredText to slugify, at most 2048 characters. Accepted: at most 2048 characters.
separatorenum, optional, default -Separator: - (default), _,. or empty. Accepted: -, _,. or empty.
maxinteger, optional, default 96Maximum slug length 1-512, default 96. Truncates at the last complete word. Accepted: integer 1-512.
caseenum, optional, default lowerlower (default), preserve or upper. Accepted: lower, preserve, upper.
langstring, optionalISO 639-1 code for locale-sensitive folding (de: ü->ue) and the Cyrillic table (ru, uk, be, bg, sr, mk). Default locale-neutral; for Cyrillic the language is then inferred from letters unique to Ukrainian, Belarusian, Serbian or Macedonian, else Russian BGN/PCGN letters with ISO 9 (accents folded) for the rest. Accepted: an ISO 639-1 language code.

Output (data): slug, length, truncated, source_length, transliterated [{from, to}] for every mapped character, removed (characters dropped entirely, deduplicated; includes the Cyrillic soft and hard signs and the Ukrainian apostrophe). Cyrillic: Ukrainian follows the 2010 national system (Київ Україна -> kyiv-ukraina); Belarusian, Bulgarian, Serbian and Macedonian use ASCII slug tables; Russian letters use BGN/PCGN (Привет -> privet); other Cyrillic letters use ISO 9:1995 without diacritics.

Example: https://api.duoleads.com/v1/text/slug?text=Cr%C3%A8me+Br%C3%BBl%C3%A9e+%E2%80%94+%C3%86r%C3%B8sk%C3%B8bing%2C+Stra%C3%9Fe+42&lang=de (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/text/transliterate R16 v1.0.0

Cyrillic transliteration to Latin (ISO 9:1995, BGN/PCGN Russian). Cyrillic transliteration to Latin using a named standard: ISO 9:1995 (one-to-one, with diacritics, covering the full standard: Russian, other Slavic, historic and non-Slavic Cyrillic letters) or BGN/PCGN, which is the Russian system only (Ukrainian, Serbian and other letters are passed through unmapped). Returns the transliteration, the source script, the standard, the mapped fraction and the unmapped characters. Other scripts are rejected with UNSUPPORTED_VALUE.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, text, unicode, transliteration.

ParameterTypeDescription
textstring, requiredText to transliterate, at most 2048 characters. Accepted: at most 2048 characters.
fromstring, optional, default autoSource script name (cyrillic), or auto (default). Accepted: cyrillic or auto.
standardstring, optionalRomanisation standard: iso-9 (default; all ISO 9:1995 Cyrillic letters) or bgn-pcgn (BGN/PCGN Russian system, Russian letters only). Accepted: iso-9 or bgn-pcgn (Russian letters only) for cyrillic.
caseenum, optional, default preservepreserve (default), lower or upper. Accepted: preserve, lower, upper.

Output (data): result, source_script (Unicode script name; Latin when the text has no Cyrillic, which is returned unchanged), standard (string: the validated standard, iso-9 by default; on text with no Cyrillic it is echoed although no character needed converting), coverage (0-1 fraction of non-ASCII characters mapped), unmapped (characters passed through). iso-9 maps every letter of ISO 9:1995 (Russian, Ukrainian, Belarusian, Serbian, Macedonian, Bulgarian, historic and non-Slavic Cyrillic, e.g. і -> ì, ѣ -> ě, ә -> a̋, қ -> k̦); a base letter plus combining marks is one unit. bgn-pcgn is the Russian system only: other Cyrillic letters are returned unmapped and lower coverage.

Example: https://api.duoleads.com/v1/text/transliterate?text=%D0%A9%D1%83%D0%BA%D0%B0&standard=iso-9 (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "romanisation-tables",
      "version": "ISO 9:1995 (full Cyrillic repertoire) and BGN/PCGN Russian system",
      "published": "2026-09-29",
      "license": "character correspondences (facts); see sources/translit.md"
    }
  ]
}

GET | POST /v1/text/unicode R17 v1.0.0

Unicode normalization (NFC/NFKC), script detection and homoglyph/confusable check. Unicode normalization and confusables check: apply NFC, NFD, NFKC or NFKD, report which forms a string is already in, list the scripts present (all Unicode scripts), and flag confusable and homoglyph characters — Cyrillic а in a Latin word, fullwidth or mathematical look-alikes, all-look-alike words — plus zero-width joiners, bidirectional overrides, invisible and blank characters. Returns per-character detail with code points, names and the ASCII character each imitates.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, text, unicode, security.

ParameterTypeDescription
textstring, requiredText to analyse, at most 1024 characters. Accepted: at most 1024 characters.
formenum, optional, default nfcNormalisation form to apply, default nfc. Accepted: nfc, nfd, nfkc or nfkd.
detailenum, optional, default summarysummary (default) or full per-code-point detail (capped at 256 entries). Accepted: summary, full.

Output (data): normalised, form, already_normalised {nfc, nfd, nfkc, nfkd}, lengths {code_points, graphemes, utf8_bytes, utf16_units} (of the normalised output), scripts (every Unicode Script property value present, from Unicode 18 Scripts.txt; Common and Inherited are not listed), mixed_script, suspicious [{index (code point index in the input), char, code_point, name (Unicode character name; string|null, null only when the name is not vendored: only ASCII, Latin-1, spaces, combining marks, format and default-ignorable characters, controls and confusable look-alikes have names), category, kind confusable|invisible|bidi|combining_excess, looks_like (string|null, null unless kind is confusable)}], ascii_safe (input is printable ASCII only); with detail=full also characters [{index, char, code_point, name (string|null, as above), category, script (string|null, null for Common/Inherited/unassigned)}] (first 256) and characters_truncated. Confusables (UTS #39 confusables.txt, the entries that map to one ASCII character): in mixed-script text every one is reported; in single-script text the compatibility look-alikes of ASCII letters and digits (fullwidth, mathematical, Roman numerals) and words written wholly in one non-Latin script whose every letter has an ASCII look-alike (whole-script confusables, e.g. Cyrillic рау). Invisible = format characters (Cf), Default_Ignorable_Code_Point (e.g. Hangul filler U+3164, variation selectors) and U+2800 braille blank; bidi = embeddings, overrides, isolates and directional marks; combining_excess = the 4th and later combining marks in a row.

Example: https://api.duoleads.com/v1/text/unicode?text=caf%C3%A9&form=nfd (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "unicode-confusables",
      "version": "18.0.0",
      "published": "2026-08-06",
      "attribution": "Unicode confusables.txt (UTS #39), (c) Unicode, Inc.",
      "license": "Unicode License v3"
    }
  ]
}

GET | POST /v1/text/similarity R22 v1.0.0

String similarity: Levenshtein, Jaro-Winkler distance and Soundex/Metaphone phonetic keys. String similarity: compare two strings and return every standard measure in one call: Levenshtein and Damerau-Levenshtein edit distance, normalised similarity, Jaro and Jaro-Winkler, longest common subsequence, Dice coefficient on character bigrams, and the Soundex, Metaphone and NYSIIS phonetic keys of each string. Optional case folding, accent folding and whitespace normalisation before comparison.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, text, similarity, phonetic.

ParameterTypeDescription
astring, requiredFirst string, at most 512 characters. Accepted: at most 512 characters.
bstring, requiredSecond string, at most 512 characters. Accepted: at most 512 characters.
foldstring, optional, default caseComma-separated folds before comparing: case, accents, space, punct. Default case. Accepted: comma-separated subset of case, accents, space, punct.
onlystring, optionalComma-separated measure names to compute: levenshtein, damerau_levenshtein, normalised_similarity, jaro, jaro_winkler, lcs_length, dice, phonetic (all three keys), soundex, metaphone, nysiis. Default all. Accepted: comma-separated subset of levenshtein, damerau_levenshtein, normalised_similarity, jaro, jaro_winkler, lcs_length, dice, phonetic, soundex, metaphone, nysiis.

Output (data): levenshtein, damerau_levenshtein, normalised_similarity (0-1), jaro, jaro_winkler, lcs_length, dice, phonetic {a: {soundex, metaphone, nysiis}, b: {...}} (Soundex, Metaphone and NYSIIS are computed exactly as the jellyfish library does, on the folded string; with only=soundex|metaphone|nysiis just that key), equal_after_fold, folded {a, b}.

Example: https://api.duoleads.com/v1/text/similarity?a=kitten&b=sitting (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

Encoding, parsing and digests

GET | POST /v1/code/url R02 v1.0.0

URL parser: parse, canonicalize and extract the registrable domain (eTLD+1). URL parser: parse and canonicalise a URL, and extract its registrable domain using the Public Suffix List — the part an agent needs to decide whether two URLs belong to the same owner. Returns scheme, host, port, path, decoded query parameters and fragment, the public suffix, the registrable domain (eTLD+1), the subdomain, whether the suffix is ICANN or private, plus a canonical form with default port, dot-segments and percent-encoding normalised. unicode_host uses WHATWG/UTS 46 (non-strict).

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, code, url, domains, psl.

ParameterTypeDescription
urlstring, requiredAbsolute URL, or a bare hostname (https:// assumed). Accepted: an absolute URL, or a hostname.
basestring, optionalBase URL to resolve url against as a relative reference. Accepted: an absolute URL.

Output (data): canonical, scheme, username (string|null, null without userinfo), host (string|null; null for absolute URLs with no host such as mailto:, urn:, data: and file:///, which parse per WHATWG with path holding everything after the scheme; for those public_suffix, registrable_domain, subdomain, host_type and unicode_host are null and suffix_source is none), port (null when default), path, fragment (string|null, null without a fragment), query [{key, value}], public_suffix (string|null, null for IP hosts), registrable_domain (eTLD+1; string|null, null when public_suffix is null or the host is the suffix itself), subdomain (string|null, null when there is none), suffix_source (icann|private|none), host_type (domain|ipv4|ipv6|idn; null without a host), unicode_host (string|null, null when the host is not an IDN).

Example: https://api.duoleads.com/v1/code/url?url=https%3A%2F%2Fa.b.example.co.uk%3A443%2Fx%2F..%2Fy%3Fq%3D1%26q%3D2%23f (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "public-suffix-list",
      "version": "a179a48c465e818cfd8d626691cb317985da87fb",
      "published": "2026-09-24",
      "license": "MPL-2.0"
    }
  ]
}

GET | POST /v1/code/idn R09 v1.0.0

Punycode converter: IDN domain to ASCII and back, with IDNA2008 label validation. Punycode converter: convert internationalised domain names between Unicode and ASCII punycode in either direction, label by label, and validate each label against IDNA2008: length, leading and trailing hyphens, the hyphen-hyphen rule at positions 3 and 4, disallowed code points and bidirectional rules. Returns both forms, the per-label breakdown and the first rule violated. Strict mode is IDNA2008 (UTS 46 non-transitional); it may reject names /v1/code/url displays.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, code, domains, idna, punycode.

ParameterTypeDescription
domainstring, requiredDomain name in Unicode or punycode form. Accepted: at most 512 characters.
toenum, optional, default bothascii, unicode or both (default). Validated only: the response always carries both forms. Accepted: ascii, unicode, both.
strictboolean, optional, default truetrue (default) applies IDNA2008 strictly; false uses UTS 46 transitional (IDNA2003-compatible) processing, which maps e.g. ß to ss; current browsers and /v1/code/url use non-transitional processing, so its output can differ from them. Accepted: true or false.

Output (data): ascii (string|null, null only when a label cannot be converted at all, e.g. a disallowed code point; a label that merely breaks a hyphen rule is still converted, valid:false), unicode (string|null, same), valid, labels [{index, unicode, ascii (string|null), length (integer|null, null when the label cannot be converted), punycoded, valid, reason (string|null)}], reason (first failure or null), total_length (integer|null, null when a label cannot be converted).

Example: https://api.duoleads.com/v1/code/idn?domain=b%C3%BCcher.example (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "unicode-idna-tables",
      "version": "Unicode 17.0.0 (UTS #46 IdnaMappingTable via tr46 6.0.0)",
      "published": "2026-09-29",
      "attribution": "Unicode IdnaMappingTable via the tr46 package (MIT); (c) Unicode, Inc.",
      "license": "Unicode License v3"
    }
  ]
}

GET | POST /v1/code/semver R15 v1.0.0

Semver parser: parse and compare versions, check range satisfaction. Semver parser and comparator: parse a semantic version into major, minor, patch, prerelease and build parts; compare two versions by precedence including prerelease ordering; or test whether a version satisfies a range expression using caret, tilde, hyphen, x-ranges and comparator sets. Returns the parsed structure, the comparison result and the reason a range did not match.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, code, versions, semver.

ParameterTypeDescription
openum, optional, default parseparse (default), compare, satisfies or sort. Accepted: parse, compare, satisfies, sort.
versionstring, optionalVersion to parse (op=parse) or test (op=satisfies). Accepted: at most 256 characters.
astring, optionalFirst version for op=compare. Accepted: at most 256 characters.
bstring, optionalSecond version for op=compare. Accepted: at most 256 characters.
rangestring, optionalRange expression for op=satisfies, e.g. ^1.2.0. Accepted: at most 256 characters.
versionsstring, optionalComma-separated versions for op=sort, at most 100. Accepted: at most 100 versions.

Output (data): parse: valid, major, minor, patch (integers; null when the version is invalid), prerelease [], build [], is_prerelease, canonical (string|null, null when invalid), reason (string|null: why an invalid version failed; null when valid). compare: result (-1|0|1), a, b, precedence_note. satisfies: satisfies, range (normalised by node-semver; the trimmed input when that is empty, as for * and x), comparators [], reason. sort: sorted [], invalid [].

Example: https://api.duoleads.com/v1/code/semver?version=1.2.3-rc.1%2Bbuild.5 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/code/hash R28 v1.0.0

SHA-256/HMAC hash generator: SHA-256, SHA-512, SHA-3, Keccak-256, BLAKE2 and HMAC digests. Hash generator: compute a cryptographic digest of supplied data: SHA-256, SHA-384, SHA-512, SHA-1, SHA3-256, SHA3-512, Keccak-256, BLAKE2b-256 and BLAKE2b-512, plus HMAC with any of them. Input is UTF-8 text, base64 or hex bytes; output is hex, base64, base64url or base32. Returns the digest, the byte length of the input, and the exact algorithm identifier used.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, code, crypto, hashing.

ParameterTypeDescription
algoenum, requiredDigest algorithm. Accepted: sha256, sha384, sha512, sha1, sha3-256, sha3-512, keccak256, blake2b-256, blake2b-512.
datastring, requiredInput data, interpreted per encoding. At most 8192 characters. An empty value hashes the empty string. Accepted: at most 8192 characters.
encodingenum, optional, default utf8Encoding of data: utf8 (default), base64, base64url or hex. Accepted: utf8, base64, base64url, hex.
outenum, optional, default hexDigest output encoding: hex (default), base64, base64url or base32. Accepted: hex, base64, base64url, base32.
hmac_keystring, optionalIf present, computes HMAC with this key. Accepted: at most 512 characters.
hmac_key_encodingenum, optional, default utf8Encoding of hmac_key, as encoding. Accepted: utf8, base64, base64url, hex.

Output (data): digest, algo, out, input_bytes, hmac (boolean), bit_length.

Example: https://api.duoleads.com/v1/code/hash?algo=sha256&data=hello (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/code/jwt R33 v1.0.0

JWT decoder: header, claims and expiry state (no signature verification). JWT decoder: decode a JSON Web Token without verifying it: returns the header, the claims, the signature length and algorithm, and a computed view of the time claims — whether exp has passed, whether nbf is in the future, and the remaining lifetime in seconds against a supplied or current instant. Reports structural problems such as a missing part, invalid base64url or an alg of none. It does not and cannot verify the signature; do not use it to decide trust.

Price: $0.05 per call. Deterministic only when the query fixes the instant; otherwise it depends on the current time and is not cached. Tags: no-api-key, code, jwt, security.

ParameterTypeDescription
tokenstring, requiredThe JWT to decode (not verified). At most 8192 characters. Accepted: at most 8192 characters.
atstring, optionalInstant to evaluate exp/nbf against: RFC 3339 or epoch seconds. Default now. Accepted: RFC 3339 timestamp or integer epoch.

Output (data): valid_structure, header and payload (the decoded JSON objects echoed exactly as sent, including non-conforming values; null when absent or not an object), alg, typ, kid (each string|null: null when the header lacks it or it is not a string), signature_bytes, parts, claims {iss, sub, aud, exp, nbf, iat, jti} (the RFC 7519 registered claims, normalised: iss, sub and jti are strings, aud is a string or an array of strings, exp, nbf and iat are numbers; each is null when absent or when its value does not conform), claim_errors [{claim, reason}] (present only when a registered claim did not conform and was nulled in claims, e.g. aud: 5 or exp: "soon"), time {evaluated_at, expired (boolean|null, null without a conforming exp), not_yet_valid (boolean|null, null without a conforming nbf), expires_in_seconds (integer|null, null without a conforming exp), age_seconds (integer|null, null without a conforming iat)}, signature_verified (always false), warnings [], reason.

Example: https://api.duoleads.com/v1/code/jwt?token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c&at=2026-09-28T00%3A00%3A00Z (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

Geodesy and geometry

GET | POST /v1/geo/geohash R03 v1.0.0

Geohash encoder and decoder with neighbour cells. Geohash encoder and decoder: encode a WGS-84 latitude and longitude to a geohash at a chosen precision, or decode a geohash back to its bounding box, centre point and error bounds in metres. Encoding also returns the eight neighbouring cells, which is what a caller needs to do proximity search over a geohash-indexed store without a spatial database.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, geo, geohash.

ParameterTypeDescription
openum, optional, default encodeencode (default): lat/lon to geohash. decode: geohash to bounding box. Accepted: encode, decode.
latnumber, optionalWGS-84 latitude, -90 to 90. Required when op=encode. Accepted: a number between -90 and 90.
lonnumber, optionalWGS-84 longitude, -180 to 180. Required when op=encode. Accepted: a number between -180 and 180.
precisioninteger, optional, default 9Geohash length 1-12, default 9 (about 4.8 m). Accepted: integer 1-12.
geohashstring, optionalGeohash to decode, 1-12 characters. Required when op=decode. Accepted: base32 geohash alphabet, excluding a, i, l and o.

Output (data): encode: geohash, precision, bbox {min_lat, min_lon, max_lat, max_lon}, center {lat, lon}, error_m {lat, lon}, neighbours {n, ne, e, se, s, sw, w, nw} (each string|null: null where the cell would lie beyond a pole). decode: the same without neighbours, plus cell_width_m, cell_height_m (metres on WGS-84). Neighbour cells that would lie beyond a pole are null; longitude wraps at the antimeridian.

Example: https://api.duoleads.com/v1/geo/geohash?op=encode&lat=52.3728&lon=4.8936&precision=9 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/geo/pluscode R04 v1.0.0

Plus code (Open Location Code) encoder and decoder. Plus code (Open Location Code) encoder and decoder: encode coordinates as a plus code at a chosen length, or decode a full code back to its bounding box and centre. Also shortens a full code against a reference coordinate and recovers a shortened code given a reference, which is how plus codes are normally exchanged in text. Returns code length, precision in metres and validity.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, geo, pluscode.

ParameterTypeDescription
openum, optional, default encodeencode (default), decode, shorten or recover. Accepted: encode, decode, shorten, recover.
latnumber, optionalLatitude for op=encode. Accepted: a number between -90 and 90.
lonnumber, optionalLongitude for op=encode. Accepted: a number between -180 and 180.
codestring, optionalPlus code for decode, shorten or recover. Accepted: at most 20 characters.
lengthinteger, optional, default 10Integer code length for op=encode: one of 2,4,6,8,10 (default),11,12,13,14,15. Other integers in 2-15 are 400 UNSUPPORTED_VALUE. Accepted: one of 2,4,6,8,10,11,12,13,14,15.
ref_latnumber, optionalReference latitude for op=shorten/recover. Accepted: a number between -90 and 90.
ref_lonnumber, optionalReference longitude for op=shorten/recover. Accepted: a number between -180 and 180.

Output (data): code, length (integer|null, null for an invalid code), bbox {min_lat, min_lon, max_lat, max_lon}, center {lat, lon}, precision_m (cell height in metres, rounded to 0.1), is_full, is_short, valid, reason (string|null, null on success). Invalid codes on op=decode return 200 with valid:false and a reason (invalid character is checked before the + position); short codes decode to valid:true, is_short:true without a bbox. shorten also returns full_code. shorten/recover with a malformed code are 400 INVALID_PARAM.

Example: https://api.duoleads.com/v1/geo/pluscode?lat=52.3728&lon=4.8936 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/geo/polygon R07 v1.0.0

Point in polygon check, plus bounding box, centroid and area for GeoJSON. Point in polygon check and GeoJSON geometry: point-in-polygon with correct hole handling, bounding box, centroid, signed area in square metres, perimeter length, and ring winding order for a geometry supplied in the request. Accepts Polygon and MultiPolygon, and a GeoJSON Feature wrapping either. Area and length are geodesic on the WGS-84 ellipsoid, correct at any latitude; containment is planar in lon/lat.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, geo, geojson, geometry.

ParameterTypeDescription
geometrystring, requiredURL-encoded GeoJSON Polygon, MultiPolygon or a Feature wrapping one. At most 3072 characters and 2000 coordinate pairs. Accepted: valid GeoJSON.
latnumber, optionalPoint latitude; with lon, runs the containment test. Accepted: a number between -90 and 90.
lonnumber, optionalPoint longitude; with lat, runs the containment test. Accepted: a number between -180 and 180.
opsstring, optionalComma-separated subset of contains,bbox,centroid,area,perimeter,winding. Default all. Accepted: comma-separated subset of contains, bbox, centroid, area, perimeter, winding.

Output (data): contains (boolean|null), on_boundary (boolean|null), bbox [minLon, minLat, maxLon, maxLat], centroid {lat, lon}, area_m2, perimeter_m, winding (cw|ccw per ring, exterior first then holes, in polygon order), rings, vertices (closing point excluded). area_m2 is the WGS-84 geodesic area, signed per RFC 7946 (exterior counter-clockwise = positive, clockwise = negative, holes subtract); perimeter_m sums every ring. Point-in-polygon and centroid are planar in lon/lat; a point on an edge is contained with on_boundary:true. With ops, only the listed fields (plus rings and vertices) are returned. Rings must be closed with at least 4 positions.

Example: https://api.duoleads.com/v1/geo/polygon?geometry=%7B%22type%22%3A%22Polygon%22%2C%22coordinates%22%3A%5B%5B%5B4.85%2C52.35%5D%2C%5B4.95%2C52.35%5D%2C%5B4.95%2C52.40%5D%2C%5B4.85%2C52.40%5D%2C%5B4.85%2C52.35%5D%5D%5D%7D&lat=52.3728&lon=4.8936 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/geo/distance R27 v1.0.0

Distance calculator: geodesic distance, bearing and destination point on WGS-84. Distance calculator: distance and direction between WGS-84 coordinates: geodesic distance by Vincenty with a haversine fallback, initial and final bearing, the midpoint, and the destination point reached from a start point on a given bearing and distance. Also computes the cumulative length of a supplied coordinate path. Results in metres, kilometres, nautical miles and miles.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, geo, geodesy, distance.

ParameterTypeDescription
openum, optional, default distancedistance (default), destination, midpoint or path. Accepted: distance, destination, midpoint, path.
lat1number, optionalStart latitude. Accepted: a number between -90 and 90.
lon1number, optionalStart longitude. Accepted: a number between -180 and 180.
lat2number, optionalEnd latitude. Accepted: a number between -90 and 90.
lon2number, optionalEnd longitude. Accepted: a number between -180 and 180.
bearingnumber, optionalInitial bearing in degrees for op=destination. Accepted: number 0-360.
distance_mnumber, optionalDistance in metres for op=destination, 0 to 1e9 (about 25 Earth circumferences); larger values are 400 INVALID_PARAM. Accepted: a number between 0 and 1e9 (metres).
pathstring, optionalComma-separated lat,lon pairs for op=path, at most 200 points. Accepted: comma-separated lat,lon pairs, at most 200 points.
methodenum, optional, default vincentyvincenty (default, WGS-84) or haversine. Accepted: vincenty, haversine.

Output (data): op=distance and op=midpoint: distance {m, km, nmi, mi}, bearing_initial, bearing_final (degrees clockwise from north, 4 dp), midpoint {lat, lon} (geodesic midpoint; spherical when method is haversine), method, converged. Vincenty on WGS-84 is used unless method=haversine (R = 6,371,008.8 m); when Vincenty fails to converge (near-antipodal pairs) the response falls back to haversine and reports method:"haversine", converged:false. op=destination: destination {lat, lon} (longitude wrapped to -180..180; Karney's direct algorithm on WGS-84, or spherical with R = 6,371,008.8 m when method=haversine), bearing_final (also for method=haversine, on the sphere), method, converged. op=path: distance {m, km, nmi, mi}, points, legs, method (vincenty, haversine, or vincenty+haversine if any leg fell back), converged. path is a flat comma list lat,lon,lat,lon,... (semicolons or spaces also separate pairs); it needs at least 2 points.

Example: https://api.duoleads.com/v1/geo/distance?lat1=52.3728&lon1=4.8936&lat2=40.7128&lon2=-74.0060 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

Blockchain primitives (no RPC)

GET | POST /v1/chain/address R10 v1.0.0

Crypto address validator: detect the blockchain and verify the checksum (EVM, Bitcoin, Solana and more). Crypto address validator: identify which blockchain an address belongs to and validate its encoding: EVM EIP-55 checksum, Bitcoin base58check and bech32/bech32m with witness version, Solana base58 and on-curve check, Cosmos bech32 with its HRP, Tron, XRP, Litecoin, Dogecoin, Cardano, Polkadot SS58 and Algorand. Returns every chain the address is valid for (ambiguous when several match), the checksummed form for EVM addresses, and the reason a check failed, including unrecognised_format.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, chain, blockchain, addresses, validation.

ParameterTypeDescription
addressstring, requiredAddress to identify and validate. Accepted: at most 128 characters.
expectenum, optionalRestrict the check to one chain id. Accepted: evm, bitcoin, solana, cosmos, tron, xrp, cardano, polkadot, algorand, litecoin, dogecoin.
chain_idinteger, optionalEVM chain id; enables EIP-1191 chain-salted checksum validation. Accepted: a positive integer chain id.

Output (data): valid, matches [{chain, format (string|null), valid, reason (string|null), detail (members depend on the format: hrp, witness_version, encoding for bech32 (cosmos adds bytes); version_byte, purpose for base58check; on_curve for Solana; address_type, header_type, network for Cardano; network_prefix for SS58)}], checksum ({input_form, checksummed, checksum_valid, eip1191_applied} for EVM, else null), ambiguous, reason (present only when the whole input failed: expect_mismatch when expect= was given and no match has that chain, unrecognised_format when no detector recognises the input and no match is listed).

Example: https://api.duoleads.com/v1/chain/address?address=0xd8da6bf26964af9d7eed9e03e53415d37aa96045 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/chain/selector R30 v1.0.0

Solidity function selector: Keccak-256, 4-byte selector and event topic from a signature. Solidity function selector and event topic: compute the Keccak-256 hash of a function or event signature and derive the 4-byte selector and the 32-byte topic. Normalises the signature first — strips parameter names, expands uint to uint256 and the other aliases, flattens tuples — so a signature copied from source code produces the same selector as the canonical form. Also hashes arbitrary text or hex bytes with Keccak-256.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, chain, blockchain, solidity, keccak.

ParameterTypeDescription
signaturestring, optionalSolidity function, event or error signature, e.g. transfer(address to, uint amount). Accepted: at most 1024 characters.
datastring, optionalAlternative to signature: raw data to Keccak-256 hash. Accepted: at most 8192 characters.
encodingenum, optional, default utf8Encoding of data: utf8 (default) or hex. Accepted: utf8, hex.
kindenum, optional, default functionfunction (default), event or error. Accepted: function, event, error.

Output (data): canonical (string|null, null in data mode), keccak256 (0x + 32 bytes), selector (0x + 4 bytes; string|null, null for kind=event and in data mode), topic0 (0x + 32 bytes; string|null, null for kind=function or error and in data mode), inputs ([] or null, null in data mode), normalisations [{from, to}]. Data mode (data= instead of signature, hashing arbitrary text or hex bytes with Keccak-256): canonical, selector, topic0 and inputs are null, normalisations is empty, and encoding (utf8|hex) and input_bytes (integer) are added.

Example: https://api.duoleads.com/v1/chain/selector?signature=transfer%28address%2Cuint256%29 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

Static reference tables

GET | POST /v1/ref/nuts R01 v1.0.0

NUTS region lookup: EU statistical region codes, names and hierarchy. NUTS region lookup (EU statistical regions): resolve a NUTS code to its name, country and level, walk up to its parents or down to its children, or search regions by name. Covers all four levels (country, major region, basic region, small region) for the 27 member states and 12 further reporting countries, from the NUTS 2024 classification. Returns the Latin-script and local-language names plus the urbanisation, coastal and mountain typologies.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, ref, eu, statistics, regions.

ParameterTypeDescription
codestring, optionalNUTS code, 2-5 characters, case-insensitive (level-3 codes may contain letters, e.g. NL32B). A GR or GB prefix is accepted for EL or UK. Accepted: 2 to 5 characters matching ^[A-Z]{2}[0-9A-Z]{0,3}$.
namestring, optionalSubstring search on region names, case- and accent-insensitive. Up to 25 matches. Accepted: at most 128 characters.
levelinteger, optionalRestrict a name search to one level, 0-3. Accepted: integer 0-3.
countrystring, optionalISO 3166-1 alpha-2 country filter (UK/GB and EL/GR both accepted). Accepted: an ISO 3166-1 alpha-2 code.
includestring, optional, default parents,typologyComma-separated: parents, children, typology. Default parents,typology. Accepted: comma-separated subset of parents, children, typology.

Output (data): found, code, level, country, name_latn, name_local, parents [{code, level, name_latn}] from level 0 down to the parent, children [{code, level, name_latn}] (direct children, sorted by code; only when include has children), typology {urban, urban_label, coastal, coastal_label, mountain, mountain_label} (codes are Eurostat typology codes as strings, null where unclassified; labels follow Eurostat's published typology definitions). Keys not named in include are omitted. A name search returns matches [{code, level, country, name_latn, name_local}] (exact name first, then by level and code) plus total_matches. NUTS uses EL and UK for Greece and the United Kingdom; country and the code prefix accept GR and GB as aliases; found responses carry canonical_country (the NUTS spelling, EL or UK for those two) and input_code (the alias as sent) when an alias was mapped.

Example: https://api.duoleads.com/v1/ref/nuts?code=NL32B&include=parents%2Ctypology (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "eurostat-nuts",
      "version": "NUTS 2024",
      "published": "2026-09-28",
      "attribution": "© European Union, Eurostat/GISCO",
      "license": "CC BY 4.0"
    }
  ]
}

GET | POST /v1/ref/airport R20 v1.0.0

Airport lookup by IATA or ICAO code: name, coordinates, elevation, time zone; nearest airports. Airport lookup by IATA or ICAO code: get the airport's name, city, country, ISO 3166-2 region code, WGS-84 coordinates, elevation and IANA time zone, or find the nearest airports to a coordinate within a radius. Covers every airport worldwide that holds a three-letter IATA code and scheduled service. Returns the code type that matched and the distance in kilometres for proximity results.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, ref, travel, airports.

ParameterTypeDescription
codestring, optional3-letter IATA or 4-letter ICAO code, case-insensitive. Accepted: a 3-letter IATA or 4-letter ICAO code.
nearstring, optionallat,lon to search around. Accepted: lat,lon.
radius_kmnumber, optional, default 100Search radius in km, 1-1000, default 100. Only with near. Accepted: number 1-1000.
limitinteger, optional, default 5Maximum results 1-25, default 5. Only with near. Accepted: integer 1-25.
countrystring, optionalISO 3166-1 alpha-2 filter. Accepted: an ISO 3166-1 alpha-2 code.

Output (data): found, matched_on (iata|icao), airport {iata, icao, name, municipality, country, region, lat, lon, elevation_ft (number|null, null when OurAirports has no elevation, 129 airports), type, timezone}, nearby (for near: the same plus distance_km and bearing_deg, nearest first; distance is haversine on a 6,371.0088 km sphere, bearing is the initial bearing in degrees from the query point; matched_on is absent). A code matches IATA (3 characters) first, then ICAO/local identifier. found is false for an unknown code or an empty nearby list. timezone is the IANA zone of the airport location, derived offline at build time from its coordinates (timezone-boundary-builder 2026d); it is the geographic zone, not an airline convention (Xinjiang airports read Asia/Urumqi, UTC+6, although flights run on Beijing time). Coordinates on a zone border can resolve to the neighbouring zone (Gold Coast OOL reads Australia/Sydney).

Example: https://api.duoleads.com/v1/ref/airport?code=AMS (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "ourairports",
      "version": "2026-09-28 extract",
      "published": "2026-09-28",
      "attribution": "OurAirports (public domain)",
      "license": "Public Domain"
    },
    {
      "name": "timezone-boundary-builder",
      "version": "2026d",
      "published": "2026-09-29",
      "attribution": "Time zones derived from timezone-boundary-builder data (https://github.com/evansiroky/timezone-boundary-builder), (c) contributors, ODbL 1.0, via timezonefinder 9.0.0",
      "license": "ODbL-1.0"
    }
  ]
}

GET | POST /v1/ref/currency R23 v1.0.0

Currency lookup: ISO 4217 codes, names, minor units and cash rounding. Currency lookup by ISO 4217 alphabetic or numeric code: the official English name, minor-unit exponent, fund flag, the smallest cash denomination where it differs from the minor unit, the territories that use it, and historic codes on request. Returns the correct rounding increment for cash amounts, which is what a caller needs to render or settle a price. This route returns currency facts only and never an exchange rate.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, ref, finance, currency, iso-4217.

ParameterTypeDescription
codestring, optionalISO 4217 alpha-3 or 3-digit numeric code. Accepted: a 3-letter alphabetic or 3-digit numeric ISO 4217 code.
countrystring, optionalISO 3166-1 alpha-2; returns the currencies in use there. Accepted: an ISO 3166-1 alpha-2 code.
includestring, optionalComma-separated: territories, historic. Default none. Accepted: comma-separated subset of territories, historic.

Output (data): found, code, numeric (3-digit string per ISO 4217; null for the three historic codes XFO, XFU, XRE), name (ISO 4217 English name, e.g. Lek, Forint, Rupiah), minor_units (ISO 4217 exponent, e.g. IDR 2, HUF 2, JPY 0, KWD 3; null where ISO lists N.A.: precious metals XAU, XAG, XPT, XPD, XDR, XXX and the other X-codes; null for historic codes), cash_minor_units (equals minor_units unless CLDR gives a cash digit count, e.g. SEK 0), cash_rounding (number|null: CLDR cash rounding increment expressed in ISO minor units, e.g. 5 for CHF and CAD means 0.05, 50 for DKK, 500 for HUF meaning 5.00; null when none), is_fund (boolean: the ISO 4217 fund flag, true for BOV, CHE, CHW, CLF, COU, MXV, USN, UYI, UYW and XAD, false otherwise), territories (ISO 3166-1 alpha-2 codes, sorted, when include has territories; territory sets come from CLDR), status (current|historic), withdrawn (ISO withdrawal date as published, usually YYYY-MM, historic codes only). Historic codes come from ISO 4217 list three and are only found with include=historic, by alphabetic or numeric code (e.g. DEM 276, ZWD 716); a code that is in both lists (EUR, RON) is current. Some numeric codes were reused by several historic codes: the most recently withdrawn code is returned and the others are listed in numeric_shared_with. With country=XX the response is {found, country, currencies: [the same record for each legal-tender currency in use there per CLDR]}. Never an exchange rate.

Example: https://api.duoleads.com/v1/ref/currency?code=EUR&include=territories (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "iso-4217",
      "version": "SIX list one 2026-09-17, list three 2026-01-01",
      "published": "2026-09-17",
      "attribution": "ISO 4217 currency and funds code lists, published by SIX Group as secretariat of the ISO 4217 Maintenance Agency (public data)",
      "license": "Public data (owner decision 2026-09-29)"
    },
    {
      "name": "cldr-currency-data",
      "version": "48.2.2",
      "published": "2026-09-28",
      "attribution": "Unicode CLDR, © Unicode, Inc.",
      "license": "Unicode-3.0"
    }
  ]
}

GET | POST /v1/ref/country R25 v1.0.0

Country lookup: ISO 3166 codes, currency, TLD, UN region and ISO 3166-2 subdivisions. Country lookup: find a country or territory by ISO 3166-1 alpha-2, alpha-3 or numeric code, or by name, and get the other codes, the official and common English names, the UN M49 region and sub-region, the currencies in use, the country-code TLD, and optionally the full ISO 3166-2 subdivision list with each subdivision's type. Also resolves an ISO 3166-2 subdivision code such as NL-NH directly. Names are matched case- and accent-insensitively.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, ref, countries, iso-3166.

ParameterTypeDescription
codestring, optionalISO 3166-1 alpha-2, alpha-3 or numeric code, or an ISO 3166-2 subdivision code such as NL-NH. Accepted: ISO 3166-1 alpha-2/alpha-3/numeric, or an ISO 3166-2 subdivision code.
namestring, optionalSubstring search on country names, case- and accent-insensitive. Accepted: at most 128 characters.
includestring, optional, default m49,currency,tldComma-separated: subdivisions, m49, currency, tld. Default m49,currency,tld. Accepted: comma-separated subset of subdivisions, m49, currency, tld.

Output (data): found, kind (country|subdivision), alpha_2, alpha_3, numeric, name, official_name (the ISO 3166-1 official name from Debian iso-codes, e.g. "Kingdom of the Netherlands"; the short name where ISO defines no separate official name; always a string), m49 {region, region_name, subregion, subregion_name, intermediate, intermediate_name} (UN M49 codes as zero-padded 3-character strings; subregion and intermediate are null where the hierarchy has no such level), currencies [ISO 4217 alpha-3, legal tender in use per CLDR], tld [".xx"] (the ccTLD in actual use, so GB gives.uk; empty where none is delegated), subdivision_count (always present: the number of ISO 3166-2 subdivisions), and with include=subdivisions subdivisions [{code, name, type, parent}] (ISO 3166-2 from Debian iso-codes main of 2026-09-28, source order; parent is the parent subdivision code or null; countries with none return an empty list). A code of the form CC-XXX (e.g. NL-NH) resolves a subdivision: kind is subdivision, subdivision {code, name, type, parent} is added, and the country fields describe its country. m49, currencies and tld are omitted when not named in include; subdivision_count is not. A name search adds matches [{alpha_2, alpha_3, numeric, name}] (exact name first, then substring; at most 25) plus total_matches, and the top-level fields describe the first match. ZZ and other non-ISO codes are never found.

Example: https://api.duoleads.com/v1/ref/country?code=NL (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "iso-codes",
      "version": "Debian iso-codes data/iso_3166-1.json (official_name) and data/iso_3166-2.json, retrieved 2026-09-28",
      "published": "2026-09-28",
      "attribution": "ISO 3166-1 official names and ISO 3166-2 subdivision data from Debian iso-codes (https://salsa.debian.org/iso-codes-team/iso-codes), (c) 2016 Dr. Tobias Quathamer, LGPL-2.1-or-later",
      "license": "LGPL-2.1-or-later"
    },
    {
      "name": "country-codes",
      "version": "datasets/country-codes, retrieved 2026-09-28",
      "published": "2026-09-28",
      "attribution": "Open Knowledge Foundation datasets/country-codes (ISO 3166-1 codes)",
      "license": "PDDL-1.0"
    },
    {
      "name": "cldr",
      "version": "48.2.2",
      "published": "2026-09-28",
      "attribution": "Unicode CLDR, © Unicode, Inc.",
      "license": "Unicode-3.0"
    }
  ]
}

Numbers and money arithmetic

GET | POST /v1/num/radix R08 v1.0.0

Base converter: integers between number bases 2 to 36 (hex, binary, octal). Base converter: convert an integer between any two numeric bases from 2 to 36 (hex, binary, octal and more), with arbitrary precision so values far beyond 2^53 are exact. Accepts an optional sign and common prefixes (0x, 0b, 0o), validates every digit against the source base, and returns the value in the target base, in decimal, and as its bit length and digit count.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, num, numbers, conversion.

ParameterTypeDescription
valuestring, requiredInteger to convert; optional sign and 0x/0b/0o prefix. Accepted: at most 1024 characters.
fromstring, optional, default autoSource base 2-36, or auto (default) to read a 0x/0b/0o prefix. Accepted: integer 2-36, or 'auto'.
tointeger, optional, default 10Target base 2-36, default 10. Accepted: integer 2-36.
caseenum, optional, default lowerDigit case for bases above 10: lower (default) or upper. Accepted: lower, upper.
prefixboolean, optional, default falseEmit 0x/0b/0o where conventional. Default false. Accepted: true or false.

Output (data): result, decimal, from, to, negative, digits, bit_length, exact (always true).

Example: https://api.duoleads.com/v1/num/radix?value=0xdeadbeef&to=10 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/num/words R11 v1.0.0

Number to words in 12 languages, with ordinal and currency forms. Number to words: spell a number out in English, Dutch, German, French, Spanish, Italian, Portuguese, Polish, Russian, Turkish, Swedish or Japanese, in cardinal, ordinal or currency form. Currency form agrees the number with the currency noun and gives real minor-unit names for 19 currencies (EUR, USD, GBP, CHF, SEK, NOK, DKK, PLN, RUB, TRY, CNY, INR, BRL, MXN, CAD, AUD, NZD, CZK, HUF); any other ISO 4217 code uses a fraction such as 56/100. Values up to 10^15.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, num, numbers, localisation.

ParameterTypeDescription
valuestring, requiredInteger or decimal number, absolute value below 1e15, e.g. 1234 or 1234.56. Accepted: an integer or decimal number, absolute value below 1e15, e.g. 1234.
langenum, optional, default enLanguage, ISO 639-1. Default en. Accepted: en, nl, de, fr, es, it, pt, pl, ru, tr, sv, ja.
formenum, optional, default cardinalcardinal (default), ordinal, currency or year. Accepted: cardinal, ordinal, currency, year.
currencystring, optionalISO 4217 code. Required when form=currency, rejected otherwise. Accepted: an ISO 4217 alpha-3 code.
caseenum, optional, default lowerlower (default), sentence or title. Accepted: lower, sentence, title.

Output (data): words (ordinals are the masculine singular nominative form, e.g. es segundo, fr deuxième, it secondo, pt segundo, pl drugi, ru второй, sv andra, tr ikinci, ja 二番目; form=year reads pl and ru as an ordinal, ja with the suffix 年, and en, nl, de and sv in hundreds; in the currency form the number agrees with the gender of the currency noun, e.g. fr une couronne, es una libra, ru одна крона, sv ett pund), value, lang, form, currency ({code, unit_singular, unit_plural, minor_singular, minor_plural, minor_units} or null; minor_singular and minor_plural are null for zero-decimal currencies and for currencies without a curated subunit name), parts ({integer_words, minor_words} for the currency form; minor_words is the subunit count in words for the 19 curated currencies (EUR, USD, GBP, CHF, SEK, NOK, DKK, PLN, RUB, TRY, CNY, INR, BRL, MXN, CAD, AUD, NZD, CZK, HUF); every other currency uses the neutral fraction <n>/<10^minor_units> with no leading zeros (10/1000, 1/100, 56/100) instead of a subunit name, and null when there is no minor part; parts is null for other forms), rounding_applied (currency form; present, true, only when surplus decimals were rounded; an amount that rounds up to 1e15 is rejected).

Example: https://api.duoleads.com/v1/num/words?value=1234&lang=nl (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/num/stats R13 v1.0.0

Statistics calculator: mean, median, standard deviation, quartiles and percentiles. Statistics calculator for a numeric array in one call: count, sum, mean, median, mode, variance and standard deviation honouring ddof (default 1, the sample form; 0 gives the population form) plus always-population *_population fields, min, max, range, the quartiles and interquartile range, skewness, kurtosis, and any requested percentiles. Percentiles use a named interpolation method so the result is reproducible rather than implementation-defined.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, num, numbers, statistics.

ParameterTypeDescription
valuesstring, requiredComma-separated finite numbers, at most 500 values. Accepted: comma-separated finite numbers.
percentilesstring, optional, default 25,50,75Comma-separated percentiles 0-100, at most 20. Default 25,50,75. Accepted: numbers between 0 and 100.
methodenum, optional, default linearPercentile interpolation (NumPy/R names): linear (default), nearest, lower, higher, midpoint. Accepted: linear, nearest, lower, higher, midpoint.
ddofinteger, optional, default 1Delta degrees of freedom for variance/stdev: 1 (default, sample, n-1) or 0 (population, n). The *_population fields are always population. Accepted: integer 0-1.

Output (data): n, sum (number|null), mean (number|null), median (number|null), mode ([] or null, null when every value is distinct), ddof (integer), variance (number|null: n-ddof divisor, null when n <= ddof), stdev (number|null, null when n <= ddof), variance_population (number|null), stdev_population (number|null), min, max, range (number|null), q1 (number|null), q3 (number|null), iqr (number|null), skewness (number|null, null when n < 3 or the variance is 0), kurtosis_excess (number|null, null when n < 4 or the variance is 0), percentiles {<p>: number|null}, method, outliers_tukey []. Any computed number is null when the result is not finite, i.e. overflows the double range (e.g. values=1e308,1e308)

Example: https://api.duoleads.com/v1/num/stats?values=1%2C2%2C3%2C4%2C5 (answers 402 until paid).

Source block:

{
  "source": null,
  "note": "No third-party dataset: computed from the inputs you supply and public standards."
}

GET | POST /v1/num/allocate R14 v1.0.0

Money split: allocate an amount into shares with no rounding loss. Money split: split a money amount into shares without losing or inventing a cent. Divide evenly into N parts, or by a list of ratios, and the remainder is distributed one minor unit at a time by a named, deterministic rule — largest-remainder, first-wins or last-wins — so the parts always sum exactly to the original. Uses the ISO 4217 minor-unit exponent of the currency, so zero- and three-decimal currencies work (JPY 0, KWD 3); metals and XXX are rejected.

Price: $0.05 per call. Deterministic: the same query always returns the same data (the paying client may cache it indefinitely: Cache-Control private, immutable). Tags: deterministic, no-api-key, num, finance, money, allocation.

ParameterTypeDescription
amountstring, requiredDecimal amount, absolute value below 1e12. Accepted: a decimal amount with absolute value below 1e12.
currencystring, requiredISO 4217 alpha-3 code. Accepted: an ISO 4217 alpha-3 code.
partsinteger, optionalNumber of equal parts, 1-1000. One of parts or ratios. Accepted: integer 1-1000.
ratiosstring, optionalComma-separated non-negative ratios, at most 1000, each with at most 15 integer digits and 15 decimal places. One of parts or ratios. Accepted: comma-separated non-negative numbers, at most 1000.
ruleenum, optional, default largest-remainderRemainder rule: largest-remainder (default), first, last or round-robin. Accepted: largest-remainder, first, last, round-robin.

Output (data): shares [decimal strings], shares_minor [integers], total (equals amount exactly), currency, minor_units, remainder_distributed, rule.

Example: https://api.duoleads.com/v1/num/allocate?amount=100.00&currency=EUR&parts=3 (answers 402 until paid).

Source block:

{
  "source": [
    {
      "name": "iso-4217",
      "version": "SIX list one 2026-09-17, list three 2026-01-01",
      "published": "2026-09-17",
      "attribution": "ISO 4217 currency and funds code lists, published by SIX Group as secretariat of the ISO 4217 Maintenance Agency (public data)",
      "license": "Public data (owner decision 2026-09-29)"
    }
  ]
}