Create links with routing rules, manage tags and custom domains and read click analytics through a REST API with an OpenAPI 3.1 spec, or the typed TypeScript SDK with zero dependencies.
Create a key in Profile β API
Last updated: November 2026
npm install revolink
Works in Node.js 18+ and any runtime with a global fetch. No dependencies, full TypeScript types generated from the API spec.
From zero to your first short link in three steps.
In Revolink open Profile β API and create a key. Pick only the permissions the key needs.
The workspace id is sent with every request, so the key always acts in one workspace.
Initialise the client with the key and the workspace id and call links.create.
Keep the key on your server. Anyone who has it can act on your workspace within the key's permissions.
With the Revolink SDK you can create short links with routing rules in just a few lines of code.
import {Revolink} from 'revolink';
const revolink = new Revolink({
apiKey: process.env.REVOLINK_API_KEY!,
workspaceId: process.env.REVOLINK_WORKSPACE_ID!,
});
const {shortLink} = await revolink.links.create({
url: 'https://example.com',
});
console.log(shortLink); // https://rvlnk.link/k3x9aRequest
await revolink.links.create({
url: 'https://example.com',
});Response
{
id: "65f1c0a2e4b0a1d2c3b4a5f6",
name: "example.com",
domain: "rvlnk.link",
slug: "k3x9a",
shortLink: "https://rvlnk.link/k3x9a",
url: "https://example.com",
active: true,
clicks: 0,
...
}Four resources and a whoami call. Every method maps to one REST endpoint.
| Resource | Methods | What it does |
|---|---|---|
| revolink.links | createupsertgetlistiterateupdatedeletecreateManyupdateManydeleteMany | Create, read, update and delete links, upsert by slug, list with filters and pagination, iterate through every page, and work in bulk (up to 100 per call). |
| revolink.tags | listgetcreateupdatedelete | Create, list, rename and delete tags. |
| revolink.domains | listgetcreatedelete | Add a custom domain, check its verification status and remove it. |
| revolink.analytics | linkworkspace | Click analytics for one link or for the whole workspace over a date range. |
| revolink.me() | Who the key acts as, the workspace and the permissions of the key. |
Send different visitors to different destinations. Exactly one rule is the default; the others match on country, device, OS and other conditions.
await revolink.links.create({
name: 'App download',
rules: [
{isDefault: true, targetUrl: 'https://example.com/download'},
{
isDefault: false,
targetUrl: 'https://apps.apple.com/app/id1',
device: ['mobile'],
os: ['iOS'],
},
],
});Every key carries scopes. An endpoint answers 403 when the scope it needs is missing, so give each integration only what it uses.
Authorization: Bearer <key>Send the key as a bearer token.
X-Api-KeyOr send the key in this header instead.
X-Workspace-IdRequired. The workspace the request acts in. The owner of the key must be a member of it.
| Scope | Allows |
|---|---|
links:read | List and read links |
links:write | Create, upsert and update links |
links:delete | Delete links |
links:bulk | Bulk create, update and delete (up to 100 links per request) |
analytics:read | Read click analytics |
tags:read | List and read tags |
tags:write | Create and update tags |
tags:delete | Delete tags |
domains:read | List and read custom domains |
domains:write | Add custom domains |
domains:delete | Delete custom domains |
API calls count towards the monthly API quota of the workspace owner's plan. When a plan limit stops a request, the error code is license_limit_reached.
Every failed request throws a RevolinkError with the HTTP status, a machine-readable code and a message that says what to fix.
import {RevolinkError} from 'revolink';
try {
await revolink.links.create({url: 'https://example.com', slug: 'taken'});
} catch (error) {
if (error instanceof RevolinkError) {
error.status; // 409
error.code; // 'conflict'
error.licenseLimitReached; // true when the plan's limit stopped the request
error.requiredPermission; // e.g. 'tags:write' when the key lacks a scope
error.retryAfter; // seconds, on 429
}
}A 429 is always retried after the Retry-After delay. Network errors and 5xx answers are retried only for GET, PUT and DELETE. A POST or PATCH that may already have been processed is never repeated, so a link is not created twice. Defaults: a 30 second timeout per attempt and 2 retries; set maxRetries to 0 to turn retries off.
| Code | Meaning |
|---|---|
invalid_request | The request is wrong (400). The message says what. |
unauthorized | No key, or an invalid or expired key (401). |
forbidden | The key lacks a permission, or your role cannot do this (403). |
license_limit_reached | The plan's limit is reached: links, tags, domains or API calls (403). |
not_found | No such item in this workspace (404). |
conflict | Already exists, for example a taken slug or tag name (409). |
rate_limited | More than 300 requests a minute for the key (429). |
network_error | No answer: a network failure or a timeout (the status is 0). |
No. The SDK is a thin typed wrapper over the REST API. You can call https://api.revolink.link/apiv2 directly from any language with an API key and the X-Workspace-Id header, or generate a client from the OpenAPI 3.1 spec.
Node.js 18 or newer and any runtime with a global fetch. It has no dependencies and ships ESM and CommonJS builds with TypeScript types generated from the API spec.
Requests are limited to 300 per minute per API key. Above that the API answers 429 with a Retry-After header, and the SDK waits and retries by itself. Separately, API calls count towards the monthly quota of the workspace owner's plan.
API v1 is frozen and its responses carry Deprecation headers. New integrations should use API v2.
No. A POST or PATCH that may have been processed is never retried. Only 429 answers and idempotent requests (GET, PUT, DELETE) are retried.
Yes. The Revolink MCP server lets Claude, Cursor and other MCP clients manage links in plain language. The SDK is the choice for your own code and scripts.
Stop sending everyone to the same page. Route by location, device, and time - start free, no credit card required.
Start for Free - No Card RequiredFree forever Β· No credit card Β· Cancel anytime
Already have links? Import them