# Changelog

Changes to the Versia protocol since Working Draft 3, newest first.

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](/extensions/social), Follow became a generic [Subscribe](/entities/subscribe), and User keeps only the fields every instance needs.

### Versions

- Protocol versions are now written as `0.X.Y`. [`X` changes on a breaking release, and `Y` on a compatible one](/federation/versions).
- Removed `compatibility.versions` from [Instance Metadata](/entities/instance-metadata). The [well-known endpoint](/federation/endpoints#well-known) is now the only list of supported versions.
- Added rules for [choosing a version](/federation/versions#choosing-a-version): senders use the highest `0.X` both instances support, instances with the same `X` must interoperate, and instances with none in common must not federate.

### Signatures and Identity

- The [signed string](/signatures) 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](/signatures#where-signatures-are-required), in both directions. The well-known endpoint, WebFinger and Instance Metadata are exempt.
- Only `2xx` responses 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-Signature` they have already accepted from the same instance on the inbox, and answer it with a `2xx`. 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 `author` must belong to the instance that signed the message](/validation#authors-and-signers), whether it was delivered or fetched. This also covers each entity in a Collection's `items`.
- [References](/entities#reference) must always be `domain:id`, using a [Domain](/entities#domain) as their prefix, so they cannot be bare IDs or contain port numbers or IP addresses. Their definition moved to [Entities](/entities#reference).
- [Domains](/entities#domain) are now defined by RFC 1123 and IDNA, and must be lowercase.
- [Domains](/entities#domain) cannot be IP addresses or single labels.
- [User addresses](/entities/user#addresses) now only allow usernames.

### Data Model

- All JSON must now be an [I-JSON message](/json). Numeric fields are now `integer`, a whole number up to 2^53-1 in any notation, or `float`. These replace `u64` and `f64`.
- An entity with a `\r\n` line break inside a string value is now invalid.
- Strings and arrays may be empty unless their field says otherwise. [`id`](/entities), `username` and a Reaction's `content` have at least 1 character.
- Senders may now omit [optional fields](/json#optional-fields) instead of setting them to `null`. Both mean the same, and receivers must accept both.
- [Entities](/entities), structures and [transient entities](/entities#transient-entities) now have definitions. Transient entities have no `id`.
- An [`id`](/entities) is now 1 to 13 characters of `a-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](/entities#choosing-ids) shows one way to make short ids.
- Added [`updated_at`](/entities) and defined [how an entity changes](/entities#changing-an-entity): the whole entity is sent again with the same `id`, and `id`, `type`, `author` and `created_at` cannot change.
- Removed `$schema` from entities, and `author` from [Collections](/structures/collection) and Reference Collections.
- ContentFormat is replaced by two types. [RichText](/structures/rich-text) is one HTML string, and other text formats are gone. [Media](/structures/media) is one file, with its `url` and `media_type` in 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-mention` attribute, and [extensions](/structures/rich-text#extension-attributes) can add `data-` attributes to `span` and `div`.
- Media's `hash` is a lowercase hexadecimal `string`, and `thumbhash` is standard padded base64. Senders should include `size` and `hash`, and `thumbhash`, `width` and `height` for images and video.
- Renamed URI Collection to [Reference Collection](/structures/collection#reference-collection). A Collection only holds entities authored on the instance serving it.
- [Note](/extensions/social#note): `quotes` is now `quoting`, and the new required `visibility` field replaces the `group` field's visibility values. Groups moved to the [Groups extension](/extensions/groups). An unknown `category` is treated as absent.
- [User](/entities/user), [Note](/extensions/social#note) and [Group](/extensions/groups) 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](/federation#delivery) and [access](/federation#access) are now defined per entity type. Instances answer `404` for entities the requester may not fetch, and `subscribers` and `mentions` Notes 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](/validation#unknown-fields-and-types). An unknown namespaced type is answered with a `2xx` and dropped, and an unknown core type is [rejected](/validation#rejecting-entities).
- Added a [status code table](/federation/http#status-codes) and an optional error body.
- Rate limits now use `429` and `Retry-After`, replacing the expired IETF draft headers. Added retry rules.
- Defined media types per route. `Content-Type` is now `application/vnd.versia+json`, with `charset=utf-8` optional, and the inbox no longer needs an `Accept` header.
- Follow, FollowAccept, FollowReject and Unfollow are replaced by [Subscribe](/entities/subscribe), [SubscribeAccept](/entities/subscribe-accept), [SubscribeReject](/entities/subscribe-reject) and [Unsubscribe](/entities/unsubscribe), which also replace the four subscription entities of [Groups](/extensions/groups). They carry `subscriber`, `target` and `target_type` instead of an `author`, and receivers [check the sender](/entities/subscribe#checking-the-sender) against `subscriber` or `target`. 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](/entities/user) `followers`, `following` and `manually_approves_followers` are now `subscribers`, `subscriptions` and `manually_approves_subscribers`, and the [Note](/extensions/social#note) `visibility` value `followers` is now `subscribers`.
- [Delete](/entities/delete): `author` is optional, instances can delete, and the instance hosting the entity must send the Delete. A Delete whose `deleted_type` differs from the stored type is ignored. Added `410` and `404` for fetching deleted entities.
- A user's [Notes collection](/extensions/social#notes-collection) holds the Notes they have authored.
- Added an [endpoint for instance collections](/federation/endpoints#instance-collections), since Instance Metadata has no `id`, and defined [pagination](/federation/endpoints#pagination).
- [Extension endpoints](/extensions) 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](/federation/http#encoding), 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](/extensions#versions), listed in `compatibility.extensions` as `pub.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.versia` is reserved.
- An extension can now [require](/extensions#requirements) 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](/extensions/social) (`pub.versia:social`), so the core has no post type. A Note's `type` is now `pub.versia:social/Note`, and a bare `Note` is an unknown core type that receivers [reject](/validation#unknown-fields-and-types). The extension also holds visibility, mentions, replies and quotes, the delivery and access rules for Notes, and the `notes`, `reply`, `quote` and `compose` [Versia Link](/links) actions.
- [User](/entities/user) `outbox` and `featured` are now the Social collections `pub.versia:social/Notes` and `pub.versia:social/Featured`. The outbox is renamed because it only ever held Notes.
- [User](/entities/user) `bio` and `fields` moved to [Profile](/extensions/profile), where `fields` is optional, and `header` moved to [Decorations](/extensions/decorations).
- [Likes](/extensions/likes), [Share](/extensions/share), [Reactions](/extensions/reactions), [Polls](/extensions/polls), [Groups](/extensions/groups) and [Interaction Controls](/extensions/interaction-controls) now require Social. The `share` and `groups` Versia Link actions moved to Share and Groups.
- All entities that act on another entity ([Like, Dislike](/extensions/likes), [Share](/extensions/share), [Reaction](/extensions/reactions) and [Vote](/extensions/polls)) now use `target`.
- The Vanity extension (`pub.versia:vanity`) is split in two. [Profile](/extensions/profile) (`pub.versia:profile`) holds `pronouns`, `birthday`, `location` and `timezone`, and [Decorations](/extensions/decorations) (`pub.versia:decorations`) holds `avatar_overlays`, `avatar_mask`, `background` and `audio`. `aliases` is removed.
- [Profile](/extensions/profile): `pronouns` is plain text for each BCP 47 language tag, replacing the five pronoun forms. `birthday` is `YYYY-MM-DD`, or `--MM-DD` without the year, replacing the `0000` year. Whether a well-formed date is plausible is up to implementations. `location` is plain text only, and `timezone` must be an IANA time zone name.
- [Decorations](/extensions/decorations): each field must hold the media type it names: images, or audio for `audio`.
- [Delegation](/extensions/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](/extensions/domain-handles) (`pub.versia:domain_handles`). A user can be shown by a domain they own, such as `@joe.example`, once a DNS `TXT` record at `_versia.joe.example`, or a file at `https://joe.example/.well-known/versia-handle`, names their Reference. The DNS record decides when both exist.
- [Groups](/extensions/groups): members join through [Subscribe](/entities/subscribe), and the GroupSubscribe, GroupUnsubscribe, GroupSubscribeAccept and GroupSubscribeReject entities are removed. Defined moderators and federation, and `GroupFederate.note` is now `target`. The instance of a Note's author sends the Note to the group's instance, which sends a `GroupFederate` to its members' instances, and those fetch the Note. `name` is a plain string, and `description` is RichText.
- [Instance Messaging](/extensions/instance-messaging): named `pub.versia:instance_messaging` so that instances can list it in `compatibility.extensions`, moved to the extensions path, and defined as unsigned with untrusted text. The body should name the sender.
- [Interaction Controls](/extensions/interaction-controls): only `allowed` remains, priorities are gone, keys are lowercase interaction types that each extension registers (such as `pub.versia:social/reply` and `pub.versia:likes/like`, replacing `reply`, `quote` and entity type names), and the `InteractionGroup` values now match their descriptions (`followed` is gone, `mentioned` is added, and `followers` and `following` are now `subscribers` and `subscriptions`). A refused interaction must be [rejected](/validation#rejecting-entities). `allowed` never widens who can see a Note.
- [Migration](/extensions/migration): `new` is now `destination`, and `previous` is optional. Migrations have defined delivery, and subscriptions move through normal Subscribes. The old account should stay served for at least 30 days.
- [Polls](/extensions/polls): `options` is now a list of objects holding `content` and `votes`. A Vote now holds all of a user's choices in an `options` list of indexes, replacing one Vote per option with `option`, 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 its `target` cannot change. A refused Vote must be [rejected](/validation#rejecting-entities).
- [Reactions](/extensions/reactions): defined how `content` holds a custom emoji, and a Reaction is undone with a Delete.
- [Reports](/extensions/reports): `reported` is now a list of objects holding `type` and `reference`.
- [Share](/extensions/share): only a public Note can be shared.
- [Versia Links](/links): `instance` is required except for `compose`, usernames are allowed, `{text}` is percent-encoded, and extensions can add actions.

### Documentation

- Requirements now use [BCP 14](/introduction#vocabulary) 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](/validation).
- Defined [conformance](/introduction#vocabulary).
- The [Security Model](/security) now says what signatures do not prove and where to report a vulnerability. [Validation](/validation#remote-content) adds rules for remote HTML and outbound requests.
- Restructured the site. `/api/basics` was split between [Versions](/federation/versions), [HTTP](/federation/http) and [Entities](/entities#domain), `/api/endpoints` moved to [Endpoints](/federation/endpoints), `/philosophy/principles` moved to [Principles](/principles), `/federation/validation` moved to [Validation](/validation), and `/federation/example` moved to [Example](/example). The old URLs redirect, without their fragments. Entity and extension pages now share one layout, so their section anchors changed.
- Added [Other Protocols](/other-protocols), which maps Versia's concepts to ActivityPub and Matrix.
- Added a [Glossary](/glossary) and guides on [signing requests](/guides/signing-requests) and [implementing a receiver](/guides/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](/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](/extensions/delegation) to an extension.
- The [well-known endpoint](/federation/endpoints#well-known) now only lists supported protocol versions.
- Changed how entities refer to each other:
  - Removed the `uri` field 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 their `id`.
- Added [References](/entities#reference) as a way to refer to other entities.
- Replaced `null` authors with an optional field.
- Replaced the `hash` field on [ContentFormat](/structures/content-format) with a hex-encoded SHA-256 hash.
- Added more guidance on [handling JSON](/json).
- Clarified what a [Domain](/entities#domain) means in Versia.
- [Note](/extensions/social#note): `is_sensitive`, `attachments`, `mentions` and `previews` are now required.
- [User](/entities/user): `fields`, `manually_approves_followers` and `indexable` are now required.
- [Vanity](/extensions/profile): removed the short pronoun form, since union types are hard to parse in strongly typed languages.

## v0.5.0

- [Reports](/extensions/reports): removed the URI, and replaced `reason` with `tags`.
- The docs now use the term "transient entity" where it applies.
- Text fields must use Unix-style `\n` line endings.
- Renamed two headers, following [RFC 6648](https://datatracker.ietf.org/doc/html/rfc6648):
  - `X-Signature` to `Versia-Signature`
  - `X-Signed-By` to `Versia-Signed-By`
- Replaced the nonce in the [signature system](/signatures) with a timestamp, sent as `Versia-Signed-At`.
- Rate limits now follow [IETF draft-polli-ratelimit-headers-02](https://www.ietf.org/archive/id/draft-polli-ratelimit-headers-02.html).
- Moved [Groups](/extensions/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](/extensions/social#note) `group` field's description changed to match.
- Added [Versia Links](/links).
- Timestamps now use [RFC 3339](https://datatracker.ietf.org/doc/html/rfc3339) 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 `$schema` field to [Entities](/entities).
- Added the [Interaction Controls extension](/extensions/interaction-controls).
- Added URI Collections, now called [Reference Collections](/structures/collection#reference-collection). Every Collection that can contain remote entities now uses one, such as [User](/entities/user) `collections.followers`.
- Added a `collections` field to [Notes](/extensions/social#note). The [Likes](/extensions/likes), [Reactions](/extensions/reactions) and [Share](/extensions/share) extensions now use it, instead of a field in `extensions`.
- [User](/entities/user) `username` may now contain uppercase letters, and is case-insensitive.
- [Vanity](/extensions/profile): added `timezone`.

## v0.4.0

- Rewrote the signature system from scratch, to be simpler and not depend on dates.
- Moved [Likes and Dislikes](/extensions/likes) to an extension.
- Added [Delegation](/extensions/delegation).
- Renamed fields on several common entities, such as [Users](/entities/user) and [Notes](/extensions/social#note).
- Removed the `Patch` entity, since edits can be sent to inboxes directly.
- A `uri` no longer has to contain the entity's `id`, and `uri` is optional on some entities that are not worth keeping track of.
- `id` can now be any string, not only a UUID.
- Added shared inboxes.
- [ContentFormat](/structures/content-format): added `remote`.
- Switched from [BlurHash](https://blurha.sh/) to [ThumbHash](https://evanw.github.io/thumbhash/).
- [Custom Emojis](/extensions/custom-emojis): added identification characters.
- [Users](/entities/user): added `manually_approves_followers`.
- [Notes](/extensions/social#note): removed `visibility`, and `subject` is now optional.
- Clarified how [Follows](/entities/subscribe) work.
- Renamed `Undo` to [Delete](/entities/delete), which is now only used to delete entities.
- Added the [Unfollow](/entities/unsubscribe) entity.
- Reworked `ServerMetadata` and renamed it to [InstanceMetadata](/entities/instance-metadata).
- Removed server actors, and moved instance public keys to [InstanceMetadata](/entities/instance-metadata).
- Added `algorithm` to the public keys of [Users](/entities/user) and [InstanceMetadata](/entities/instance-metadata), for future use. Only `ed25519` is allowed. The second `public_key` is renamed to `key`.
- Renamed `Announce` to [Share](/extensions/share).
- [Collections](/structures/collection): renamed `prev` to `previous`.
- Removed `extension_type` from entities, which now use the `type` field instead.
- [Polls](/extensions/polls): removed `VoteResult`.
