Changelog
Changes to the protocol since Working Draft 3, newest first. Versions used to be called Working Drafts: Working Draft X is version 0.X.
v0.7.0
All endpoints moved from /.versia/v0.6/ to /.versia/v0.7/. This version also includes the changes previously listed as v0.6.1.
The core is now general-purpose. Posts moved to the Social extension, Follow became a generic Subscribe, and User keeps only the fields every instance needs.
Versions
- Protocol versions are now written as
0.X.Y.Xchanges on a breaking release, andYon a compatible one. - Removed
compatibility.versionsfrom Instance Metadata. The well-known endpoint is now the only list of supported versions. - Added rules for choosing a version: senders use the highest
0.Xboth instances support, instances with the sameXmust interoperate, and instances with none in common must not federate.
Signatures and Identity
- The signed string is now
$method $host $path?query $timestamp $bodyhash, on one line with parts separated by single spaces. It now covers the target host and the query string. - Signing inputs are now fully defined: bytes as sent, a hash over the raw body, and standard padded base64.
- Listed which routes require signatures, in both directions. The well-known endpoint, WebFinger and Instance Metadata are exempt.
- Only
2xxresponses have to verify. A response whose signature fails, or that is signed by an instance other than the one asked, is discarded and counts as a failed attempt. - Receivers ignore a
Versia-Signaturethey have already accepted from the same instance on the inbox, and answer it with a2xx. Processing must be idempotent. - Defined key rotation: an instance has one current key, and a receiver fetches the signer’s metadata again before rejecting a signature that fails to verify.
- An entity’s
authormust belong to the instance that signed the message, whether it was delivered or fetched. This also covers each entity in a Collection’sitems. - References must always be
domain:id, using a Domain as their prefix, so they cannot be bare IDs or contain port numbers or IP addresses. Their definition moved to Entities. - Domains are now defined by RFC 1123 and IDNA, and must be lowercase.
- Domains cannot be IP addresses or single labels.
- User addresses now only allow usernames.
Data Model
- All JSON must now be an I-JSON message. Numeric fields are now
integer, a whole number up to 2^53-1 in any notation, orfloat. These replaceu64andf64. - An entity with a
\r\nline break inside a string value is now invalid. - Strings and arrays may be empty unless their field says otherwise.
id,usernameand a Reaction’scontenthave at least 1 character. - Senders may now omit optional fields instead of setting them to
null. Both mean the same, and receivers must accept both. - Entities, structures and transient entities now have definitions. Transient entities have no
id. - An
idis now 1 to 13 characters ofa-z,0-9,-and_, so UUIDs and uppercase letters are no longer valid. Ids are opaque: receivers must not read a time or an order from them. Choosing IDs shows one way to make short ids. - Added
updated_atand defined how an entity changes: the whole entity is sent again with the sameid, andid,type,authorandcreated_atcannot change. - Removed
$schemafrom entities, andauthorfrom Collections and Reference Collections. - ContentFormat is replaced by two types. RichText is one HTML string, and other text formats are gone. Media is one file, with its
urlandmedia_typein the same object, and no other versions of the file. - RichText defines the elements and attributes senders can use, a fallback for each, and how to turn it into plain text. Mentions are links with a
data-mentionattribute, and extensions can adddata-attributes tospananddiv. - Media’s
hashis a lowercase hexadecimalstring, andthumbhashis standard padded base64. Senders should includesizeandhash, andthumbhash,widthandheightfor images and video. - Renamed URI Collection to Reference Collection. A Collection only holds entities authored on the instance serving it.
- Note:
quotesis nowquoting, and the new requiredvisibilityfield replaces thegroupfield’s visibility values. Groups moved to the Groups extension. An unknowncategoryis treated as absent. - User, Note and Group have a new optional
url, the address of their page on their instance. - Removed the Types page. RFC3339 and URI types now link directly to their RFCs.
Federation
- Delivery and access are now defined per entity type. Instances answer
404for entities the requester may not fetch, andsubscribersandmentionsNotes also reach the authors of the Notes they reply to. - Delivery has no guaranteed order. Receivers should fetch missing references, and ignore entities with nothing to apply to.
- Receivers must ignore unknown fields. An unknown namespaced type is answered with a
2xxand dropped, and an unknown core type is rejected. - Added a status code table and an optional error body.
- Rate limits now use
429andRetry-After, replacing the expired IETF draft headers. Added retry rules. - Defined media types per route.
Content-Typeis nowapplication/vnd.versia+json, withcharset=utf-8optional, and the inbox no longer needs anAcceptheader. - Follow, FollowAccept, FollowReject and Unfollow are replaced by Subscribe, SubscribeAccept, SubscribeReject and Unsubscribe, which also replace the four subscription entities of Groups. They carry
subscriber,targetandtarget_typeinstead of anauthor, and receivers check the sender againstsubscriberortarget. They can target any type whose page says it accepts subscriptions. The target’s instance must answer every Subscribe, with no time limit on a pending request, Unsubscribe cancels a pending request, and SubscribeReject also removes an existing subscriber. - Followers are now called subscribers. User
followers,followingandmanually_approves_followersare nowsubscribers,subscriptionsandmanually_approves_subscribers, and the Notevisibilityvaluefollowersis nowsubscribers. - Delete:
authoris optional, instances can delete, and the instance hosting the entity must send the Delete. A Delete whosedeleted_typediffers from the stored type is ignored. Added410and404for fetching deleted entities. - A user’s Notes collection holds the Notes they have authored.
- Added an endpoint for instance collections, since Instance Metadata has no
id, and defined pagination. - Extension endpoints must be under
/.versia/v0.X/extensions/{extension_name}/. Extensions now state their own delivery and access rules. - Entity types and collection names in paths are no longer percent-encoded, as in
/entities/pub.versia:groups/Group/1234. - Entity types in URLs are always capitalized, and examples no longer have port numbers in domains.
Extensions
- Extensions now have versions, listed in
compatibility.extensionsaspub.versia:likes@1. Instances use the highest version they have in common. - Extension values must be JSON objects, namespaces must come from a domain the author controls, and
pub.versiais reserved. - An extension can now require other extensions at a version. An instance that lists it must also list what it requires, and instances leave out its data unless they share those too. Extensions may still never be required to process core entities.
- Notes moved out of the core into the new Social extension (
pub.versia:social), so the core has no post type. A Note’stypeis nowpub.versia:social/Note, and a bareNoteis an unknown core type that receivers reject. The extension also holds visibility, mentions, replies and quotes, the delivery and access rules for Notes, and thenotes,reply,quoteandcomposeVersia Link actions. - User
outboxandfeaturedare now the Social collectionspub.versia:social/Notesandpub.versia:social/Featured. The outbox is renamed because it only ever held Notes. - User
bioandfieldsmoved to Profile, wherefieldsis optional, andheadermoved to Decorations. - Likes, Share, Reactions, Polls, Groups and Interaction Controls now require Social. The
shareandgroupsVersia Link actions moved to Share and Groups. - All entities that act on another entity (Like, Dislike, Share, Reaction and Vote) now use
target. - The Vanity extension (
pub.versia:vanity) is split in two. Profile (pub.versia:profile) holdspronouns,birthday,locationandtimezone, and Decorations (pub.versia:decorations) holdsavatar_overlays,avatar_mask,backgroundandaudio.aliasesis removed. - Profile:
pronounsis plain text for each BCP 47 language tag, replacing the five pronoun forms.birthdayisYYYY-MM-DD, or--MM-DDwithout the year, replacing the0000year. Whether a well-formed date is plausible is up to implementations.locationis plain text only, andtimezonemust be an IANA time zone name. - Decorations: each field must hold the media type it names: images, or audio for
audio. - Delegation: now only changes who an action is shown as. It grants no rights over the other user’s entities. A delegator that cannot be fetched counts as not listing the delegate.
- Added the Domain Handles extension (
pub.versia:domain_handles). A user can be shown by a domain they own, such as@joe.example, once a DNSTXTrecord at_versia.joe.example, or a file athttps://joe.example/.well-known/versia-handle, names their Reference. The DNS record decides when both exist. - Groups: members join through Subscribe, and the GroupSubscribe, GroupUnsubscribe, GroupSubscribeAccept and GroupSubscribeReject entities are removed. Defined moderators and federation, and
GroupFederate.noteis nowtarget. The instance of a Note’s author sends the Note to the group’s instance, which sends aGroupFederateto its members’ instances, and those fetch the Note.nameis a plain string, anddescriptionis RichText. - Instance Messaging: named
pub.versia:instance_messagingso that instances can list it incompatibility.extensions, moved to the extensions path, and defined as unsigned with untrusted text. The body should name the sender. - Interaction Controls: only
allowedremains, priorities are gone, keys are lowercase interaction types that each extension registers (such aspub.versia:social/replyandpub.versia:likes/like, replacingreply,quoteand entity type names), and theInteractionGroupvalues now match their descriptions (followedis gone,mentionedis added, andfollowersandfollowingare nowsubscribersandsubscriptions). A refused interaction must be rejected.allowednever widens who can see a Note. - Migration:
newis nowdestination, andpreviousis optional. Migrations have defined delivery, and subscriptions move through normal Subscribes. The old account should stay served for at least 30 days. - Polls:
optionsis now a list of objects holdingcontentandvotes. A Vote now holds all of a user’s choices in anoptionslist of indexes, replacing one Vote per option withoption, and a user has at most one Vote in each poll. A Vote can change by being sent again, and is withdrawn by a Delete, but itstargetcannot change. A refused Vote must be rejected. - Reactions: defined how
contentholds a custom emoji, and a Reaction is undone with a Delete. - Reports:
reportedis now a list of objects holdingtypeandreference. - Share: only a public Note can be shared.
- Versia Links:
instanceis required except forcompose, usernames are allowed,{text}is percent-encoded, and extensions can add actions.
Documentation
- Requirements now use BCP 14 key words, only in bold capitals. Some that were only written in lowercase now use them, including undoing a Like or Dislike with a Delete and the limits on remote data in Validation.
- Defined conformance.
- The Security Model now says what signatures do not prove and where to report a vulnerability. Validation adds rules for remote HTML and outbound requests.
- Restructured the site.
/api/basicswas split between Versions, HTTP and Entities,/api/endpointsmoved to Endpoints,/philosophy/principlesmoved to Principles,/federation/validationmoved to Validation, and/federation/examplemoved to Example. The old URLs redirect, without their fragments. Entity and extension pages now share one layout, so their section anchors changed. - Added Other Protocols, which maps Versia’s concepts to ActivityPub and Matrix.
- Added a Glossary and guides on signing requests and implementing a receiver.
- Removed repeated statements of rules, which now link to the page that defines them, along with promotional text. No rule changed.
- Corrected samples across the specification, including the federation example and its signatures.
v0.6.0
- Added a media type for Versia entities:
application/vnd.versia+json. - Overhauled the instance-to-instance API. Its endpoints are now defined and namespaced under
/.versia/v0.6/, instead of each implementation choosing its own. - Removed per-user key pairs. Only the instance key pair is used for signing.
- Moved Delegation to an extension.
- The well-known endpoint now only lists supported protocol versions.
- Changed how entities refer to each other:
- Removed the
urifield from all entities. - Every field that held a URI now holds that entity’s
id. - Added endpoints under
/.versia/v0.6/to fetch entities by theirid.
- Removed the
- Added References as a way to refer to other entities.
- Replaced
nullauthors with an optional field. - Replaced the
hashfield on ContentFormat with a hex-encoded SHA-256 hash. - Added more guidance on handling JSON.
- Clarified what a Domain means in Versia.
- Note:
is_sensitive,attachments,mentionsandpreviewsare now required. - User:
fields,manually_approves_followersandindexableare now required. - Vanity: removed the short pronoun form, since union types are hard to parse in strongly typed languages.
v0.5.0
- Reports: removed the URI, and replaced
reasonwithtags. - The docs now use the term “transient entity” where it applies.
- Text fields must use Unix-style
\nline endings. - Renamed two headers, following RFC 6648:
X-SignaturetoVersia-SignatureX-Signed-BytoVersia-Signed-By
- Replaced the nonce in the signature system with a timestamp, sent as
Versia-Signed-At. - Rate limits now follow IETF draft-polli-ratelimit-headers-02.
- Moved Groups to an extension, as they were getting too complex for the core protocol, and documented how groups federate and how subscribing works. The Note
groupfield’s description changed to match. - Added Versia Links.
- Timestamps now use RFC 3339 instead of ISO 8601. The two are mostly interchangeable, and RFC 3339 is stricter, so most implementations should not need to change anything.
- Added an optional
$schemafield to Entities. - Added the Interaction Controls extension.
- Added URI Collections, now called Reference Collections. Every Collection that can contain remote entities now uses one, such as User
collections.followers. - Added a
collectionsfield to Notes. The Likes, Reactions and Share extensions now use it, instead of a field inextensions. - User
usernamemay now contain uppercase letters, and is case-insensitive. - Vanity: added
timezone.
v0.4.0
- Rewrote the signature system from scratch, to be simpler and not depend on dates.
- Moved Likes and Dislikes to an extension.
- Added Delegation.
- Renamed fields on several common entities, such as Users and Notes.
- Removed the
Patchentity, since edits can be sent to inboxes directly. - A
urino longer has to contain the entity’sid, anduriis optional on some entities that are not worth keeping track of. idcan now be any string, not only a UUID.- Added shared inboxes.
- ContentFormat: added
remote. - Switched from BlurHash to ThumbHash.
- Custom Emojis: added identification characters.
- Users: added
manually_approves_followers. - Notes: removed
visibility, andsubjectis now optional. - Clarified how Follows work.
- Renamed
Undoto Delete, which is now only used to delete entities. - Added the Unfollow entity.
- Reworked
ServerMetadataand renamed it to InstanceMetadata. - Removed server actors, and moved instance public keys to InstanceMetadata.
- Added
algorithmto the public keys of Users and InstanceMetadata, for future use. Onlyed25519is allowed. The secondpublic_keyis renamed tokey. - Renamed
Announceto Share. - Collections: renamed
prevtoprevious. - Removed
extension_typefrom entities, which now use thetypefield instead. - Polls: removed
VoteResult.