Skip to content

Gated group

How to create a gated group chat through an admin agent.

Create the group

Send this message to the bot to kickstart the creation of the group.

create group

The bot will create a private group where you and the bot are the admins.Then will provide some information like:

Group created!
- ID: {groupId}
- Group Frame URL: https://converse.xyz/group/{groupId}:
- This url will deelink to the group inside Converse
- Once in the other group you can share the invite with your friends.

For more abstraction use the Xmtp Groups plugin.

Start the server

The code for the server is the following:

src/index.ts
// [!include ~/../../templates/gated-group/src/index.ts:gated]

Endpoint

Once you start the server on your port 3000 by default you can ping this endpoint with the parameters

curl -X POST http://localhost:3000/add-wallet \
 -H "Content-Type: application/json" \
 -d '{"walletAddress": "0x93E2fc3e99dFb1238eB9e0eF2580EFC5809C7204", "groupId": "b9ab876c87ef3cf63b81c8d45c824fae"}'

Skill

The code for the skill is the following:

src/skills/gated.ts
import { Context, Skill } from "@xmtp/message-kit";
import express from "express";
import { Client } from "@xmtp/node-sdk";
import { checkNft } from "../plugins/alchemy.js";
import { addToGroup, createGroup } from "../plugins/xmtp-groups.js";
 
export const gated: Skill[] = [
  {
    skill: "create",
    examples: ["/create"],
    handler: handler,
    adminOnly: true,
    description: "Create a new group.",
  },
];
 
async function handler(context: Context) {
  const {
    message: {
      sender,
      content: { skill },
    },
    xmtp,
  } = context;
 
  if (skill === "create") {
    const group = await createGroup(xmtp.client, sender.address, xmtp.address);
 
    await context.send({
      message: `Group created!\n- ID: ${group?.id}\n- Group Frame URL: https://converse.xyz/group/${group?.id}: \n- This url will deelink to the group inside Converse\n- Once in the other group you can share the invite with your friends.`,
      originalMessage: context.message,
    });
    return;
  } else {
    await context.send({
      message:
        "👋 Welcome to the Gated Bot Group!\nTo get started, type /create to set up a new group. 🚀\nThis example will check if the user has a particular nft and add them to the group if they do.\nOnce your group is created, you'll receive a unique Group ID and URL.\nShare the URL with friends to invite them to join your group!",
      originalMessage: context.message,
    });
  }
}
 
export function startGatedGroupServer(client: Client) {
  async function addWalletToGroup(
    walletAddress: string,
    groupId: string,
  ): Promise<string> {
    const verified = await checkNft(walletAddress, "XMTPeople");
    if (!verified) {
      console.log("User cant be added to the group");
      return "not verified";
    } else {
      try {
        await addToGroup(groupId, client, walletAddress);
        return "success";
      } catch (error: any) {
        console.log(error.message);
        return "error";
      }
    }
  }
 
  // Endpoint to add wallet address to a group from an external source
  const app = express();
  app.use(express.json());
  app.post("/add-wallet", async (req, res) => {
    try {
      const { walletAddress, groupId } = req.body;
      const result = await addWalletToGroup(walletAddress, groupId);
      res.status(200).send(result);
    } catch (error: any) {
      res.status(400).send(error.message);
    }
  });
  // Start the servfalcheer
  const PORT = process.env.PORT || 3000;
  const url = process.env.URL || `http://localhost:${PORT}`;
  app.listen(PORT, () => {
    console.warn(
      `Use this endpoint to add a wallet to a group indicated by the groupId\n${url}/add-wallet <body: {walletAddress, groupId}>`,
    );
  });
}