REST API · Session Auth · JSON

# API Reference

Complete reference for the QRknit REST API. Manage links, generate QR codes, pull analytics, and administer users — all from your own code.

Base URL: https://your-instance.com · Format: application/json

## Authentication

Authenticated endpoints accept either of two credentials. Session cookie: log in via the web UI or call `POST /api/auth/login` with `{"username": "…", "password": "…"}` — the server sets an HttpOnly session cookie valid for 30 days. API key: create a key in the dashboard (or via `POST /api/keys`) and send it as `Authorization: Bearer qrk_…`. Keys carry a `read` or `write` scope — read-only keys may only call GET endpoints. Endpoints marked Admin additionally require the authenticated user to have admin privileges.

Auth

Session-based login. A successful login sets a 30-day HttpOnly cookie used for all authenticated requests.

Method | Endpoint | Auth | Description
--- | --- | --- | ---
POST | /api/auth/login | — | Login — body: `{"username": "…", "password": "…"}`. Sets session cookie and returns `plan`, `plan_limits`, and `org_id`.
POST | /api/auth/logout | Session | Clear the current session and invalidate the cookie.
GET | /api/auth/me | Session | Returns `{"authenticated": true, "username": "…", "is_admin": bool, "org_id": int|null, "plan": "…", "plan_limits": {…}}`.
GET | /api/keys | Session | List your API keys — prefix, scope, created and last-used timestamps. Full tokens are never returned.
POST | /api/keys | Session | Create an API key. Body: `{"name": "…", "scope": "read"|"write"}`. The response includes the full `token` exactly once — only a hash is stored.
DELETE | /api/keys/:id | Session | Revoke an API key immediately. Admins may revoke any user's key.

Links

Create, read, update, and delete short links. Org members see all links within their org. Admin accounts see only their own links by default, with optional `?user=` filtering.

Method | Endpoint | Auth | Description
--- | --- | --- | ---
POST | /api/shorten | Session | Create a short link. Body: `{"url": "…", "custom_code": "…", "title": "…", "expires_at": "…", "tags": […], "redirect_type": 301|302, "password": "…"}`. All fields except `url` are optional — redirects default to 302; a `password` gates the link behind a branded unlock page.
GET | /api/links | Session | List links. Query params: `?q=` (search), `?tag=`, `?page=`, `?per_page=`. Admin can add `?user=<username>` to filter by user.
GET | /api/links/:code | Session | Link detail — includes `created_by` username.
PATCH | /api/links/:code | Session | Edit link — updatable fields: `url`, `title`, `expires_at`, `tags`, `is_pinned`, `redirect_type` (301/302), `password` (empty string removes protection; omit to leave unchanged).
DELETE | /api/links/:code | Session | Delete a link.
GET | /api/links/:code/analytics | Session | Click analytics. Query: `?days=7|30|90` (capped to plan's max window), `?exclude_bots=1` to filter crawler/bot traffic. Returns `daily` (each day includes `unique` visitors), `unique_visitors`, `bot_clicks`, `referrers`, `devices`, `browsers`, `countries`, `heatmap` (7×24 array), and `max_days`.
GET | /api/analytics/aggregate | Session | Aggregate analytics across your whole account (or org). Query: `?days=`, `?tag=` to scope to one tag, `?exclude_bots=1`. Returns `daily`, `unique_visitors`, `referrers`, `devices`, `browsers`, `countries`, and `top_links`.
GET | /api/links/:code/clicks/export | Session | Download raw click events as CSV. Columns: `timestamp`, `referrer`, `device`, `browser`, `country`.

Utilities

Stats, plan usage, tags, QR code generation, bulk operations, and CSV import/export.

Method | Endpoint | Auth | Description
--- | --- | --- | ---
GET | /api/stats | Session | Dashboard stats: total links, total clicks, clicks in last 7 days, top 5 links, and a 30-day `daily` click array.
GET | /api/plan | Session | Current user's effective plan, limits, and live usage — `{plan, limits: {max_links, monthly_clicks, analytics_days}, usage: {active_links, monthly_clicks}}`. Org members see pooled usage across all org members.
GET | /api/tags | Session | Tags scoped to the requesting user — own tags for solo users and admins; all org member tags for org members.
GET | /api/fetch-title | Session | Server-side page title fetch. Query: `?url=<url>`. Returns `{"title": "…"}`.
GET | /api/qr/:code | — | QR for a short link. Query params: `?format=png|svg|pdf`, `?ec=L|M|Q|H` (error correction), `?fg=`, `?bg=`, `?size=`, `?style=` (raster formats only), `?download=1` for an attachment.
GET | /api/qr/custom | — | QR for any URL. Query: `?url=` plus the same params as above (`format`, `ec`, `fg`, `bg`, `size`, `style`, `download`). Styles: `square`, `rounded`, `dots`, `vertical`, `horizontal`.
POST | /api/qr/custom | — | QR with logo overlay. Body: `{url, fg, bg, size, style, ec, format, logo}` where `logo` is a base64-encoded image string (forces error correction H; SVG embeds the logo as a data URI).
POST | /api/links/bulk | Session | Bulk operations. Body: `{"action": "delete"|"tag"|"expire", "codes": […]}`.
GET | /api/links/export | Session | Download all links as CSV.
POST | /api/links/import | Session | Import links from CSV. Body: `{"csv": "…"}`.
GET | /api/health | — | Health check — returns `{"status": "ok"}`. Used by Docker and uptime monitors.
GET | /api/config | — | Public deployment config — returns non-sensitive values like `app_name` and `base_url`.

Admin

All Admin endpoints require an authenticated admin session. These manage users, organizations, and the message inbox.

Method | Endpoint | Auth | Description
--- | --- | --- | ---
GET | /api/admin/users | Admin | List all users with link counts, plan, org name, and org plan.
POST | /api/admin/users | Admin | Create user. Body: `{"username": "…", "password": "…", "is_admin": bool, "plan": "…"}`.
PATCH | /api/admin/users/:id | Admin | Update plan, admin status, and/or org. Body: `{plan?, is_admin?, org_id?}`. Set `org_id: null` to remove from org.
DELETE | /api/admin/users/:id | Admin | Delete user. Cannot delete yourself.
PATCH | /api/admin/users/:id/password | Admin | Change user password. Body: `{"password": "…"}`.
GET | /api/admin/organizations | Admin | List all organizations with member counts and plan.
POST | /api/admin/organizations | Admin | Create organization. Body: `{"name": "…", "plan": "…"}`.
PATCH | /api/admin/organizations/:id | Admin | Update organization name and/or plan. Body: `{name?, plan?}`.
DELETE | /api/admin/organizations/:id | Admin | Delete organization. Members are unassigned but not deleted.
GET | /api/admin/messages | Admin | List all contact/portal messages, newest first.
DELETE | /api/admin/messages/:id | Admin | Delete a message.
PATCH | /api/admin/messages/:id/read | Admin | Mark a message as read.
GET | /api/admin/overview | Admin | Platform overview — totals (users, orgs, links, clicks), a 30-day click series, top links, and per-user quota usage with near-limit flags.
GET | /api/admin/audit | Admin | Audit log of administrative actions (user/org changes, password resets, key events, purges). Query: `?limit=` (default 200).
GET | /api/admin/keys | Admin | List all API keys across users — prefix, scope, last-used timestamp, revocation state.
POST | /api/admin/purge | Admin | Hard-delete soft-deleted links older than `{"days": N}` — frees their short codes and removes click history. Irreversible.

Contact

Public endpoint for submitting contact and support messages. No authentication required.

Method | Endpoint | Auth | Description
--- | --- | --- | ---
POST | /api/contact | — | Submit a contact message. Body: `{"name": "…", "email": "…", "subject": "…", "body": "…"}`.

Public Redirects

Short link redirection and SEO endpoints. No authentication required.

Method | Endpoint | Auth | Description
--- | --- | --- | ---
GET | /:code | — | Redirect to the destination URL for a short code (302 by default, 301 if configured per link). Records click analytics asynchronously (referrer, device, browser, country, bot detection). Password-protected links show a branded unlock page; expired or missing links show branded visitor pages.
POST | /:code/unlock | — | Password submission for protected links (form field `password`). Redirects to the destination on success.
GET | /robots.txt | — | Standard robots.txt for crawler directives.
GET | /sitemap.xml | — | Auto-generated XML sitemap.