Skip to content

Links API

API endpoints for managing short links

Create and manage short links programmatically.

Create a new short link.

POST /v1/links

Request Body

ParameterTypeRequiredDescription
urlstringYesThe destination URL
slugstringNoCustom slug (auto-generated if not provided)
titlestringNoLink title for analytics
startsAtstringNoStart date (ISO 8601)
expiresAtstringNoExpiration date (ISO 8601)
clickLimitnumberNoMaximum number of clicks allowed
expirationUrlstringNoURL to redirect to after expiration
utmSourcestringNoUTM source parameter
utmMediumstringNoUTM medium parameter
utmCampaignstringNoUTM campaign parameter
appLinkingEnabledbooleanNoEnable deep linking for supported apps
iosEnabledbooleanNoEnable App Linking for iOS
androidEnabledbooleanNoEnable App Linking for Android
redirectDelayEnabledbooleanNoEnable a 5-second delay before redirecting

Example Usage

interface CreateLinkRequest {
  url: string;
  slug?: string;
  title?: string;
  startsAt?: string;
  expiresAt?: string;
  clickLimit?: number;
  expirationUrl?: string;
  utmSource?: string;
  utmMedium?: string;
  utmCampaign?: string;
  appLinkingEnabled?: boolean;
  iosEnabled?: boolean;
  androidEnabled?: boolean;
  redirectDelayEnabled?: boolean;
}

interface LinkResponse {
  id: string;
  url: string;
  slug: string;
  shortUrl: string;
  title: string;
  clicks: number;
  createdAt: string;
  startsAt: string | null;
  expiresAt: string | null;
  clickLimit: number | null;
  expirationUrl: string | null;
  utmSource: string | null;
  utmMedium: string | null;
  utmCampaign: string | null;
  appLinkingEnabled: boolean;
  iosEnabled: boolean;
  androidEnabled: boolean;
  redirectDelayEnabled: boolean;
}

interface ApiResponse<T> {
  success: boolean;
  data: T;
}
<script setup lang="ts">
const createLink = async () => {
  const response = await fetch("https://api.linked.is/v1/links", {
    method: "POST",
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      url: "https://example.com/my-long-url",
      slug: "my-link",
      title: "My Example Link",
      startsAt: "2024-02-01T00:00:00Z",
      clickLimit: 1000,
      utmSource: "newsletter",
    }),
  });

  const data = await response.json();
  console.log(data);
  return data;
};
</script>

<template>
  <div>
    <button @click="createLink">Create Link</button>
  </div>
</template>

Response Example

<script setup lang="ts">
const linkResponse = {
  success: true,
  data: {
    id: "clx1234567890",
    url: "https://example.com/my-long-url",
    slug: "my-link",
    shortUrl: "https://linked.is/my-link",
    title: "My Example Link",
    clicks: 0,
    createdAt: "2024-01-15T10:30:00Z",
    startsAt: "2024-02-01T00:00:00Z",
    expiresAt: null,
    clickLimit: 1000,
    expirationUrl: null,
    utmSource: "newsletter",
    utmMedium: "email",
    utmCampaign: null,
  },
};
</script>

<template>
  <pre>{{ JSON.stringify(linkResponse, null, 2) }}</pre>
</template>

Retrieve a specific link by ID.

GET /v1/links/:id

Example Usage

<script setup lang="ts">
const getLink = async () => {
  const response = await fetch("https://api.linked.is/v1/links/clx1234567890", {
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  });

  const data = await response.json();
  console.log(data);
  return data;
};
</script>

<template>
  <div>
    <button @click="getLink">Get Link</button>
  </div>
</template>

Response Example

<script setup lang="ts">
const linkResponse = {
  success: true,
  data: {
    id: "clx1234567890",
    url: "https://example.com/my-long-url",
    slug: "my-link",
    shortUrl: "https://linked.is/my-link",
    title: "My Example Link",
    clicks: 42,
    createdAt: "2024-01-15T10:30:00Z",
    expiresAt: null,
  },
};
</script>

<template>
  <pre>{{ JSON.stringify(linkResponse, null, 2) }}</pre>
</template>

Update an existing link.

PATCH /v1/links/:id

Request Body

ParameterTypeDescription
urlstringThe destination URL
slugstringCustom slug
titlestringLink title
startsAtstringStart date (ISO 8601)
expiresAtstringExpiration date (ISO 8601)
clickLimitnumberMaximum number of clicks allowed
expirationUrlstringURL to redirect to after expiration
utmSourcestringUTM source parameter
utmMediumstringUTM medium parameter
utmCampaignstringUTM campaign parameter
appLinkingEnabledbooleanEnable deep linking for supported apps
iosEnabledbooleanEnable App Linking for iOS
androidEnabledbooleanEnable App Linking for Android
redirectDelayEnabledbooleanEnable a 5-second delay before redirecting

Example Usage

<script setup lang="ts">
const updateLink = async () => {
  const response = await fetch("https://api.linked.is/v1/links/clx1234567890", {
    method: "PATCH",
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      title: "Updated Title",
      clickLimit: 5000,
      utmCampaign: "summer_sale",
    }),
  });

  const data = await response.json();
  console.log(data);
  return data;
};
</script>

<template>
  <div>
    <button @click="updateLink">Update Link</button>
  </div>
</template>

Response Example

<script setup lang="ts">
const updateResponse = {
  success: true,
  data: {
    id: "clx1234567890",
    url: "https://example.com/new-url",
    slug: "my-link",
    shortUrl: "https://linked.is/my-link",
    title: "Updated Title",
    clicks: 42,
    createdAt: "2024-01-15T10:30:00Z",
    updatedAt: "2024-01-16T14:20:00Z",
    startsAt: null,
    expiresAt: null,
    clickLimit: 5000,
    expirationUrl: null,
    utmSource: null,
    utmMedium: null,
    utmCampaign: "summer_sale",
  },
};
</script>

<template>
  <pre>{{ JSON.stringify(updateResponse, null, 2) }}</pre>
</template>

Delete a link permanently.

DELETE /v1/links/:id

Example Usage

<script setup lang="ts">
const deleteLink = async () => {
  const response = await fetch("https://api.linked.is/v1/links/clx1234567890", {
    method: "DELETE",
    headers: {
      Authorization: "Bearer YOUR_API_TOKEN",
    },
  });

  const data = await response.json();
  console.log(data);
  return data;
};
</script>

<template>
  <div>
    <button @click="deleteLink" class="danger">Delete Link</button>
  </div>
</template>

Response Example

<script setup lang="ts">
const deleteResponse = {
  success: true,
  data: {
    deleted: true,
  },
};
</script>

<template>
  <pre>{{ JSON.stringify(deleteResponse, null, 2) }}</pre>
</template>

Get a paginated list of all your links.

GET /v1/links

Query Parameters

ParameterTypeDefaultDescription
pagenumber1Page number
limitnumber20Items per page (max 100)
searchstring-Search by title or slug
sortstringcreatedAtSort field
orderstringdescSort order (asc or desc)

Example Usage

<script setup lang="ts">
const listLinks = async () => {
  const response = await fetch(
    "https://api.linked.is/v1/links?page=1&limit=10&sort=clicks&order=desc",
    {
      headers: {
        Authorization: "Bearer YOUR_API_TOKEN",
      },
    },
  );

  const data = await response.json();
  console.log(data);
  return data;
};
</script>

<template>
  <div>
    <button @click="listLinks">List Links</button>
  </div>
</template>

Response Example

<script setup lang="ts">
const listResponse = {
  success: true,
  data: {
    items: [
      {
        id: "clx1234567890",
        url: "https://example.com/my-long-url",
        slug: "my-link",
        shortUrl: "https://linked.is/my-link",
        title: "My Example Link",
        clicks: 42,
        createdAt: "2024-01-15T10:30:00Z",
      },
    ],
    pagination: {
      page: 1,
      limit: 10,
      total: 25,
      totalPages: 3,
    },
  },
};
</script>

<template>
  <pre>{{ JSON.stringify(listResponse, null, 2) }}</pre>
</template>

Get QR Code

Generate a QR code image for a short link.

GET /v1/links/:id/qr

Query Parameters

ParameterTypeDefaultDescription
sizenumber256Image size in pixels (100-1000)
formatstringpngOutput format: png, svg, or base64
marginnumber2Quiet zone margin (0-10)
darkstring#000000Dark/foreground color (hex)
lightstring#ffffffLight/background color (hex)

Example Usage

<script setup lang="ts">
const getQrCodeBase64 = async () => {
  const response = await fetch(
    "https://api.linked.is/v1/links/clx1234567890/qr?format=base64",
    {
      headers: {
        Authorization: "Bearer YOUR_API_TOKEN",
      },
    },
  );

  const { data } = await response.json();
  console.log(data.qrCode); // data:image/png;base64,...
  return data;
};
</script>

<template>
  <div>
    <button @click="getQrCodeBase64">Get QR Code (Base64)</button>
  </div>
</template>

Response Examples

<script setup lang="ts">
const qrResponse = {
  success: true,
  data: {
    url: "https://linked.is/my-link",
    qrCode: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA...",
    format: "base64",
    size: 256,
  },
};
</script>

<template>
  <pre>{{ JSON.stringify(qrResponse, null, 2) }}</pre>
</template>
Note: For png and svg formats, the response is the raw image data with appropriate Content-Type header. For base64 format, the response is a JSON object containing the data URL.

## Error Codes

| Code             | Description                       |
| ---------------- | --------------------------------- |
| `LINK_NOT_FOUND` | The specified link does not exist |
| `SLUG_TAKEN`     | The slug is already in use        |
| `INVALID_URL`    | The provided URL is not valid     |
| `LINK_EXPIRED`   | The link has expired              |