MUST be application/vnd.versia+json on every /.versia/ route except the inbox and Instance Messaging, which do not need it. Basic application/json MUST NOT be used on those routes. The well-known and WebFinger routes state their own.
HTTP
Versia uses the HTTP protocol for all communications between instances.
Signatures lists the routes where requests and responses are signed.
TLS
Requests not encrypted with TLS (HTTPS) MUST NOT be sent or responded to. All implementations MUST use TLS 1.2 or higher, and MUST support HTTP/2.
Requests
Headers
Accept string MUST be application/vnd.versia+json if the request has a body, except on the Instance Messaging route. Receivers MUST accept it with or without charset=utf-8.
See Signatures for more information.
See Signatures.
See Signatures.
User-Agent string A string identifying the software making the request. SHOULD contain the name of the software, its version, and a link to its homepage.
CoolServer/1.0 (https://coolserver.example)POST /.versia/v0.7/inbox HTTP/1.1
Host: bob.example
Content-Type: application/vnd.versia+json
User-Agent: CoolServer/1.0 (https://coolserver.example)
Versia-Signature: RW7hr/xNzshs446OAPnPxR1vh7ZfZH+FDfn59bLc3LD3SIeR7udR2NqsMLfb4IQvhoFRWE1IL3sdQTPPVaDwCg==
Versia-Signed-By: example.com
Versia-Signed-At: 1729241687
{"type":"Delete","created_at":"2024-10-18T08:54:47Z","author":"example.com:033wv9k6n0007","deleted_type":"pub.versia:social/Note","deleted":"example.com:033qtdbdkj006"}Encoding
Entity types, extension names and collection names go in paths as they are, so a namespaced type spans two path segments. They MUST NOT be percent-encoded, so that each path has one spelling for signatures to cover. A receiver does not have to accept an encoded form.
/.versia/v0.7/entities/pub.versia:groups/Group/1234
/.versia/v0.7/entities/User/1234/collections/pub.versia:likes/Likes
Redirects
API endpoints MUST NOT redirect to other endpoints, with the following exceptions:
- When a
GETrequest does not have anAccept: application/vnd.versia+jsonheader, the server MAY redirect to an HTML representation of the resource.
API endpoints MUST NOT redirect from HTTP to HTTPS. This is to force all API communication to be encrypted, and to avoid accidentally leaking sensitive data over unencrypted connections.
This is forbidden:
GET /.versia/v0.7/entities/User/1234 HTTP/1.1
Host: example.com
Accept: application/vnd.versia+json
HTTP/1.1 301 Moved Permanently
Location: https://example.com/users/1234
This is allowed:
GET /.versia/v0.7/entities/User/1234 HTTP/1.1
Host: example.com
Accept: text/html
HTTP/1.1 301 Moved Permanently
Location: https://example.com/users/1234
Rate Limits
An instance that rate limits a request MUST respond with a 429 Too Many Requests status code and a Retry-After header. The sender MUST NOT retry the request before the time that header gives.
Retries
A sender delivering to an inbox SHOULD retry with increasing delays after a network failure, a 5xx status code, a 408 Request Timeout, a 429 Too Many Requests, or a 2xx response it had to discard. It MUST honor any Retry-After header. It MUST NOT retry after any other 4xx status code.
Each retry MUST be signed again, as the signature’s timestamp will no longer be valid.
How long to keep trying is up to the implementation. 48 hours is a reasonable default.
Responses
Headers
MUST be application/vnd.versia+json if the response has a body, unless specified otherwise. Receivers MUST accept it with or without charset=utf-8.
See Signatures for more information.
See Signatures.
See Signatures.
# Answers GET /.versia/v0.7/instance/collections/admins, sent to bob.example
HTTP/1.1 200 OK
Content-Type: application/vnd.versia+json
Versia-Signature: 9Xkg1gy82HxAoXeXk7je0Qc9kiBWXuVRmqXXdvBUW+z3USKzCkfGrttFHkqBALPlexghmiXzMzxM98kURplxAA==
Versia-Signed-By: bob.example
Versia-Signed-At: 1729241717
{"total":0,"items":[]}Status Codes
Every federation route uses these status codes. An inbox that answers 2xx before it has finished checking an entity cannot report a problem found later, so it drops the entity.
| Status code | Meaning |
|---|---|
200 OK | The requested entity or collection is in the body. |
202 Accepted | The inbox took the entity. A repeated signature and an unknown extension type also get a 2xx status code. |
400 Bad Request | The body is not valid JSON. |
401 Unauthorized | The signature is missing or invalid, or its timestamp is too old or too new. |
403 Forbidden | The receiver refuses to federate with the sender’s instance. |
404 Not Found | There is no such entity, or the requesting instance may not fetch it. |
410 Gone | The entity was deleted. |
415 Unsupported Media Type | The Content-Type is wrong. |
422 Unprocessable Entity | The entity is invalid, its author does not belong to the signer, or its core type is unknown. Also used for invalid pagination parameters. |
429 Too Many Requests | The sender is rate limited. |
The inbox SHOULD answer with 202 Accepted and no body. Senders MUST treat any 2xx status code from the inbox as delivered, as long as its signature verifies.
Error Bodies
A response with a 4xx or 5xx status code MAY have a body in the format below. The status code is what counts: an instance MUST NOT change its behavior based on an error body.
Fields
Short description of the problem.
error_description string Longer description of the problem, for humans.
details object Problems by field. Keys are paths to the field, and values are arrays of strings describing what is wrong with it.
{
"error": "Validation failed",
"error_description": "The entity does not match its definition.",
"details": {
"created_at": ["Must be an RFC 3339 timestamp"]
}
}