Alpha

Sockethub 5.0.0-alpha.17 is the current active-use release. See the changelog.

Platforms

Supported platforms

Each platform maps ActivityStreams 2.0 onto a specific network. Same JSON envelope on the way in, same shape on the way back. If you need more, the platform interface is small enough to implement in an afternoon.

IRC

Chat and channels on the original open protocol.

@sockethub/platform-irc ↗

Speak to any IRC network — Libera, OFTC, your local. Sockethub handles reconnects, PINGs, and nick collision for you.

The full IRC flow is credentials → connect → join → send. Each envelope shares the same @context; only type and the target change.

1. Credentials

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://sockethub.org/ns/context/v1.jsonld",
    "https://sockethub.org/ns/context/platform/irc/v1.jsonld"
  ],
  "type":   "credentials",
  "actor":  {
    "id":   "alice@irc.libera.chat",
    "type": "person"
  },
  "object": {
    "type":   "credentials",
    "nick":   "alice",
    "server": "irc.libera.chat",
    "port":   6697,
    "secure": true,
    "token":  "…"
  }
}

2. Connect

{
  "@context": [ /* as above */ ],
  "type":   "connect",
  "actor":  { "id": "alice@irc.libera.chat", "type": "person" }
}

3. Join a channel

{
  "@context": [ /* as above */ ],
  "type":   "join",
  "actor":  { "id": "alice@irc.libera.chat",     "type": "person" },
  "target": { "id": "#sockethub@irc.libera.chat", "type": "room" }
}

4. Send a message

{
  "@context": [ /* as above */ ],
  "type":   "send",
  "actor":  { "id": "alice@irc.libera.chat",     "type": "person" },
  "target": { "id": "#sockethub@irc.libera.chat", "type": "room" },
  "object": { "type": "message", "content": "hey everyone" }
}

XMPP

Federated messaging, rooms, and presence.

@sockethub/platform-xmpp ↗

Connect to any XMPP service — public or self-hosted. Multi-user chat, direct messages, presence, and roster updates all come through as ActivityStreams objects.

Full XMPP MUC flow is credentials → connect → join → send. For a 1:1 message to a contact, skip join and target the person JID directly (shown at the end).

1. Credentials

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://sockethub.org/ns/context/v1.jsonld",
    "https://sockethub.org/ns/context/platform/xmpp/v1.jsonld"
  ],
  "type":   "credentials",
  "actor":  {
    "id":   "alice@chat.example",
    "type": "person"
  },
  "object": {
    "type":        "credentials",
    "userAddress": "alice@chat.example",
    "password":    "…",
    "server":      "chat.example",
    "resource":    "sockethub"
  }
}

2. Connect

{
  "@context": [ /* as above */ ],
  "type":   "connect",
  "actor":  { "id": "alice@chat.example", "type": "person" }
}

3. Join a room (MUC)

{
  "@context": [ /* as above */ ],
  "type":   "join",
  "actor":  { "id": "alice@chat.example",              "type": "person" },
  "target": { "id": "sockethub@conference.chat.example", "type": "room" }
}

4a. Send to the room

{
  "@context": [ /* as above */ ],
  "type":   "send",
  "actor":  { "id": "alice@chat.example",              "type": "person" },
  "target": { "id": "sockethub@conference.chat.example", "type": "room" },
  "object": { "type": "message", "content": "hey everyone" }
}

4b. Send 1:1 to a contact (no join needed)

{
  "@context": [ /* as above */ ],
  "type":   "send",
  "actor":  { "id": "alice@chat.example", "type": "person" },
  "target": { "id": "bob@chat.example",   "type": "person" },
  "object": { "type": "message", "content": "ping" }
}

RSS / Atom

Fetch, parse, and stream updates from feeds.

@sockethub/platform-feeds ↗

Point the feeds platform at any RSS or Atom URL and it returns normalized entries as ActivityStreams objects. Useful for reader apps, dashboards, or anywhere you'd otherwise reach for a polling cron.

Fetch once

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://sockethub.org/ns/context/v1.jsonld",
    "https://sockethub.org/ns/context/platform/feeds/v1.jsonld"
  ],
  "type":   "fetch",
  "actor":  { "id": "https://example.org/reader",    "type": "person" },
  "target": { "id": "https://blog.example/feed.xml", "type": "feed" }
}

Metadata

Link previews and structured-data extraction.

@sockethub/platform-metadata ↗ New in 5.0

Fetch a URL, extract Open Graph, oEmbed, microformats2, and JSON-LD, and hand back a single normalized object. Built for chat link previews and reader summaries.

Fetch metadata for a URL

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://sockethub.org/ns/context/v1.jsonld",
    "https://sockethub.org/ns/context/platform/metadata/v1.jsonld"
  ],
  "type":   "fetch",
  "actor":  { "id": "https://example.org/reader",    "type": "person" },
  "target": { "id": "https://blog.example/article", "type": "link" }
}

CalDAV

Calendars, events, and tasks on any CalDAV server.

@sockethub/platform-caldav ↗ New in 5.0

Discover calendars, then read, create, update, and delete events (VEVENT) and tasks (VTODO) on any CalDAV server — Nextcloud, Radicale, Fastmail, and friends. Every write is guarded by an ETag check, so you never silently overwrite a change made by another client.

The full CalDAV flow is credentials → fetch → query / create / update / delete. fetch discovers your calendars; every later request targets one of the discovered calendar URLs.

1. Credentials

{
  "@context": [
    "https://www.w3.org/ns/activitystreams",
    "https://sockethub.org/ns/context/v1.jsonld",
    "https://sockethub.org/ns/context/platform/caldav/v1.jsonld"
  ],
  "type":   "credentials",
  "actor":  {
    "id":   "caldav:alice",
    "type": "person"
  },
  "object": {
    "type":  "credentials",
    "url":   "https://calendar.example/dav/",
    "token": "…"
  }
}

token is sent as an HTTP Bearer token (your app runs the OAuth flow itself). For Basic auth — typically an app password — replace it with username and password. The URL can be a service root; discovery also tries /.well-known/caldav.

2. Discover calendars

{
  "@context": [ /* as above */ ],
  "type":   "fetch",
  "actor":  { "id": "caldav:alice", "type": "person" }
}

The response lists your calendars as objects with an id (the calendar URL), a name, a color, and which components they support (event, task).

3. Query events in a date range

{
  "@context": [ /* as above */ ],
  "type":   "query",
  "actor":  { "id": "caldav:alice", "type": "person" },
  "target": {
    "id":   "https://calendar.example/calendars/alice/personal/",
    "type": "calendar"
  },
  "object": {
    "type":      "event",
    "startTime": "2026-08-01T00:00:00Z",
    "endTime":   "2026-09-01T00:00:00Z"
  }
}

Each returned item carries its resource id, uid, and etag — keep the ETag for later update or delete requests.

4. Create an event

{
  "@context": [ /* as above */ ],
  "type":   "create",
  "actor":  { "id": "caldav:alice", "type": "person" },
  "target": {
    "id":   "https://calendar.example/calendars/alice/personal/",
    "type": "calendar"
  },
  "object": {
    "type":      "event",
    "name":      "Project planning",
    "startTime": "2026-08-03T15:00:00",
    "endTime":   "2026-08-03T16:00:00",
    "timeZone":  "Europe/Prague"
  }
}

Events and tasks support recurrence, attendees, reminders, and attachments. update and delete send the item's etag; if another client changed it in the meantime you get caldav:conflict back — query again and retry with the fresh ETag.

Want to add another protocol? Platform interface Get started