Developer docs

API reference / Links

Update many links

PATCHhttps://app.clik.so/api/links/bulk

In short

Moves up to 100 links to a folder, or changes their status, in one call. Use it to archive, restore or refile links in bulk.

You need

API key
write permission (Write or Admin). See Authentication.
Role
Editor or admin in the key's workspace.
Plan
Any plan, including Free.

Example

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
  }
}

Other responses: 401 · 403 · 422 · 429

Request body

  • idsarray of string · uuidrequired

    The links to change, at most 100.

    Up to 100 items

  • statusstring

    The new status for all of them.

    One of: active, archived, expired

  • folder_idstring · uuid or null

    The new folder for all of them. null takes them out of their folders.

What you get back

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

  • updated_countintegerrequired

    Number of links that were changed.

    Min 0

Common errors

401UNAUTHORIZEDThe API key is missing, malformed or unknown.
403FORBIDDENThe key only has Read permission, or its creator is a viewer in this workspace.
422VALIDATION_ERRORids is empty or has more than 100 entries, neither status nor folder_id was sent, or the folder is not in this workspace.
429RATE_LIMITEDThe key went over its per-minute request limit.

Every code and what to do about it: Errors.

Good to know

  • Send at most 100 ids per call. For more, split them into batches.
  • Only status and folder_id can be changed in bulk. There is no bulk tagging and no bulk create.
  • folder_id: null takes the links out of their folders.
  • Ids that do not exist, belong to another workspace or are deleted are skipped silently. updated_count tells you how many changed.
  • Archiving stops the short URLs from working. Setting status back to active turns them on again.