One short link can be created by hand. A thousand cannot. Invoice notifications, order tracking, personalised campaigns — all of them need link generation triggered from your own system.

Authentication

The API is not publicly open. You authenticate with HTTP Basic using a username (key_id) and password (secret) generated in the dashboard.

curl -u "lk_9f3c2a71b0e84d55:sk_XXXXXXXXXXXXXXXXXXXX" \
  https://lnkz.tr/api/v1/me

The secret is shown only once at creation; only a hash is stored. Lose it and you generate a new key — that is a deliberate design choice.

Key hygiene

  • Never hard-code the key; keep it in an environment variable.
  • Generate a separate key per application. A leak then costs you one key, not all of them.
  • Do not use the key client-side (browser JavaScript, mobile apps) — no secret stored there stays secret. Make the call from your own server.

Creating a single link

POST /api/v1/links
Content-Type: application/json

{
  "url": "https://randevu.selfklinik.com/?GUID=a8faa905-477a-11f0-89df-52e18006e243",
  "title": "Appointment link",
  "tags": ["clinic", "booking"],
  "expires_at": "2026-12-31 23:59:00",
  "max_clicks": 5000
}

A successful call returns 201 with short_url, code and qr_url. Each success costs 1 credit; credits are refunded automatically on validation errors.

PHP

function shorten(string $url, array $extra = []): array
{
    $ch = curl_init('https://lnkz.tr/api/v1/links');
    curl_setopt_array($ch, [
        CURLOPT_POST           => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_USERPWD        => getenv('LNKZ_KEY_ID') . ':' . getenv('LNKZ_KEY_SECRET'),
        CURLOPT_HTTPHEADER     => ['Content-Type: application/json'],
        CURLOPT_POSTFIELDS     => json_encode(['url' => $url] + $extra),
    ]);

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

    $data = json_decode((string) $response, true);

    if ($status !== 201) {
        throw new RuntimeException($data['error']['message'] ?? 'Could not create link');
    }

    return $data['link'];
}

Python

import os, requests

AUTH = (os.environ["LNKZ_KEY_ID"], os.environ["LNKZ_KEY_SECRET"])

def shorten(url, **extra):
    response = requests.post(
        "https://lnkz.tr/api/v1/links",
        auth=AUTH,
        json={"url": url, **extra},
        timeout=15,
    )
    payload = response.json()
    if response.status_code != 201:
        raise RuntimeError(payload["error"]["message"])
    return payload["link"]

Bulk generation

The endpoint creates one link per call. Three rules matter when processing tens of thousands of records.

1. Respect the rate limit

120 requests per minute per key. Exceed it and you get 429 with a Retry-After header. Work through a queue; do not fan out parallel requests and fight the limit.

import time

def shorten_with_retry(url, attempts=5, **extra):
    for attempt in range(attempts):
        try:
            return shorten(url, **extra)
        except RuntimeError:
            raise                      # validation error: retrying is pointless
        except requests.HTTPError as e:
            if e.response.status_code == 429:
                time.sleep(int(e.response.headers.get("Retry-After", 60)))
                continue
            raise
    raise RuntimeError("rate limit exceeded")

2. Distinguish retryable errors

CodeMeaningWhat to do
401Invalid keyDo not retry; fix configuration
402Not enough creditsStop, alert, top up
422Invalid field or code takenFix the data; the same request will fail again
429Rate limitedWait for Retry-After, then retry
5xxServer errorRetry with exponential backoff

3. Store the result on your side

Write the returned code into your own database. It prevents processing the same record twice (and spending credits twice). Simple rule: if your record already has a short_code, never call the API for it.

Budgeting credits

Check your balance before starting:

GET /api/v1/me
→ { "account": { "credits": 4820 }, "costs": { "link": 1, "ai_slug": 5 } }

A 50,000-link send needs 50,000 credits. Running out mid-job leaves a half-finished send — calculate and top up before bulk work.

Meaningful codes with AI

For human-facing links, readable codes outperform random ones. The AI endpoint analyses the destination and proposes candidates:

POST /api/v1/ai/suggest
{ "task": "slug", "url": "https://example.com/campaigns/summer-sale-2026" }

→ {
  "result": {
    "suggestions": [
      { "code": "summer-sale",   "reason": "The campaign name is directly recognisable" },
      { "code": "summer26-deal", "reason": "Also states the period" }
    ]
  },
  "credits_charged": 5
}

At 5 credits per call this is not economical per record in bulk. Use it where links are singular and human-facing — campaigns, products, categories — and leave random codes on the thousands of per-recipient links.

Checklist

  1. Keep the key in an environment variable, one per application.
  2. Set a timeout on every request (15 s is plenty).
  3. Honour Retry-After on 429; never retry other 4xx responses.
  4. Persist the generated code and guard against duplicate creation.
  5. Verify your credit balance before a bulk run.
  6. Set expires_at and max_clicks on per-recipient links.
  7. Test with 10 records before running the full list.