REST API

Programmatically create smart links and pull click analytics. All endpoints are under /api/v1 and authenticated with your project API key.

Prefer an interactive spec? See the API Reference or download openapi.yaml.

Authentication

Send your project API key (found on the project page) as a bearer token or an x-api-key header.

curl https://your-domain.com/api/v1/links \
  -H "Authorization: Bearer lk_your_api_key"
POST/api/v1/links

Create a smart link. Only fallbackUrl is required.

curl -X POST https://your-domain.com/api/v1/links \
  -H "Authorization: Bearer lk_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Spring sale",
    "fallbackUrl": "https://shop.example.com/spring",
    "iosUrl": "https://apps.apple.com/app/id123456789",
    "androidUrl": "https://play.google.com/store/apps/details?id=com.acme.app",
    "deepLinkPath": "/products/123",
    "data": { "campaign": "spring", "product_id": "123" },
    "channel": "email",
    "campaign": "spring_sale",
    "tags": ["promo", "q2"]
  }'

Response 201

{
  "id": "clx...",
  "slug": "ab12cd3",
  "url": "https://your-domain.com/l/ab12cd3",
  "fallbackUrl": "https://shop.example.com/spring",
  ...
}
GET/api/v1/links

List links (newest first). ?limit=50

{ "data": [ { "id": "...", "slug": "ab12cd3", "url": "...", "clicks": 42 } ] }
GET/api/v1/links/:id

Fetch a single link with its click count.

DELETE/api/v1/links/:id

Delete a link permanently.

{ "deleted": true }
GET/api/v1/links/:id/stats

Click analytics for a link. ?days=30 (1–365).

{
  "total": 128,
  "unique": 96,
  "byPlatform": [ { "name": "ios", "value": 70 }, { "name": "android", "value": 40 } ],
  "byOs": [ ... ],
  "byReferrer": [ ... ],
  "timeseries": [ { "date": "2026-05-01", "clicks": 4 } ]
}

How redirection works

  • Visiting /l/:slug detects the device from the User-Agent.
  • Desktop visitors are 302-redirected to the desktop/fallback URL.
  • Mobile visitors get an interstitial that attempts to open your app via its custom scheme + deep-link path, then falls back to the App Store / Play Store.
  • Every visit is recorded with platform, OS, referrer and a hashed IP.

Keys: secret vs publishable

  • apiKeysecret, server-side only. Full REST API (list, stats, delete).
  • sdkKeypublishable, safe to embed in the Web / Android / iOS SDKs. Can open sessions and create links.

SDKs — reading attributes in your app

The redirect engine gets users to your app; the SDKs deliver the link's attributes into it — including deferred deep linking, where data survives an App Store / Play Store install. Each SDK is a thin client over the session endpoint below.

  • Web: /sdk/linkly.js — try it on the live demo.
  • Android (Kotlin) and iOS (Swift) — see /sdk in the repo.
<script src="/sdk/linkly.js"></script>
<script>
  Linkly.init({ key: "<sdkKey>" }).then(function (session) {
    if (session.matched) {
      console.log("deep link data:", session.data);
      // route with session.deepLinkPath
    }
  });
</script>

Smart App Banner

Show a Branch-style "Open in app" bar on the mobile web that deep-links into the native app (with App/Play Store fallback). Hidden on desktop by default; dismissal is remembered.

Linkly.init({ key: "<sdkKey>" }).then(function () {
  Linkly.banner({
    title: "Acme Mobile",
    text: "Open this in the app for the full experience.",
    button: "Open",
    position: "bottom",   // or "top"
    forDays: 7            // remember dismissal
  });
});
POST/api/v1/open

Open a session / match a deep link. Direct (with link) or deferred (by fingerprint). Used by every SDK.

curl -X POST https://your-domain.com/api/v1/open \
  -H "Content-Type: application/json" \
  -d '{ "key": "<sdkKey>", "platform": "ios", "link": "welcome" }'

Response

{
  "matched": true,
  "is_first_session": true,   // true on a deferred (post-install) match
  "is_deferred": true,
  "link": { "slug": "welcome", "url": "...", "title": "..." },
  "deepLinkPath": "/products/123",
  "data": { "product_id": "123", "~campaign": "spring_sale" },
  "routing": { "fallbackUrl": "...", "iosUrl": "...", "androidUrl": "..." }
}

Omit link for deferred matching: the server pairs the request's IP + platform with a recent click (≤ 60 min) and returns its attributes once.