QuIXI Message Queue Topics
QuIXI acts as a bridge between the Ixian P2P network and traditional message queue systems (MQTT, RabbitMQ). When QuIXI receives Ixian protocol messages, it publishes them to specific topics that external applications can subscribe to.
This allows IoT devices, AI agents, and legacy systems to interact with the Ixian network without implementing the full P2P protocol.
Message Format
All messages published to MQ topics are StreamMessage objects serialized according to the Ixian protocol. The message contains:
sender: The Ixian wallet address of the senderrecipient: The Ixian wallet address of the recipient (QuIXI's address)data: TheSpixiMessagepayload (nested protocol message)timestamp: When the message was sentid: Unique message identifier
Topic Categories
Topics are organized into three categories:
Protocol Messages
Streaming protocol messages received from Ixian peers. These correspond to SpixiMessage types.
Misc Messages
Internal QuIXI events not directly tied to incoming protocol messages (e.g., friend status updates, transaction confirmations).
Raw Out
Low-level topics for debugging and advanced integrations.
Protocol Message Topics
Chat & Messaging
Chat
Message Code: 1 (SpixiMessageCode.chat)
Receives text chat messages from contacts.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 1,
"channel": 0,
"data": "UTF-8 encoded chat message"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.type field corresponds to the SpixiMessageCode (1 for chat). The outer type field (2) indicates this is a StreamMessageCode message.
Use Case: Build chat bots, log conversations, implement chatbot responses.
Nick
Message Code: 2 (SpixiMessageCode.nick)
Receives nickname updates from contacts.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 2,
"channel": 0,
"data": "UTF-8 encoded nickname"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Use Case: Track contact name changes, update local directories.
MsgRead
Message Code: 8 (SpixiMessageCode.msgRead)
Notification that a message has been read by the recipient.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 8,
"channel": 0,
"data": "base64_message_id"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains the base64-encoded message ID that was read.
Use Case: Implement read receipts, message delivery tracking.
MsgReceived
Message Code: 9 (SpixiMessageCode.msgReceived)
Notification that a message has been received (but not necessarily read).
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 9,
"channel": 0,
"data": "base64_message_id"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains the base64-encoded ID of the message that was received.
Use Case: Delivery confirmation, message status updates.
MsgDelete
Message Code: 33 (SpixiMessageCode.msgDelete)
Notification that a message has been deleted by the sender.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 33,
"channel": 0,
"data": "base64_message_id"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains the base64-encoded ID of the message to delete.
Use Case: Synchronize message deletions across systems.
MsgReaction
Message Code: 34 (SpixiMessageCode.msgReaction)
Receives emoji reactions to messages.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 34,
"channel": 0,
"data": {
"msgId": "base64_message_id",
"reaction": "emoji_string"
}
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is deserialized as a ReactionMessage object containing msgId (base64) and reaction (string).
Use Case: Display reactions, track engagement.
MsgTyping
Message Code: 35 (SpixiMessageCode.msgTyping)
Notification that a contact is typing.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 35,
"channel": 0,
"data": "AQ=="
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": false,
"version": 1
}
Note: The data.data field is typically a single byte indicator (base64-encoded). Non-zero means typing, zero means stopped typing.
Use Case: Real-time typing indicators in chat UIs.
Contact Management
RequestAdd2
Message Code: 40 (SpixiMessageCode.requestAdd2, SpixiMessageCode.requestAdd)
Receives incoming contact requests.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 40,
"channel": 0,
"data": {
"maxProtocolVersion": 2,
"pubKey": "base64_public_key"
}
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is deserialized as a RequestAdd2Message object. For requestAdd (code 3), the data is raw bytes.
Use Case: Auto-accept contacts, implement contact approval workflows.
AcceptAdd2
Message Code: 41 (SpixiMessageCode.acceptAdd2, SpixiMessageCode.acceptAdd)
Receives contact acceptance confirmations.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 41,
"channel": 0,
"data": {
"version": 2,
"rsaPubKey": "base64_rsa_public_key",
"ecdhPubKey": "base64_ecdh_public_key",
"mlkemPubKey": "base64_kyber_public_key",
"aesSalt": "base64_aes_salt",
"capabilities": 15
}
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is deserialized as an AcceptAdd2Message object containing cryptographic keys for establishing a secure channel. The capabilities field is a bitfield: 1=Incoming, 2=Outgoing, 4=IPN, 8=Apps.
Use Case: Complete contact exchange, establish encrypted channels.
LeaveConfirmed
Message Code: 38 (SpixiMessageCode.leaveConfirmed)
Notification that a contact has removed you or left a conversation.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 38,
"channel": 0,
"data": ""
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is empty (raw bytes).
Use Case: Clean up contact lists, handle contact removals.
Avatar
Message Code: 24 (SpixiMessageCode.avatar)
Receives avatar/profile picture updates (< 500KB).
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 24,
"channel": 0,
"data": "base64_image_bytes"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains the raw image bytes (base64-encoded). QuIXI only publishes this message if the avatar is smaller than 500KB.
Use Case: Display profile pictures, sync contact avatars.
Financial Transactions
SentFunds
Message Code: 5 (SpixiMessageCode.sentFunds)
Notification that someone has sent you IXI tokens.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 5,
"channel": 0,
"data": "base64_transaction_id"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains the raw transaction ID bytes (base64-encoded). QuIXI automatically broadcasts a getTransaction request to verify the transaction on the blockchain.
Use Case: Payment processing, automatic fund acknowledgment, invoice tracking.
RequestFunds
Message Code: 6 (SpixiMessageCode.requestFunds)
Receives payment requests from contacts.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 6,
"channel": 0,
"data": "amount_in_ixi_string"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is a UTF-8 string representing the amount in IXI (e.g., "10.5").
Use Case: Payment reminders, invoice systems, automated payment approvals.
RequestFundsResponse
Message Code: 18 (SpixiMessageCode.requestFundsResponse)
Response to a payment request (accept/decline).
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 18,
"channel": 0,
"data": "base64_response_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes. The application should parse this based on the specific response format.
Use Case: Payment confirmation tracking, accounting systems.
File Transfers
FileHeader
Message Code: 12 (SpixiMessageCode.fileHeader)
Initial file transfer metadata.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 12,
"channel": 0,
"data": "base64_file_header_bytes"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract file UID, name, size, and hash.
Use Case: Receive file offers, implement file filtering.
AcceptFile
Message Code: 13 (SpixiMessageCode.acceptFile)
Notification that a file offer was accepted.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 13,
"channel": 0,
"data": "base64_file_uid"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains the file UID bytes (base64-encoded).
Use Case: Start file transfer, allocate storage.
RequestFileData
Message Code: 11 (SpixiMessageCode.requestFileData)
Request for specific file chunks.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 11,
"channel": 0,
"data": "base64_request_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract file UID and chunk number.
Use Case: Resume file transfers, implement chunk-based delivery.
FileData
Message Code: 10 (SpixiMessageCode.fileData)
Receives file data chunks.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 10,
"channel": 0,
"data": "base64_file_chunk_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract file UID, chunk number, and actual chunk data.
Use Case: Reconstruct files, stream data to storage.
FileFullyReceived
Message Code: 23 (SpixiMessageCode.fileFullyReceived)
Notification that a file transfer completed successfully.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 23,
"channel": 0,
"data": "base64_file_uid"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains the file UID bytes (base64-encoded).
Use Case: Verify file completeness, trigger post-processing.
Mini-Apps
AppRequest
Message Code: 22 (SpixiMessageCode.appRequest)
Invitation to start a Mini-App session.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 22,
"channel": 0,
"data": "base64_app_request_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract session ID, app ID, and initialization data.
Use Case: Launch apps, accept/reject app invitations, bot integrations.
AppRequestAccept
Message Code: 28 (SpixiMessageCode.appRequestAccept)
Acceptance of an app session invitation.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 28,
"channel": 0,
"data": "base64_accept_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract session ID and optional response data.
Use Case: Begin app session, exchange initial state.
AppRequestReject
Message Code: 29 (SpixiMessageCode.appRequestReject)
Rejection of an app session invitation.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 29,
"channel": 0,
"data": "base64_reject_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract session ID and optional reason.
Use Case: Handle declined invitations, clean up resources.
AppRequestError
Message Code: 30 (SpixiMessageCode.appRequestError)
Error during app session initialization.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 30,
"channel": 0,
"data": "base64_error_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract session ID, error code, and error message.
Use Case: Error handling, diagnostics, app availability checks.
AppData
Message Code: 21 (SpixiMessageCode.appData)
Application-specific data for active sessions.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 21,
"channel": 0,
"data": {
"sessionId": "base64_session_id",
"data": "base64_app_payload",
"appId": "com.company.appname"
}
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is deserialized as an AppDataMessage object containing session ID, payload data, and optionally an app ID.
Use Case: Real-time app communication, game state updates, collaborative editing.
AppEndSession
Message Code: 31 (SpixiMessageCode.appEndSession)
Notification that an app session has ended.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 31,
"channel": 0,
"data": "base64_end_session_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract session ID and optional final data.
Use Case: Clean up session resources, save final state.
GetAppProtocols
Message Code: 43 (SpixiMessageCode.getAppProtocols)
Request for supported app protocols.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 43,
"channel": 0,
"data": ""
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is empty (raw bytes).
Use Case: Capability discovery, protocol negotiation.
AppProtocols
Message Code: 44 (SpixiMessageCode.appProtocols)
List of supported app protocols.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 44,
"channel": 0,
"data": {
"protocolIds": ["base64_protocol_id_1", "base64_protocol_id_2"]
}
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is deserialized as an AppProtocolsMessage object containing a list of protocol IDs (each base64-encoded).
Use Case: Feature negotiation, compatibility checks.
AppProtocolData
Message Code: 45 (SpixiMessageCode.appProtocolData)
Advanced protocol-specific app data.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 45,
"channel": 0,
"data": {
"sessionId": "base64_session_id",
"data": "base64_protocol_payload",
"appId": "com.company.appname"
}
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is deserialized as an AppDataMessage object (same structure as AppData).
Use Case: Advanced Mini-App features, protocol extensions.
Bots
AcceptAddBot
Message Code: 19 (SpixiMessageCode.acceptAddBot)
Acceptance of a bot contact request.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 19,
"channel": 0,
"data": "base64_bot_data"
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field contains raw bytes that need to be parsed to extract bot-specific information.
Use Case: Bot onboarding, service registration.
BotAction
Message Code: 32 (SpixiMessageCode.botAction)
Bot-specific commands or actions.
StreamMessage Structure:
{
"type": 2,
"sender": "base58_sender_address",
"recipient": "base58_recipient_address",
"data": {
"type": 32,
"channel": 0,
"data": {
"action": 0,
"data": "base64_action_data"
}
},
"encryptionType": 4,
"id": "message_id_base64",
"timestamp": 1234567890,
"requireRcvConfirmation": true,
"version": 1
}
Note: The data.data field is deserialized as a SpixiBotAction object. The action field is a SpixiBotActionCode enum (0=getInfo, 1=info, 2=getChannels, 3=channel, 4=getUsers, 5=user, etc.).
Use Case: Bot commands, automated workflows, service invocation.
Misc Message Topics
FriendStatusUpdate
Internal QuIXI event when a contact's online status changes.
Data Structure:
{
"address": "base58_address",
"online": true,
"lastSeen": 1234567890
}
Use Case: Presence indicators, availability tracking.
MessageSent
Internal QuIXI event confirming a message was successfully sent.
Data Structure:
{
"messageId": "sent_message_id",
"recipient": "base58_address",
"timestamp": 1234567890
}
Use Case: Delivery confirmation, message logging.
MessageExpired
Internal QuIXI event when a message fails to deliver within the TTL.
Data Structure:
{
"messageId": "expired_message_id",
"recipient": "base58_address",
"reason": "timeout"
}
Use Case: Retry logic, failure notifications.
TransactionStatusUpdate
Internal QuIXI event when a blockchain transaction status changes.
Data Structure:
{
"txId": "transaction_id",
"status": "confirmed",
"blockHeight": 123456
}
Use Case: Payment confirmation, transaction tracking.
Configuration
To enable message queue integration in QuIXI, configure ixian.cfg:
# Message queue driver: mqtt or rabbitmq
mqDriver = mqtt
# MQTT settings
mqHost = localhost
mqPort = 1883
# Client nickname
name = My QuIXI
Example: MQTT Subscription
import paho.mqtt.client as mqtt
import json
def on_connect(client, userdata, flags, rc):
print("Connected to QuIXI MQTT broker")
# Subscribe to chat messages
client.subscribe("Chat")
# Subscribe to payment notifications
client.subscribe("SentFunds")
def on_message(client, userdata, msg):
message = json.loads(msg.payload)
print(f"Received on {msg.topic}: {message}")
if msg.topic == "Chat":
sender = message['sender']
text = message['data']
print(f"Chat from {sender}: {text}")
elif msg.topic == "SentFunds":
sender = message['sender']
tx_id = message['data']
print(f"Payment received from {sender}: {tx_id}")
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect("localhost", 1883, 60)
client.loop_forever()
Example: RabbitMQ Subscription
const amqp = require('amqplib');
async function subscribeToQuIXI() {
const connection = await amqp.connect('amqp://localhost');
const channel = await connection.createChannel();
// Subscribe to app requests
await channel.assertQueue('AppRequest');
channel.consume('AppRequest', (msg) => {
const message = JSON.parse(msg.content.toString());
console.log('App Request:', message);
// Process app request
const { sender, data } = message;
const { sessionId, appId } = data;
console.log(`App ${appId} requested by ${sender}`);
channel.ack(msg);
});
}
subscribeToQuIXI().catch(console.error);
Best Practices
- Topic Filtering: Only subscribe to topics your application needs to reduce overhead
- Message Validation: Always validate sender addresses and message signatures
- Idempotency: Messages may be delivered multiple times; implement idempotent handling
- Error Handling: Gracefully handle malformed messages or missing fields
- Rate Limiting: Implement rate limits on message processing to prevent abuse
- Replay Position: Use appropriate replay strategies (FromLast, FromBeginning, FromSpecific) based on your use case