Skip to content

Commit 86def99

Browse files
committed
docs: add API, OCC commands, and architecture documentation
Signed-off-by: schBenedikt <benedikt.schaechner@web.de>
1 parent c58c2d6 commit 86def99

3 files changed

Lines changed: 809 additions & 0 deletions

File tree

docs/API.md

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
# Nextcloud Social API Reference
2+
3+
## Overview
4+
5+
The Social app provides three categories of APIs:
6+
7+
- **Mastodon-compatible REST API** under `/api/v1/` — designed to be compatible with the Mastodon client API specification
8+
- **Custom Local API** under `/api/v1/` and `/local/v1/` — app-specific endpoints for the Vue frontend
9+
- **ActivityPub Federation API** under `/users/`, `/@{username}/`, and `/inbox` — W3C ActivityPub protocol endpoints
10+
11+
Base URL: `/apps/social` (e.g. `https://cloud.example/apps/social/api/v1/statuses`)
12+
13+
---
14+
15+
## Authentication
16+
17+
The API supports two authentication methods:
18+
19+
1. **OAuth Bearer Token** — obtained via the OAuth flow (see OAuth section below). Include as `Authorization: Bearer <token>` header.
20+
2. **Session-based** — uses the Nextcloud session cookie when the user is logged in to the web UI.
21+
22+
Public endpoints (ActivityPub, media serving) do not require authentication.
23+
24+
---
25+
26+
## Mastodon-compatible API
27+
28+
### Instance
29+
30+
| Method | Route | Description |
31+
|--------|-------|-------------|
32+
| GET | `/api/v1/instance/` | Returns local instance metadata (title, version, usage stats, registration) |
33+
| GET | `/api/v1/apps/verify_credentials` | Returns connected app name and website |
34+
| GET | `/api/v1/custom_emojis` | Returns custom emoji list (currently empty, not implemented) |
35+
36+
### Accounts
37+
38+
| Method | Route | Parameters | Description |
39+
|--------|-------|------------|-------------|
40+
| GET | `/api/v1/accounts/verify_credentials` || Returns the authenticated user's account |
41+
| GET | `/api/v1/accounts/relationships` | `id[]` (account IDs) | Returns relationship info (following, followed_by, etc.) |
42+
| GET | `/api/v1/accounts/{account}/statuses` | `limit`, `max_id`, `min_id`, `since_id` | Returns statuses by a specific account |
43+
| GET | `/api/v1/accounts/{account}/following` | `limit`, `max_id`, `min_id` | Returns who an account is following |
44+
| GET | `/api/v1/accounts/{account}/followers` | `limit`, `max_id`, `min_id` | Returns an account's followers |
45+
46+
### Statuses
47+
48+
| Method | Route | Parameters | Description |
49+
|--------|-------|------------|-------------|
50+
| POST | `/api/v1/statuses` | `status`, `visibility`, `media_ids[]`, `in_reply_to_id`, `spoiler_text`, `sensitive` | Create a new post |
51+
| GET | `/api/v1/statuses/{nid}` || Get a single status by NID |
52+
| PUT | `/api/v1/statuses/{nid}` | `status`, `spoiler_text`, `sensitive` | Edit an existing post |
53+
| GET | `/api/v1/statuses/{nid}/context` || Get conversation context (ancestors and descendants) |
54+
| POST | `/api/v1/statuses/{nid}/{act}` | `act`: `favourite`, `unfavourite`, `boost`, `unboost` | Perform an action on a status |
55+
56+
### Timelines
57+
58+
| Method | Route | Parameters | Description |
59+
|--------|-------|------------|-------------|
60+
| GET | `/api/v1/timelines/{timeline}/` | `local`, `limit` (20), `max_id`, `min_id`, `since_id` | Get a timeline. `timeline` values: `home`, `account`, `public`, `direct`, `favourites` |
61+
| GET | `/api/v1/timelines/tag/{hashtag}` | `limit` (20), `max_id`, `min_id`, `since_id`, `local`, `only_media` | Get posts with a specific hashtag |
62+
| GET | `/api/v1/favourites/` | `limit` (20), `max_id`, `min_id`, `since_id` | Get liked/favourited posts |
63+
64+
### Notifications
65+
66+
| Method | Route | Parameters | Description |
67+
|--------|-------|------------|-------------|
68+
| GET | `/api/v1/notifications` | `limit` (20), `max_id`, `min_id`, `since_id`, `types[]`, `exclude_types[]`, `accountId` | Get notifications for the viewer |
69+
70+
### Media
71+
72+
| Method | Route | Parameters | Description |
73+
|--------|-------|------------|-------------|
74+
| POST | `/api/v1/media` | `file` (multipart upload) | Upload a media attachment |
75+
| GET | `/api/v1/media/{nid}` | `preview` (optional) | Get media metadata by NID (stub, not fully implemented) |
76+
| GET | `/media/{uuid}` || Serve a media file by UUID (supports optional `.ext` suffix) |
77+
78+
### Search
79+
80+
| Method | Route | Parameters | Description |
81+
|--------|-------|------------|-------------|
82+
| GET | `/api/v1/search` | `search` (query string) | Unified search across accounts, hashtags, and post content |
83+
| GET | `/api/v1/global/accounts/search` | `search` | Search cached accounts by name/identifier |
84+
| GET | `/api/v1/global/tags/search` | `search` | Search hashtags |
85+
86+
### Pagination
87+
88+
Endpoints that return lists support cursor-based pagination via these query parameters:
89+
90+
- `limit` — maximum number of items to return (default: 20)
91+
- `max_id` — return items older than this ID
92+
- `min_id` — return items newer than this ID
93+
- `since_id` — return items created after this ID
94+
- `since` — return items published after this Unix timestamp
95+
96+
---
97+
98+
## Custom Local API
99+
100+
### Streams
101+
102+
| Method | Route | Parameters | Description |
103+
|--------|-------|------------|-------------|
104+
| GET | `/api/v1/stream/home` | `since`, `limit` | Home timeline (posts from followed accounts) |
105+
| GET | `/api/v1/stream/notifications` | `since`, `limit` | User notifications |
106+
| GET | `/api/v1/stream/timeline` | `since`, `limit` | Local timeline (all local public posts) |
107+
| GET | `/api/v1/stream/federated` | `since`, `limit` | Global/federated timeline |
108+
| GET | `/api/v1/stream/direct` | `since`, `limit` | Direct messages |
109+
| GET | `/api/v1/stream/liked` | `since`, `limit` | Liked posts |
110+
| GET | `/api/v1/stream/tag/{hashtag}/` | `since`, `limit` | Posts by hashtag |
111+
| GET | `/api/v1/account/{username}/stream` | `since`, `limit` | Posts by a specific account |
112+
113+
### Posts
114+
115+
| Method | Route | Parameters | Description |
116+
|--------|-------|------------|-------------|
117+
| GET | `/local/v1/post` | `id` (ActivityPub ID) | Get a single post by its ActivityPub ID |
118+
| GET | `/local/v1/post/replies` | `id`, `since`, `limit` | Get replies to a post |
119+
| POST | `/api/v1/post` | `content`, `to[]`, `type`, `replyTo`, `attachments`, `hashtags[]` | Create a new post |
120+
| DELETE | `/api/v1/post` | `id` | Delete own post |
121+
| POST | `/api/v1/post/like` | `postId` | Like a post |
122+
| DELETE | `/api/v1/post/like` | `postId` | Unlike a post |
123+
124+
### Current User
125+
126+
| Method | Route | Description |
127+
|--------|-------|-------------|
128+
| GET | `/api/v1/current/info` | Get current user's actor info with complete details |
129+
| GET | `/api/v1/current/followers` | Get current user's followers |
130+
| GET | `/api/v1/current/following` | Get who the current user follows |
131+
| PUT | `/api/v1/current/follow` | Follow an account (`?account=`) |
132+
| DELETE | `/api/v1/current/follow` | Unfollow an account (`?account=`) |
133+
134+
### Account Info
135+
136+
| Method | Route | Parameters | Description |
137+
|--------|-------|------------|-------------|
138+
| GET | `/api/v1/account/{username}/info` || Get info for a local account (with cache fallback) |
139+
| GET | `/api/v1/global/account/info` | `account` (e.g. `@user@domain`) | Get info for any local or remote account |
140+
| GET | `/api/v1/global/actor/info` | `id` (ActivityPub actor ID) | Get actor info by raw ActivityPub ID |
141+
| GET | `/api/v1/global/actor/avatar` | `id` | Serve an actor's avatar image |
142+
| GET | `/api/v1/global/actor/header` | `id` | Redirect to an actor's banner/header image |
143+
144+
### Banner
145+
146+
| Method | Route | Parameters | Description |
147+
|--------|-------|------------|-------------|
148+
| POST | `/api/v1/banner` | `file` (multipart) | Upload a profile banner image |
149+
| POST | `/api/v1/banner/url` | `url` | Download and set a profile banner from a URL |
150+
151+
### Config
152+
153+
| Method | Route | Parameters | Description |
154+
|--------|-------|------------|-------------|
155+
| POST | `/api/v1/config/cloudAddress` | `cloudAddress` | Set the cloud base URL in app config |
156+
157+
### System
158+
159+
| Method | Route | Description |
160+
|--------|-------|-------------|
161+
| GET | `/local/` | Get app version and setup status |
162+
| GET | `/test/{account}/` | Run a WebFinger test against an account (debug only, requires `social.tests` system config) |
163+
164+
---
165+
166+
## OAuth
167+
168+
The Social app implements a Mastodon-compatible OAuth flow.
169+
170+
| Method | Route | Parameters | Description |
171+
|--------|-------|------------|-------------|
172+
| POST | `/api/v1/apps` | `client_name`, `redirect_uris`, `website`, `scopes` | Register a new OAuth client app |
173+
| GET | `/oauth/authorize` | `client_id`, `redirect_uri`, `response_type`, `scope` | Show OAuth authorization page |
174+
| POST | `/oauth/authorize` | `client_id`, `redirect_uri`, `response_type`, `scope` | Confirm OAuth authorization |
175+
| POST | `/oauth/token` | `client_id`, `client_secret`, `redirect_uri`, `grant_type`, `code` | Exchange authorization code for bearer token |
176+
177+
**Grant types:** `authorization_code`, `client_credentials`
178+
179+
**Default scope:** `read`
180+
181+
---
182+
183+
## ActivityPub Federation
184+
185+
The app implements the W3C ActivityPub protocol (Server-to-Server). All endpoints return `application/activity+json` content type for ActivityPub clients, and fall back to HTML for browsers.
186+
187+
### Actor
188+
189+
| Method | Route | Description |
190+
|--------|-------|-------------|
191+
| GET | `/users/{username}` | Get ActivityPub Actor object for a local user |
192+
| GET | `/@{username}/` | Alias for actor endpoint |
193+
194+
### Inbox
195+
196+
| Method | Route | Description |
197+
|--------|-------|-------------|
198+
| POST | `/@{username}/inbox` | Receive ActivityPub activities for a specific user |
199+
| GET | `/@{username}/inbox` | Get an empty OrderedCollection (inbox is not enumerable) |
200+
| POST | `/inbox` | Shared inbox — receives activities for all local actors |
201+
202+
### Outbox
203+
204+
| Method | Route | Description |
205+
|--------|-------|-------------|
206+
| GET | `/@{username}/outbox` | Get the user's outbox as an OrderedCollection |
207+
| POST | `/@{username}/outbox` | Create a new activity in the outbox |
208+
209+
### Followers / Following
210+
211+
| Method | Route | Description |
212+
|--------|-------|-------------|
213+
| GET | `/@{username}/followers` | Get the followers collection |
214+
| GET | `/@{username}/following` | Get the following collection |
215+
216+
### Posts
217+
218+
| Method | Route | Description |
219+
|--------|-------|-------------|
220+
| GET | `/@{username}/{token}` | Get a single post as ActivityPub JSON-LD |
221+
222+
### Discovery
223+
224+
| Route | Description |
225+
|-------|-------------|
226+
| `/.well-known/webfinger` | WebFinger endpoint for `acct:user@domain` lookups (returns `self` link to Actor) |
227+
| `/.well-known/nodeinfo/2.0` | NodeInfo 2.0 document |
228+
229+
---
230+
231+
## Legacy OStatus
232+
233+
| Method | Route | Description |
234+
|--------|-------|-------------|
235+
| GET | `/ostatus/follow/` | Renders follow page via OStatus (`?uri=`) |
236+
| GET | `/api/v1/ostatus/followRemote/{local}` | Render guest follow page for remote account |
237+
| GET | `/api/v1/ostatus/link/{local}/{account}` | Perform WebFinger and get OStatus subscribe link |
238+
239+
---
240+
241+
## Frontend / Document Serving
242+
243+
| Method | Route | Description |
244+
|--------|-------|-------------|
245+
| GET | `/` | Main SPA entry point (renders the Vue app) |
246+
| GET | `/timeline/{path}` | SPA timeline route |
247+
| GET | `/document/get` | Get a cached document by ID (requires auth) |
248+
| GET | `/document/public` | Get a public cached document by ID (no auth) |
249+
| GET | `/document/get/resized` | Get a resized/preview of a cached document (requires auth) |
250+
| GET | `/document/public/resized` | Get a public resized/preview document (no auth) |
251+
252+
---
253+
254+
## Async Queue
255+
256+
| Method | Route | Description |
257+
|--------|-------|-------------|
258+
| POST | `/async/request/{token}` | Process queued ActivityPub federation requests for a given token |
259+
260+
---
261+
262+
## Error Responses
263+
264+
The API returns standard HTTP status codes:
265+
266+
| Status | Meaning |
267+
|--------|---------|
268+
| 200 | Success |
269+
| 201 | Created |
270+
| 204 | No Content (deletion success) |
271+
| 400 | Bad Request |
272+
| 401 | Unauthorized |
273+
| 403 | Forbidden |
274+
| 404 | Not Found |
275+
| 405 | Method Not Allowed |
276+
| 500 | Internal Server Error |
277+
278+
Error bodies are JSON: `{"message": "...", "code": ...}`

0 commit comments

Comments
 (0)