---
title: "List links"
method: GET
path: "/api/links"
tags: ["Links"]
---

# List links

`GET /api/links`

## Request

- Base URL: `https://www.flyn.to`
- URL: `https://www.flyn.to/api/links`
- Auth: HTTP bearer

Lists links in the caller's workspace (the team, or the personal account), paginated, filterable and sortable. Each item is a full Link.

**Auth:** API key (`Bearer flyn_sk_live_...`) or an MCP OAuth access token (`Bearer flyn_mcp_at_...`). The dashboard session cookie is not accepted.

**Plan:** every plan. Any team role, including viewer.

**Rate limit:** 30 requests per 60 s per client IP, fixed window, in memory per server instance, checked before authentication.

Unrecognised `status` and `sort` values are ignored rather than rejected.

## Query parameters

- `page` integer
- `limit` integer
- `status` 'active' | 'expired' | 'archived'
- `search` string
- `tag` string
- `folder_id` string, uuid
- `sort` 'created_at' | 'clicks' | 'slug' | 'title'
- `order` 'asc' | 'desc'

## Response `200`

The page of links.

- LinkList
  - `links` Link[], required
    - `id` string, uuid, required: Link id.
    - `slug` string, required: Back-half of the short URL.
    - `url` string, required: Destination URL.
    - `shortUrl` string, uri, required: Full short URL, `https://<domain>/<slug>`.
    - `domain` string, required: Short domain the link lives on. New links default to the current Flyn short domain.
    - `title` string, nullable, required: Display title.
    - `clicks` integer, required: Human clicks (bots and scanners excluded). This is the headline number.
    - `botClicks` integer, required: Clicks filtered out as bots or scanners.
    - `qrScans` integer, required: Clicks that arrived from a Flyn QR code; a subset of `clicks`.
    - `totalClicks` integer, required: `clicks` + `botClicks`.
    - `status` 'active' | 'expired' | 'archived', required: Stored status. A link past `expiresAt` keeps `active` here; the redirect checks the expiry itself.
    - `tags` string[], required
    - `createdAt` string, date-time, required
    - `expiresAt` string, nullable, required: Expiry as stored (ISO 8601), or null.
    - `folderId` string, uuid, nullable, required
    - `password` boolean, required: True when the link is password protected. The password itself is never returned.
    - `ogTitle` string, nullable, required
    - `ogDescription` string, nullable, required
    - `ogImage` string, nullable, required
    - `targeting` Targeting, required: Smart-routing rules as stored. `device` takes four keys, `ios`, `android`, `windows` and `macos`, each applying only to visitors on that operating system, and a device rule takes priority. There is no `desktop` key: Linux, ChromeOS and any other or unrecognised system match no device rule and fall through to the link's other rules. `windows` and `macos` must be http or https URLs, and the aliases `mac`, `osx`, `win`, `desktop` and `linux` are rejected with 400 `INVALID_TARGETING`. `geo` maps ISO 3166-1 alpha-2 country codes (upper case) to a destination and applies to every visitor whose country is known, desktop included. A visitor matching no rule falls through to the rotation, or the legacy A/B split, when one is set, else goes to the link url. A PATCH replaces the whole targeting object; nothing is merged into the stored rules. Safari on an iPad usually sends the same user agent as Safari on a Mac, so on a link with a `macos` destination, Safari on a Mac or an iPad (or any browser sending that same user agent) first loads a blank check page that tells a Mac from an iPad, then continues at once. A browser with JavaScript off continues as a Mac. The check page records no click; the click is recorded once, when the browser continues to the short link with the reserved query parameters `flyn_os` and `flyn_ref` (the original referrer), which are never passed to a destination. Chrome, Edge and Firefox on a Mac skip the check page, and a link without a `macos` rule never shows it. Device and country rules, including the Safari check page, do not apply to password-protected links, to a link that has reached its click limit, or to mailto, tel and sms links.
      - `device` object
        - `ios` string: Destination for iOS visitors, such as an iPhone. Safari on an iPad usually sends the same user agent as Safari on a Mac (see Targeting).
        - `android` string: Destination for Android visitors.
        - `windows` string: Destination for Windows visitors. Must be an http or https URL, for example a Microsoft Store or download page.
        - `macos` string: Destination for Mac visitors. Must be an http or https URL, for example a Mac App Store or download page. Setting it turns on the Safari check page described on Targeting.
      - `geo` object: Country code to destination, for example {"US": "https://example.com/us"}.
    - `cloaking` boolean, required
    - `noIndex` boolean, required: Stored value of the legacy per-link no-index flag. It has no effect on how the link is served: every short link is already served with a noindex robots header on every plan, whether or not this is set.
    - `notes` string, nullable, required: Private notes.
    - `abUrlB` string, nullable, required: Legacy two-way A/B view of `rotation`, kept for older integrations.
    - `abSplit` number, nullable, required: Legacy A/B split: percent kept on the primary url.
    - `rotation` RotationEntry[], nullable, required: Weighted destinations, or null when the link does not rotate.
      - `id` string, required: Stable destination id (8 characters when minted by Flyn). Reported as `variant` on link.click deliveries.
      - `url` string, uri, required: Destination URL.
      - `weight` number, required: Relative weight, not a percentage. Weights are normalised when a visitor is routed.
      - `label` string, nullable, required: Optional display label.
    - `deepLink` boolean, required: Native-app handoff mode on mobile.
    - `pixelIds` string[], required: Retargeting pixels fired on click.
    - `forwardParams` boolean, required: Query-string passthrough to the destination.
    - `clickLimit` integer, nullable, required: Maximum human clicks. Once reached, visitors go to `fallbackUrl`, or to the expired-link page when no http(s) `fallbackUrl` is set.
    - `fallbackUrl` string, nullable, required: Destination after the click limit is reached.
    - `conversionTracking` boolean, required: When true, each human click gets a `flyn_id` click id for conversion pings.
    - `conversions` integer, required: Recorded conversions, net of refunds (never below 0).
    - `conversionValueCents` integer, required: Summed conversion value in minor units.
    - `conversionCurrency` string, nullable, required: Currency of the summed value.
  - `pagination` Pagination, required
    - `page` integer, required: Current page, starting at 1.
    - `limit` integer, required: Items per page after clamping.
    - `total` integer, required: Total matching items.
    - `totalPages` integer, required: ceil(total / limit).
    - `hasMore` boolean, required: True when another page exists.

## Other responses

- `401`: Missing header, wrong prefix, unknown or revoked key, expired key, or an invalid MCP OAuth token. Messages: "Missing or invalid API key. Use: Authorization: Bearer flyn_sk_live_...", "Invalid or revoked API key", "API key has expired", "Invalid or expired OAuth token".
- `403`: The account is suspended.
- `429`: More than 30 requests in the window. Counted per client IP. Retry-After gives the seconds until the window resets.
- `500`: Query error.

---

[API](https://skmtc.dev/flyn/apis/flyn-api.md) · [All operations](https://skmtc.dev/flyn/apis/flyn-api/llms.txt) · [OpenAPI document](https://skmtc.dev/flyn/apis/flyn-api/revisions/977962a98ccb?raw)
