Cardinal to ordinal number converter
21 becomes 21st, and the tricky teens stay right: 11th, 12th and 13th, never 11st. One rule set for rankings, race results, certificates and product copy, with the suffix also given alone for styling. Free in your browser.
- Free
- Runs in your browser
- No sign-up
- Your data stays on your device
Run — free
Worked example
- Number
- 21
- Ordinal
- 21st
- Suffix
- st
Writers, product copy, ranking tables, and document generators constantly need ordinal forms of whole numbers: first place as 1st, second as 2nd, and twenty-first as 21st. Doing that by hand invites off-by-one mistakes on teens and on numbers that end in one, two, or three. This capability accepts a single integer and returns the standard English ordinal abbreviation with the correct suffix, using one deterministic rule set.
What an ordinal abbreviation is and when you need one
A cardinal number answers how many; an ordinal answers which position in a sequence. English often writes short ordinals with a numeral plus a two-letter suffix: 1st, 2nd, 3rd, 4th. The hard part is not remembering that most numbers take th, but applying the exceptions consistently.
Numbers that end in one usually take st, except eleven; those ending in two take nd, except twelve; those ending in three take rd, except thirteen. Every other case, including the teens through nineteen and multiples of ten, takes th. Spreadsheets and ad-hoc conditionals often mishandle 11–13 or apply the unit digit alone without checking the last two digits, so 11 becomes 11st or 23 becomes 23th.
You send one integer; you get a stable object with the original number, the full ordinal string, and the suffix alone for styling.
How the conversion works and what counts as valid input
The algorithm is pure and deterministic. After validating that the input is a true integer, the converter takes the absolute value, looks at the last two digits, and selects st, nd, rd, or th. If the last two digits form eleven, twelve, or thirteen, the suffix is always th.
Otherwise the last single digit decides: one maps to st, two to nd, three to rd, and every other digit to th. The sign of the original number is preserved on the numeral, so negative integers keep their minus sign before the digits and suffix. Zero becomes 0th.
Safe-integer bounds apply so results stay exact in JavaScript environments. There is no locale switch in this capability; the abbreviations follow common English editorial practice used in product UI and technical writing. The response always includes number, ordinal, and suffix so consumers can display the full form or style the suffix separately without re-deriving the rule client-side.
What you can do with it
Leaderboards and race results
Turn place integers into 1st, 2nd, 3rd labels for standings tables, podiums, and post-event recaps without hard-coding suffix tables in every client.
Document and certificate generation
Insert correct English ordinals into anniversary wording, edition numbers, and ranked award lines when rendering PDFs or mail-merge output.
Product copy and CMS templates
Expand ranking or step fields into ordinal strings in release notes, onboarding steps, and marketing blocks with one shared rule.
FAQ
What input does the ordinal converter accept?
A single integer (for example 1, 21, or -3), optionally as a digit string without a decimal point.
How are 11, 12, and 13 handled?
They always take the th suffix (11th, 12th, 13th), even though they end in 1, 2, and 3. The same teen rule applies to 111th, 112th, and 113th.
What does a successful response contain?
The original integer as number, the full abbreviation as ordinal (for example 21st), and the two-letter suffix alone for optional styling.
Does it support languages other than English?
No. This capability implements English ordinal abbreviations only. Other languages use different morphology and should be handled by dedicated formatters.
What happens with zero and negative numbers?
Zero becomes 0th, and negative integers keep their minus sign in front of the digits and the suffix. Decimals such as 21.5 are rejected, because only whole numbers have an ordinal form.
Related tools
For developers — API access
Everything on this page is available programmatically. This section is for teams who want to wire it into their own systems; everyone else can just use the tool above.
API endpoint
Prefer to automate it? One authenticated POST creates the task; the result comes back by webhook or a signed link. The same capability also runs here on the web, by email and from Telegram — and soon from our app too.
Call it from your stack
curl -X POST https://api.kit.forhosting.com/fmt/ordinal \
-H "Authorization: Bearer $KIT_KEY" \
-H "Content-Type: application/json" \
-d '{"number":21}'const res = await fetch("https://api.kit.forhosting.com/fmt/ordinal", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.KIT_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
"number": 21
})
});
const { task_id } = await res.json();import os, requests
res = requests.post(
"https://api.kit.forhosting.com/fmt/ordinal",
headers={"Authorization": f"Bearer {os.environ['KIT_KEY']}"},
json={
"number": 21
},
)
task_id = res.json()["task_id"]<?php
$res = file_get_contents("https://api.kit.forhosting.com/fmt/ordinal", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer " . getenv("KIT_KEY") . "\r\nContent-Type: application/json",
"content" => '{"number":21}',
],
]));
$task = json_decode($res, true);body := bytes.NewBufferString(`{"number":21}`)
req, _ := http.NewRequest("POST", "https://api.kit.forhosting.com/fmt/ordinal", body)
req.Header.Set("Authorization", "Bearer "+os.Getenv("KIT_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)Example request
{
"number": 21
}Example response
{
"task_id": "tsk_a1b2c3d4e5f6a1b2c3d4e5f6",
"type": "fmt.ordinal",
"status": "queued",
"_links": {
"result": "/tasks/tsk_…/result"
}
}The API is asynchronous: the call returns a task_id immediately and the result arrives by webhook. Polling is capped at 1 req/s per task.
Pricing
Published price — no tokens, no invented credits. A failed task is never charged.
Errors
| HTTP | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
402 | insufficient_balance | Your balance doesn't cover the task price. |
404 | unknown_type | That task type doesn't exist. |
429 | rate_limited | Too many requests. Use the webhook instead of polling. |
Technical notes
Run it free in your browser for a quick check, or call the API at $0.002 per successful request when you need the same result in a pipeline.
What an ordinal abbreviation is and when you need one
Centralizing the rule behind one endpoint means marketing copy, PDF templates, and mobile screens all spell the same positions the same way.
How the conversion works and what counts as valid input
Non-integer values are rejected: floating-point numbers such as 21.5, strings with decimal points, empty fields, and non-numeric text all fail with invalid_input and a clear message that an integer is required.
Where to run it: free browser tool or automated API
For a one-off check—confirming that twenty-first is 21st, that twelfth is 12th, or that a ranking table will not print 2th—use the free in-browser tool on this page. The same pure function powers the API path when you generate certificates, leaderboards, invoice lines, newsletter subject lines, or localized templates that still use English ordinals. Each successful API call costs $0.002; failed validation is not billed, so probing a bad float or omitting the field does not drain prepaid balance. Drop the call into an ETL step that normalizes place columns, a CMS plugin that expands merge tags like place number into display text, or a game client that shows finish positions after a race. When your product ships in more languages, keep ordinal wording for those locales in separate formatters; this endpoint owns the English abbreviation contract only.
Technical questions
How much does the API cost?
$0.002 per successful request. The browser tool is free. Invalid non-integer input is not charged.