anonym.es

Link API

The API creates anonymous short links, returns their click statistics, changes their settings and deletes them. Requests and responses use JSON. CORS is enabled, so calls work from browser code as well.

Base address:

http://anonym.es/api/v1

Quick start

To create a short link, send the destination address:

curl -X POST http://anonym.es/api/v1/links \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/article"}'

No token is required for this call. Without one, the link is created as a guest link within the Free quota of your IP address.

With an account token the same call puts the link into your dashboard and counts it against your plan:

curl -X POST http://anonym.es/api/v1/links \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/article"}'

The response contains the short address, the link id and the token that manages this link. Keep the token: it is needed to read or delete the link later.

{
  "ok": true,
  "link": {
    "id": 4821,
    "short": "http://anonym.es/k7m2q",
    "url": "https://example.com/article",
    "status": "active",
    "password": false,
    "created_at": "2026-09-05T14:02:11Z",
    "expires_at": null,
    "max_hits": null,
    "self_destruct": false,
    "delay": null,
    "no_countdown": false,
    "adult": false,
    "note": null,
    "tags": [],
    "clicks": 0,
    "uniques": 0
  },
  "token": "3f9c1b7e2d4a4c0e9b8f7a6d5c4b3a21",
  "left": 4
}

Fields of the link object

All endpoints that return a link use this structure. Timestamps are ISO 8601 in UTC. The clicks and uniques counters cover the entire lifetime of the link.

FieldTypeWhat it does
idintegerNumeric id of the link, used by the other calls.
shortstringThe short address to share.
urlstring | nullThe destination; null for a note-only link.
statusstringactive | expired | exhausted (visit cap reached) | flagged (destination on a safety list) | banned.
passwordbooleanVisitors must enter a password.
created_atstringISO 8601, UTC.
expires_atstring | nullWhen the link expires; null = no expiry.
max_hitsinteger | nullVisit cap; null = no cap.
self_destructbooleanThe link deletes itself, for good, when the cap or the lifetime is reached.
delayinteger | nullSeconds on the forwarding page; null = the plan default, 0 = instant.
no_countdownbooleanThe forwarding page shows no countdown and waits for a click on the address.
adultbooleanVisitors confirm being 18 or older before the forwarding page.
notestring | nullThe note shown on the forwarding page.
tagsstring[]Tags, lowercase.
clicksintegerVisits for the whole life of the link.
uniquesintegerUnique visitors (one per address per day) for the whole life of the link.

Authorization

Authorized requests carry the token in the Authorization header. The X-API-Key header is accepted as an alternative. Tokens are never passed in the query string.

Authorization: Bearer YOUR_TOKEN
TokenWhere to get itWhat it is for
Account tokenIn the dashboardAll links of the account, with the rights of the plan
Link tokenReturned when a link is createdOne specific link, with the rights of the Free plan

An account token starts with anon_. A link token consists of 32 characters. Generating a new account token invalidates the previous one.

Example:

curl http://anonym.es/api/v1/me \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN"

Generate an account token in the dashboard

Endpoints

Request bodies may be sent as application/json or as application/x-www-form-urlencoded. Parameter names and error codes are identical across all endpoints.

MethodPathTokenCostWhat it does
GET/api/v1optional 1About this API: version, documentation and schema addresses.
POST/api/v1/linksoptional 5 + 1/urlCreate a link, or up to 50 at once. Without a token: as a guest, on the Free quota. Returns the link with its token.
GET/api/v1/names/checkoptional 2Is this custom name available? Suggestions when it is taken.
GET/api/v1/linksaccount 2The account's links, newest first.
GET/api/v1/links/lookuplink or account 1Find one of your links by its short address.
GET/api/v1/links/{id}link or account 1One link: settings, status, clicks and unique visitors for its whole life. Account tokens may add a statistics report.
PATCH/api/v1/links/{id}link or account 3Change settings. Only the fields sent change. Paid plans (a link token has Free rights, so it cannot edit).
DELETE/api/v1/links/{id}link or account 2Delete the link; the name becomes free again.
GET/api/v1/links/{id}/qrlink or account 3The QR code of the short address as an image (PNG or SVG); needs a token, so it suits server-side use.
GET/api/v1/qroptional 3The QR code of a short address as an image, without a token: the address itself is the key. Made for <img> tags.
GET/api/v1/meaccount 1The account: plan, limits, quota left, alias domains, what the plan allows.
GET/api/v1/openapi.jsonoptional 1This API as an OpenAPI 3.1 document.

The cost is given in rate-limit units, see Rate limits.

Creating a link

POST /api/v1/links

The minimal request contains only the url field:

curl -X POST http://anonym.es/api/v1/links \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/article"}'

With an account token the link belongs to the account and counts against its plan. Without a token it is a guest link on the IP quota:

curl -X POST http://anonym.es/api/v1/links \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/article"}'

A successful request returns status 201 together with the link, its token and the number of links left in the current quota period.

Fields of the response:

FieldTypeWhat it does
linkobjectThe created link.
tokenstringThe link token (32 characters): manages this link.
leftinteger | nullLinks still available in the current quota period; null when the plan has no limit.
qrobjectThe QR code, present when qr=true was sent.
batchbooleantrue when several addresses were sent.
resultsarrayOne entry per address, in the order sent: {ok: true, link, token, qr} or {ok: false, url, error, message, field}.

Link with a custom name

The short address gets the name my-article if it is free and meets the rules below.

curl -X POST http://anonym.es/api/v1/links \
  -H "Content-Type: application/json" \
  -d '{"url":"https://example.com/article","name":"my-article"}'

Name rules:

A name can be checked before the link is created:

curl "http://anonym.es/api/v1/names/check?name=my-article"

Fields of the check response:

FieldTypeWhat it does
availablebooleantrue when the name can be used.
namestringThe name that was checked.
errorstringWhy the name is not available: taken, reserved, too_short and the other name errors.
messagestringThe reason in words.
fieldstringAlways name.
suggestarrayFree alternatives when the name is taken.

Several links at once

The urls field accepts up to 50 addresses, as a JSON array or as text with one address per line. Each address becomes its own link with its own token, and the other fields apply to all of them. A custom name is not available in a batch.

curl -X POST http://anonym.es/api/v1/links \
  -H "Content-Type: application/json" \
  -d '{"urls":["https://example.com/a","https://example.com/b","https://example.com/c"]}'

The response contains batch: true and a results array with one entry per address, in the order sent. A faulty address produces an entry with ok: false and the error code without stopping the rest.

Additional settings

curl -X POST http://anonym.es/api/v1/links \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/article",
    "name": "my-article",
    "expires_days": 30,
    "max_hits": 1000,
    "self_destruct": true,
    "password": "secret",
    "note": "Available until the end of the month",
    "delay": 5,
    "tags": "blog,promo",
    "qr": true,
    "qr_size": 300,
    "qr_format": "png"
  }'

Options marked as paid are ignored for guests and on the Free plan. The response reflects the settings the link actually received.

FieldTypeWhat it does
urlstring, requiredThe destination. Or urls: several addresses, one per line or as a JSON array (up to 50); each gets its own link.
namestringCustom name for a single link (checked against the rules and the name filter).
domainstringOne of the alias domains, random, or random-alias (random among the alias domains only). Paid plans; default is random: links never sit on the main domain. Free and guests: anonymes.click.
subbooleanMake it name.alias instead of alias/name. Max plan, alias domains only.
expires_daysintegerLifetime in days. Paid plans.
max_hitsintegerVisit cap. Paid plans.
self_destructbooleanDelete the link for good when the visit cap or the lifetime is reached (needs max_hits or expires_days).
passwordstringPassword visitors must enter. Paid plans.
notestringText shown on the forwarding page. Paid plans; length by plan.
note_onlybooleanThe link opens the note itself, no destination. Pro+ and up.
delayintegerSeconds on the forwarding page, 0 = instant. Paid plans.
no_countdownbooleanNo countdown on the forwarding page: no timer, no automatic forward, the visitor clicks the address. Paid plans.
adultbooleanAdult content (18+): visitors confirm their age on a page of its own before anything else is shown. Every plan.
tagsstringComma-separated tags (up to 5, 24 characters each). Account tokens on paid plans.
qrbooleanInclude the QR code of the short address (base64) in the response.
qr_sizeintegerSide of the QR image in pixels, 100-1000 (default 300; PNG rounds down to whole modules).
qr_formatstringpng (default) or svg.
qr_logobooleanfalse = plain code without the logo; paid plans only, otherwise ignored.

Listing links

GET /api/v1/links

Requires an account token.

Requires an account token. Links are returned newest first.

curl "http://anonym.es/api/v1/links?page=1&per=50" \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN"
FieldTypeWhat it does
pageintegerPage number (default 1).
perintegerLinks per page, 1-100 (default 50).
qstringSearch in the short name, domain and destination (one flat list, up to 50).
tagstringOnly links with this tag.

Search and the tag filter can be combined:

curl "http://anonym.es/api/v1/links?q=example&tag=promo" \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN"

Fields of the response:

FieldTypeWhat it does
pageintegerCurrent page.
perintegerLinks per page.
totalintegerNumber of links matched.
pagesintegerNumber of pages.
linksarrayLink objects, newest first.

Finding a link by its short address

A link is addressed by its numeric id (the id field, for example 4821), not by the name in the short address. When only the short address is known, the id can be looked up with any token that manages the link:

curl --get http://anonym.es/api/v1/links/lookup \
  -H "Authorization: Bearer YOUR_TOKEN" \
  --data-urlencode "short=http://anonym.es/k7m2q"

Link details and statistics

GET /api/v1/links/{id}

Returns the settings of the link, its status, the number of visits and the number of unique visitors for its whole life:

curl http://anonym.es/api/v1/links/4821 \
  -H "Authorization: Bearer YOUR_TOKEN"

With an account token, a visits report can be added with the stats parameter:

curl "http://anonym.es/api/v1/links/4821?stats=day" \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN"
ValueReport period
dayLast 30 days, by day
weekLast 26 weeks, by ISO week
monthLast 24 months, by month

Fields of the response: stats

FieldTypeWhat it does
modestringday, week or month.
fromstringFirst day of the report, YYYY-MM-DD.
tostringLast day of the report.
seriesarrayOne entry per bucket, oldest first: [from, to, visits, uniques].
summaryobjectcur (the current bucket), prev (the previous one), avg (the average of the buckets before the current one), each with hits and uniq.
dimsobjectBreakdown for the range: ref, country, device, os, browser, hour, each a list of [value, visits].

Editing a link

PATCH /api/v1/links/{id}

Only the fields sent change:

curl -X PATCH http://anonym.es/api/v1/links/4821 \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"max_hits": 2000, "delay": 3, "tags": "blog,updated"}'

Editing requires a paid plan. A link token has the rights of the Free plan and cannot change settings.

FieldTypeWhat it does
urlstringNew destination. Pro+ and up.
namestringNew name (same rules as a custom name).
expires_daysintegerNew lifetime in days; empty = no expiry.
max_hitsintegerNew visit cap; empty = no cap.
self_destructbooleanDelete for good when the cap or the lifetime is reached; false turns it off.
passwordstringNew password; an empty string removes the password.
notestringNew note; empty removes it (a note-only link keeps needing one).
delayintegerSeconds on the forwarding page; empty = the plan default.
no_countdownbooleantrue = no countdown on the forwarding page; false turns the countdown back on.
adultbooleantrue = age confirmation (18+) before the forwarding page; false removes it.
tagsstringNew comma-separated tag list; empty removes all tags.

Clearing a value

curl -X PATCH http://anonym.es/api/v1/links/4821 \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"password": "", "note": "", "expires_days": null, "max_hits": null, "delay": 0}'

Deleting a link

DELETE /api/v1/links/{id}
curl -X DELETE http://anonym.es/api/v1/links/4821 \
  -H "Authorization: Bearer YOUR_TOKEN"

After deletion the custom name becomes free again. The statistics are deleted together with the link.

Fields of the response:

FieldTypeWhat it does
deletedintegerThe id of the deleted link.

QR code

For an HTML img tag, request the code by the short address. This endpoint needs no token: the short address itself is the key, and anyone who has it can generate the same code.

<img
  src="http://anonym.es/api/v1/qr?short=http%3A%2F%2Fanonym.es%2Fk7m2q&qr_size=400"
  alt="QR code"
>

Server-side code can also request the image by id with a token, or receive it base64-encoded in JSON by adding qr=true to the create or details call:

curl "http://anonym.es/api/v1/links/4821/qr?qr_size=400&qr_format=svg" \
  -H "Authorization: Bearer YOUR_TOKEN" -o qr.svg

Parameters of both image endpoints:

FieldTypeWhat it does
shortstring, requiredThe short address, for example https://anonym.es/abc12.
qr_sizeintegerSide of the QR image in pixels, 100-1000 (default 300; PNG rounds down to whole modules).
qr_formatstringpng (default) or svg.
qr_logobooleanfalse = plain code without the logo; paid plans only, otherwise ignored.

The qr member in JSON responses:

FieldTypeWhat it does
formatstringpng or svg.
mimestringimage/png or image/svg+xml.
sizeintegerRequested side length in pixels.
logobooleanWhether the logo is drawn in the center.
base64stringThe image, base64-encoded.

Account details

GET /api/v1/me

Requires an account token. Returns the plan, its limits and the remaining quota:

curl http://anonym.es/api/v1/me \
  -H "Authorization: Bearer anon_YOUR_ACCOUNT_TOKEN"
FieldTypeWhat it does
loginstringThe account login.
planstringPlan key: free, pro, pro_plus, max or enterprise.
plan_labelstringThe plan name as shown on the site.
untilstring | nullWhen the paid plan ends, ISO 8601; null on Free or without an end date.
limitsobjectlinks (per period), per (day or month), ai_hourly (custom names per hour), name_min (shortest custom name), note_max (note length), api_units (API budget per minute).
leftinteger | nullLinks still available in the current quota period; null without a limit.
aliasesarrayThe alias domains the plan may use.
canobjectOne boolean per option: password, ttl, edit, edit_url, tags, note, note_only, alias, sub, instant, qr_no_logo.

Errors

Errors are returned in a single JSON format:

{
  "ok": false,
  "error": "taken",
  "message": "This name is already taken.",
  "field": "name",
  "suggest": ["my-article-26", "my-my-article", "my-article-link"]
}

field contains the name of the faulty parameter, or null when the error does not concern a specific field. A taken name adds suggest, a paid option adds upgrade, quotas and rate limits add the Retry-After header.

HTTPMeaning
400Error in the request parameters
401Token missing or invalid
403The plan or the token type does not allow this call
404The link does not exist or belongs to someone else
405Method not allowed for this path
409The custom name is taken
429Rate limit or quota exhausted. See Retry-After
501PNG is not available on this server. Request svg
All error codes
CodeHTTPFieldWhat it does
bad_request400Malformed request.
bad_url400urlThe address is missing or is not a valid http(s) URL.
blocked400urlThis destination cannot be linked.
bad_name400nameThis name is not allowed.
dirty400nameThis name is not allowed.
brand400nameThis name looks like a brand name and cannot be used.
reserved400nameThis name is reserved.
too_short400nameThe name is too short for your plan.
sub_format400nameA subdomain name is 3 to 32 letters, digits or hyphens.
sub_main400domainSubdomain links exist on the alias domains only.
name_batch400nameA custom name works for a single address, not for a batch.
taken409nameThis name is already taken.
note_long400noteThe note is longer than your plan allows.
note_required400noteA note-only link needs a note.
bad_tag400tagsTags: up to 5 of them, each up to 24 characters.
pro_only403This option needs a paid plan.
max_only403Subdomain links need the Max plan.
account_only403This call needs an account token.
limit429The link quota for this period is used up.
domain_limit429urlToday's limit for links to this site without an account is used up.
ai_limit429nameToo many custom names this hour; try again later.
rate_limited429Too many requests; slow down.
busy429Too many links being created at once; retry in a moment.
auth401Missing or invalid token.
not_found404No such link.
no_route404No such endpoint.
method405Method not allowed.
fetch500Could not create the link; try again.
qr_unavailable501qr_formatPNG QR codes are not available on this server; request svg.

Rate limits

Each call costs units, and each plan has a budget of units per minute (see Plans and limits). A read costs 1 unit, a list page 2, a QR code 3, an edit 3, a deletion 2, a creation 5 plus 1 per address. Every response carries these headers:

HeaderValue
X-RateLimit-LimitBudget of units per minute
X-RateLimit-RemainingUnits left in the current minute
X-RateLimit-ResetSeconds until the budget renews
Retry-AfterOn 429: seconds to wait before retrying

Within any 10-second window at most a quarter of the minute budget can be spent, with a minimum of 20 units. When the budget is exhausted, the API responds with status 429.

Plans and limits

The exact limits of each plan. Links are counted per day and IP address on Free, per month and account on paid plans. The last column lists the settings a plan can use.

PlanLinksCustom names per hourShortest nameNote lengthUnits a minuteOptions
Free 5 per day, per IP address 5 5 0 60 none
Pro 500 per month 10 3 300 150 password, expires_days, max_hits, edit, tags, note, domain, delay, qr_logo
Pro+ 2,000 per month 50 3 2,000 400 password, expires_days, max_hits, edit, edit url, tags, note, note_only, domain, delay, qr_logo
Max 50,000 per month 200 3 5,000 1,000 password, expires_days, max_hits, edit, edit url, tags, note, note_only, domain, sub, delay, qr_logo
Enterprise unlimited unlimited 3 5,000 2,500 password, expires_days, max_hits, edit, edit url, tags, note, note_only, domain, sub, delay, qr_logo

Without an account token, creation counts against the Free quota of the IP address: 5 links per day. Links to a destination domain registered less than a year ago share one guest cap of 5 a day, whoever makes them. At most 2 links per caller can be in creation at the same time.

OpenAPI specification

The complete technical description as an OpenAPI 3.1 document: http://anonym.es/api/v1/openapi.json

It contains schemas and examples of every request and response, the plan limits, the name rules and the error codes. It suits Swagger UI, Postman, Insomnia and client generators.