Skip to main content

API Reference

All endpoints are JSON. Authentication uses a JWT bearer token returned by /auth/register and /auth/login. Interactive docs are available at /docs (Swagger UI) when the server is running.

Base URL

http://localhost:8000

Authentication

POST /auth/register

Create an account and receive a JWT.

Request body

{ "email": "you@example.com", "password": "hunter2" }

Responses

StatusBody
200{ "access_token": "<jwt>", "token_type": "bearer" }
400{ "detail": "Email already registered" }

POST /auth/login

Authenticate and receive a JWT.

Request body

{ "email": "you@example.com", "password": "hunter2" }

Responses

StatusBody
200{ "access_token": "<jwt>", "token_type": "bearer" }
401{ "detail": "Incorrect email or password" }

GET /auth/me

Return the authenticated user's profile.

Headers

Authorization: Bearer <jwt>

Responses

StatusBody
200{ "id": 1, "email": "you@example.com" }
401{ "detail": "Not authenticated" }

URLs

All /urls routes except stats and redirect require a JWT bearer header.

POST /urls/shorten

Create a short URL.

Request — query parameter target_url (a bare scalar in the FastAPI handler, so it is a query parameter, not a JSON body):

POST /urls/shorten?target_url=https://example.com/very/long/path
curl -s -X POST 'http://localhost:8000/urls/shorten?target_url=https://example.com/very/long/path' \
-H 'Authorization: Bearer <jwt>'

Response 200

{
"id": 12,
"short_code": "Ab3xY9",
"target_url": "https://example.com/very/long/path",
"clicks": 0,
"is_active": true
}

GET /urls/my

List the authenticated user's URLs, newest first.

Response 200

[
{
"id": 12,
"short_code": "Ab3xY9",
"target_url": "https://example.com/very/long/path",
"clicks": 3,
"is_active": true
}
]

GET /urls/{short_code}/stats

Public click statistics for any short code.

Response 200

{
"short_code": "Ab3xY9",
"target_url": "https://example.com/very/long/path",
"clicks": 3,
"total": 3
}
StatusBody
404{ "detail": "Not Found" }

DELETE /urls/{short_code}

Delete a URL. Owner-scoped — only the user who created the URL can delete it. Returns 204 No Content on success.

StatusDetail
204Deleted
404URL not found or not owned by you

GET /urls/r/{short_code}

Redirect to the target URL and increment the click counter.

Responses

StatusDetail
302Redirect to target_url
404{ "detail": "URL not found" } (inactive URLs are ignored)

Only active URLs redirect — is_active = true is required.

System

GET /health

Liveness probe.

{ "status": "ok" }

Data model

Userid, email (unique), password_hash

URLid, short_code (unique), target_url, owner_id (FK → User), clicks (int, default 0), is_active (bool), created_at

Error format

FastAPI errors follow the standard shape:

{ "detail": "Human-readable message" }