Verified against ActivityPub REC 2018 and Editor's Draft (Oct 2026), AS2 Vocabulary, Mastodon v4.7.3 CHANGELOG and routes, Pleroma/Akkoma routers, Pixelfed v0.14.4, Lemmy 0.19.20, PeerTube v8.3.1 routes on 2026-10-15.
ActivityPub Overview
ActivityPub is a W3C Recommendation that defines a protocol for decentralized social networking. It provides both a client-to-server (C2S) API and a server-to-server (S2S) federation protocol.
Specification
- Status: W3C Recommendation (January 2018), under active maintenance by the rechartered Social Web Working Group — a backwards-compatible update incorporating accepted errata is in progress; as of October 2026 no new draft has been published to /TR
- URL: https://www.w3.org/TR/activitypub/
- Editor's Draft: w3c.github.io/activitypub — incorporates accepted errata ahead of the updated Recommendation
- Editors: Christine Lemmer-Webber, Jessica Tallon
- Authors: Christine Lemmer-Webber, Jessica Tallon, Erin Shepherd, Amy Guy, Evan Prodromou
Two Protocols in One
ActivityPub defines two complementary protocols:
Client-to-Server (C2S)
The C2S protocol defines how clients (apps) interact with servers:
- POST to Outbox: Submit activities the user wants to perform
- GET from Inbox: Read activities sent to the user
- GET from Collections: Read followers, following, likes
Most Fediverse software implements a custom REST API instead of C2S. The S2S protocol is universally implemented.
Server-to-Server (S2S)
The S2S protocol defines how servers federate:
- POST to Inbox: Deliver activities to remote users
- GET Actor: Fetch remote user profiles
- GET Objects: Fetch remote content
Core Components
1. Actors
Every user or entity is represented as an Actor with:
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Person",
"id": "https://example.com/users/alice",
"inbox": "https://example.com/users/alice/inbox",
"outbox": "https://example.com/users/alice/outbox",
"preferredUsername": "alice"
}
2. Activities
Actions are represented as Activity objects:
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Create",
"actor": "https://example.com/users/alice",
"object": {
"type": "Note",
"content": "Hello, world!"
}
}
3. Objects
Content is represented as Objects:
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "Note",
"id": "https://example.com/notes/1",
"content": "Hello, world!",
"attributedTo": "https://example.com/users/alice"
}
4. Collections
Lists of items are represented as Collections:
{
"@context": "https://www.w3.org/ns/activitystreams",
"type": "OrderedCollection",
"id": "https://example.com/users/alice/outbox",
"totalItems": 42,
"first": "https://example.com/users/alice/outbox?page=1"
}
Learn more about Collections →
Required Endpoints
For All Actors
Actor objects MUST have an inbox and an outbox; they SHOULD have followers and following, and MAY have liked (AP §4.1).
| Endpoint | Method | Description |
|---|---|---|
| Actor URL | GET | Returns the actor's profile |
| Inbox | POST | Receives activities from other servers (federated servers) |
| Outbox | GET | Returns activities by this actor, filtered by what the requester may see (AP §5.1) |
For C2S (Optional)
| Endpoint | Method | Description |
|---|---|---|
| Outbox | POST | Client submits new activities |
| Inbox | GET | Client reads incoming activities |
Endpoints at a Glance
| Endpoint | Method | Purpose | Authentication |
|---|---|---|---|
/.well-known/webfinger | GET | Resolve user@domain to an actor URL (WebFinger) | None |
Actor (e.g. /users/{name}) | GET | Fetch the actor document | None, or a signed GET under authorized fetch |
inbox | POST | Receive activities from other servers | HTTP signature — see Verifying incoming requests |
shared inbox (endpoints.sharedInbox) | POST | One delivery per server instead of per recipient | HTTP signature |
outbox | GET | List the actor's public activities | None |
outbox | POST | Publish an activity (C2S) | Not specified by AP; OAuth by convention (FEP-d8c2) |
followers / following | GET | Social graph (many servers return only totalItems) | Varies |
/.well-known/nodeinfo | GET | Server software and usage metadata (NodeInfo) | None |
Actor and object fetches use content negotiation, described next.
Content Negotiation
The spec says the client MUST send an Accept header with the application/ld+json; profile="https://www.w3.org/ns/activitystreams" media type, and servers MUST respond to it with an ActivityStreams representation; servers SHOULD also respond to application/activity+json (AP §3.2). Sending both is the safe choice in practice:
Request:
GET /users/alice HTTP/1.1
Accept: application/ld+json; profile="https://www.w3.org/ns/activitystreams", application/activity+json
Response:
HTTP/1.1 200 OK
Content-Type: application/activity+json
{ ... actor JSON ... }
Accepted media types:
application/ld+json; profile="https://www.w3.org/ns/activitystreams"(MUST be supported by servers)application/activity+json(SHOULD be supported; what most servers send)
If the same URL also serves HTML, send Vary: Accept so caches don't mix the representations up.
Addressing
Activities specify recipients using:
| Property | Purpose |
|---|---|
to | Primary recipients (visible) |
cc | Secondary recipients (visible) |
bto | Private primary recipients — removed before delivery (AP §6, §7.1) |
bcc | Private secondary recipients — removed before delivery |
audience | The total population the object is relevant to (e.g. a group); also a delivery target (AS2 Vocab, AP §7.1) |
Special addresses:
https://www.w3.org/ns/activitystreams#Public- Public visibility. The compact formsas:PublicandPublicmean the same thing and implementations should accept all three. It is not a real inbox: servers MUST NOT deliver to it (AP §5.6).
Security
The ActivityPub spec itself does not mandate an authentication mechanism (AP §B.1). In practice the fediverse relies on:
- HTTPS - Required in practice by every major implementation
- HTTP Signatures - De facto requirement for server-to-server delivery (draft-cavage, and increasingly RFC 9421, which Mastodon verifies since 4.5)
- Object Integrity Proofs - (Optional) sign objects themselves with FEP-8b32, which Mastodon 4.7 verifies (CHANGELOG). The older Linked Data Signatures are deprecated: Mastodon's docs advise against implementing them, and a JSON-LD named-graph bypass hit both Mastodon (CVE-2026-46349) and Fedify (CVE-2026-42462) in 2026
Relationship to Other Specs
Common Extensions
The Fediverse has developed de facto extensions:
| Extension | Purpose | Used By |
|---|---|---|
sensitive | Marks media/content as sensitive (the CW text itself goes in summary) | Mastodon |
Emoji | Custom emoji | Mastodon, Misskey |
PropertyValue | Profile fields | Mastodon |
Hashtag | Hashtag type | Most platforms |
Implementation Status
Checked against each project's routes: Pleroma exposes POST /users/:nickname/outbox and GET /users/:nickname/inbox (Pleroma source, lib/pleroma/web/router.ex); Mastodon, Pixelfed, Lemmy and PeerTube only serve outboxes for reading.
| Platform | C2S | S2S |
|---|---|---|
| Mastodon | ❌ | ✅ |
| Pleroma | ✅ | ✅ |
| Pixelfed | ❌ | ✅ |
| Lemmy | ❌ | ✅ |
| PeerTube | ❌ | ✅ |
Next Steps
- Actors - Deep dive into Actor objects
- Activities - Activity types and handling
- Server-to-Server - Federation mechanics
- Building an Actor - Practical implementation