Authentication
Every request must include your secret key as a Bearer token. API access is included on the Growth and Premium plans.
- Open Settings → API and click New key.
- Copy the key — it looks like
lali_xxxxxxxxxxxx…and is shown only once (only a hash is stored). If you lose it, revoke it and create a new one.
bash
Authorization: Bearer lali_xxxxxxxxxxxxxxxxxxxxxxxxxxxxKeep your key secret — treat it like a password. Revoked or expired keys return
401. All operations are scoped to the key’s owner: you only ever see and modify your own links.Create a link
POST/api/v1/links
bash
curl -X POST https://lali.lu/api/v1/links \
-H "Authorization: Bearer $LALI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"destination": "https://example.com/a-very-long-url",
"code": "promo",
"title": "Spring promo"
}'Body
| Field | Type | Required | Notes |
|---|---|---|---|
| destination | string | Yes | Target URL (http/https, ≤ 2048 chars, validated). |
| code | string | — | Custom alias (≤ 64 chars, A–Z a–z 0–9 _ -). Random if omitted. Reserved words rejected. |
| title | string | — | Optional label. |
| tags | string[] | — | Up to 20 tags. |
| expiresAt | ISO date | — | Requires the Link expiration feature. |
| password | string | — | ≥ 8 chars. Requires the Password-protected links feature. |
| utmSource … | string | — | utmSource/Medium/Campaign/Term/Content. Requires the UTM builder feature. |
Response · 201 Created
json
{
"data": {
"id": "clz…",
"code": "promo",
"destination": "https://example.com/a-very-long-url",
"title": "Spring promo",
"status": "ACTIVE",
"clickCount": 0,
"createdAt": "2026-06-29T12:00:00.000Z"
}
}Your short link is then lali.lu/promo.
List links
GET/api/v1/links
bash
curl "https://lali.lu/api/v1/links?status=ACTIVE&sort=clickCount&order=desc&page=1&pageSize=20" \
-H "Authorization: Bearer $LALI_API_KEY"Query parameters: search, status (ACTIVE · DISABLED · ARCHIVED · ALL), tag, sort (createdAt · clickCount · updatedAt), order (asc · desc), page, pageSize (≤ 100).
Returns { "data": { "items": [...], "total", "page", "pageSize" } }.
Errors
Errors use a consistent envelope and standard HTTP status codes.
json
{
"error": {
"code": "BAD_REQUEST",
"message": "Validation failed.",
"details": { }
}
}| Status | Code | When |
|---|---|---|
| 400 | BAD_REQUEST | Invalid body/params, or an invalid/reserved destination or alias. |
| 401 | UNAUTHORIZED | Missing, invalid, revoked, or expired key. |
| 402 | LIMIT_EXCEEDED / FEATURE_LOCKED | Plan link limit hit, or a field needs a feature your plan lacks. |
| 403 | FORBIDDEN | The public API is disabled. |
| 409 | CONFLICT | The custom alias is already taken. |
| 429 | RATE_LIMITED | Too many requests. |
Rate limits
Each key is limited to 60 requests / 60 s. Responses carry X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers; over-limit requests return 429.
Need a key? Create one in Settings