> ## Documentation Index
> Fetch the complete documentation index at: https://docs.photon.codes/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Interactive Messages

> Buttons, lists, product messages, and flows

export const TypeTooltip = ({name, type, children}) => {
  const [visible, setVisible] = React.useState(false);
  const [pos, setPos] = React.useState({
    top: 0,
    left: 0
  });
  const triggerRef = React.useRef(null);
  const show = () => {
    if (triggerRef.current) {
      const rect = triggerRef.current.getBoundingClientRect();
      setPos({
        top: rect.bottom + 6,
        left: rect.left
      });
    }
    setVisible(true);
  };
  const hide = () => setVisible(false);
  return <>
      <span ref={triggerRef} onMouseEnter={show} onMouseLeave={hide} style={{
    cursor: "pointer",
    position: "relative",
    display: "inline"
  }}>
        {children || <code>{name}</code>}
      </span>
      {visible && <span style={{
    position: "fixed",
    top: pos.top,
    left: pos.left,
    zIndex: 9999,
    padding: "8px 12px",
    borderRadius: "8px",
    fontSize: "13px",
    lineHeight: "1.5",
    fontFamily: "'Azeret Mono', monospace",
    whiteSpace: "pre",
    backgroundColor: "var(--tw-prose-pre-bg, #1e1e1e)",
    color: "var(--tw-prose-pre-code, #e5e5e5)",
    border: "1px solid var(--border, rgba(128,128,128,0.2))",
    boxShadow: "0 4px 16px rgba(0,0,0,0.3)",
    pointerEvents: "none"
  }}>
          {type}
        </span>}
    </>;
};

Interactive messages let the recipient tap a button, pick from a list, or launch a WhatsApp Flow instead of typing a reply. Pass the result to `send` under the `interactive` key — the SDK ships with builders so you rarely construct the raw <TypeTooltip name="InteractiveInput" type={`interface InteractiveInput {
readonly action?: InteractiveActionInput;
readonly body?: string;
readonly footer?: string;
readonly header?: InteractiveHeaderInput;
readonly type: string;
}`} /> by hand.

```ts theme={null}
import { buttons, button } from "@photon-ai/whatsapp-business";

await client.messages.send({
  to: "+15551234567",
  interactive: buttons(
    "How would you like to continue?",
    button("confirm", "Confirm order"),
    button("cancel", "Cancel"),
  ),
});
```

## Reply buttons

Up to three buttons, each with an ID you'll receive back on tap:

```ts theme={null}
import { buttons, button } from "@photon-ai/whatsapp-business";

const msg = buttons(
  "Your package is ready for pickup. What now?",
  button("pickup_now", "Pick up now"),
  button("reschedule", "Reschedule"),
  button("hold", "Hold 3 days"),
);

await client.messages.send({ to, interactive: msg });
```

When the user taps, you'll receive an `interactive` event:

```ts theme={null}
for await (const event of client.events.subscribe()) {
  if (event.type !== "message") continue;
  if (event.message.content.type !== "interactive") continue;

  const { interactive } = event.message.content;
  if (interactive.type === "button_reply") {
    console.log(interactive.reply.id);    // "pickup_now"
    console.log(interactive.reply.title); // "Pick up now"
  }
}
```

## Lists

Lists support up to ten rows grouped into sections. The builder is immutable — chain `.section()` to add content:

```ts theme={null}
import { list } from "@photon-ai/whatsapp-business";

const menu = list("Pick a drink", "Open menu")
  .section("Hot", [
    { id: "coffee", title: "Coffee", description: "House blend" },
    { id: "tea", title: "Tea" },
  ])
  .section("Cold", [
    { id: "iced", title: "Iced coffee" },
    { id: "smoothie", title: "Smoothie" },
  ])
  .withHeader({ type: "text", text: "Menu" })
  .withFooter("Ships in 5 minutes");

await client.messages.send({ to, interactive: menu });
```

List taps arrive as `list_reply`:

```ts theme={null}
if (interactive.type === "list_reply") {
  console.log(interactive.reply.id);          // "coffee"
  console.log(interactive.reply.description); // "House blend"
}
```

## Product and product list

Single product — opens the catalog page:

```ts theme={null}
import { product } from "@photon-ai/whatsapp-business";

await client.messages.send({
  to,
  interactive: product("catalog-123", "SKU-456"),
});
```

Multi-product, grouped by category:

```ts theme={null}
import { productList } from "@photon-ai/whatsapp-business";

const catalog = productList("catalog-123", "Spring collection")
  .section("New arrivals", ["SKU-100", "SKU-101", "SKU-102"])
  .section("Back in stock", ["SKU-050", "SKU-051"])
  .withFooter("Free shipping on orders over $50");

await client.messages.send({ to, interactive: catalog });
```

Orders placed through a product message arrive as an `order` inbound content type — see [Events](/advanced-kits/whatsapp/events).

## Flows

Launch a WhatsApp Flow (a structured form experience) with the `flow` helper:

```ts theme={null}
import { flow } from "@photon-ai/whatsapp-business";

await client.messages.send({
  to,
  interactive: flow({
    body: "Book an appointment",
    parameters: {
      flowId: "1234567890",
      flowToken: "your-flow-token",
      flowCta: "Book now",
      flowMessageVersion: "3",
      flowAction: "navigate",
      flowActionPayloadJson: JSON.stringify({ screen: "START" }),
    },
  }),
});
```

Flow submissions arrive as `nfm_reply`:

```ts theme={null}
if (interactive.type === "nfm_reply") {
  const data = JSON.parse(interactive.reply.responseJson);
  // handle the structured form response
}
```

## Building raw interactive messages

If you need a shape the builders don't cover, pass a plain <TypeTooltip name="InteractiveInput" type={`interface InteractiveInput {
readonly action?: InteractiveActionInput;
readonly body?: string;
readonly footer?: string;
readonly header?: InteractiveHeaderInput;
readonly type: string;
}`} />:

```ts theme={null}
await client.messages.send({
  to,
  interactive: {
    type: "button",
    body: "...",
    action: {
      buttons: [{ type: "reply", reply: { id: "a", title: "A" } }],
    },
  },
});
```

The builders are thin wrappers — they exist to catch typos and make common shapes ergonomic, not to restrict what you can send.
