API Reference

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

GET /:code Public — no auth required

Redirects to the destination URL associated with :code. Records a click with device, browser, OS, country, and referrer metadata.

Responses
StatusDescription
302Redirect to destination URL
404Short code not found — returns landing page with 404 header

Projects

GET /api/projects List all projects
Response
[
  {
    "id":         1,
    "name":       "Marketing",
    "color":      "#6366f1",
    "link_count": 12,
    "created_at": "2025-01-01 12:00:00"
  }
]
POST /api/projects Create a project
Request body (JSON)
FieldTypeDescription
namestringrequiredProject name (max 80 chars)
colorstringoptionalHex color, e.g. #6366f1. Defaults to a random color.
Response — 201 Created
{ "id": 3 }
PUT /api/projects/:id Update a project
FieldTypeDescription
namestringNew project name
colorstringNew color hex
Response — 200 OK
{ "ok": true }
DELETE /api/projects/:id Delete a project

Permanently deletes the project. All links in the project and their click history are also deleted.

Response — 200 OK
{ "ok": true }
⚠️
This is a cascading delete. All links and all click history for this project are permanently removed.

Analytics

GET /api/stats Per-link analytics

Returns click analytics for a single link, broken down by time period, country, device, browser, OS, and referrer.

Query parameters
ParamTypeDescription
codestringrequiredShort code to fetch stats for
periodstringoptional7d | 30d | 90d | all (default: 30d)
Response
{
  "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 }, ...]
}
GET /api/overview Aggregate dashboard stats

Returns aggregate statistics used by the dashboard overview tab — totals, top links, daily chart data, and breakdowns.

Query parameters
ParamTypeDescription
projectstringoptionalProject ID to scope stats to. Omit for all-link aggregate.
periodstringoptional7d | 30d | 90d | all (default: 30d)

Import / Export

GET /api/export Export links as CSV

Downloads all links as a CSV file with columns: code, url, title, project, clicks, created_at.

Query parameters
ParamTypeDescription
projectstringoptionalExport only links in this project ID
Response

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
POST /api/import Import links from CSV

Accepts a CSV (same format as export) and inserts new links. Rows with duplicate short codes are skipped.

Request

Send the CSV as multipart/form-data with the file field named file, or as raw text/csv body.

Response — 200 OK
{
  "inserted": 15,
  "skipped":  2,   // duplicate codes
  "errors":   0
}
ℹ️
The dashboard's Import tab shows a preview of how rows will be handled before committing. This API endpoint commits immediately.