Developer docs

API reference / Links

Get a link

GEThttps://app.clik.so/api/links/{id}

In short

Returns one link by its id, with its tags, creator and lifetime click count.

You need

API key
read permission or higher. See Authentication.
Role
Any member (viewer and up) in the key's workspace.
Plan
Any plan, including Free.

Example

curl "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY"
const res = await fetch("https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c", {
  headers: {
    Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
  },
});

const data = await res.json();
console.log(res.status, data);

Uses fetch (Node 18+ or the browser). Set CLIKSO_API_KEY first.

import os
import requests

response = requests.get(
    "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
)

print(response.status_code, response.json())

Uses requests. Set CLIKSO_API_KEY first.

<?php

$ch = curl_init('https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CLIKSO_API_KEY'),
    ],
]);

$response = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);

echo $status, PHP_EOL, $response, PHP_EOL;

Uses the curl extension. Set CLIKSO_API_KEY first.

package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	req, err := http.NewRequest("GET", "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c", nil)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("CLIKSO_API_KEY"))

	res, err := http.DefaultClient.Do(req)
	if err != nil {
		panic(err)
	}
	defer res.Body.Close()

	data, err := io.ReadAll(res.Body)
	if err != nil {
		panic(err)
	}
	fmt.Println(res.StatusCode, string(data))
}

Uses net/http. Set CLIKSO_API_KEY first.

require "net/http"

uri = URI('https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c')
request = Net::HTTP::Get.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("CLIKSO_API_KEY")}"

response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
  http.request(request)
end

puts response.code, response.body

Uses Net::HTTP. Set CLIKSO_API_KEY first.

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c"))
            .header("Authorization", "Bearer " + System.getenv("CLIKSO_API_KEY"))
            .GET()
            .build();

        HttpResponse<String> response = HttpClient.newHttpClient()
            .send(request, HttpResponse.BodyHandlers.ofString());

        System.out.println(response.statusCode());
        System.out.println(response.body());
    }
}

Uses java.net.http (Java 15+). Set CLIKSO_API_KEY first.

using System.Net.Http.Headers;

using var client = new HttpClient();
var request = new HttpRequestMessage(new HttpMethod("GET"), "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c");
request.Headers.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));

using var response = await client.SendAsync(request);
Console.WriteLine((int)response.StatusCode);
Console.WriteLine(await response.Content.ReadAsStringAsync());

Uses HttpClient (C# 11+). Set CLIKSO_API_KEY first.

#include <cstdlib>
#include <iostream>
#include <string>
#include <curl/curl.h>

static size_t collect(char* data, size_t size, size_t n, void* out) {
    static_cast<std::string*>(out)->append(data, size * n);
    return size * n;
}

int main() {
    CURL* curl = curl_easy_init();
    if (!curl) return 1;

    const char* key = std::getenv("CLIKSO_API_KEY");
    std::string auth = std::string("Authorization: Bearer ") + (key ? key : "");
    struct curl_slist* headers = curl_slist_append(nullptr, auth.c_str());
    std::string response;

    curl_easy_setopt(curl, CURLOPT_URL, "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, collect);
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);

    CURLcode rc = curl_easy_perform(curl);
    long status = 0;
    curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &status);
    curl_slist_free_all(headers);
    curl_easy_cleanup(curl);

    if (rc != CURLE_OK) {
        std::cerr << curl_easy_strerror(rc) << std::endl;
        return 1;
    }
    std::cout << status << "\n" << response << std::endl;
    return 0;
}

Uses libcurl. Set CLIKSO_API_KEY first.

Response 200
{
  "status": 200,
  "success": true,
  "message": "Success",
  "data": {
    "id": "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
    "workspace_id": "8a1f2c3d-4b5e-4f60-9a7b-1c2d3e4f5a6b",
    "custom_domain_id": null,
    "domain": "clik.is",
    "domain_status": "default",
    "title": "Summer sale",
    "description": "",
    "short_code": "summer-sale",
    "destination_url": "https://example.com/summer-sale",
    "status": "active",
    "expires_at": "2026-12-31T23:59:00.000Z",
    "expired_redirect_url": "https://example.com/sale-ended",
    "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    "ab_testing": [],
    "geo_targeting": null,
    "device_targeting": null,
    "qr_metadata": null,
    "og_preview": null,
    "meta_pixel_id": null,
    "tiktok_pixel_id": null,
    "ga4_measurement_id": null,
    "gtm_container_id": null,
    "has_password": false,
    "click_count": 128,
    "created_by": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
    "created_at": "2026-10-09T09:30:00.000Z",
    "updated_at": "2026-10-09T11:02:00.000Z",
    "tags": [
      {
        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "name": "launch",
        "color": "#3b82f6"
      }
    ],
    "creator": {
      "id": "c4d5e6f7-a8b9-4c0d-9e1f-2a3b4c5d6e7f",
      "display_name": "Asha Rao",
      "email": "asha@example.com",
      "photo_url": ""
    }
  }
}

Other responses: 401 · 404 · 429

Path parameters

  • idstring · uuidrequired

    The link's id.

What you get back

200 with the usual envelope — status, success, message, data. data has these fields:

  • idstring · uuidrequired

    The link's id.

  • workspace_idstring · uuidrequired

    The workspace the link belongs to.

  • custom_domain_idstring · uuid or null

    The custom domain's id, or null on a Clikso domain.

  • domainstringrequired

    The link's domain, like clik.is or links.example.com.

  • domain_statusstringrequired

    default on a Clikso domain, active on a live custom domain, deleted when the custom domain was removed and the link no longer works.

    One of: default, active, deleted

  • titlestringrequired

    A name for the link. Empty string when not set.

    Up to 60 characters

  • descriptionstringrequired

    A note about the link. Empty string when not set.

    Up to 250 characters

  • short_codestringrequired

    The part after the domain in the short URL: 3–30 letters, digits and hyphens, and on Starter and up / for a nested code like acme/launch (at most 5 parts). Up to 20 characters before 1.64.0.

    3–30 characters · Pattern ^(?:[a-zA-Z0-9-]+|-*[a-zA-Z0-9][a-zA-Z0-9-]*(?:/-*[a-zA-Z0-9][a-zA-Z0-9-]*){1,4})$

  • destination_urlstring · urirequired

    Where the short link sends visitors.

  • statusstringrequired

    active links redirect. archived and expired links do not.

    One of: active, archived, expired

  • expires_atstring · date-time or null

    When the link stops working, or null for never.

  • expired_redirect_urlstring · uri or null

    Where visitors go after the link expires, or null for Clikso's expired page.

  • folder_idstring · uuid or null

    The folder the link is in, or null.

  • ab_testingarray of ABVariant

    A/B split destinations. An empty array when not set, never null.

  • ab_testing[].urlstring · urirequired

    Where this share of visitors goes.

  • ab_testing[].percentageintegerrequired

    This variant's weight. Weights are relative, so they do not have to add up to 100.

    0–100

  • geo_targetingGeoTargeting or any or null

    Destination per country, or null.

  • device_targetingDeviceTargeting or any or null

    Destination per device, or null.

  • qr_metadataQrMetadata or any or null

    Saved QR style, or null.

  • og_previewOgPreview or any or null

    Custom social preview, or null.

  • meta_pixel_idstring or null

    Meta Pixel id, or null.

  • tiktok_pixel_idstring or null

    TikTok Pixel id, or null.

  • ga4_measurement_idstring or null

    Google Analytics 4 measurement id, or null.

  • gtm_container_idstring or null

    Google Tag Manager container id, or null.

  • has_passwordbooleanrequired

    true when visitors must enter a password. The password itself is never returned.

  • click_countintegerrequired

    Lifetime clicks on this link.

    Min 0

  • created_bystring · uuid

    The user id of the member who created it.

  • created_atstring · date-timerequired

    When the link was created.

  • updated_atstring · date-time or null

    When the link last changed.

  • tagsarray of TagRefrequired

    The link's tags. An empty array when it has none.

  • tags[].idstring · uuidrequired

    The tag's id.

  • tags[].namestringrequired

    The tag's name.

    Up to 10 characters

  • tags[].colorstring or nullrequired

    The tag's colour as #rrggbb, or an empty string.

  • creatorCreator or any or null

    The member who created the link, or null if unknown.

Common errors

401UNAUTHORIZEDThe API key is missing, malformed or unknown.
404NOT_FOUNDNo live link with this id exists in the key's workspace.
429RATE_LIMITEDThe key went over its per-minute request limit.

Every code and what to do about it: Errors.

Good to know

  • click_count is the link's lifetime click total. For a date range or a breakdown, use the Analytics endpoints.
  • The password itself is never returned. has_password tells you whether the link has one.
  • domain_status: deleted means the link's custom domain was removed and the short URL no longer works. Move the link to another domain with Update a link.