API Authentication

How to authenticate against the LinkTrail REST API: SDK API keys for the event endpoints, access tokens and X-Workspace-Id for the management endpoints.

The LinkTrail REST API is served at https://backend.linktrail.io/v1 and speaks JSON. It is the same API the dashboard and the SDKs use, and it takes two kinds of credential depending on the endpoint.

EndpointsCredentialHeaders
SDK endpoints — /events/install, /events/open, /events, /events/click/{token}A workspace API key (lt_live_…)X-Api-Key: lt_live_… or Authorization: Bearer lt_live_…
Link resolution — /links/resolveNone (public, read-only)—
Management — apps, domains, links, stats, webhooks, API keysA user access token, plus the workspace to act inAuthorization: Bearer <accessToken> and X-Workspace-Id: <id>

API keys

API keys authenticate the SDK endpoints. Create one in the dashboard (Settings → API Keys → Create key) or with POST /api-keys. The full key is returned once — store it then; afterwards only its prefix is shown. Revoke a key with DELETE /api-keys/:keyId; the dashboard shows when each key was last used.

POST /v1/api-keys → 201JSON
{ "id": 1, "name": "iOS production", "prefix": "lt_live_3f9a1b", "key": "lt_live_3f9a1b…", "lastUsedAt": null, "createdAt": "2026-06-28T00:00:00Z" }

The key decides the workspace. Every API key belongs to one workspace, and so do apps, domains and links. An install sent with a key is recorded in that key's workspace, so the app's identifier must be registered there — the same identifier in another workspace answers 404.

Resolve a click tokenShell
curl -H 'X-Api-Key: lt_live_…' \
  https://backend.linktrail.io/v1/events/click/460ce0f7bf4e840eb18da7fb793eb5f7

Access tokens

The management endpoints authenticate a user, not a key. Exchange an email and password for tokens with POST /auth/login. The access token lasts about 30 minutes; get a new one with POST /auth/refresh-tokens and the refresh token. API keys are not accepted on these endpoints, and there is no long-lived server-to-server credential for them.

POST /v1/auth/login — requestJSON
{ "email": "you@acme.com", "password": "…" }
200 response (tokens)JSON
{ "user": { /* … */ },
  "tokens": { "access":  { "token": "eyJ…", "expires": "…" },
              "refresh": { "token": "eyJ…", "expires": "…" } } }
  • With two-factor authentication on, login returns { "twoFactorRequired": true, "challengeToken": "eyJ…" } instead. Send the challenge and the 6-digit code to POST /auth/login/totp for the tokens.
  • Login fails with 403 until the account's email address is verified.
  • A missing or expired token gets {"code":401,"message":"Please authenticate"}.

Workspaces

Most management endpoints act inside a workspace: send its id in X-Workspace-Id. GET /workspaces lists the workspaces you belong to (a plain array, not paginated). A workspace you are not a member of answers 404, not 403, and a missing header answers 400.

GET /v1/workspaces → 200JSON
[ { "id": 1, "name": "Acme Inc", "timezone": "Asia/Karachi", "region": "us", "defaultAttribution": null } ]

What a call may do depends on your role in that workspace. Every member can read apps, domains, links and stats. Managing links needs editor, admin or owner; managing apps and domains needs developer, admin or owner. API keys and webhooks — reading them included — need developer, admin or owner. A call without the right answers 403.

Conventions

  • Pagination. The paginated lists — links, apps and domains — take ?page=1&limit=10&sortBy=createdAt:desc and answer { "results": [ /* … */ ], "page": 1, "limit": 10, "totalPages": 4, "totalResults": 37 }. /workspaces, /api-keys and /webhooks answer a plain array.
  • Errors. Errors are JSON of the shape { "code": 400, "message": "Human-readable reason" }: 400 validation, 401 bad or missing credentials, 402 the plan does not include the feature, 403 the role does not allow it, 404 not found or not a member, 429 rate-limited. The one exception is the per-IP 429 on the SDK endpoints and /links/resolve, whose body is plain text (Too many requests, please try again later.), not JSON. The SDK-facing statuses are on Errors.
  • Rate limits. The SDK endpoints and /links/resolve are limited per IP address (currently 100 requests a minute); over the limit they answer 429. Failed sign-ins are limited too.
  • Idempotency. A POST may carry Idempotency-Key: <uuid>; repeating it with the same key returns the original response instead of acting twice.
Warning

{"code":401,"message":"Invalid or missing API key"} on an SDK endpoint means the key is wrong, revoked or missing — check it in Settings → API Keys.