The inbound feed

Every provider merges into one async iterable:
for await (const [space, message] of app.messages) {
  console.log(message.platform, message.sender.id, message.content);
}
Filter by platform, content type, or sender:
for await (const [space, message] of app.messages) {
  if (message.isFromMe) continue;
  if (message.platform !== "imessage") continue;
  if (message.content.type !== "text") continue;

  await space.send(`you said: ${message.content.text}`);
}

Message shape

interface Message {
  platform: "imessage" | "terminal" | "whatsapp" | "whatsapp_business";
  content: MessageContent;
  sender: User;
  timestamp: Date;
  guid?: string;
  isFromMe: boolean;
  group?: GroupContext;
}

Text content

if (message.content.type === "text") {
  const body = message.content.text;
}

App card content

Inbound mini-app submissions arrive as app content:
if (message.content.type === "app") {
  const { appId, data, caption } = message.content;
}

Flow content

Server-driven flow submissions:
if (message.content.type === "flow") {
  const { state, screen, done, payment } = message.content;
}

Group context

When a message arrives from a group chat, message.group identifies the chat and submitting participant:
if (message.group?.isGroup) {
  const who = message.group.participant.id;
  const chatId = message.group.chatId;
}

Replying

Thread off the inbound message when the platform provides a guid:
if (message.guid) {
  await space.reply(message.guid, "On it.");
}

Send receipts

Outbound sends return a receipt with the platform-assigned guid when available:
const receipt = await space.send("hello");
console.log(receipt.guid, receipt.sentAt);