Files
SocialPub/docs/MASTODON-API.md
T
thepraandClaude Opus 5.5 9b792042e6 R9 Web Push, then the honest version: VAPID key, push subscriptions, encrypted pushes, 4.5.0 advertised
The server's VAPID key (PushKeys, made on first need, in Mongo) is the instance API's vapid.public_key and every app's
vapid_key. /api/v1/push/subscription (POST, GET, PUT, DELETE) keeps one subscription per access token, so per persona;
every notification kept (never a filtered one) is queued as a SendPush job for the subscriptions whose alert and policy
admit it, and sent through the `push` client (the safe handler, https only) encrypted as RFC 8291 aes128gcm or the
aesgcm draft with an ES256 VAPID JWT. 404/410 delete the subscription, 429/5xx/timeouts retry, other answers drop the
push. Subscriptions end with their tokens (revocation, sessions ended, suspension, deletion, a restore); backups hold
neither keys nor subscriptions. The walk of every Mastodon 4.3-4.5 client route (docs/MASTODON-API.md) added
conversations/:id/unread, domain_blocks/preview, v2 notifications clear and PUT policy, /oauth/userinfo and stubs, so both
instance APIs now say 4.5.0 (compatible; PrivaPub <release>). The pasture gets a push sink (pushsink.test) and
scenarios/push.sh in batch A.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpVCoDeM1qUTRp4fXQdfof
2026-10-18 09:18:26 +02:00

7.4 KiB

The Mastodon client API: what PrivaPub answers

The walk behind the version PrivaPub advertises (completion program R9, 2026-10-18). Every client route of Mastodon 4.3.0, 4.4.0 and 4.5.0, as their config/routes/api.rb and config/routes.rb define them, set against PrivaPub's controllers (PrivaPub/Api/Mastodon/Controllers). Since nothing a client relies on is missing, both instance APIs say 4.5.0 (compatible; PrivaPub <release>) (InstanceController.Version; Mastodon invariant 6 in CLAUDE.md), and api_versions.mastodon is 7, 4.5's own.

  • Served: the route does what Mastodon's does, within PrivaPub's rules (a token is one persona, per-persona state, located posts outside the Mastodon API).
  • Stub: the route answers as Mastodon answers when the feature is off or empty here (an empty list, {}, 403, 404 or 422 with Mastodon's message), so clients degrade instead of breaking (Mastodon invariant 5). Each is a decision, named.
  • Missing: no route. None of these is the client API.

When a route is added to Mastodon, add it here, and keep the advertised version honest.

Served

Area Routes
Statuses GET /api/v1/statuses (id[]), POST, GET/PUT/DELETE /api/v1/statuses/:id, context, history, source, reblogged_by, favourited_by, reblog/unreblog, favourite/unfavourite, bookmark/unbookmark, mute/unmute, pin/unpin; 4.5's GET …/quotes, POST …/quotes/:id/revoke and PUT …/interaction_policy
Timelines home, public, tag/:hashtag, list/:id
Streaming /api/v1/streaming (WebSocket) and /api/v1/streaming/* (server-sent events), health: user, user:notification, public, public:local, public:remote, hashtag, hashtag:local, list, direct
Accounts verify_credentials (4.4: the profile scope too), update_credentials, search, lookup, relationships, familiar_followers (empty for every account by design: R8), GET /api/v1/accounts (id[]), :id, :id/statuses, followers, following, lists, featured_tags, endorsements (4.4; to the persona itself), follow, unfollow, remove_from_followers, block, unblock, mute, unmute, pin/unpin and 4.4's endorse/unendorse, note
Relationships blocks, mutes, domain_blocks (GET, POST, DELETE), domain_blocks/preview (R9: how many follows and followers the block would take), follow_requests with authorize and reject, endorsements
Notifications v1 notifications (index, :id, clear, unread_count, :id/dismiss), notifications/requests (index, :id, accept, dismiss, the bulk accept and dismiss, merged), notifications/policy (GET, PUT, PATCH); v2 grouped notifications (index, :group_key, :group_key/accounts, :group_key/dismiss, unread_count, clear since R9), notifications/policy (GET, PATCH, PUT since R9)
Web Push POST, GET, PUT, DELETE /api/v1/push/subscription (R9; CLAUDE.md, Web Push)
Conversations conversations (index), DELETE :id, :id/read, :id/unread (R9)
Media and polls POST /api/v1/media, /api/v2/media, GET/PUT/DELETE /api/v1/media/:id; polls/:id, polls/:id/votes
Lists, filters, tags lists (CRUD, :id/accounts GET/POST/DELETE); v1 filters and v2 filters with keywords and statuses (both nested and by id); tags/:name with follow, unfollow and 4.4's feature, unfeature; followed_tags; featured_tags (index, create, destroy) and featured_tags/suggestions
Discovery /api/v2/search, trends and trends/tags, trends/statuses, trends/links, directory, suggestions (v1 index and destroy, v2 index)
The persona's own bookmarks, favourites, markers (GET, POST), preferences, scheduled_statuses (index, show, update, destroy), profile/avatar and profile/header (DELETE), reports
The server v1 and v2 instance, instance/peers (empty by design: which servers this one talks to is not published), rules, domain_blocks (the published ones), extended_description, privacy_policy, 4.4's terms_of_service and terms_of_service/:date, languages, translation_languages (none: translation is cut), activity (empty unless the administrator publishes it), custom_emojis, announcements with dismiss and reactions
Apps and OAuth POST /api/v1/apps, apps/verify_credentials, /oauth/authorize, /oauth/token, /oauth/revoke, /.well-known/oauth-authorization-server, 4.4's /oauth/userinfo (GET and POST, the profile scope; R9)

Stubs

Route Answer Why
POST /api/v1/statuses/:id/translate 422 Translation is not available on this server translation is cut (owner decision 2026-10-17)
GET /api/v1/timelines/link [] 4.3's timeline of a trending link: not built (trending links themselves are served)
GET /api/v1/annual_reports, 4.4's GET /api/v1/annual_reports/:year {"annual_reports": [], "accounts": [], "statuses": []} no yearly reports are made
4.4's POST /api/v1/annual_reports/:year/read {} there is none to read
POST /api/v1/accounts 403 This action is not allowed (Mastodon's answer with registrations closed) registration through the API is cut: logins are made by setup or invitation on /clientapi
POST /api/v1/emails/confirmations 403 This method is only available while the e-mail is awaiting confirmation no account here waits for a confirmation
GET /api/v1/emails/check_confirmation true the same
GET /api/v1/peers/search [] peers are not published, as instance/peers
4.4's GET /api/v1_alpha/async_refreshes/:id 404 Record not found PrivaPub never sends Mastodon-Async-Refresh: a thread's replies are read in the background and show up
GET /api/v1/accounts/:id/identity_proofs [] gone from Mastodon long ago; still asked by old clients
every verb under /api/v1/admin/**, GET/POST under /api/v2/admin/** 403 This action is not allowed, signed in or not the Mastodon admin API is cut: moderation is on /clientapi

Missing, and not the client API

Route Why it is not served
GET /api/oembed embedding a post in another website; PrivaPub's public pages have no embed view
/api/web/* (settings, embeds, push_subscriptions) Mastodon's own web interface, signed in by its session cookie; PrivaPub's client is decePub on /clientapi
/oauth/authorized_applications Doorkeeper's HTML page of a user's applications, in Mastodon's web interface
/invite/:code (JSON) Mastodon's app shows an invitation before registering through the API, which is cut; PrivaPub's invitations are /clientapi's
/.well-known/host-meta OStatus-era discovery; every client and server here uses WebFinger directly
POST /api/v1/polls in 4.3's route list with no action behind it; gone in 4.4

Beyond routes: the public:media streams (and their :local and :remote forms) are not offered; the media-only public timelines (only_media) are, so a client polls them.

PrivaPub's own, on the same API

/api/v1/pleroma/statuses/:id/reactions (Pleroma's emoji reactions), /api/v1/statuses/:id/downvote and undownvote, /api/v1/feeds and /api/v1/timelines/feed/:id (PieFed's and Lemmy's feeds), and /api/privapub/v1/* (provenance, servers, CDNs, events' join and leave): Mastodon invariant 7.