# AI agent in group chat: build one for a crypto room

> Wire an AI agent into a Cherry group chat: bot keys and scopes, the update loop, the context a gated room hands the agent, and the guardrails.


Putting an AI agent in group chat is a wiring problem more than a modeling one: the model already reasons, and it has nowhere to speak. This guide connects one to a room on Cherry, the wallet-to-wallet messenger where people sign in with a wallet and join token-gated, NFT-gated and paid group chats. The [Cherry API and its bots](https://cherry.fun/learn/features/cherry-api-and-bots/) give your agent its own identity in the room, a stream of updates to react to, and one call to post back. The members on the other side are wallets, and that changes both what the agent can do and what it must refuse.

## Before you start

You need four things, and none of them cost anything.

- A wallet and a project in [Cherry Portal](https://cherry.fun/learn/guides/cherry-portal-for-developers/). Sign-in is Sign In With Solana: the wallet signs a message, nothing goes on-chain.
- A bot inside that project, with a bot key (`cherry_bot_...`). Bot keys carry the `bots:*` scopes. Project keys (`cherry_sk_...`) carry the Apps API scopes and manage rooms your project owns. Each key is one opaque token, shown once, and it belongs on your server.
- A model you can call from a backend, plus somewhere to run a long-lived process.
- A room for the agent to live in: one your project created, one you own, or a community whose owner agrees to add your bot.

## What an AI agent in group chat gets from the room

A Cherry room answers three questions the agent would otherwise have to ask: who is allowed in, who outranks whom, and what the room has already settled.

Membership is the holder check. In a [token-gated room](https://cherry.fun/learn/features/token-gated-chat/) the chain was checked before the member arrived, and Cherry keeps re-checking in the background, so a wallet that sells is paywalled. Everyone your agent is talking to either passed the rule or was vouched for by an admin, which means the agent never has to run its own eligibility logic, and never has to ask a member to prove anything.

Roles are the second layer: owner, admin, moderator, member. They are the natural gate for the expensive actions, so "summarize the last hour" can be an admin-only request while "what is the mint" stays open to everyone.

Pinned posts are the third. A room keeps up to 20 of them, and they are usually the rules, the official links and the answers the mods are tired of typing. That is the corpus your agent should answer from.

The Seeker Club, gated by a `.skr` domain, had 8,640 members in September 2026. In a room that size the same five questions arrive every hour, from people who each had to prove a holding to get in.

[Seeker Club on Cherry](https://chat.cherry.fun/@seekerclub)

One honest caveat before you build. Group chats on Cherry are not end-to-end encrypted, by design, so moderation and bots can work at all; that is the only reason your agent can read anything. [DMs are encrypted](https://cherry.fun/learn/features/encrypted-dms-no-phone-no-kyc/) with keys derived from each wallet, and no bot key opens them. An agent reads the rooms it belongs to and the DMs sent to the bot itself, and nothing else.

## Step 1: Create the bot and scope its key narrowly

An answering agent needs to hear and to speak. Grant it that and stop.

1. In the portal, open your project, create a bot, and give it a name and an avatar. Members see that name on every post, which is how they tell the agent apart from the admins.
2. Create a bot key under the bot's **Keys** section and tick the scopes it needs: `bots:updates:poll` for long polling or `bots:webhook:manage` for a webhook, plus `bots:groups:send` to post. Add `bots:interactive` only if replies carry buttons.
3. Leave `bots:groups:moderate` unticked. Step 2 explains why.

You know it worked when `GET /api/v1/bots/me` with the bot key returns the bot's wallet and exactly the scope list you ticked. Scopes are keyed per endpoint, so a call outside the list is refused before anything else happens.

## Step 2: Put the bot in the room, and no higher

A bot posts only into rooms it belongs to, so membership comes before any privilege. With a project key that has `members:invite`, invite the bot's wallet and activate it:

```bash
curl -X POST https://api.cherry.fun/api/v1/apps/groups/$ROOM_ID/members \
  -H "Authorization: Bearer $PROJECT_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"wallets\":[\"$BOT_WALLET\"],\"autoAccept\":true}"
```

In a room your project does not own, the owner or an admin invites the bot's wallet the same way a human joins.

Promote the agent to moderator only if deleting and muting is the job. Moderation passes two independent gates: the `bots:groups:moderate` scope authorizes the call, and the bot's in-room role authorizes acting on a person. An agent that answers questions clears neither and needs neither. Two invariants help if you do promote it. Bots cannot set roles, so the agent can never promote itself, and muting the bot stops it in one action, which makes mute a working kill switch. Cherry's own [anti-spam and moderation layers](https://cherry.fun/learn/features/anti-spam/) keep running either way.

You know it worked when the bot appears in the member list and a test post lands under its name.

## Step 3: Run the loop

The loop is three moves, repeated: receive updates, call your model, post back as the bot. Receive by long-polling the bot's update feed, or configure a webhook and let Cherry deliver. A bot in a room receives the messages that @-mention it. For the whole room, an owner or admin turns on Read all for your bot in the group's bot settings; without it the agent only hears the mentions. Each update names the room it came from and the wallet that sent it, so routing is already done for you.

```ts
const BOT = {
  Authorization: `Bearer ${process.env.CHERRY_BOT_KEY}`,
  'Content-Type': 'application/json',
};

// 1. receive
const res = await fetch('https://api.cherry.fun/api/v1/bots/getUpdates', { headers: BOT });
if (res.status === 429) {
  await sleep(Number(res.headers.get('Retry-After') ?? 60) * 1000);
  return;
}

for (const update of await res.json()) {
  // 2. think: your model, your prompt, the room's pinned posts as context
  const { roomId, reply } = await askYourModel(update);
  if (!reply) continue; // silence is a valid answer

  // 3. speak: the post carries the bot's name, not yours
  await fetch('https://api.cherry.fun/api/v1/bots/sendGroupMessage', {
    method: 'POST',
    headers: BOT,
    body: JSON.stringify({ roomId, content: reply }),
  });
}
```

Budget the reads. The published limits are 600 requests per minute and 50,000 per day per app as of September 2026, and every key in the project shares them, reads and writes alike. A tight poll in a busy room meets that ceiling long before your model bill does, so hold the long poll open and honor the `Retry-After` value on a 429 rather than retrying straight away.

You know it worked when a member asks something in the room and the answer arrives with the bot's avatar next to it.

## Step 4: Wire the first three actions

Three actions pay for themselves in a crypto room, and they are the ones to ship before anything cleverer.

- Answer from the pinned posts. Feed the pins into the system prompt and let the agent handle "what is the mint", "when is the call", "how do I get in". Refresh them on a schedule, because pins change.
- Summarize the last hour. Keep your own buffer from the update stream, or, in a room your project created, read its history with a project key and the `messages:read` scope, then post a digest when an admin asks for one.
- Flag a contract address for review. When a message carries an address, the agent posts a short notice and mentions a moderator. It reports that an address was posted; it does not rule on whether the token is good.

## Guardrails for a room full of wallets

Two rules matter more than the rest, and both exist because the agent speaks with a name the room trusts.

Never let the agent repeat a contract address a member handed it. A reply under the bot's avatar reads as vouched, and a scammer who gets the agent to echo their address has borrowed your credibility for free. Strip addresses from anything the agent quotes back and let it name the token in words.

Never let the agent sign. The signing scopes sit behind an admin review before they take effect, and an agent that answers questions has no business holding them. Keep the bot key server-side, rotate it the moment you suspect it leaked, and keep every model output on the posting path only.

## Troubleshooting

- The bot's post is refused: the bot is not an active member of that room. Invite its wallet and accept.
- The bot hears nothing but @-mentions: Read all is off for the bot in that room; an owner or admin turns it on.
- A moderation call is refused: check both gates, the scope on the key and the bot's role in that room. A plain member with the moderation scope is still denied.
- A call fails on scope: scopes are granted per key, not per project, so a second key does not inherit the first one's list.
- Requests start failing at peak: you hit the per-minute ceiling. Wait out the `Retry-After` value and widen the poll.
- The agent answers in a conversation you did not expect: a DM sent to the bot arrives on the same feed as room messages. Route by room before you reply.

## Related guides

- [Cherry API and bots](https://cherry.fun/learn/features/cherry-api-and-bots/) for the full surface, both key types and what each one can do.
- [Add chat to your dapp](https://cherry.fun/learn/guides/add-chat-to-your-dapp/) if the agent needs a chat window inside your own product.
- [Mini apps](https://cherry.fun/learn/features/mini-apps/) if it needs a screen of its own inside Cherry.

Start at [portal.cherry.fun](https://portal.cherry.fun) and create the project and the bot; both are free.

## FAQ

### Can an AI agent read a Cherry group chat?

Yes, if the bot is a member of that room. Group chats on Cherry are not end-to-end encrypted, by design, so bots and moderation can work. A bot key with the polling scope receives the messages that mention the bot; an owner or admin can turn on Read all for the bot to send it every message in the room.

### Can an agent read direct messages between two members?

No. DMs on Cherry are end-to-end encrypted with keys derived from each wallet, and no bot key opens them. The only DMs an agent sees are the ones sent to the bot itself.

### Does the agent need moderator rights to answer questions?

No. Posting needs the group-send scope and membership in the room. Moderation is a separate scope plus an in-room role, and an agent that only answers should hold neither.

### What are the Cherry API rate limits for a bot?

600 requests per minute and 50,000 per day per app as of September 2026, shared by every key in the project. Over the ceiling you get a 429 with a Retry-After header in seconds.

### Does it cost anything to run a bot on Cherry?

Free. Cherry Portal, the Cherry API, bots and the SDKs cost nothing to use.

## Sources

- [Cherry API authentication and key types](https://portal.cherry.fun/docs/api/authentication)
- [Cherry API scopes](https://portal.cherry.fun/docs/api/scopes)
- [Cherry API rate limits and errors](https://portal.cherry.fun/docs/api/rate-limits)
- [Cherry API endpoint reference](https://portal.cherry.fun/docs/api/reference)
- [Members and moderation](https://portal.cherry.fun/docs/api/members)
- [Guide: build a moderation bot](https://portal.cherry.fun/docs/guides/moderation-bot)

