Minlink
Links API
Create, manage, and analyze Minlink short links with the developer API.
- Base URL:
https://cm.minlink.io/v1/api - Auth:
x-minlink-api-key: <your-key>(create keys in the console → Developer → API Keys) - Responses:
{ status, message, data }; errors:{ status: "error", error: { code, message } }
Quickstart (backend)
const BASE = 'https://cm.minlink.io/v1/api';
const API_KEY = process.env.MINLINK_API_KEY!;
async function createLink() {
const res = await fetch(`${BASE}/links`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-minlink-api-key': API_KEY,
},
body: JSON.stringify({
originalUrl: 'https://example.com/landing',
title: 'Launch page',
tags: ['launch', 'promo'],
expiration: { type: 'never' },
}),
});
const json = await res.json();
console.log(json.data.link.shortUrl);
}
createLink().catch(console.error);Frontend snippets
// app/api/link/route.ts
import { NextResponse } from 'next/server';
export async function POST(req: Request) {
const API_KEY = process.env.MINLINK_API_KEY!;
const BASE = 'https://cm.minlink.io/v1/api';
const payload = await req.json();
const res = await fetch(`${BASE}/links`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-minlink-api-key': API_KEY,
},
body: JSON.stringify(payload),
});
return NextResponse.json(await res.json(), { status: res.status });
}Link lifecycle endpoints
Create a link
POST /links- Body: see the payload map below.
| Prop | Type | What it controls |
|---|---|---|
originalUrl | string (required) | Destination URL to shorten. |
title | string (required) | Friendly name shown in dashboards. |
tags | string[] | Optional labels for filtering (e.g., ["launch","promo"]). |
expiration | object { type: "never" | "date" | "clicks", value?: string | number } | Expiration mode: never, fixed date (value ISO string), or max clicks (value number). |
expiresAt | string (ISO) | Concrete date when expiration.type === "date". |
customDomain | string | Override default domain when building shortUrl. |
status | string | Optional lifecycle toggle, defaults to active if omitted. |
- Notes: duplicate
originalUrl+customDomainfor the same owner returns 409 withLINK_ALREADY_EXISTS. - Sample response:
data.linkincludes_id,originalUrl,shortUrl,title,tags,status,expiration,clicks, timestamps.
List links
GET /links- returns all links for the API key owner, newest first.
Get a link
GET /links/:id
Update a link
PUT /links/:id- Body: any subset of
originalUrl,title,tags,expiration,customDomain,expiresAt,status. - Custom domains: updating
customDomainrewritesshortUrltohttps://<new-domain>/r/<code>.
Delete a link
DELETE /links/:id
Redirect + public behavior
Consumer-facing redirects are public at https://<frontend>/r/<code>. The API gives you the shortUrl to share; it enforces:
- expiration by date or click count
- optional maxClicks
- optional password (prompts end users if set)
Analytics
Link analytics
GET /links/:id/analytics- Returns (inside
data.analytics):totalClicks,uniqueVisitors(array of visitor fingerprints),uniqueVisitorsCountaverageClickTime,averageClicksPerVisitorclicksData(time-series),topCountries,devices,timeOfDay,topReferrers,topBrowserslastUpdated,lastClickAt
Tracking pixel (auto-enqueued)
This is public-facing and normally used by the redirect flow. It is available at /links/track/:id on the main router; developer API consumers typically do not need to call it directly because clicks are recorded from redirects.
Frontend integration
- Share the returned
shortUrl; redirects from/r/:shortCodehandle analytics, expiration, passwords, and max-click rules automatically. - If you host a landing page and still want server analytics, embed a 1×1 pixel:
<img
src="https://cm.minlink.io/v1/links/track/<linkId>?ua=${encodeURIComponent(
navigator.userAgent,
)}&screen=${window.innerWidth}x${window.innerHeight}&referrer=${encodeURIComponent(document.referrer)}"
alt=""
width="1"
height="1"
/>- Public links:
POST /links/p(rate-limited) creates a 30-day link; your UI can poll/links/analyticsUpdate?shortUrl=<full-short-url>to show status/metrics. - Reachability check before creation:
GET https://cm.minlink.io/v1/links/check-url?url=<encodedUrl>. - QR: render the QR endpoint output directly as an
<img>or download it for reuse.
QR codes
Fetch QR code image
GET /links/:id/qrcode- Query params:
format:png(default) |jpg|svgsize: number (pixels) optional
- Returns the image buffer.
Error codes to expect
- 401/403 if the API key is missing, invalid, inactive, suspended owner, or lacks permissions.
- 402 if the developer account is paused (low balance).
- 404 if a link is not found.
- 409 if a duplicate link exists.
Helpful patterns
Create, then fetch analytics
import fetch from 'node-fetch';
const headers = {
'content-type': 'application/json',
'x-minlink-api-key': process.env.MINLINK_API_KEY!,
};
const BASE = 'https://cm.minlink.io/v1/api';
async function run() {
const create = await fetch(`${BASE}/links`, {
method: 'POST',
headers,
body: JSON.stringify({
originalUrl: 'https://example.com',
title: 'Example',
expiration: { type: 'never' },
}),
}).then((r) => r.json());
const linkId = create.data.link._id;
const analytics = await fetch(`${BASE}/links/${linkId}/analytics`, {
headers,
}).then((r) => r.json());
console.log('Short URL:', create.data.link.shortUrl);
console.log('Top countries:', analytics.data.analytics.topCountries);
}
run().catch(console.error);Delete a link
await fetch(`https://cm.minlink.io/v1/api/links/${linkId}`, {
method: 'DELETE',
headers: { 'x-minlink-api-key': process.env.MINLINK_API_KEY! },
});