Developer docs

Guides

Folders and tags

In short

A folder holds links, and each link sits in at most one folder. A tag is a coloured label, and a link can have many. You create both with the API, then send their ids when you create or update a link.

You need

API key
Read to list folders and tags. Write to create, change or delete them.
Role
Editor or admin to make changes. Any member can read.
Plan
Any plan, including Free. Each plan allows a set number of folders and tags.

Create a folder

Folder names can be up to 20 characters.

curl -X POST "https://app.clik.so/api/folders" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Campaigns"
  }'
const res = await fetch("https://app.clik.so/api/folders", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Campaigns"
  }),
});

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.post(
    "https://app.clik.so/api/folders",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
    json={
        "name": "Campaigns",
    },
)

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

Uses requests. Set CLIKSO_API_KEY first.

<?php

$body = <<<'JSON'
{
  "name": "Campaigns"
}
JSON;

$ch = curl_init('https://app.clik.so/api/folders');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CLIKSO_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$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"
	"strings"
)

func main() {
	body := strings.NewReader(`{
  "name": "Campaigns"
}`)

	req, err := http.NewRequest("POST", "https://app.clik.so/api/folders", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("CLIKSO_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	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"
require "json"

uri = URI('https://app.clik.so/api/folders')
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("CLIKSO_API_KEY")}"
request["Content-Type"] = "application/json"
request.body = {
  'name' => 'Campaigns'
}.to_json

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 {
        String body = """
            {
              "name": "Campaigns"
            }
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.clik.so/api/folders"))
            .header("Authorization", "Bearer " + System.getenv("CLIKSO_API_KEY"))
            .header("Content-Type", "application/json")
            .method("POST", HttpRequest.BodyPublishers.ofString(body))
            .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("POST"), "https://app.clik.so/api/folders");
request.Headers.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));
request.Content = new StringContent(
    """
    {
      "name": "Campaigns"
    }
    """,
    System.Text.Encoding.UTF8,
    "application/json");

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());
    headers = curl_slist_append(headers, "Content-Type: application/json");
    const char* body = R"json({
  "name": "Campaigns"
})json";
    std::string response;

    curl_easy_setopt(curl, CURLOPT_URL, "https://app.clik.so/api/folders");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
    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 201
{
  "status": 201,
  "success": true,
  "message": "Created",
  "data": {
    "id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    "name": "Campaigns",
    "created_at": "2026-10-09T09:30:00.000Z",
    "updated_at": "2026-10-09T09:30:00.000Z",
    "link_count": 0
  }
}

Keep the id. You use it to put links in the folder.

Create a tag

Tag names can be up to 10 characters. The colour is optional. If you send one, use a six-digit hex code like #3b82f6.

curl -X POST "https://app.clik.so/api/tags" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "launch",
    "color": "#3b82f6"
  }'
const res = await fetch("https://app.clik.so/api/tags", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "launch",
    "color": "#3b82f6"
  }),
});

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.post(
    "https://app.clik.so/api/tags",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
    json={
        "name": "launch",
        "color": "#3b82f6",
    },
)

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

Uses requests. Set CLIKSO_API_KEY first.

<?php

$body = <<<'JSON'
{
  "name": "launch",
  "color": "#3b82f6"
}
JSON;

$ch = curl_init('https://app.clik.so/api/tags');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CLIKSO_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$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"
	"strings"
)

func main() {
	body := strings.NewReader(`{
  "name": "launch",
  "color": "#3b82f6"
}`)

	req, err := http.NewRequest("POST", "https://app.clik.so/api/tags", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("CLIKSO_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	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"
require "json"

uri = URI('https://app.clik.so/api/tags')
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("CLIKSO_API_KEY")}"
request["Content-Type"] = "application/json"
request.body = {
  'name' => 'launch',
  'color' => '#3b82f6'
}.to_json

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 {
        String body = """
            {
              "name": "launch",
              "color": "#3b82f6"
            }
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.clik.so/api/tags"))
            .header("Authorization", "Bearer " + System.getenv("CLIKSO_API_KEY"))
            .header("Content-Type", "application/json")
            .method("POST", HttpRequest.BodyPublishers.ofString(body))
            .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("POST"), "https://app.clik.so/api/tags");
request.Headers.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));
request.Content = new StringContent(
    """
    {
      "name": "launch",
      "color": "#3b82f6"
    }
    """,
    System.Text.Encoding.UTF8,
    "application/json");

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());
    headers = curl_slist_append(headers, "Content-Type: application/json");
    const char* body = R"json({
  "name": "launch",
  "color": "#3b82f6"
})json";
    std::string response;

    curl_easy_setopt(curl, CURLOPT_URL, "https://app.clik.so/api/tags");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
    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 201
{
  "status": 201,
  "success": true,
  "message": "Created",
  "data": {
    "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "name": "launch",
    "color": "#3b82f6",
    "created_at": "2026-10-09T09:30:00.000Z",
    "updated_at": "2026-10-09T09:30:00.000Z",
    "link_count": 0
  }
}

Send folder_id and tags when you create a link, or later with an update. tags is a list of tag ids.

curl -X PUT "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    "tags": [
      "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
    ]
  }'
const res = await fetch("https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    "tags": [
      "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
    ]
  }),
});

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.put(
    "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
    json={
        "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
        "tags": [
            "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        ],
    },
)

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

Uses requests. Set CLIKSO_API_KEY first.

<?php

$body = <<<'JSON'
{
  "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
  "tags": [
    "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
  ]
}
JSON;

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

$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"
	"strings"
)

func main() {
	body := strings.NewReader(`{
  "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
  "tags": [
    "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
  ]
}`)

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

	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"
require "json"

uri = URI('https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c')
request = Net::HTTP::Put.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("CLIKSO_API_KEY")}"
request["Content-Type"] = "application/json"
request.body = {
  'folder_id' => '6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e',
  'tags' => [
    '1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d'
  ]
}.to_json

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 {
        String body = """
            {
              "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
              "tags": [
                "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
              ]
            }
            """;

        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"))
            .header("Content-Type", "application/json")
            .method("PUT", HttpRequest.BodyPublishers.ofString(body))
            .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("PUT"), "https://app.clik.so/api/links/3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c");
request.Headers.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));
request.Content = new StringContent(
    """
    {
      "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
      "tags": [
        "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
      ]
    }
    """,
    System.Text.Encoding.UTF8,
    "application/json");

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());
    headers = curl_slist_append(headers, "Content-Type: application/json");
    const char* body = R"json({
  "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
  "tags": [
    "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"
  ]
})json";
    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_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
    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.

The update answers with the whole link, now with its folder_id and full tags.

How the two fields behave on an update:

  • tags replaces the link’s whole tag list. Send every tag the link should keep.
  • tags: [] removes all tags. Leave tags out, or send null, to keep them as they are.
  • folder_id: null takes the link out of its folder.

To put up to 100 links in one folder, use a bulk update:

curl -X PATCH "https://app.clik.so/api/links/bulk" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": [
      "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
      "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
    ],
    "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"
  }'
const res = await fetch("https://app.clik.so/api/links/bulk", {
  method: "PATCH",
  headers: {
    Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "ids": [
      "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
      "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
    ],
    "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"
  }),
});

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.patch(
    "https://app.clik.so/api/links/bulk",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
    json={
        "ids": [
            "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
            "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a",
        ],
        "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    },
)

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

Uses requests. Set CLIKSO_API_KEY first.

<?php

$body = <<<'JSON'
{
  "ids": [
    "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
    "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
  ],
  "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"
}
JSON;

$ch = curl_init('https://app.clik.so/api/links/bulk');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PATCH',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CLIKSO_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$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"
	"strings"
)

func main() {
	body := strings.NewReader(`{
  "ids": [
    "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
    "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
  ],
  "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"
}`)

	req, err := http.NewRequest("PATCH", "https://app.clik.so/api/links/bulk", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("CLIKSO_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	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"
require "json"

uri = URI('https://app.clik.so/api/links/bulk')
request = Net::HTTP::Patch.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("CLIKSO_API_KEY")}"
request["Content-Type"] = "application/json"
request.body = {
  'ids' => [
    '3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c',
    '5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a'
  ],
  'folder_id' => '6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e'
}.to_json

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 {
        String body = """
            {
              "ids": [
                "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
                "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
              ],
              "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"
            }
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.clik.so/api/links/bulk"))
            .header("Authorization", "Bearer " + System.getenv("CLIKSO_API_KEY"))
            .header("Content-Type", "application/json")
            .method("PATCH", HttpRequest.BodyPublishers.ofString(body))
            .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("PATCH"), "https://app.clik.so/api/links/bulk");
request.Headers.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));
request.Content = new StringContent(
    """
    {
      "ids": [
        "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
        "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
      ],
      "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"
    }
    """,
    System.Text.Encoding.UTF8,
    "application/json");

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());
    headers = curl_slist_append(headers, "Content-Type: application/json");
    const char* body = R"json({
  "ids": [
    "3f6c1a2e-9b4d-4e8f-a1c2-7d9e0f1a2b3c",
    "5d4c3b2a-1f0e-4d9c-8b7a-6f5e4d3c2b1a"
  ],
  "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"
})json";
    std::string response;

    curl_easy_setopt(curl, CURLOPT_URL, "https://app.clik.so/api/links/bulk");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
    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": {
    "updated_count": 2
  }
}

There is no bulk tagging. To tag many links, update them one by one.

Filter the link list with folder_id, tags, or both. tags takes tag ids, separated by commas. A link matches if it has at least one of them.

curl "https://app.clik.so/api/links?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20" \
  -H "Authorization: Bearer $CLIKSO_API_KEY"
const res = await fetch("https://app.clik.so/api/links?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20", {
  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",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
    params={
        "folder_id": "6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
        "tags": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "limit": 20,
    },
)

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

Uses requests. Set CLIKSO_API_KEY first.

<?php

$ch = curl_init('https://app.clik.so/api/links?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20');
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?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20", 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?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20')
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?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20"))
            .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?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20");
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?folder_id=6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e&tags=1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d&limit=20");
    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.

You get a page of links in data, and paging details in meta. See Manage links for paging.

Rename and delete

Rename a folder or a tag with PUT and the new value:

curl -X PUT "https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d" \
  -H "Authorization: Bearer $CLIKSO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "promo",
    "color": "#16a34a"
  }'
const res = await fetch("https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "promo",
    "color": "#16a34a"
  }),
});

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.put(
    "https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
    json={
        "name": "promo",
        "color": "#16a34a",
    },
)

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

Uses requests. Set CLIKSO_API_KEY first.

<?php

$body = <<<'JSON'
{
  "name": "promo",
  "color": "#16a34a"
}
JSON;

$ch = curl_init('https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'PUT',
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        'Authorization: Bearer ' . getenv('CLIKSO_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS => $body,
]);

$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"
	"strings"
)

func main() {
	body := strings.NewReader(`{
  "name": "promo",
  "color": "#16a34a"
}`)

	req, err := http.NewRequest("PUT", "https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d", body)
	if err != nil {
		panic(err)
	}
	req.Header.Set("Authorization", "Bearer "+os.Getenv("CLIKSO_API_KEY"))
	req.Header.Set("Content-Type", "application/json")

	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"
require "json"

uri = URI('https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d')
request = Net::HTTP::Put.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("CLIKSO_API_KEY")}"
request["Content-Type"] = "application/json"
request.body = {
  'name' => 'promo',
  'color' => '#16a34a'
}.to_json

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 {
        String body = """
            {
              "name": "promo",
              "color": "#16a34a"
            }
            """;

        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d"))
            .header("Authorization", "Bearer " + System.getenv("CLIKSO_API_KEY"))
            .header("Content-Type", "application/json")
            .method("PUT", HttpRequest.BodyPublishers.ofString(body))
            .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("PUT"), "https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d");
request.Headers.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));
request.Content = new StringContent(
    """
    {
      "name": "promo",
      "color": "#16a34a"
    }
    """,
    System.Text.Encoding.UTF8,
    "application/json");

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());
    headers = curl_slist_append(headers, "Content-Type: application/json");
    const char* body = R"json({
  "name": "promo",
  "color": "#16a34a"
})json";
    std::string response;

    curl_easy_setopt(curl, CURLOPT_URL, "https://app.clik.so/api/tags/1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, body);
    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": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
    "name": "promo",
    "color": "#16a34a",
    "created_at": "2026-10-01T08:00:00.000Z",
    "updated_at": "2026-10-09T09:30:00.000Z",
    "link_count": 4
  }
}

Delete them like this:

curl -X DELETE "https://app.clik.so/api/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e" \
  -H "Authorization: Bearer $CLIKSO_API_KEY"
const res = await fetch("https://app.clik.so/api/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
  },
});

console.log(res.status); // 204 = done, no body

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

import os
import requests

response = requests.delete(
    "https://app.clik.so/api/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e",
    headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
)

print(response.status_code)  # 204 = done, no body

Uses requests. Set CLIKSO_API_KEY first.

<?php

$ch = curl_init('https://app.clik.so/api/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e');
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    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; // 204 = done, no body

Uses the curl extension. Set CLIKSO_API_KEY first.

package main

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

func main() {
	req, err := http.NewRequest("DELETE", "https://app.clik.so/api/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e", 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/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e')
request = Net::HTTP::Delete.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 # 204 = done, no 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/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e"))
            .header("Authorization", "Bearer " + System.getenv("CLIKSO_API_KEY"))
            .DELETE()
            .build();

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

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

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("DELETE"), "https://app.clik.so/api/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e");
request.Headers.Authorization = new AuthenticationHeaderValue(
    "Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));

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

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/folders/6b7c8d9e-0f1a-4b2c-8d3e-4f5a6b7c8d9e");
    curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
    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 204 No Content — an empty body means it worked.

Deleting a folder keeps its links. They simply move out of the folder. Deleting a tag removes it from every link, and you cannot undo it.

How many you can have

Folders and tags per workspace

Folders
3
Tags
5

An API key that tries to create one more than the plan allows gets 402 UPGRADE_REQUIRED.

What you get back

  • List calls return an array in data, sorted by name. Each item has id, name, created_at, updated_at and link_count. Tags also have color.
  • Create returns 201 and the new folder or tag, with link_count: 0.
  • Update returns 200 and the changed folder or tag.
  • Delete returns 204 with an empty body.

Tags always come with their real link_count. A single folder, from get or update, has no link_count, so use the list call to count a folder's links.

Common errors

402UPGRADE_REQUIREDThe workspace already has as many folders or tags as its plan allows.Leave the field out, or upgrade the workspace.
403FORBIDDENThe key has only Read permission, or its owner is a viewer.Check the key’s permission and your role. If you send Workspace-Id, it must match the key’s workspace.
404NOT_FOUNDNo folder or tag with that id in this workspace.Check the id. Ids from another workspace are never found.
422VALIDATION_ERRORThe name is empty or too long, the colour is not #rrggbb, or a link update names a folder or tag id from another workspace.Fix the field and send the request again.

Good to know

  • Folders are flat. There are no folders inside folders.
  • A link sits in at most one folder, but it can have any number of tags.
  • Folders and tags only organise links. They do not limit who can see them. Every member of the workspace sees every link.
  • The bulk call moves links between folders, archives them or deletes them. It cannot add tags.
  • Each call costs one request from the key’s per-minute limit. See Limits.