Skip to main content

Overview

The Advanced iMessage Kit SDK uses WebSocket-based real-time events to notify you of incoming messages, status updates, and other chat activities.

Basic Setup

1

Initialize the SDK

Create an SDK instance with your server URL and API key.
import { AdvancedIMessageKit } from "@photon-ai/advanced-imessage-kit";

const sdk = new AdvancedIMessageKit({
  serverUrl: "http://localhost:1234",
  apiKey: "your-api-key"
});
2

Listen for the ready event

Wait for the SDK to connect and authenticate before setting up other listeners.
sdk.on("ready", () => {
  console.log("SDK connected and ready!");
});
3

Connect to the server

Establish the WebSocket connection.
await sdk.connect();

Simple Message Listener

The most basic way to receive messages is using the new-message event.
import { AdvancedIMessageKit } from "@photon-ai/advanced-imessage-kit";
import { isPollMessage, getPollSummary } from "advanced-imessage-kit/lib/poll-utils";

const sdk = new AdvancedIMessageKit({
  serverUrl: "http://localhost:1234",
  apiKey: "your-api-key"
});

sdk.on("ready", () => {
  console.log("Ready to receive messages");
});

sdk.on("new-message", (message) => {
  const sender = message.handle?.address ?? "unknown";
  
  // Handle polls differently
  if (isPollMessage(message)) {
    const pollSummary = getPollSummary(message);
    console.log(`${sender}: ${pollSummary}`);
  } else {
    console.log(`${sender}: ${message.text ?? "(no text)"}`);
  }
});

sdk.on("error", (error) => {
  console.error("Error:", error.message);
});

await sdk.connect();
The new-message event fires for ALL incoming messages, including those you send from other devices.

Advanced Message Handling

Implement more sophisticated message handling with filtering and detailed logging.
sdk.on("ready", async () => {
  try {
    // Get chat list on startup
    const chatList = await sdk.chats.getChats();
    console.log(`Monitoring ${chatList.length} chats`);
    
    chatList.slice(0, 10).forEach((chat, i) => {
      console.log(`  ${i + 1}. ${chat.displayName || chat.chatIdentifier}`);
    });

    // Get server info
    const serverInfo = await sdk.server.getServerInfo();
    console.log(`Server version: ${serverInfo.version}`);
  } catch (error) {
    console.error("Setup failed:", error);
  }
});

sdk.on("new-message", (message) => {
  // Parse poll messages
  if (isPollMessage(message)) {
    if (isPollVote(message)) {
      const voteData = parsePollVotes(message);
      const votesWithText = voteData?.votes.map(v => ({
        ...v,
        optionText: getOptionTextById(v.voteOptionIdentifier) ?? null
      }));
      console.log(JSON.stringify({ ...message, parsedVotes: votesWithText }, null, 2));
    } else {
      const pollData = parsePollDefinition(message);
      console.log(JSON.stringify({ ...message, parsedPoll: pollData }, null, 2));
    }
  } else {
    console.log(JSON.stringify(message, null, 2));
  }
});

Filtering Messages

Filter messages by sender, content, or chat.
sdk.on("new-message", (message) => {
  // Only process messages from a specific number
  if (message.handle?.address === "+1234567890") {
    console.log(`Message from watched contact: ${message.text}`);
  }
});

Auto-Reply Bot

Create a simple auto-reply bot that responds to incoming messages.
sdk.on("ready", () => {
  console.log("Auto-reply bot is running...");
});

sdk.on("new-message", async (message) => {
  // Don't reply to our own messages
  if (message.isFromMe) return;
  
  // Don't reply to empty messages
  if (!message.text) return;
  
  const text = message.text.toLowerCase();
  const sender = message.handle?.address;
  
  // Only reply to messages containing "hey"
  if (text.includes("hey")) {
    console.log(`Received "hey" from ${sender}`);
    
    // Get the chat GUID to reply to
    const chatGuid = message.chats?.[0]?.guid;
    if (!chatGuid) return;
    
    try {
      const reply = await sdk.messages.sendMessage({
        chatGuid,
        message: "Hey! I'm an auto-reply bot."
      });
      
      console.log(`Sent auto-reply: ${reply.guid}`);
    } catch (error) {
      console.error("Failed to send auto-reply:", error);
    }
  }
});

await sdk.connect();
Be careful with auto-reply bots to avoid creating message loops. Always check isFromMe to prevent replying to your own messages.

Message Status Updates

Track message delivery and read status with the updated-message event.
sdk.on("updated-message", (message) => {
  const status = message.dateRead 
    ? "read" 
    : message.dateDelivered 
    ? "delivered" 
    : "sent";
  
  console.log(`Message ${message.guid}: ${status}`);
  
  if (message.dateRead) {
    const readTime = new Date(message.dateRead);
    console.log(`Read at: ${readTime.toLocaleString()}`);
  }
});

Typing Indicators

Receive notifications when someone is typing.
sdk.on("typing-indicator", (data) => {
  console.log(`${data.display} is typing...`);
});
Typing indicators are ephemeral and don’t indicate when typing stops.

Message History

Fetch historical messages from a chat.
sdk.on("ready", async () => {
  const CHAT_GUID = "iMessage;-;+1234567890";
  
  try {
    // Get last 50 messages
    const messages = await sdk.messages.getMessages({
      chatGuid: CHAT_GUID,
      limit: 50,
      sort: "DESC" // Most recent first
    });
    
    console.log(`Found ${messages.length} messages`);
    
    messages.forEach(msg => {
      const sender = msg.isFromMe ? "Me" : msg.handle?.address;
      const time = new Date(msg.dateCreated).toLocaleString();
      console.log(`[${time}] ${sender}: ${msg.text}`);
    });
  } catch (error) {
    console.error("Failed to fetch messages:", error);
  }
});

Filtering by Sender

Receive messages only from specific contacts.
const MONITORED_CONTACTS = ["+1234567890", "+0987654321"];

sdk.on("new-message", async (message) => {
  if (message.isFromMe) return;
  
  const sender = message.handle?.address;
  
  // Only process messages from monitored contacts
  if (sender && MONITORED_CONTACTS.includes(sender)) {
    console.log(`Message from ${sender}: ${message.text}`);
    
    // Fetch full message details if needed
    try {
      const fullMessage = await sdk.messages.getMessage(message.guid, {
        with: ["chat", "handle", "attachment"]
      });
      
      console.log("Full message data:", fullMessage);
    } catch (error) {
      console.error("Failed to fetch message details:", error);
    }
  }
});

Graceful Shutdown

Properly close the connection when your application exits.
process.on("SIGINT", async () => {
  console.log("\nShutting down...");
  await sdk.close();
  process.exit(0);
});

process.on("SIGTERM", async () => {
  console.log("\nShutting down...");
  await sdk.close();
  process.exit(0);
});

Connection Management

Handle connection errors and disconnections.
sdk.on("disconnect", () => {
  console.log("Disconnected from server");
});

sdk.on("error", (error) => {
  console.error("SDK error:", error.message);
});

// The SDK automatically reconnects, but you can monitor reconnection attempts
sdk.socket.io.on("reconnect_attempt", (attempt) => {
  console.log(`Reconnection attempt #${attempt}`);
});

sdk.socket.io.on("reconnect", (attempt) => {
  console.log(`Reconnected after ${attempt} attempt(s)`);
});
The SDK includes automatic reconnection with exponential backoff. It will keep trying to reconnect indefinitely.

Next Steps

Real-Time Events

Comprehensive guide to all event types

Managing Chats

Learn how to manage chats and groups

Build docs developers (and LLMs) love