Developer docs

API reference / Links

Suggest slugs with AI

POSThttps://app.clik.so/api/links/ai-slug

In short

Suggests up to three short, readable slugs for a destination URL, from the URL and the title and description you send. Each call uses one of your workspace's daily AI slug credits.

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 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.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 = """
            {
              "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.

Response 200
{
  "status": 200,
  "success": true,
  "message": "Success",
  "data": {
    "slugs": [
      "summer-sale",
      "sale-30-off",
      "summer-deals"
    ]
  }
}

Other responses: 401 · 403 · 422 · 429 · 500

Request body

  • urlstring · urirequired

    The destination page. Must be http(s).

  • titlestring

    The page title, if you have it. The AI does not fetch the page, so this helps a lot.

  • descriptionstring

    A page description, if you have it.

  • excludearray of string

    Codes 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 stringrequired

    Suggested short codes. Not checked for availability.

    Up to 3 items

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_ERRORurl is missing or is not an http(s) URL.
429USAGE_LIMIT_REACHEDThe workspace used today's AI slug credits. They reset at midnight UTC.
429RATE_LIMITEDMore than 15 calls in a minute from this workspace, or the key's per-minute limit.
500INTERNAL_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 title and description you send — get those from Preview a page's social card first for better ideas.
  • Send exclude with 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.