99L API
Turn a long URL into a short one with a single HTTP call. No key, no signup, no SDK. Custom names and bulk import are supported too.
1 Quick start
One required field. This is the whole thing:
$ curl -s https://99l.in/api/shorten.php \ -d "url=https://example.com/a/very/long/page" {"ok":true,"short":"https://99l.in/gx","code":"gx", "long":"https://example.com/a/very/long/page","custom":false}
const res = await fetch("https://99l.in/api/shorten.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ url: "https://example.com/page" }) }); const data = await res.json(); console.log(data.short); // https://99l.in/gx
import requests r = requests.post("https://99l.in/api/shorten.php", data={"url": "https://example.com/page"}) print(r.json()["short"]) # https://99l.in/gx
$ch = curl_init("https://99l.in/api/shorten.php"); curl_setopt_array($ch, [ CURLOPT_POST => true, CURLOPT_POSTFIELDS => ["url" => "https://example.com/page"], CURLOPT_RETURNTRANSFER => true, ]); $out = json_decode(curl_exec($ch), true); echo $out["short"];
No API key needed. Both form-encoded and JSON bodies work. If you leave off https:// we add it for you.
2 Custom names
Add alias to choose the ending yourself. Names are first-come, first-served and permanent.
$ curl -s https://99l.in/api/shorten.php \ -d "url=https://example.com/spring-sale" \ -d "alias=spring-sale" {"ok":true,"short":"https://99l.in/spring-sale","code":"spring-sale","custom":true}
| Rule | Detail |
|---|---|
| Length | 3 to 40 characters |
| Allowed | Letters, numbers, - and _ |
| Must | Start and end with a letter or number |
| Case | Stored lowercase, Spring-Sale becomes spring-sale |
| Blocked | Reserved paths, repeated separators, all-digit names, and names imitating banks, wallets or account-security flows |
| Taken | Returns 409, pick another |
Why some names are refused. A short link reading 99l.in/hdfc-kyc-update is a ready-made phishing tool, and one abuse report can get the whole domain blocklisted, breaking every other link on it. So finance, wallet and “verify your account” style names are rejected.
3 Rate limits
| Endpoint | Limit | Scope |
|---|---|---|
/api/shorten.php random code | 15/min, 120/hour | Per IP |
/api/shorten.php custom name | 5/min, 25/hour, 60/day | Per IP |
/api/bulk.php | 100 links/request + daily quota | Per API key |
Over the limit you get 429 with a Retry-After header saying how many seconds to wait. Back off and retry, don't hammer.
4 Responses
Every response is JSON with an ok boolean. On failure, error is a sentence you can show a user directly.
| Status | Meaning |
|---|---|
200 | Link created |
400 | Invalid URL, or a name that breaks the rules |
401 / 403 | Bulk only, missing, invalid or disabled key |
405 | Use POST |
409 | Custom name already taken |
413 | More than 100 links in one bulk call |
429 | Rate limited or daily quota reached |
503 | Database briefly unavailable, retry |
What we block. Only http and https links. Non-web schemes such as javascript: and data: are rejected, as are private and loopback addresses, so 99L can't be pointed at an internal network.
5 Bulk API
Shorten up to 100 links per call, with optional names per item. Each row succeeds or fails on its own, so one bad URL in a CSV import doesn't discard the other 99.
$ curl -s https://99l.in/api/bulk.php \ -H "Authorization: Bearer YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"links":[ {"url":"https://example.com/one","alias":"promo-one"}, {"url":"https://example.com/two"} ]}' {"ok":true,"requested":2,"created":2,"failed":0,"remaining":1998, "results":[ ... ]}
Who it's for
Bulk SMS and WhatsApp campaigns, CRM exports, affiliate feeds, print runs with per-item QR codes.
What it costs
Low, flat and based on volume, not an enterprise pricing maze. Tell us your monthly volume and we'll quote it.
Request a key
Tell us roughly what you need and we'll reply within one working day.
6 MCP server
99L speaks the Model Context Protocol, so an AI assistant can shorten links for you directly. There is nothing to install and no key to request. Add this URL as a remote MCP server:
https://99l.in/mcp
| Tool | What it does |
|---|---|
shorten_url | Shorten a URL, optionally with a custom name |
expand_url | See where a 99l.in link points, without opening it or counting a click |
get_link_stats | Click count, destination and creation date for a link |
Transport is Streamable HTTP (JSON-RPC 2.0 over POST). The server is stateless and unauthenticated, so no session handling or OAuth flow is involved. The same rate limits as the REST API apply.
Adding it by hand in a client that uses a JSON config file:
{
"mcpServers": {
"99l": {
"type": "http",
"url": "https://99l.in/mcp"
}
}
}
Opening https://99l.in/mcp in a browser returns a short JSON descriptor listing the protocol versions and tools, which is handy for checking the endpoint is reachable.
7 Interactive reference
The full OpenAPI 3 spec, live. Expand an endpoint and hit Try it out to call the real API from this page.