Base URL prefix: /api/v1
This API is built with FastAPI and uses JWT Bearer auth for protected routes.
- Public endpoints:
POST /api/v1/users/(register)POST /api/v1/users/login(login)- Secret endpoints under
/api/v1/secrets/*currently do not require Bearer auth.
- Protected endpoints:
- Most
/usersand all/notesoperations except route roots.
- Most
- Auth header format:
Authorization: Bearer <token>JWT details:
subclaim holds user ID.- Token expiry is set to about 1 hour.
Successful responses are wrapped like:
{
"code": "SUCCESS",
"message": "Human-readable message",
"pagination": null,
"<result_key>": {}
}Error responses are usually:
{
"code": "ERROR_CODE",
"info": "Error details"
}For query endpoints (/search), pagination is filled and the result list is returned under note_query or user_query.
Route root: GET /api/v1/users/
-
POST /api/v1/users/- Creates a new user.
- Body:
{ "username": "john_doe", "password": "StrongPass1!", "email": "[email protected]" }- Username rules: 3-20 chars, alnum + underscore.
- Password rules: min 8, upper, lower, digit, special char required.
- Returns created user data plus JWT token.
-
POST /api/v1/users/login- Authenticates by
usernameoremailwithpassword. - Body:
{ "username": "john_doe", "password": "StrongPass1!" }- Returns token on success.
- Authenticates by
-
POST /api/v1/users/search?offset=0&limit=100- Search/filter users.
- Body fields:
username,email,username_contains. - Non-admin views mask email.
-
GET /api/v1/users/{user_id}- Gets a user by ID.
- Special value:
meresolves to authenticated user ID.
-
GET /api/v1/users/{user_id}/username- Gets only username for the target user.
- Supports
me.
-
PATCH /api/v1/users/- Modifies user fields.
- Body:
{ "user_id": 1, "modifications": { "username": "new_name" } }- Allowed keys are controlled by core schema mutable set.
-
DELETE /api/v1/users/{user_id}- Deletes a user if policy allows.
-
Role management
POST /api/v1/users/rolesadd rolesDELETE /api/v1/users/rolesremove rolesPUT /api/v1/users/rolesreplace all roles- Example body:
{ "user_id": 1, "roles": ["moderator"] }or
{ "user_id": 1, "new_roles": ["user", "moderator"] }
Route root: GET /api/v1/notes/
All note operations below require Bearer token.
-
POST /api/v1/notes/- Creates a note.
- Body:
{ "author_id": 1, "title": "My first note", "content": "Hello world", "flags": ["private"] }author_idmust match authenticated user ID.- Valid flags:
private,admin_only,archived.
-
GET /api/v1/notes/{note_id}- Gets one note if readable by policy.
-
PATCH /api/v1/notes/- Modifies note fields.
- Body:
{ "note_id": 10, "modifications": { "title": "Updated title", "content": "Updated content" } }- Mutable keys: title and content.
-
DELETE /api/v1/notes/{note_id}- Deletes note if editable by policy.
-
POST /api/v1/notes/search?offset=0&limit=100- Query notes with fields:
note_id,author_id,title,title_contains,content_contains,flags
- Query notes with fields:
-
Flag management
POST /api/v1/notes/flagsadd flagsDELETE /api/v1/notes/flagsremove flagsPATCH /api/v1/notes/flagsreplace flags (new_flags)- Add/remove body:
{ "note_id": 10, "flags": ["private"] }- Replace body:
{ "note_id": 10, "new_flags": ["private", "archived"] }
Route group: /api/v1/secrets
-
GET /api/v1/secrets/homer?secret_key=beer- Returns an MP3 file response.
-
GET /api/v1/secrets/homer?secret_key=donut- Returns plain text:
Mmm... Donuts!
- Returns plain text:
-
GET /api/v1/secrets/homer?secret_key=quotes- Returns one random quote from Homer quotes JSON.
-
GET /api/v1/secrets/homer?secret_key=<anything_else>- Returns 403 with
INVALID_KEYJSON.
- Returns 403 with
-
GET /api/v1/secrets/coffee- Returns 418 teapot JSON:
{ "code": "I_AM_A_TEAPOT", "info": "I'm a teapot, I cannot brew coffee." }
What a user represents:
- An authenticated account that owns notes and has role-based permissions.
What a user holds:
- Database fields:
id(int)email(unique string)username(unique string)created_at(datetime)password_hash(stored hash, never exposed by API serializer)roles(comma-separated string in DB; returned as list in API responses)
How a user behaves:
- Auth:
- Can register and login to receive JWT.
- Visibility:
- Can fetch own data.
- Search results may hide email for non-admin views.
- Role effects:
- Roles map to permissions (examples: create notes, edit any note, manage users).
- Valid roles:
user,moderator,admin,owner,banned.
- Management rules:
- Owners can manage everyone.
- Non-owner admins/moderators cannot manage owner/admin targets.
What a note represents:
- A user-authored text record with optional visibility/processing flags.
What a note holds:
- Database fields:
id(int)author_id(user foreign key)title(string)content(string)posted_at(datetime)flags(comma-separated string in DB; serialized as list in API responses)
How a note behaves:
- Ownership:
- Author can always edit own note.
- Read policy:
privatenotes need owner or private-read permission.admin_onlynotes need manage-user-level permission.
- Write policy:
- Create requires create-note permission.
author_idin create request must equal token user ID.- Non-owner edits require elevated permission.
- Flag rules:
- Valid flags:
private,admin_only,archived. - Owners can only add/remove/set
privateon their own notes.
- Valid flags:
- Register user:
POST /api/v1/users/ - Login:
POST /api/v1/users/login - Use returned token as Bearer token.
- Create note:
POST /api/v1/notes/ - Query notes:
POST /api/v1/notes/search