API reference
The LinkSnap API is a REST API that uses JSON for both requests and responses. It's the same API our portal, CLI, and SDKs use; if you want to integrate LinkSnap directly without an SDK, this section covers everything you need.
Base URL
https://linksnap.com
All API routes are under /api/v1/. For example, the links resource lives at https://linksnap.com/api/v1/links.
For staging:
https://staging-linksnap.forjio.com
Email hello@linksnap.com if you need staging credentials.
Authentication
LinkSnap uses Bearer-token authentication — the same scheme as standard OAuth. Every authenticated request carries:
Authorization: Bearer <token>
Tokens come from one of two sources:
- API keys — long-lived, minted in the dashboard. Prefix:
lk_live_…. - Huudis access tokens — short-lived, minted via the OIDC device flow (CLI) or authorization-code flow (portal).
There's no HMAC request signing. A plain bearer token is sufficient. See Authentication for the full recipe with worked examples.
Response envelope
Every successful API response is wrapped in a uniform envelope (from @forjio/sdk):
{
"data": { /* the response payload */ },
"error": null,
"meta": {
"requestId": "req_01H...",
"timestamp": "2026-05-12T10:42:00Z"
}
}
List endpoints have a paginated variant:
{
"data": [ /* items */ ],
"error": null,
"meta": {
"requestId": "req_01H...",
"timestamp": "2026-05-12T10:42:00Z",
"page": {
"limit": 50,
"hasMore": true,
"nextCursor": "cur_xxx"
}
}
}
Errors keep the envelope shape but set error:
{
"data": null,
"error": {
"code": "VALIDATION_ERROR",
"message": "url must be a valid http(s) URL",
"field": "url"
},
"meta": { "requestId": "...", "timestamp": "..." }
}
Pagination
List endpoints use cursor-based pagination:
GET /api/v1/links?limit=50
Response includes meta.page.nextCursor. To fetch the next page:
GET /api/v1/links?limit=50&cursor=cur_xxx
When hasMore is false, you've reached the end. Default limit is 50; max is 200.
Common parameters
Most list endpoints accept these filters:
| Param | Type | Means |
|---|---|---|
q |
string | Free-text search (slug, title, description, destination) |
tag |
string or array | Filter by tag; repeatable |
status |
active | expired | archived |
Filter by link status |
sort |
createdAt | lastClickAt | clickCount |
Sort key |
order |
asc | desc |
Sort direction (default desc) |
limit |
int (1-200) | Page size |
cursor |
string | Pagination cursor |
Resources
The API is organized by resource. Each has the obvious CRUD surface:
| Resource | Path prefix | Notes |
|---|---|---|
| Links | /api/v1/links |
Create, list, get, update, delete, bulk |
| Link stats | /api/v1/links/:id/stats |
Time-series, geo, device, referrer |
| QR codes | /api/v1/qr-codes |
Create, list, get, update, delete; download with token |
| Tags | /api/v1/tags |
List (read-only; created implicitly via links) |
| Domains | /api/v1/domains |
Add, verify, list, get, remove |
| Workspaces | /api/v1/workspaces |
List your memberships, switch, view current |
| API keys | /api/v1/auth/api-keys |
Mint and revoke |
| Auth | /api/v1/auth/* |
Login, signup, refresh, forgot-password, etc. |
| Billing | /api/v1/billing/* |
Plan and usage |
Every endpoint returns the standard envelope above. Per-resource details (params, response shapes) are documented in the SDK reference, which mirrors the HTTP surface 1:1 — the Node SDK source is a fine reference for parameter names.
Redirect endpoints
Public redirect endpoints are not part of the /api/v1/* surface — they live at the root and serve plain HTTP redirects:
GET /:slug → 302 to destination
GET /q/:downloadToken → QR image (PNG or SVG)
These are unauthenticated and don't return JSON. They're served by the same backend but a different router (redirect.ts and qr-redirect.ts).
Rate limits
Default limits per workspace, applied via the rateLimiter middleware:
| Endpoint class | Limit |
|---|---|
| Read (GET) | 100 req/sec |
| Write (POST/PUT/PATCH/DELETE) | 20 req/sec |
| Auth endpoints | 10 req/min per IP |
On exceeding a limit you get 429 Too Many Requests with a Retry-After header.
Tighter limits apply to FREE-plan workspaces; PRO and BUSINESS scale linearly. Email hello@linksnap.com to request increases.
Versioning
The API version is in the path: /api/v1/.... We commit to no breaking changes within v1. Additive changes (new fields, new endpoints) ship without notice.
Next
- Authentication — bearer tokens, device flow, refresh.
- SDKs — the same API in Node, Python, and Go.