Update wiki page 'API-Reference'
294
API-Reference.md
294
API-Reference.md
@@ -1,8 +1,8 @@
|
||||
# API Reference
|
||||
|
||||
**Base URL:** `/api/v1`
|
||||
**Data format:** JSON
|
||||
**Interactive docs:** `/api/swagger` (served by the backend at runtime)
|
||||
**Base URL:** `/` (all REST endpoints at root)
|
||||
**API port:** `8000` (default)
|
||||
**Interactive docs:** `/docs` (Swagger UI) · `/scalar` (Scalar UI)
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -11,90 +11,46 @@
|
||||
| JWT | `Authorization: Bearer <token>` | Web client (short-lived) |
|
||||
| API Key | `Authorization: ApiKey <key>` | Third-party apps (long-lived) |
|
||||
|
||||
Generate API keys from the Settings → API Keys page.
|
||||
Obtain a JWT from `POST /auth/login`. Generate API keys from Settings → API Keys.
|
||||
|
||||
---
|
||||
|
||||
## Auth Endpoints
|
||||
## Auth
|
||||
|
||||
### `POST /auth/register`
|
||||
|
||||
Creates a new user account.
|
||||
|
||||
**Public** — no auth required.
|
||||
Create a new user account. **Public.**
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "frutiger",
|
||||
"email": "aero@example.com",
|
||||
"password": "strongpassword123"
|
||||
}
|
||||
{ "username": "frutiger", "email": "aero@example.com", "password": "..." }
|
||||
```
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| 201 | Created — returns new User object (password omitted) |
|
||||
| 400 | Bad Request — invalid input |
|
||||
| 409 | Conflict — username or email already exists |
|
||||
|
||||
---
|
||||
| 201 | Created — returns User object |
|
||||
| 400 | Bad Request |
|
||||
| 409 | Conflict — username or email taken |
|
||||
|
||||
### `POST /auth/login`
|
||||
|
||||
Authenticates a user and returns a JWT.
|
||||
|
||||
**Public** — no auth required.
|
||||
Authenticate and receive a JWT. **Public.**
|
||||
|
||||
```json
|
||||
{
|
||||
"username": "frutiger",
|
||||
"password": "strongpassword123"
|
||||
}
|
||||
{ "username": "frutiger", "password": "..." }
|
||||
```
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"token": "eyJhbGci..."
|
||||
}
|
||||
```
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| 200 | OK — returns JWT |
|
||||
| 400 | Bad Request |
|
||||
| 401 | Unauthorized |
|
||||
Response: `{ "token": "eyJ..." }`
|
||||
|
||||
---
|
||||
|
||||
## User & Profile Endpoints
|
||||
## Users & Profiles
|
||||
|
||||
### `GET /users/{username}`
|
||||
|
||||
Retrieves the public profile of a user.
|
||||
|
||||
**Public.**
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| 200 | OK — returns public User object |
|
||||
| 404 | Not Found |
|
||||
|
||||
---
|
||||
Public profile. Content negotiation: returns AP actor JSON if `Accept: application/activity+json`, otherwise REST profile.
|
||||
|
||||
### `GET /users/me`
|
||||
|
||||
Retrieves the full profile of the authenticated user (includes private fields like email).
|
||||
|
||||
**Required:** JWT.
|
||||
|
||||
---
|
||||
Authenticated user's full profile (includes email). **JWT required.**
|
||||
|
||||
### `PUT /users/me`
|
||||
|
||||
Updates the authenticated user's profile.
|
||||
|
||||
**Required:** JWT.
|
||||
Update profile. **JWT required.**
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -107,146 +63,175 @@ Updates the authenticated user's profile.
|
||||
}
|
||||
```
|
||||
|
||||
- `topFriends`: up to 8 usernames displayed on your profile
|
||||
- `customCss`: sanitized on the server (malicious patterns stripped)
|
||||
`customCss` is sanitized server-side. `topFriends` accepts up to 5 usernames.
|
||||
|
||||
---
|
||||
### `GET /users`
|
||||
List all users with stats. **Public.**
|
||||
|
||||
### `GET /users/{username}/thoughts`
|
||||
|
||||
All thoughts for a specific user, paginated.
|
||||
|
||||
**Public.**
|
||||
User's thoughts, paginated. **Public.**
|
||||
|
||||
---
|
||||
|
||||
## Thoughts Endpoints
|
||||
## Thoughts
|
||||
|
||||
### `POST /thoughts`
|
||||
|
||||
Creates a new thought.
|
||||
|
||||
**Required:** JWT or API Key.
|
||||
Create a thought. **JWT or API Key required.**
|
||||
|
||||
```json
|
||||
{
|
||||
"content": "This is my first thought! #welcome"
|
||||
}
|
||||
{ "content": "Hello world! #welcome", "visibility": "public" }
|
||||
```
|
||||
|
||||
`visibility`: `public` | `followers` | `private`. Hashtags parsed automatically. Max 128 chars.
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| 201 | Created — returns new Thought object |
|
||||
| 400 | Bad Request (e.g. content > 128 chars) |
|
||||
| 201 | Created |
|
||||
| 400 | Content too long or invalid |
|
||||
|
||||
Hashtags in `content` are parsed automatically.
|
||||
|
||||
---
|
||||
### `GET /thoughts/{id}`
|
||||
Get a single thought. **Public** (respects visibility).
|
||||
|
||||
### `DELETE /thoughts/{id}`
|
||||
Delete own thought. **JWT or API Key required.**
|
||||
|
||||
Deletes a thought. Caller must be the author.
|
||||
### `GET /thoughts/{id}/thread`
|
||||
Full reply thread. **Public.**
|
||||
|
||||
**Required:** JWT or API Key.
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| 204 | No Content |
|
||||
| 403 | Forbidden |
|
||||
| 404 | Not Found |
|
||||
### `PUT /thoughts/{id}`
|
||||
Edit thought content. **JWT required.** Broadcasts `Update(Note)` to federation.
|
||||
|
||||
---
|
||||
|
||||
## Social Endpoints
|
||||
## Social
|
||||
|
||||
### `POST /users/{username}/follow`
|
||||
|
||||
Follow a user.
|
||||
|
||||
**Required:** JWT.
|
||||
|
||||
| Status | Meaning |
|
||||
|---|---|
|
||||
| 204 | No Content |
|
||||
| 404 | Not Found |
|
||||
| 409 | Conflict — already following |
|
||||
|
||||
---
|
||||
Follow a local user. **JWT required.**
|
||||
|
||||
### `DELETE /users/{username}/follow`
|
||||
Unfollow. **JWT required.**
|
||||
|
||||
Unfollow a user.
|
||||
### `GET /users/{username}/followers`
|
||||
Follower list. **Public.**
|
||||
|
||||
**Required:** JWT.
|
||||
### `GET /users/{username}/following`
|
||||
Following list. **Public.**
|
||||
|
||||
### `POST /thoughts/{id}/like`
|
||||
Like a thought. **JWT required.** Sends `Like` activity to remote authors.
|
||||
|
||||
### `DELETE /thoughts/{id}/like`
|
||||
Unlike. **JWT required.**
|
||||
|
||||
### `POST /thoughts/{id}/boost`
|
||||
Boost (announce) a thought. **JWT required.** Broadcasts `Announce`.
|
||||
|
||||
### `DELETE /thoughts/{id}/boost`
|
||||
Undo boost. **JWT required.**
|
||||
|
||||
### `POST /users/{username}/block`
|
||||
Block a user. **JWT required.** Delivers `Block` activity.
|
||||
|
||||
---
|
||||
|
||||
## Feed & Discovery
|
||||
|
||||
### `GET /feed`
|
||||
Home feed — thoughts from followed users, reverse-chronological. **JWT required.**
|
||||
|
||||
The authenticated user's main feed — thoughts from all followed users in reverse-chronological order, paginated.
|
||||
|
||||
**Required:** JWT.
|
||||
|
||||
---
|
||||
|
||||
## Discovery Endpoints
|
||||
### `GET /feed/public`
|
||||
Public feed — all public thoughts. **Public** (optional auth for like/boost state).
|
||||
|
||||
### `GET /tags/popular`
|
||||
|
||||
List of currently trending tags.
|
||||
|
||||
**Public.**
|
||||
|
||||
---
|
||||
Popular tags list. **Public.**
|
||||
|
||||
### `GET /tags/{tagName}`
|
||||
|
||||
All thoughts with a specific tag, paginated, chronological.
|
||||
|
||||
**Public.**
|
||||
|
||||
---
|
||||
Thoughts for a specific tag. **Public.**
|
||||
|
||||
### `GET /search`
|
||||
Full-text search over thoughts and users (PostgreSQL trigram). **Public.**
|
||||
|
||||
Full-text search across thoughts and users.
|
||||
|
||||
**Public** (optional auth for personalized results).
|
||||
Query params: `q`, `page`, `per_page`.
|
||||
|
||||
---
|
||||
|
||||
## API Key Endpoints
|
||||
## Notifications
|
||||
|
||||
### `GET /notifications`
|
||||
List notifications for the authenticated user. **JWT required.**
|
||||
|
||||
### `GET /notifications/unread-count`
|
||||
Count of unread notifications. **JWT required.**
|
||||
|
||||
### `POST /notifications/{id}/read`
|
||||
Mark a notification read. **JWT required.**
|
||||
|
||||
### `POST /notifications/read-all`
|
||||
Mark all notifications read. **JWT required.**
|
||||
|
||||
---
|
||||
|
||||
## API Keys
|
||||
|
||||
### `GET /api-keys`
|
||||
|
||||
List all API keys for the authenticated user.
|
||||
|
||||
**Required:** JWT.
|
||||
|
||||
---
|
||||
List own keys. **JWT required.**
|
||||
|
||||
### `POST /api-keys`
|
||||
Create a key. **JWT required.** Raw key returned **once** — store immediately.
|
||||
|
||||
Create a new API key.
|
||||
|
||||
**Required:** JWT.
|
||||
|
||||
The raw key is returned **once** at creation time — store it securely.
|
||||
### `DELETE /api-keys/{id}`
|
||||
Revoke a key. **JWT required.**
|
||||
|
||||
---
|
||||
|
||||
### `DELETE /api-keys/{id}`
|
||||
## Federation Management
|
||||
|
||||
Revoke an API key.
|
||||
### `GET /federation/pending-followers`
|
||||
List remote actors with pending follow requests. **JWT required.**
|
||||
|
||||
**Required:** JWT.
|
||||
### `POST /federation/accept-follower`
|
||||
Accept a remote follow request. **JWT required.**
|
||||
|
||||
### `POST /federation/reject-follower`
|
||||
Reject a remote follow request. **JWT required.**
|
||||
|
||||
### `DELETE /federation/remote-follower`
|
||||
Remove an accepted remote follower. **JWT required.**
|
||||
|
||||
### `GET /federation/remote-following`
|
||||
List remote actors this user follows. **JWT required.**
|
||||
|
||||
### `POST /federation/follow-remote`
|
||||
Follow a remote actor by `@user@instance` handle. **JWT required.**
|
||||
|
||||
### `POST /federation/unfollow-remote`
|
||||
Unfollow a remote actor. **JWT required.**
|
||||
|
||||
### `GET /remote-actors`
|
||||
Look up a remote actor by handle. **JWT required.**
|
||||
|
||||
---
|
||||
|
||||
## ActivityPub Endpoints
|
||||
|
||||
These are consumed by other Fediverse servers, not the frontend.
|
||||
|
||||
| Endpoint | Description |
|
||||
|---|---|
|
||||
| `GET /.well-known/webfinger` | WebFinger discovery |
|
||||
| `GET /.well-known/nodeinfo` | NodeInfo pointer |
|
||||
| `GET /nodeinfo/2.1` | NodeInfo stats |
|
||||
| `GET /users/{username}` (AP Accept) | Actor JSON |
|
||||
| `GET /users/{username}/outbox` | Paginated outbox |
|
||||
| `GET /users/{username}/followers` | Followers collection |
|
||||
| `GET /users/{username}/following` | Following collection |
|
||||
| `POST /users/{username}/inbox` | Shared inbox |
|
||||
|
||||
---
|
||||
|
||||
## Data Models
|
||||
|
||||
### User (Public)
|
||||
|
||||
### User (public)
|
||||
```json
|
||||
{
|
||||
"username": "frutiger",
|
||||
@@ -255,37 +240,30 @@ Revoke an API key.
|
||||
"avatarUrl": "https://...",
|
||||
"headerUrl": "https://...",
|
||||
"customCss": "body { background: blue; }",
|
||||
"topFriends": ["username1", "username2"],
|
||||
"joinedAt": "2024-01-01T12:00:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
### Thought
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "uuid-v4-string",
|
||||
"id": "uuid",
|
||||
"authorUsername": "frutiger",
|
||||
"content": "This is my first thought! #welcome",
|
||||
"content": "Hello world! #welcome",
|
||||
"tags": ["welcome"],
|
||||
"visibility": "public",
|
||||
"replyTo": null,
|
||||
"likeCount": 3,
|
||||
"boostCount": 1,
|
||||
"likedByMe": false,
|
||||
"boostedByMe": false,
|
||||
"createdAt": "2024-01-01T12:01:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
`visibility` values: `public`, `followers`, `private`.
|
||||
`replyTo`: UUID of the parent thought if this is a reply.
|
||||
|
||||
### Pagination
|
||||
|
||||
Paginated endpoints accept `page` and `per_page` query params and return:
|
||||
|
||||
All paginated endpoints accept `page` and `per_page` and return:
|
||||
```json
|
||||
{
|
||||
"data": [...],
|
||||
"page": 1,
|
||||
"per_page": 20,
|
||||
"total": 142
|
||||
}
|
||||
{ "data": [...], "page": 1, "per_page": 20, "total": 142 }
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user