API reference / Links
Suggest slugs with AI
https://app.clik.so/api /links/ai-slugIn short
You need
- API key
writepermission (Write or Admin). See Authentication.- Role
- Editor or admin in the key's workspace.
- Plan
- Any plan, including Free.
Example
curl -X POST "https://app.clik.so/api/links/ai-slug" \
-H "Authorization: Bearer $CLIKSO_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything"
}'const res = await fetch("https://app.clik.so/api/links/ai-slug", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CLIKSO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything"
}),
});
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/links/ai-slug",
headers={"Authorization": f"Bearer {os.environ['CLIKSO_API_KEY']}"},
json={
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything",
},
)
print(response.status_code, response.json())Uses requests. Set CLIKSO_API_KEY first.
<?php
$body = <<<'JSON'
{
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything"
}
JSON;
$ch = curl_init('https://app.clik.so/api/links/ai-slug');
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(`{
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything"
}`)
req, err := http.NewRequest("POST", "https://app.clik.so/api/links/ai-slug", 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/ai-slug')
request = Net::HTTP::Post.new(uri)
request["Authorization"] = "Bearer #{ENV.fetch("CLIKSO_API_KEY")}"
request["Content-Type"] = "application/json"
request.body = {
'url' => 'https://example.com/summer-sale',
'title' => 'Summer sale — 30% off everything'
}.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
puts response.code, response.bodyUses 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 = """
{
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything"
}
""";
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://app.clik.so/api/links/ai-slug"))
.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/links/ai-slug");
request.Headers.Authorization = new AuthenticationHeaderValue(
"Bearer", Environment.GetEnvironmentVariable("CLIKSO_API_KEY"));
request.Content = new StringContent(
"""
{
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything"
}
""",
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({
"url": "https://example.com/summer-sale",
"title": "Summer sale — 30% off everything"
})json";
std::string response;
curl_easy_setopt(curl, CURLOPT_URL, "https://app.clik.so/api/links/ai-slug");
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.
{
"status": 200,
"success": true,
"message": "Success",
"data": {
"slugs": [
"summer-sale",
"sale-30-off",
"summer-deals"
]
}
}Request body
urlstring · urirequiredThe destination page. Must be http(s).
titlestringThe page title, if you have it. The AI does not fetch the page, so this helps a lot.
descriptionstringA page description, if you have it.
excludearray of stringCodes you do not want suggested again. Only the first 50 are used.
Up to 50 items
What you get back
200 with the usual envelope — status, success, message, data. data has these fields:
slugsarray of stringrequiredSuggested short codes. Not checked for availability.
Up to 3 items
Common errors
UNAUTHORIZEDThe API key is missing, malformed or unknown.FORBIDDENThe key only has Read permission, or its creator is a viewer in this workspace.VALIDATION_ERRORurl is missing or is not an http(s) URL.USAGE_LIMIT_REACHEDThe workspace used today's AI slug credits. They reset at midnight UTC.RATE_LIMITEDMore than 15 calls in a minute from this workspace, or the key's per-minute limit.INTERNAL_ERRORThe AI service failed or returned nothing usable. Try again, or use a random slug.Every code and what to do about it: Errors.
Good to know
- Rate limit: 15 calls per minute per workspace, plus the plan's daily AI slug quota: Free 10, Starter 30, Pro 200, Business unlimited (per UTC day).
- Suggestions are lower-case letters, digits and hyphens, 4 to 20 characters. You get at most 3, sometimes fewer.
- They are not checked for availability. Check one with Check a slug, or just create the link and handle
409. - Every successful call uses one credit, even if you use none of the suggestions. See what is left with Get AI slug usage.
- The AI does not open the page. It works from the URL and any
titleanddescriptionyou send — get those from Preview a page's social card first for better ideas. - Send
excludewith codes you already rejected to get new ideas. The first 50 are kept; put the ones you most want to avoid first. - If the AI service is down you get
500 INTERNAL_ERROR. Fall back to Generate a random slug.
