🍔 burg.nr

API docs. Create short links with one request. No API key and no sign-up.

Create a link

POST https://burg.nr/api/shorten

FieldDescription
urlRequired. The long link. If you leave out https://, it's added for you.
aliasOptional. Your own ending: 3 to 32 letters, numbers, - or _. Case sensitive. Leave it out for a random one.

Send JSON with Content-Type: application/json. Regular form data works too.

Response

A new link returns status 201:

{
  "ok": true,
  "code": "abc12",
  "short": "https://burg.nr/abc12",
  "url": "https://example.com/very/long/link"
}

Errors return {"ok":false,"error":"..."} with one of these statuses:

400Bad URL, or an invalid or reserved alias.
405Wrong HTTP method. Creating a link needs POST, and the other endpoints need GET.
409That alias is already taken.
429Rate limit reached. Try again later.
500Server error.

Get link info and clicks

GET https://burg.nr/api/link/{code}

Returns where a link goes, how many times it has been clicked, and when it was created (server time). An unknown code returns status 404.

{
  "ok": true,
  "code": "abc12",
  "short": "https://burg.nr/abc12",
  "url": "https://example.com/very/long/link",
  "clicks": 42,
  "created_at": "2026-11-14 09:30:00"
}

Every visit counts as a click, including bots and link previews.

Site stats

GET https://burg.nr/api/stats

Totals for the whole site. today counts links made in the last 24 hours.

{ "ok": true, "links": 1240, "clicks": 8431, "today": 12 }

Examples

curl

curl -X POST https://burg.nr/api/shorten \
  -H "Content-Type: application/json" \
  -d '{"url":"example.com/very/long/link","alias":"my-link"}'

curl https://burg.nr/api/link/my-link
curl https://burg.nr/api/stats

Node.js 18+ or browser

const res = await fetch('https://burg.nr/api/shorten', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ url: 'example.com/very/long/link' }),
});
const data = await res.json();
console.log(data.ok ? data.short : data.error);

// Get the click count
const info = await (await fetch(`https://burg.nr/api/link/${data.code}`)).json();
console.log(info.clicks);

Python

import requests

r = requests.post('https://burg.nr/api/shorten',
                  json={'url': 'example.com/very/long/link'})
data = r.json()
print(data['short'] if data['ok'] else data['error'])

# Get the click count
info = requests.get(f"https://burg.nr/api/link/{data['code']}").json()
print(info['clicks'])

Discord bots

Two small bots with /shorten and /clicks slash commands. Put your bot token in a DISCORD_TOKEN environment variable instead of the code.

Node.js with discord.js v14 (Node 18 or newer, npm i discord.js)

const { Client, GatewayIntentBits, SlashCommandBuilder } = require('discord.js');

const API = 'https://burg.nr/api';
const client = new Client({ intents: [GatewayIntentBits.Guilds] });

client.once('ready', () => {
  client.application.commands.set([
    new SlashCommandBuilder().setName('shorten').setDescription('Shorten a link')
      .addStringOption(o => o.setName('url').setDescription('The long link').setRequired(true))
      .addStringOption(o => o.setName('alias').setDescription('Custom ending')),
    new SlashCommandBuilder().setName('clicks').setDescription('Get the clicks on a short link')
      .addStringOption(o => o.setName('code').setDescription('The short code').setRequired(true)),
  ]);
});

client.on('interactionCreate', async (i) => {
  if (!i.isChatInputCommand()) return;
  await i.deferReply();

  if (i.commandName === 'shorten') {
    const res = await fetch(`${API}/shorten`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        url: i.options.getString('url'),
        alias: i.options.getString('alias') || undefined,
      }),
    });
    const d = await res.json();
    return i.editReply(d.ok ? `🍔 ${d.short}` : `Couldn't shorten: ${d.error}`);
  }

  if (i.commandName === 'clicks') {
    const code = encodeURIComponent(i.options.getString('code'));
    const d = await (await fetch(`${API}/link/${code}`)).json();
    return i.editReply(d.ok ? `${d.short} has ${d.clicks} clicks.` : `Error: ${d.error}`);
  }
});

client.login(process.env.DISCORD_TOKEN);

Python with discord.py (Python 3.10 or newer, pip install discord.py aiohttp)

import os
from urllib.parse import quote

import aiohttp
import discord
from discord import app_commands

API = 'https://burg.nr/api'


class Bot(discord.Client):
    def __init__(self):
        super().__init__(intents=discord.Intents.default())
        self.tree = app_commands.CommandTree(self)

    async def setup_hook(self):
        await self.tree.sync()


bot = Bot()


@bot.tree.command(description='Shorten a link')
async def shorten(interaction: discord.Interaction, url: str, alias: str | None = None):
    await interaction.response.defer()
    payload = {'url': url}
    if alias:
        payload['alias'] = alias
    async with aiohttp.ClientSession() as s:
        async with s.post(f'{API}/shorten', json=payload) as r:
            d = await r.json()
    await interaction.followup.send(f"🍔 {d['short']}" if d['ok'] else f"Couldn't shorten: {d['error']}")


@bot.tree.command(description='Get the clicks on a short link')
async def clicks(interaction: discord.Interaction, code: str):
    await interaction.response.defer()
    async with aiohttp.ClientSession() as s:
        async with s.get(f'{API}/link/{quote(code)}') as r:
            d = await r.json()
    await interaction.followup.send(f"{d['short']} has {d['clicks']} clicks." if d['ok'] else f"Error: {d['error']}")


bot.run(os.environ['DISCORD_TOKEN'])

Rate limits apply per IP address, so everyone using your bot shares one limit.

Limits and rules

Each IP address can create 60 links per hour through the API. Only http and https links work, and links to burg.nr itself or to private addresses are blocked.

The same acceptable use rules as the website apply. No spam, phishing, malware, or scams. Abusive links are removed, and abusers may be blocked.