AnvilJSON utilities

Anvil › Docs › /v1/slug

Slugify API: turn any title into a clean URL slug

Turn "Héllo, World’s Best Café!" into hello-worlds-best-cafe. Slugs are the readable part of a web address, and getting them consistent matters for links that should never change.

In one line: GET /v1/slug?text=H%C3%A9llo,%20World%E2%80%99s%20Best%20Caf%C3%A9%21 returns JSON. No key, CORS on, 60 requests a minute.
GET

/v1/slug

Turn a title into a clean URL slug. Change the values and press Send request to call the live API.

Parameters

NameTypeWhat it doesDefault
text requiredstringUp to 4 KB—
sepstringSeparator: - or _-
maxintegerMax length 1–20080

Example

Request:

GET https://api.oddlathe.com/v1/slug?text=H%C3%A9llo,%20World%E2%80%99s%20Best%20Caf%C3%A9%21

Response (generated by the real code when these docs were last built):

{
 "slug": "hello-worlds-best-cafe"
}

Code examples

curl
curl -G 'https://api.oddlathe.com/v1/slug' \
  --data-urlencode 'text=Héllo, World’s Best Café!'
JavaScript (browser or Node 18+)
const params = new URLSearchParams({
  text: "Héllo, World’s Best Café!"
});
const res = await fetch(`https://api.oddlathe.com/v1/slug?${params}`);
if (!res.ok) throw new Error((await res.json()).error.message);
const data = await res.json();
console.log(data);
Python (standard library only)
import json, urllib.parse, urllib.request

params = urllib.parse.urlencode({"text": "Héllo, World’s Best Café!"})
url = "https://api.oddlathe.com/v1/slug?" + params
# Send a User-Agent: the edge network refuses Python's default one.
req = urllib.request.Request(url, headers={"User-Agent": "my-script/1.0"})
with urllib.request.urlopen(req, timeout=10) as r:
    data = json.load(r)
print(data)

When it's useful

  • URLs for blog posts, products or docs pages
  • Safe file names from user-supplied titles
  • Anchor IDs for headings

Good to know

  • Letters with accents are folded to their base letter using Unicode decomposition (é → e, ñ → n).
  • Characters with no plain-letter form are dropped, for example ß, ø, ł, emoji and non-Latin scripts. Transliterate first if you need those.
  • Runs of anything that isn't a letter or digit become one separator, trimmed from both ends. A cut at max never leaves a trailing separator.

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

Errors

Errors are JSON like {"error": {"code": "…", "message": "…"}}. The ones this endpoint can return:

  • missing_param (400): a required parameter is missing or empty
  • bad_param (400): a value is the wrong type or out of range (the message says which)
  • too_long (413): text is over 4 KB
  • rate_limited (429): over 60 requests a minute; wait for Retry-After seconds

Questions

Why is the apostrophe dropped instead of becoming a hyphen?

So that world’s becomes worlds rather than world-s, which reads better.

Will the same title always give the same slug?

Yes, it's deterministic. Responses are cacheable for that reason.

Related endpoints

Prefer a page to an API?

Published · OpenAPI 3.1 spec · Limits and privacy