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.