API reference
All API endpoints are served by the same Worker. Redirect endpoints are public.
All /api/* endpoints require an authenticated session (via Cloudflare Access)
— unauthenticated requests return 401.
Redirects
Redirects to the destination URL associated with :code. Records a click with device, browser, OS, country, and referrer metadata.
| Status | Description |
|---|---|
| 302 | Redirect to destination URL |
| 404 | Short code not found — returns landing page with 404 header |
Links
Returns all short links, optionally filtered by project.
| Param | Type | Description | |
|---|---|---|---|
project | string | optional | Project ID to filter by |
[
{
"id": 1,
"code": "abc123",
"url": "https://example.com/very/long/url",
"title": "Example page",
"project_id": 2, // null if not in a project
"project_name": "Marketing",
"project_color":"#6366f1",
"clicks": 42,
"created_at": "2025-01-01 12:00:00"
}
]
| Field | Type | Description | |
|---|---|---|---|
url | string | required | Destination URL (must be a valid URL) |
code | string | optional | Custom short code. Auto-generated if omitted. |
title | string | optional | Human-readable label shown in the dashboard |
project_id | number | optional | Assign link to a project |
201 Created{ "id": 7, "code": "x9kp2" }
| Status | Body | Cause |
|---|---|---|
| 400 | {"error":"Invalid URL"} | URL failed validation |
| 409 | {"error":"Code already taken"} | Custom code is in use |
Update any fields of an existing link. All fields are optional — only provided fields are changed.
| Field | Type | Description |
|---|---|---|
url | string | New destination URL |
code | string | New short code |
title | string | New title |
project_id | number | null | Move to project, or pass null to remove from project |
200 OK{ "ok": true }
Permanently deletes the link and all associated click history.
200 OK{ "ok": true }
Projects
[
{
"id": 1,
"name": "Marketing",
"color": "#6366f1",
"link_count": 12,
"created_at": "2025-01-01 12:00:00"
}
]
| Field | Type | Description | |
|---|---|---|---|
name | string | required | Project name (max 80 chars) |
color | string | optional | Hex color, e.g. #6366f1. Defaults to a random color. |
201 Created{ "id": 3 }
| Field | Type | Description |
|---|---|---|
name | string | New project name |
color | string | New color hex |
200 OK{ "ok": true }
Permanently deletes the project. All links in the project and their click history are also deleted.
200 OK{ "ok": true }
Analytics
Returns click analytics for a single link, broken down by time period, country, device, browser, OS, and referrer.
| Param | Type | Description | |
|---|---|---|---|
code | string | required | Short code to fetch stats for |
period | string | optional | 7d | 30d | 90d | all (default: 30d) |
{
"code": "abc123",
"url": "https://example.com/...",
"title": "Example",
"total": 142,
"daily": [
{ "date": "2025-06-01", "count": 14 },
...
],
"by_country": [{ "label": "US", "count": 80 }, ...],
"by_device": [{ "label": "mobile", "count": 95 }, ...],
"by_browser": [{ "label": "Chrome", "count": 70 }, ...],
"by_os": [{ "label": "iOS", "count": 60 }, ...],
"by_referer": [{ "label": "twitter.com", "count": 30 }, ...]
}
Returns aggregate statistics used by the dashboard overview tab — totals, top links, daily chart data, and breakdowns.
| Param | Type | Description | |
|---|---|---|---|
project | string | optional | Project ID to scope stats to. Omit for all-link aggregate. |
period | string | optional | 7d | 30d | 90d | all (default: 30d) |
Import / Export
Downloads all links as a CSV file with columns: code, url, title, project, clicks, created_at.
| Param | Type | Description | |
|---|---|---|---|
project | string | optional | Export only links in this project ID |
Returns text/csv with Content-Disposition: attachment; filename="links.csv".
code,url,title,project,clicks,created_at
abc123,https://example.com,Example,Marketing,42,2025-01-01 12:00:00
Accepts a CSV (same format as export) and inserts new links. Rows with duplicate short codes are skipped.
Send the CSV as multipart/form-data with the file field named file, or as raw text/csv body.
200 OK{
"inserted": 15,
"skipped": 2, // duplicate codes
"errors": 0
}