Developer API
API reference
Send a bearer token. Bodies can be form-encoded or JSON; responses are JSON. Make a token in your dashboard.
Authentication
Authorization: Bearer u4_…
Tokens are shown once and stored hashed. Revoking takes effect immediately.
No valid token means 401. Every request is logged with the token and the
caller's IP address, so keep tokens out of client-side code.
Create a link
POST https://u4.nz/api/links
url required http(s) destination
slug optional custom slug, 4+ characters: letters, digits, - and _ ; omit for a random one.
Reserved words (site paths, common brands, profanity) return 400.
3 characters or fewer are not available (403).
expires optional days until the link stops resolving (max 3650)
curl -X POST https://u4.nz/api/links \
-H "Authorization: Bearer $U4_TOKEN" \
-d url="https://example.com/launch" -d slug=launch -d expires=30
{
"slug": "launch",
"short": "https://u4.nz/launch",
"qr": "https://u4.nz/launch.qr.svg",
"url": "https://example.com/launch",
"created_at": 1789425751886,
"expires_at": 1792017751886,
"clicks": 0
}
Bulk create
Up to 100 per call. Each one succeeds or fails on its own, so the response is 207.
curl -X POST https://u4.nz/api/links/bulk \
-H "Authorization: Bearer $U4_TOKEN" -H "Content-Type: application/json" \
-d '{"links":[{"url":"https://a.example"},{"url":"https://b.example","slug":"b"}]}'
{ "created": 2, "results": [ { "ok": true, "slug": "…", … }, … ] }
List, read, update, delete
GET https://u4.nz/api/links?limit=100 # newest first, limit ≤ 1000
GET https://u4.nz/api/links/launch
PATCH https://u4.nz/api/links/launch # url and/or expires (null = never)
DELETE https://u4.nz/api/links/launch # also deletes its click history
Click stats
curl "https://u4.nz/api/links/launch/stats?days=30" -H "Authorization: Bearer $U4_TOKEN"
{
"slug": "launch",
"clicks": 412, // all-time
"window_days": 30,
"window_clicks": 118,
"by_day": [{"day":"2026-09-14","n":37}, …],
"by_country": [{"k":"NZ","n":61}, …],
"by_referer": [{"k":"news.ycombinator.com","n":40}, …],
"by_device": [{"k":"mobile","n":70}, {"k":"desktop","n":44}, {"k":"bot","n":4}]
}
Raw events: GET /api/links/:slug/clicks.csv — timestamp, country, referer, device
for the last 90 days (50,000 rows max).
Account
GET https://u4.nz/api/me
{ "id": "…", "email": "…", "links": 12, "clicks": 4031, "top": [{"k":"launch","n":118}, …] }
Public extras
No token needed:
https://u4.nz/launch 302 redirect
https://u4.nz/launch+ preview page: shows the destination instead of following it
https://u4.nz/launch.qr.svg QR code, SVG
Errors and limits
Errors look like {"error":"…"} with the status you'd expect:
| 400 | bad URL, bad slug, or bad body |
| 401 | missing or invalid token |
| 403 | destination host is blocked, or slug is 3 characters or fewer |
| 404 | no such link (or not yours) |
| 409 | slug already taken |
| 429 | rate limited — 600 requests/min per account |
Destinations must be http or https. Private hosts,
raw IPs and u4.nz itself are refused. Redirects are never rate limited.