b59.link API
A simple REST API for shortening URLs, generating QR codes, and reading click stats. No API key required — anyone can use it. If you sign up, your links are tracked to your account.
Base URL
All endpoints accept and return JSON. Errors follow a standard { detail: string } shape.
Authentication
All endpoints work without authentication. Links created anonymously are public and permanent. Sign in with your b59.link account to associate links with your profile and manage them from the dashboard.
/api/shortenShorten a long URL. Omit slug to get suggestions; include slug to create the link immediately.
Request body
{
"url": "https://example.com/very/long/url",
"slug": "my-link" // optional
}Response
// Without slug — returns suggestions:
{ "suggestions": ["cool-jump", "fast-fly", "slim-run"] }
// With slug — creates the link:
{
"slug": "my-link",
"short_url": "https://b59.link/my-link"
}Code sample
// Shorten a URL
const res = await fetch("https://b59.link/api/shorten", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
url: "https://example.com/very/long/path",
slug: "my-link", // optional
}),
});
const data = await res.json();
console.log(data.short_url); // https://b59.link/my-link
console.log(data.slug); // my-link/api/qrGenerate a QR code for a URL. Also creates a short link in one call. Returns a base64-encoded PNG.
Request body
{
"url": "https://example.com"
}Response
{
"slug": "cool-jump",
"short_url": "https://b59.link/cool-jump",
"qr_code_data": "<base64 PNG>"
}Code sample
// Generate a QR code (also creates a short link)
const res = await fetch("https://b59.link/api/qr", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ url: "https://example.com" }),
});
const data = await res.json();
// data.qr_code_data is a base64-encoded PNG
const img = document.createElement("img");
img.src = `data:image/png;base64,${data.qr_code_data}`;
document.body.appendChild(img);/api/stats/{identifier}Get click stats for a link. Pass either a slug or the original URL as the identifier.
Request body
GET /api/stats/my-link
// or
GET /api/stats/https%3A%2F%2Fexample.comResponse
{
"slug": "my-link",
"original_url": "https://example.com/...",
"short_url": "https://b59.link/my-link",
"qr_code_data": "<base64 PNG or null>",
"total_hits": 42,
"hits": [
{
"timestamp": "2025-05-19T10:00:00",
"ip_address": "1.2.3.4",
"referer": "https://instagram.com",
"user_agent": "Mozilla/5.0 ..."
}
]
}Code sample
// Get stats by slug or original URL
const slug = "my-link";
const res = await fetch(`https://b59.link/api/stats/${slug}`);
const data = await res.json();
console.log(data.total_hits); // 42
console.log(data.original_url); // https://example.com/...
// You can also pass the original URL as the identifier
const res2 = await fetch(
`https://b59.link/api/stats/${encodeURIComponent("https://example.com")}`
);/api/links/lookupCheck if a URL already has a b59.link. Automatically tries http/https, www, and trailing-slash variations.
Request body
GET /api/links/lookup?url=https%3A%2F%2Fexample.comResponse
// Found:
{
"found": true,
"slug": "cool-jump",
"short_url": "https://b59.link/cool-jump",
"stats_url": "https://b59.link/stats/cool-jump",
"qr_code_data": "<base64 PNG or null>"
}
// Not found:
{ "found": false }Code sample
// Check if a URL already has a b59 link (handles http/https/www variations)
const url = "https://example.com";
const res = await fetch(
`https://b59.link/api/links/lookup?url=${encodeURIComponent(url)}`
);
const data = await res.json();
if (data.found) {
console.log(data.short_url); // https://b59.link/cool-jump
console.log(data.stats_url); // https://b59.link/stats/cool-jump
// data.qr_code_data — base64 PNG if QR exists
} else {
console.log("No link yet — create one with POST /qr");
}Error responses
All errors return a JSON body with a detail field.
| Status | Meaning |
|---|---|
| 400 | Bad request — invalid slug format |
| 404 | Link not found |
| 409 | Conflict — URL or slug already exists |
| 422 | Validation error — missing required field |
| 500 | Internal server error |