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.

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, V3Client } from "@xmtp/message-kit";
import express from "express";
import { checkNft } from "../plugins/alchemy.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 },
    },
    client,
  } = context;
 
  if (skill === "create") {
    const group = await context.xmtp.createGroup(
      client,
      sender.address,
      client.accountAddress,
    );
 
    await context.send(
      `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.`,
    );
    return;
  } else {
    await context.send(
      "👋 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!",
    );
  }
}
 
export function startGatedGroupServer(client: V3Client) {
  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 {
        const added = await client.conversations.getConversationById(groupId);
        if (added) {
          added.addMembers([walletAddress]);
          console.log(`Added wallet address: ${walletAddress} to the group`);
          return "success";
        } else {
          return "error";
        }
      } 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}>`,
    );
  });
}