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}
RuleDetail
Length3 to 40 characters
AllowedLetters, numbers, - and _
MustStart and end with a letter or number
CaseStored lowercase, Spring-Sale becomes spring-sale
BlockedReserved paths, repeated separators, all-digit names, and names imitating banks, wallets or account-security flows
TakenReturns 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

EndpointLimitScope
/api/shorten.php random code15/min, 120/hourPer IP
/api/shorten.php custom name5/min, 25/hour, 60/dayPer IP
/api/bulk.php100 links/request + daily quotaPer 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.

StatusMeaning
200Link created
400Invalid URL, or a name that breaks the rules
401 / 403Bulk only, missing, invalid or disabled key
405Use POST
409Custom name already taken
413More than 100 links in one bulk call
429Rate limited or daily quota reached
503Database 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.

or email [email protected]

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
ToolWhat it does
shorten_urlShorten a URL, optionally with a custom name
expand_urlSee where a 99l.in link points, without opening it or counting a click
get_link_statsClick 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.