Compare commits
4 changed files with 364 additions and 487 deletions
|
|
@ -2,117 +2,33 @@
|
||||||
title: Endpoints
|
title: Endpoints
|
||||||
---
|
---
|
||||||
|
|
||||||
All application messages arrive at the `Iota` through an authenticated MTP
|
All messages to the `Iota` are either from the `Omikron` directly, from a `Client` or another `Iota` trying to message a `User` on the `Iota`.
|
||||||
connection. A sealed application operation uses the reserved `Relay`
|
All messages will be marked with a `sender_id` this will be added on the `Omikron`.
|
||||||
communication type. Its outer sender is absent, and its outer receiver is
|
It is important to note that the `Iota ID` is not shared with others as it is what verifies the `Iota` users to Tensamin.
|
||||||
only the next-hop Iota or local client ID.
|
In the response the `sender_id` & `receiver_id` must be swapped as sender.
|
||||||
|
When a message comes from an iota without a `sender-id` that the iota has access to or is designated for the client (`33333333-3333-3333-3333-333333333333`) the message will not be send.
|
||||||
The Iota opens and verifies Relay metadata and content. It resolves the
|
|
||||||
claimed signer ID through trusted user key history; it never treats a public
|
|
||||||
key carried by the message as authoritative. The `sender_id` fields in the
|
|
||||||
examples below describe authenticated application data inside the protected
|
|
||||||
Relay, not an outer MTP sender added by Omikron.
|
|
||||||
|
|
||||||
The Iota ID is used by the MTP routing layer and is not an application signer
|
|
||||||
identity. Omikron does not rewrite a Relay's sender, emit `MessageOtherIota`,
|
|
||||||
or inspect the protected operation to choose a route.
|
|
||||||
|
|
||||||
## MTP Relay API
|
|
||||||
|
|
||||||
The Relay API uses the MTP `0.3.0` implementation and protocol version `3.0`.
|
|
||||||
MTP sends the frame as binary data; the shapes below describe its logical
|
|
||||||
fields for application integration.
|
|
||||||
|
|
||||||
### `Relay` frame
|
|
||||||
|
|
||||||
```text
|
|
||||||
CommunicationValue {
|
|
||||||
id: optional u32,
|
|
||||||
type: Relay,
|
|
||||||
sender: absent,
|
|
||||||
receiver: next-hop u64,
|
|
||||||
payload: encrypted relay metadata,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
The clear `receiver` is the only routing identity. The payload is sealed from
|
|
||||||
Omikron and Omega. The `id` is an MTP correlation value and is not the
|
|
||||||
authenticated application message identity.
|
|
||||||
|
|
||||||
After the metadata recipient opens the payload, the authenticated metadata
|
|
||||||
contains:
|
|
||||||
|
|
||||||
```text
|
|
||||||
RelayVersion: unsigned integer
|
|
||||||
MessageId: string
|
|
||||||
FinalRecipientId: unsigned integer
|
|
||||||
CreatedAt: Unix epoch milliseconds
|
|
||||||
Content: encrypted signed application content
|
|
||||||
Metadata: optional application metadata
|
|
||||||
```
|
|
||||||
|
|
||||||
The signed content contains `MessageType` and the application `Content` value.
|
|
||||||
The content recipient set is separate from the metadata recipient set. Include
|
|
||||||
the destination Iota in the content recipient set when that Iota must apply
|
|
||||||
the operation; metadata-only participants forward the sealed content.
|
|
||||||
|
|
||||||
### Relay verification
|
|
||||||
|
|
||||||
The receiving Iota performs these checks before dispatching application data:
|
|
||||||
|
|
||||||
1. The outer receiver is the local Iota ID.
|
|
||||||
2. The outer sender is absent.
|
|
||||||
3. The claimed signer ID is read from decrypted metadata but remains untrusted.
|
|
||||||
4. Trusted signing-key history is resolved from local user state or the
|
|
||||||
authenticated Omega control plane.
|
|
||||||
5. The metadata signature and final recipient are verified with those keys.
|
|
||||||
6. `(signer_id, MessageId)` is inserted into durable replay storage before an
|
|
||||||
application side effect.
|
|
||||||
7. The content signature is checked against the same trusted signer keys.
|
|
||||||
|
|
||||||
An application `SenderId` field is checked against the authenticated signer;
|
|
||||||
it is not a substitute for Relay signature verification. `CreatedAt` can be
|
|
||||||
used for retention, but it is not part of the replay identity.
|
|
||||||
|
|
||||||
### Relay routing
|
|
||||||
|
|
||||||
The outer receiver changes when the Relay crosses a routing boundary. The
|
|
||||||
sealed payload and absent outer sender remain unchanged.
|
|
||||||
|
|
||||||
| Stage | Outer receiver | Operation |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| Client to origin Iota | Origin Iota ID | Verify the local user's Relay and resolve the final recipient's hosting Iota. |
|
|
||||||
| Origin Iota to remote Iota | Destination Iota ID | Call `forward_relay_frame()` and send the unchanged sealed Relay through Omikron. |
|
|
||||||
| Destination Iota to client | Final user ID | Verify and apply content, then forward the original Relay to the local client. |
|
|
||||||
|
|
||||||
The Iota never creates `MessageOtherIota`, reconstructs `SetChatSecret`, or
|
|
||||||
adds the authenticated signer as an outer MTP sender. Failed delivery stores
|
|
||||||
the encoded sealed Relay for retry.
|
|
||||||
|
|
||||||
## Messages
|
## Messages
|
||||||
|
|
||||||
### Messaging Lifecycle
|
### Messaging Lifecycle
|
||||||
|
|
||||||
The messaging system persists and verifies each protected operation before it
|
The messaging system follows a strict derivation loop to ensure delivery and correct state synchronization:
|
||||||
is delivered or forwarded:
|
|
||||||
|
|
||||||
1. The client sends a sealed `Relay` containing the application operation to
|
1. The client sends a `message_send` to its Iota.
|
||||||
its associated Iota.
|
2. The Iota sends a response `message_send` as confirmation back to the client.
|
||||||
2. The Iota verifies the protected signer, final recipient, message ID, and
|
3. The Iota sends a `message_other_iota` to the chat partner's Iota.
|
||||||
application content before applying the operation.
|
- **If it times out:**
|
||||||
3. When another Iota must receive the operation, the Iota persists any
|
- The initial Iota sends a `message_state` to the client with the state `"sending"`.
|
||||||
required delivery state and forwards the same sealed `Relay` through
|
- **If successful:**
|
||||||
Omikron. The outer receiver changes only when the next hop changes.
|
- The other Iota receives the `message_other_iota` and handles it.
|
||||||
4. The recipient Iota verifies the Relay again, stores the operation, and
|
- The other Iota informs its client with a `message_live`.
|
||||||
sends the resulting application update to its local client.
|
- **If the client doesn't answer:**
|
||||||
|
1. The other Iota will send a `message_state` to the initial Iota with the state `"sent"`.
|
||||||
|
2. The initial Iota will store the state and forward the `message_state` to its client.
|
||||||
|
|
||||||
### Message mutations
|
### Message mutations
|
||||||
|
|
||||||
`Iota` stores each mutation on the sender and recipient replicas. `Content`
|
`Iota` stores each mutation on the sender and recipient replicas. `Content` remains encrypted chat content. The sender is taken from the authenticated MTP connection and must own the original message for edits and deletion.
|
||||||
remains encrypted chat content. The sender is the authenticated signer from
|
|
||||||
the protected Relay and must own the original message for edits and deletion.
|
|
||||||
The request and update examples in this section show protected application
|
|
||||||
content, not the outer MTP `CommunicationValue`.
|
|
||||||
|
|
||||||
#### `MessageEdit`
|
#### `MessageEdit`
|
||||||
|
|
||||||
|
|
@ -159,10 +75,6 @@ Changes an existing message. `ChatPartnerId` and `SendTime` identify the message
|
||||||
|
|
||||||
Adds one reaction for the authenticated user. Repeating the same request does not create a duplicate row.
|
Adds one reaction for the authenticated user. Repeating the same request does not create a duplicate row.
|
||||||
|
|
||||||
Iota stores at most ten distinct reaction strings per message. A user may use
|
|
||||||
an existing reaction string after the limit is reached. A new string at the
|
|
||||||
limit returns `ErrorInvalidData` and produces no live update.
|
|
||||||
|
|
||||||
##### `REQ (C2S):`
|
##### `REQ (C2S):`
|
||||||
|
|
||||||
```json
|
```json
|
||||||
|
|
@ -230,27 +142,6 @@ Removes the authenticated user's matching reaction.
|
||||||
|
|
||||||
`Accepted` is `true` for an add and `false` for a removal.
|
`Accepted` is `true` for an add and `false` for a removal.
|
||||||
|
|
||||||
#### `MessageGet`
|
|
||||||
|
|
||||||
Fetches one visible message by `SendTime`. Include `ChatPartnerId` when the
|
|
||||||
request is a reply lookup. The successful response then includes `Offset`,
|
|
||||||
the message's absolute position in the same descending history order used by
|
|
||||||
`MessagesGet`.
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"type": "MessageGet",
|
|
||||||
"data": {
|
|
||||||
"ChatPartnerId": "<chat-partner-id>",
|
|
||||||
"SendTime": "<message-unix-milliseconds>"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
Use the returned `Offset` as the starting position for a page that contains
|
|
||||||
the target. Requests without `ChatPartnerId` remain accepted for compatibility
|
|
||||||
but do not include an offset.
|
|
||||||
|
|
||||||
#### `MessageDeleteLive`
|
#### `MessageDeleteLive`
|
||||||
|
|
||||||
Deletes a message from both replicas. The existing `MessageDeleteLive` MTP type is used for both the authenticated delete request and the recipient update because no separate delete request type exists in the client type map.
|
Deletes a message from both replicas. The existing `MessageDeleteLive` MTP type is used for both the authenticated delete request and the recipient update because no separate delete request type exists in the client type map.
|
||||||
|
|
@ -294,10 +185,8 @@ Deletes a message from both replicas. The existing `MessageDeleteLive` MTP type
|
||||||
2. The initial Iota will store the state and forward the `message_state` to its client.
|
2. The initial Iota will store the state and forward the `message_state` to its client.
|
||||||
|
|
||||||
### Client adds someone to their contacts
|
### Client adds someone to their contacts
|
||||||
|
When adding via name, the omikron will intercept and fill the chat_partner_id.
|
||||||
Resolve a contact name through the control plane before creating the protected
|
The iota will never read, or handle the chat_partner_name.
|
||||||
`AddConversation` operation. Omikron does not inspect or mutate this
|
|
||||||
operation. The JSON below represents the protected application content.
|
|
||||||
|
|
||||||
##### `REQ:`
|
##### `REQ:`
|
||||||
|
|
||||||
|
|
@ -308,7 +197,7 @@ operation. The JSON below represents the protected application content.
|
||||||
|
|
||||||
"type": "add_conversation",
|
"type": "add_conversation",
|
||||||
"id": "<uuid>",
|
"id": "<uuid>",
|
||||||
|
|
||||||
"data": {
|
"data": {
|
||||||
"chat_partner_id": id,
|
"chat_partner_id": id,
|
||||||
"chat_partner_name": "name"
|
"chat_partner_name": "name"
|
||||||
|
|
@ -331,33 +220,41 @@ operation. The JSON below represents the protected application content.
|
||||||
|
|
||||||
### Client messages someone
|
### Client messages someone
|
||||||
|
|
||||||
The following object is the protected application content passed to the MTP
|
##### `REQ:`
|
||||||
Relay builder. It is not the outer frame and its `SenderId`, when present, is
|
|
||||||
checked against the authenticated Relay signer.
|
|
||||||
|
|
||||||
##### `CONTENT:`
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"MessageType": "MessageSend",
|
"sender_id": "<user-id>",
|
||||||
"Content": {
|
"receiver_id": "<user-id>",
|
||||||
"ReceiverId": "<user-id>",
|
|
||||||
"Content": "<markdown (encrypted)>",
|
"type": "message_send",
|
||||||
"Files": [
|
"id": "<uuid>",
|
||||||
|
"data": {
|
||||||
|
"receiver_id": "<uuid>",
|
||||||
|
"content": "<markdown (encrypted)>",
|
||||||
|
"files": [
|
||||||
{
|
{
|
||||||
"Name": "<file-name>",
|
"name": "<cool name>",
|
||||||
"Id": "<uuid>",
|
"id": "<uuid>",
|
||||||
"Type": "[ image | image_top_right | file ]"
|
"type": "[ image | image_top_right | file ]"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The Relay metadata carries the authenticated `MessageId` and
|
##### `RES:`
|
||||||
`FinalRecipientId`. It also carries `CreatedAt` as Unix epoch milliseconds.
|
|
||||||
The application does not put the signer identity in the outer MTP sender
|
```json
|
||||||
field.
|
{
|
||||||
|
"sender_id": "<user-id>",
|
||||||
|
"receiver_id": "<user-id>",
|
||||||
|
|
||||||
|
"type": "message_send",
|
||||||
|
"id": "<uuid>",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Client loads messages
|
### Client loads messages
|
||||||
|
|
||||||
|
|
@ -416,50 +313,49 @@ field.
|
||||||
|
|
||||||
`ClientConnected` and `MessagesGet` include `Edited: true` for messages with at least one edit and a `Reactions` array. Each reaction contains `Reaction` and `SenderId` fields. Clients that do not consume these fields continue to receive the existing message fields.
|
`ClientConnected` and `MessagesGet` include `Edited: true` for messages with at least one edit and a `Reactions` array. Each reaction contains `Reaction` and `SenderId` fields. Clients that do not consume these fields continue to receive the existing message fields.
|
||||||
|
|
||||||
### Route a message to another Iota
|
### Send a message to other Iota
|
||||||
|
|
||||||
The client sends the same `Relay` frame to its origin Iota regardless of the
|
##### `REQ:`
|
||||||
final recipient's hosting Iota.
|
|
||||||
|
|
||||||
```text
|
```json
|
||||||
Relay {
|
{
|
||||||
id: <optional-mtp-frame-id>,
|
"type": "message_send",
|
||||||
sender: absent,
|
"id": "<message_id>",
|
||||||
receiver: <origin-iota-id>,
|
"data": {
|
||||||
payload: <sealed MessageSend operation>,
|
"receiver_id": "99999999-8888-7777-6666-555555555555",
|
||||||
|
"content": "Hello, how are you?"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The origin Iota resolves the final recipient through the authenticated control
|
##### `RES:`
|
||||||
plane and forwards the original sealed frame with `receiver` set to the
|
|
||||||
destination Iota. It does not create a second application message.
|
|
||||||
|
|
||||||
```text
|
```json
|
||||||
Relay {
|
{
|
||||||
id: <same-mtp-frame-id>,
|
"type": "message",
|
||||||
sender: absent,
|
"id": "<message_id>",
|
||||||
receiver: <destination-iota-id>,
|
"receiver": "<user_id>"
|
||||||
payload: <same sealed MessageSend operation>,
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Receive a live message from a sealed Relay
|
### Receive live message (`message_other_iota`)
|
||||||
|
|
||||||
##### `UPDATE:`
|
##### `UPDATE:`
|
||||||
|
|
||||||
```text
|
```json
|
||||||
Relay {
|
{
|
||||||
id: <same-mtp-frame-id>,
|
"type": "message_live",
|
||||||
sender: absent,
|
"id": "<message_id>",
|
||||||
receiver: <final-user-id>,
|
"receiver": "<user_id>",
|
||||||
payload: <same sealed MessageSend operation>,
|
|
||||||
|
"data": {
|
||||||
|
"send_time": unixstamp,
|
||||||
|
"message": "<content>",
|
||||||
|
"sender_id": "99999999-8888-7777-6666-555555555555"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The destination Iota applies the authenticated operation before forwarding
|
|
||||||
the frame to the local client. The client receives the application update
|
|
||||||
through its authenticated MTP connection.
|
|
||||||
|
|
||||||
## Communities
|
## Communities
|
||||||
|
|
||||||
### Client storing a community on their Iota
|
### Client storing a community on their Iota
|
||||||
|
|
|
||||||
|
|
@ -1,93 +1,73 @@
|
||||||
---
|
---
|
||||||
title: MTP Endpoints
|
title: WSS Endpoints
|
||||||
lastUpdated: 2026-08-14
|
|
||||||
---
|
---
|
||||||
|
|
||||||
`Omega` serves HTTPS API routes and authenticated MTP WebTransport sessions.
|
The `Omega` can be reached by HTTPS request from `Client` and `Iota`.
|
||||||
`Omikron` connects through the MTP WebTransport endpoint. The Omega service
|
`Omikron` servers establish a Secure Websocket when booting.
|
||||||
uses MTP protocol version `0.3.0` and requires transport authentication before
|
|
||||||
dispatching application frames.
|
|
||||||
|
|
||||||
This document covers the MTP connection between `Omikron` and `Omega` and the
|
This documentation is split into `Omikron` (WSS) and `HTTPS`.
|
||||||
control messages handled after authentication. HTTP routes are documented in
|
|
||||||
[`https.md`](./https.md).
|
|
||||||
|
|
||||||
## MTP Omikron Connection
|
## Omikron
|
||||||
|
|
||||||
### Authentication
|
### Identification
|
||||||
|
|
||||||
The MTP opening exchange negotiates protocol version `3.0` and completes the
|
Any message to the `Omega` will be ignored until Identification.
|
||||||
configured cryptographic login or registration flow. Omega uses
|
|
||||||
`ForceAuthentication`, so an unauthenticated WebTransport session does not
|
|
||||||
reach the application dispatcher. The authenticated MTP client ID identifies
|
|
||||||
the `Omikron` connection.
|
|
||||||
|
|
||||||
The MTP `Identification`, `Register`, challenge, and signed proof frames are
|
##### `REQ:`
|
||||||
transport messages. They are not application-level JSON endpoints. After the
|
|
||||||
handshake, Omega validates the authenticated `Omikron` capability description
|
|
||||||
before accepting control messages or Relay frames.
|
|
||||||
|
|
||||||
### Relay Routing
|
|
||||||
|
|
||||||
`Relay` is the reserved MTP communication type for opaque routing between
|
|
||||||
`Omikron` instances. The logical shape below describes the MTP frame; MTP sends
|
|
||||||
the frame as binary data, not as JSON.
|
|
||||||
|
|
||||||
#### `Relay`
|
|
||||||
|
|
||||||
The outer `receiver` is the destination `Iota` next hop. The outer `sender`
|
|
||||||
field must be absent. The payload contains the sealed Relay metadata and
|
|
||||||
content and is not opened by Omega.
|
|
||||||
|
|
||||||
##### `REQ (Omikron → Omega):`
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "Relay",
|
"type": "identification",
|
||||||
"id": "<frame-id>",
|
"data": {
|
||||||
"receiver": "<iota-id>",
|
"omikron": "<omikron-id>",
|
||||||
"payload": "<opaque sealed relay payload>"
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
##### `FORWARD:`
|
##### `REQ & RES:`
|
||||||
|
|
||||||
Omega resolves the destination `Iota` through its primary `Omikron` route and
|
|
||||||
sends the Relay to that one authenticated connection. The outer receiver and
|
|
||||||
sealed payload remain unchanged. Omega does not decrypt Relay metadata or
|
|
||||||
content, resolve the original signer, rewrite the sender, or interpret the
|
|
||||||
inner application type.
|
|
||||||
|
|
||||||
Relay route failures are infrastructure failures. Omega rejects a frame with
|
|
||||||
an outer sender, a missing destination `Iota`, an unavailable primary route,
|
|
||||||
an unavailable target connection, or a route that points back to the source
|
|
||||||
`Omikron`. Omega does not turn these failures into user-authored Relay content.
|
|
||||||
|
|
||||||
### Control Messages
|
|
||||||
|
|
||||||
Control messages use the negotiated MTP type map after the authenticated
|
|
||||||
connection is established.
|
|
||||||
|
|
||||||
#### `PushNotification`
|
|
||||||
|
|
||||||
Sends a notification to a user. The receiver ID can be specified in the MTP
|
|
||||||
frame's `receiver` field or in the data payload.
|
|
||||||
|
|
||||||
##### `REQ (Omikron → Omega):`
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "PushNotification",
|
"type": "challenge",
|
||||||
"receiver_id": "<user-id>?",
|
"data": {
|
||||||
"sender_id": "<user-id>"
|
"public_key": "<omegas public key>",
|
||||||
|
"challenge": "<random encrypted b64 string>"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
##### `REQ & RES:`
|
||||||
##### `RES (Omega → Omikron):`
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"type": "PushNotification",
|
"type": "challenge_response",
|
||||||
"id": "<frame-id>"
|
"data": {
|
||||||
|
"challenge": "<decrypted b64 string>",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
##### `RES:`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "identification_response",
|
||||||
|
"data": {
|
||||||
|
"accepted": boolean,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Push Notification
|
||||||
|
|
||||||
|
Sends a push notification to a user. The receiver ID can be specified either in the `receiver` field of the message or in the data payload.
|
||||||
|
|
||||||
|
##### `REQ:`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "push_notification",
|
||||||
|
"data": {
|
||||||
|
"receiver_id": "<user-id>", // Optional, if not in receiver field
|
||||||
|
"sender_id": "<user-id>"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
||||||
|
|
@ -1,126 +1,22 @@
|
||||||
---
|
---
|
||||||
title: HTTPS Endpoints
|
title: HTTPS Endpoints
|
||||||
lastUpdated: 2026-08-14
|
|
||||||
---
|
---
|
||||||
|
#### GET `/api/get/omikron/`
|
||||||
|
Get an Omikron to connect to.
|
||||||
|
#### GET `/api/get/omikron/<omikron-id>`
|
||||||
|
Get an Omikron to connect to, when needing a certain omikron.
|
||||||
|
|
||||||
`Omega` exposes discovery and profile data over HTTPS. All identifiers in the
|
#### GET `/api/get/omikron/<user-id>`
|
||||||
routes below are positive decimal integers.
|
Get an Omikron to connect to, when needing the Omikron a certain User / a certains user's Iota is connected to.
|
||||||
|
#### GET `/api/get/omikron/<iota-id>`
|
||||||
#### GET `/api/get/omikron`
|
Get an Omikron to connect to, when needing the Omikron a certain Iota is connected to.
|
||||||
|
|
||||||
Returns a randomly selected connected `Omikron`.
|
|
||||||
|
|
||||||
##### `RES:`
|
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"status": "success",
|
"type": "omikron",
|
||||||
"id": "<omikron-id>",
|
"data": {
|
||||||
"public_key": "<base64>",
|
"omikron_id": id,
|
||||||
"ip_address": "<ip-address>",
|
"domain": "omikron.tensamin.net"
|
||||||
"port": "<port>"
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### GET `/api/get/omikron/<id>`
|
|
||||||
|
|
||||||
Returns a connected `Omikron` by ID. If `<id>` identifies a connected `Iota`
|
|
||||||
or a user with an assigned `Iota`, the response identifies that account's
|
|
||||||
primary connected `Omikron`.
|
|
||||||
|
|
||||||
##### `RES:`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "success",
|
|
||||||
"id": "<omikron-id>",
|
|
||||||
"public_key": "<base64>",
|
|
||||||
"ip_address": "<ip-address>",
|
|
||||||
"port": "<port>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GET `/api/get/connections`
|
|
||||||
|
|
||||||
Returns the live in-memory map of `Omikron` IDs to their connected `Iota` IDs
|
|
||||||
and hosted user IDs. The map is empty after an Omega restart until connected
|
|
||||||
`Omikron` instances publish their state.
|
|
||||||
|
|
||||||
##### `RES:`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "success",
|
|
||||||
"<omikron-id>": {
|
|
||||||
"<iota-id>": ["<user-id>", "..."]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GET `/api/get/iota/<id>`
|
|
||||||
|
|
||||||
Returns the public identity data for an `Iota`.
|
|
||||||
|
|
||||||
##### `RES:`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "success",
|
|
||||||
"iota_id": "<iota-id>",
|
|
||||||
"public_key": "<base64>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GET `/api/get/user/<id>`
|
|
||||||
|
|
||||||
Returns a user's profile and assigned `Iota` ID.
|
|
||||||
|
|
||||||
##### `RES:`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "success",
|
|
||||||
"username": "<username>",
|
|
||||||
"public_key": "<base64>",
|
|
||||||
"user_id": "<user-id>",
|
|
||||||
"iota_id": "<iota-id>?",
|
|
||||||
"sub_level": "<integer>",
|
|
||||||
"sub_end": "<unix-milliseconds>",
|
|
||||||
"display": "<string>?",
|
|
||||||
"status_message": "<string>?",
|
|
||||||
"about": "<string>?",
|
|
||||||
"avatar": "<base64>?"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GET `/api/get/id/<username>`
|
|
||||||
|
|
||||||
Resolves a username to its public profile and identity IDs. The username is
|
|
||||||
limited to 15 characters after URL decoding.
|
|
||||||
|
|
||||||
##### `RES:`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "success",
|
|
||||||
"username": "<username>",
|
|
||||||
"public_key": "<base64>",
|
|
||||||
"user_id": "<user-id>",
|
|
||||||
"iota_id": "<iota-id>?",
|
|
||||||
"sub_level": "<integer>",
|
|
||||||
"sub_end": "<unix-milliseconds>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### GET `/api/get/public_key`
|
|
||||||
|
|
||||||
Returns Omega's public MTP key bundle in base64 form.
|
|
||||||
|
|
||||||
##### `RES:`
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"status": "success",
|
|
||||||
"public_key": "<base64>"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
@ -1,147 +1,252 @@
|
||||||
---
|
---
|
||||||
title: Endpoints
|
title: Endpoints
|
||||||
lastUpdated: 2026-08-14
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Omikron exposes an MTP WebTransport endpoint through its HTTPS listener. It
|
To use the `Omikrons` functions a Secure Websocket connection must be established.
|
||||||
does not expose the previous JSON-over-WebSocket challenge protocol. Native
|
Where to connect is provided by the `Omega` Server.
|
||||||
and browser clients use the MTP client APIs described in the repository's
|
All entries are split into `Iota` & `Client`.
|
||||||
`mtp-docs` guides.
|
As the `Omikron` connects the `Iota` and `Client` by passing messages from one to the other all Communication from `Iota` to `Client` has to contain a `receiver_id`
|
||||||
|
The `Omikron` will add a `sender_id` to Messages from `Client` to the `Iota`.
|
||||||
|
|
||||||
Omikron and its peers use the MTP `0.3.0` implementation and the wire protocol
|
The `receiver_id` and `sender_id` of the `Omikron` server are `22222222-2222-2222-2222-222222222222`.
|
||||||
version `3.0`. The MTP opening exchange negotiates the version and completes
|
|
||||||
transport authentication before Omikron dispatches application frames.
|
|
||||||
|
|
||||||
## Connection identities
|
## Messages
|
||||||
|
|
||||||
The MTP connection description selects the Omikron connection class:
|
### Message mutation forwarding
|
||||||
|
|
||||||
| Description | Authentication | Connection | Relay access |
|
`Omikron` forwards `MessageEditLive`, `MessageReactionLive`, and `MessageDeleteLive` by their MTP receiver. The sender Iota persists the authenticated request before forwarding it. The recipient Iota persists the live update before Omikron sends it to the recipient client.
|
||||||
| --- | --- | --- | --- |
|
|
||||||
| `client` | Registered MTP authentication | User client | Yes |
|
|
||||||
| `iota` | Registered MTP authentication | Iota node | Yes |
|
|
||||||
| `anonymous` | Unauthenticated | Temporary anonymous client | No |
|
|
||||||
|
|
||||||
The `client` ID is the authenticated user ID. The `iota` ID is the
|
The request types `MessageEdit`, `MessageReactionAdd`, and `MessageReactionRemove` stay on the sender Iota. `MessageDeleteLive` is both the delete request and the live update; the authenticated connection direction distinguishes the request from a forwarded update.
|
||||||
authenticated Iota ID. A connection with an unknown description is rejected by
|
|
||||||
the application dispatcher. MTP challenge and proof frames are transport
|
|
||||||
messages, not application endpoints.
|
|
||||||
|
|
||||||
## MTP frame shape
|
> See also: `components/iota/endpoints.md` for message mutation payloads.
|
||||||
|
|
||||||
MTP sends binary `CommunicationValue` frames. The following is a logical shape
|
## Identification
|
||||||
for documentation; it is not a JSON wire format.
|
|
||||||
|
|
||||||
```text
|
Any message to the `Omikron` will be ignored until Identification.
|
||||||
CommunicationValue {
|
|
||||||
id: optional u32,
|
### Iota
|
||||||
type: CommunicationType,
|
|
||||||
sender: optional u64,
|
##### `REQ:`
|
||||||
receiver: optional u64,
|
|
||||||
payload: DataValue,
|
```json
|
||||||
|
{
|
||||||
|
"type": "identification",
|
||||||
|
"data": {
|
||||||
|
"iota_id": "<iota-id>",
|
||||||
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
`Relay` is the reserved opaque communication type. A Relay has no outer
|
##### `REQ & RES:`
|
||||||
`sender`, its outer `receiver` is the next-hop ID, and its payload contains
|
|
||||||
protected relay metadata and content. Omikron reads only the clear routing
|
|
||||||
fields. It never opens relay metadata or content, resolves the original
|
|
||||||
signer, or changes the sealed payload.
|
|
||||||
|
|
||||||
Tensamin user IDs and Iota IDs currently share the same numeric range. An
|
```json
|
||||||
Iota-origin Relay whose receiver matches both a local Client identity and a
|
{
|
||||||
local Iota identity is rejected as ambiguous; Omikron never chooses a route
|
"type": "challenge",
|
||||||
from a colliding numeric ID.
|
"data": {
|
||||||
|
"public_key": "<omikrons public key>",
|
||||||
|
"challenge": "<random encrypted b64 string>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
##### `REQ & RES:`
|
||||||
|
|
||||||
## Relay
|
```json
|
||||||
|
{
|
||||||
|
"type": "challenge_response",
|
||||||
|
"data": {
|
||||||
|
"challenge": "<decrypted b64 string>",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
##### `RES:`
|
||||||
|
|
||||||
### Client to Iota
|
```json
|
||||||
|
{
|
||||||
A registered Client may send a Relay only to the Iota currently associated
|
"type": "identification_response",
|
||||||
with that Client.
|
"data": {
|
||||||
|
"accepted": boolean,
|
||||||
```text
|
}
|
||||||
Relay {
|
|
||||||
id: request or correlation ID,
|
|
||||||
sender: absent,
|
|
||||||
receiver: associated Iota ID,
|
|
||||||
payload: opaque sealed relay,
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Omikron validates the Relay layout with MTP's `forward_relay_frame` and sends
|
---
|
||||||
the unchanged frame to the local Iota connection. A Client cannot address an
|
|
||||||
arbitrary Iota or Omikron through this path.
|
|
||||||
|
|
||||||
### Iota routing
|
### Client
|
||||||
|
|
||||||
An Iota may send a Relay to a locally connected Client, another locally
|
This is a two step process.
|
||||||
connected Iota, or Omega. Omikron chooses the destination from the clear outer
|
|
||||||
receiver and the authenticated connection that supplied the frame.
|
|
||||||
|
|
||||||
| Source connection | Destination | Omikron action |
|
Get a challenge:
|
||||||
| --- | --- | --- |
|
|
||||||
| Client | Its associated Iota | Send to that local Iota |
|
|
||||||
| Iota | Local Client | Send to matching client sessions |
|
|
||||||
| Iota | Local Iota | Send to that Iota |
|
|
||||||
| Iota | Remote Iota | Send to Omega |
|
|
||||||
| Omega | Local Iota | Send to that Iota |
|
|
||||||
| Anonymous client | Any destination | Reject |
|
|
||||||
|
|
||||||
Omega sends a Relay to one destination Omikron. Omikron accepts it only when
|
#### `REQ:`
|
||||||
the destination Iota is connected locally. It never sends an unavailable
|
|
||||||
Omega Relay back to Omega or broadcasts it to other Omikrons.
|
|
||||||
|
|
||||||
### Validation and errors
|
```json
|
||||||
|
{
|
||||||
|
"id": "<uuid>",
|
||||||
|
"type": "identification",
|
||||||
|
"data": {
|
||||||
|
"user_id": "<user-id>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Omikron rejects a Relay when:
|
#### `RES:`
|
||||||
|
|
||||||
- the communication type is not the reserved `Relay` type;
|
```json
|
||||||
- an outer sender is present;
|
{
|
||||||
- the next-hop receiver is missing;
|
"id": "<uuid>",
|
||||||
- a Client addresses an Iota other than its associated Iota;
|
"type": "challenge",
|
||||||
- an Iota routes to itself;
|
"data": {
|
||||||
- the destination Iota or Client is unavailable; or
|
"challenge": "<base64 string>",
|
||||||
- the frame cannot be sent on the selected connection.
|
"public_key": "<base64 string>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Routing failures are ordinary service error frames sent to the authenticated
|
Send back the solved challenge:
|
||||||
source connection. The failure frame is not a Relay and does not claim to be
|
|
||||||
from the original user. Unknown non-Relay application messages are rejected;
|
|
||||||
Omikron does not use generic fallthrough forwarding.
|
|
||||||
|
|
||||||
## Application messages
|
#### `REQ:`
|
||||||
|
|
||||||
Direct control messages remain available after MTP authentication. Examples
|
```json
|
||||||
include `GetUserData`, `GetIotaData`, `ChangeUserData`, `ClientChanged`, and
|
{
|
||||||
registration control messages. These messages use the negotiated MTP type map
|
"id": "<uuid>",
|
||||||
and may use the existing control-plane sender semantics.
|
"type": "challenge_response",
|
||||||
|
"data": {
|
||||||
|
"challenge": "<decrypted challenge>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
`MessageGet`, `MessagesGet`, and `GetChatSecret` are authenticated peer-control
|
#### `RES:`
|
||||||
messages. A Client sends them to its associated Iota through Omikron. Omikron
|
|
||||||
adds the authenticated client ID as the outer sender for the Iota request,
|
|
||||||
waits for the correlated response, and returns that response to the Client.
|
|
||||||
It does not read or store message contents.
|
|
||||||
|
|
||||||
Those semantics do not apply to `Relay`. Omikron never adds a user or Iota ID
|
```json
|
||||||
to a Relay and never uses the outer sender as the original message identity.
|
{
|
||||||
|
"id": "<uuid>",
|
||||||
|
"type": "identification_response",
|
||||||
|
"data": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
Message delivery, edits, reactions, deletion, chat secrets, and other
|
## Ping & Pong
|
||||||
application operations travel inside the sealed Relay. The recipient Iota
|
|
||||||
opens and verifies the Relay, checks the original signer against its trusted
|
|
||||||
public-key history, applies the operation, and persists or forwards the sealed
|
|
||||||
Relay when required.
|
|
||||||
|
|
||||||
## Keepalive
|
A ping request comes from the Client or Iota and the Omikron returns a pong answer.
|
||||||
|
The ping request should contain the last Client or Iota ping and the pong answer will contain the last ping of the Omikron.****
|
||||||
|
|
||||||
MTP handles protocol Ping and Pong frames through the connection dispatcher.
|
### Iota
|
||||||
Application handlers must not treat keepalive frames as Relay traffic. See the
|
|
||||||
repository's `mtp-docs/CONNECTIONS.md` and `mtp-docs/PROTOCOL-REFERENCE.md`
|
|
||||||
files.
|
|
||||||
|
|
||||||
## Related API documentation
|
#### REQ:
|
||||||
|
|
||||||
- [Calling](./calling)
|
```json
|
||||||
- [User management](./user-management)
|
{
|
||||||
- `mtp-docs/CONNECTOR.md`
|
"id": "<uuid>",
|
||||||
- `mtp-docs/NATIVE-CLIENT.md`
|
"type": "ping",
|
||||||
- `mtp-docs/NATIVE-HOST-WEB-SERVER.md`
|
"data": {
|
||||||
|
"last_ping": long
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### RES:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "<uuid>",
|
||||||
|
"type": "pong",
|
||||||
|
"data": {
|
||||||
|
"user_ping": {
|
||||||
|
"<user-id>": long,
|
||||||
|
"<user-id>": long
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Client
|
||||||
|
|
||||||
|
#### `REQ:`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "<uuid>",
|
||||||
|
"type": "ping",
|
||||||
|
"data": {
|
||||||
|
"last_ping": long
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### `RES:`
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "<uuid>",
|
||||||
|
"type": "pong",
|
||||||
|
"data": {
|
||||||
|
"last_ping": long
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## User Online Status
|
||||||
|
|
||||||
|
### Set Client Status
|
||||||
|
|
||||||
|
The client can change their online status by sending a `client_changed` message.
|
||||||
|
Supported status values: `user_online`, `user_offline`, `user_dnd`, `user_idle`, `user_wc`, `user_invisible`.
|
||||||
|
|
||||||
|
When `user_invisible` is set, the user remains connected and can send/receive messages, but appears as `user_offline` to all other users.
|
||||||
|
|
||||||
|
#### `REQ` (Client → Omikron):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "<uuid>",
|
||||||
|
"type": "client_changed",
|
||||||
|
"data": {
|
||||||
|
"user_state": "<status>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Online Status Notifications
|
||||||
|
|
||||||
|
When a connected user changes their status, interested clients receive a notification:
|
||||||
|
|
||||||
|
#### `EVENT` (Omikron → Client):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"type": "client_changed",
|
||||||
|
"data": {
|
||||||
|
"user_id": "<user-id>",
|
||||||
|
"user_state": "<status>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Online Status in User Data
|
||||||
|
|
||||||
|
When fetching another user's profile via `get_user_data`, their online status is included in the response. Invisible users are reported as `user_offline`.
|
||||||
|
|
||||||
|
#### `RES` (Omikron → Client, field in `get_user_data`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "<uuid>",
|
||||||
|
"type": "get_user_data",
|
||||||
|
"data": {
|
||||||
|
"user_id": long,
|
||||||
|
"username": "<string>",
|
||||||
|
"display": "<string>",
|
||||||
|
"public_key": "<base64>",
|
||||||
|
"iota_id": long,
|
||||||
|
"online_status": "<status>",
|
||||||
|
"omikron_id": long,
|
||||||
|
"omikron_connections": [long, ...],
|
||||||
|
"sub_level": long,
|
||||||
|
"sub_end": long,
|
||||||
|
"about": "<string>?",
|
||||||
|
"avatar": "<base64>?",
|
||||||
|
"status": "<string>?"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue