API documentation

Hubble serves a public atproto API (XRPC) with a permissive CORS policy. All responses are JSON except archive files. No authentication is required.

The blue.microcosm.hubble.* lexicon definitions live in the hubble repo under lexicons/.

Errors

Most error responses include a JSON body with an error field and optional message. Example:

{ "error": "RepoNotFound", "message": "repo not found" }

Endpoints

blue.microcosm.hubble.getStats

Global stats for the hubble instance. No parameters.

{
  "records": integer,            // total records stored across all repos
  "upstream": string?,           // the upstream this instance is
                                 // subscribed to
  "reposBySyncState": {
    "synchronized": integer,
    "desynchronized": integer,   // total across every desync reason
    "deactivated": integer,
    "gone": integer
  },
  "reposByAccountStatus": {
    "active": integer,
    "deactivated": integer,
    "suspended": integer,
    "takendown": integer,
    "deleted": integer,
    "other": integer
  }
}

blue.microcosm.hubble.getRepoInfo

Everything hubble knows about one repo.

parametertype
didDIDrequired
{
  "did": did,
  "unverifiedHandle": handle?,   // claimed in the DID document; NOT
                                 // bidirectionally verified
  "pds": uri?,                   // the account's current PDS
  "accountStatus": {
    "active": boolean,
    "upstreamStatus": string?,   // "takendown" | "suspended" |
                                 // "deactivated" | "other" (open set)
    "locallyModerated": boolean?
  },
  "syncState": {
    "state": string,             // "synchronized" | "desynchronized" |
                                 // "pending" (open set)
    "rev": tid?,                 // repo revision of hubble's copy
    "desyncReason": string?,     // see token list below (open set)
    "nextRetryAt": datetime?
  },
  "archive": {
    "available": boolean,        // whether the repo can be downloaded
    "records": integer,
    "formats": [string]          // media types getRepo can negotiate
  },
  "history": {
    "firstSeenAt": datetime,
    "resyncs": integer,
    "pdsChanges": integer,
    "handleChanges": integer,
    "commitsSeen": integer?,
    "lastResync": {
      "at": datetime,
      "source": string?,         // where the resync data came from
      "records": integer?,
      "size": integer?,          // total size of the CAR's blocks, bytes
      "durationMs": integer?
    }?
  }
}

Errors: RepoNotFound (hubble has never seen this DID), RepoGone (the account was deleted and hubble no longer holds its data).

blue.microcosm.hubble.getAccountStatusLog

Upstream account status events hubble has observed for a DID, newest first.

parametertype
didDIDrequired
limitinteger1–100, default 50
cursorstringfrom a previous page
{
  "events": [
    {
      "at": datetime,            // time of the upstream event
      "status": string,          // "active" | "deactivated" | "suspended" |
                                 // "takendown" | "deleted" | "other"
                                 // (open set)
      "upstream": {
        "host": string,          // upstream that reported the event
        "seq": integer?          // its sequence number on that host
      }?
    }
  ],
  "cursor": string?              // absent on the last page
}

Errors: RepoNotFound. Note that deleted accounts still answer here (with a deleted event), even though getRepoInfo reports them as RepoGone.

com.atproto.sync.getRepo

The archive download itself, streamed. Available when getRepoInfo reports archive.available.

parametertype
didDIDrequired
accept string car (default) or star-lite. This is a non-standard query parameter for Hubble.

Responds with application/vnd.ipld.car by default. The format is negotiable via the accept parameter or the Accept header. archive.formats in getRepoInfo lists what's offered (currently CAR and application/x.microcosm.star-lite).

com.atproto.sync.listRepos

Enumerate the repos hubble hosts, paginated by DID.

parametertype
limitintegerdefault 500
cursorstringfrom a previous page
{
  "repos": [
    {
      "did": did,
      "head": cid,               // current commit CID
      "rev": tid,                // current repo revision
      "active": boolean
    }
  ],
  "cursor": string?
}

desyncReason values

Known values for syncState.desyncReason. This list is non-exhaustive: additional values may be added.

  • firstSeen
  • unresolvableIdentity
  • firehoseCommitVerificationFail
  • firehoseCommitFutureRev
  • firehoseSyncEvent
  • upstreamAccountEventThrottled
  • upstreamAccountEventDesynchronized
  • localAppDesync
  • localThrottle
  • notSync11