Use cases

An iMessage Group Chat Assistant for Teams, Clubs and Communities

A team, club or community can add a ZeroSettle number to its iMessage group and let it do the coordinating: answer “where is practice?” from your schedule, collect RSVPs and drivers with Messages polls, and post reminders before every game, service or meeting. The hosted AI agent answers questions inside the group with no code, but its triggers never fire into a group, so scheduled reminders come from a small script of yours that sends with the group's chat_id. A group holds up to 31 people, every member must have agreed to hear from you, and one member's STOP blocks sends into the group until they are removed.

Key takeaways

  • Questions: the hosted AI agent answers in the group only when a message is meant for it, from a business context and files (like your season schedule) that you write and upload.
  • Reminders: agent triggers never fire into a group. Send reminders and RSVP polls from your own code on a schedule with POST /api/imessage/send and chat_id.
  • RSVPs: a poll in the group lets every member vote; voters lists each member's handle, so your code can see who hasn't answered.
  • Group or broadcast: use a group when members should see each other; use POST /api/imessage/broadcast for a club-wide announcement sent as separate 1:1 texts.
  • Rules: up to 31 people per group, consent from every member (from the parent or guardian for minors), and a STOP from any member blocks the group until they are removed.

What can an assistant do in a team or club group chat?

An assistant in a team or club group takes over the repeat work of the organizer: answering the same logistics questions, counting who is coming, reminding people the day before, and finding drivers. ZeroSettle gives your group a dedicated iMessage number, running on Apple hardware we operate for you in a server facility, that can start a group, send into it, read it and manage its members through the group chat API. Group chats are on for every number.

Who does each job matters, because the hosted AI agent and your own code have different powers in a group:

Group coordination jobs and who handles them (ZeroSettle API docs, checked November 2, 2026)
JobHosted AI agentYour code (API)
Answer “where is practice?”Yes, when the message is meant for itYes, with your own model behind a webhook
Reminder the night beforeNo: triggers never fire into a groupYes: send with chat_id on your schedule
RSVP or driver pollNo: it sends texts, so send polls from your codeYes: poll with chat_id
Read poll resultsPoll votes don't wake itYes: GET /api/imessage/messages/{id}/poll or the poll.voted webhook
Add or remove membersNoYes: POST /api/imessage/groups/update

Answering is either-or: inbound messages go to the hosted agent (managed_by: "zerosettle") or to your webhook (managed_by: "api"), not both. Sending is not: a number managed by the hosted agent still accepts your own POST /api/imessage/send calls, so a script can post reminders while the agent answers questions.

Building the assistant into your own app? How to build an AI assistant for iMessage group chats covers the code in depth.

How do you set up the group?

Set up the group by getting every member to text the number first, then starting the group from the number with one API call (or having an organizer add the number to a group that already exists). Texting first decides whether setup works on day one.

Here is why. When your number starts a group or adds someone, each member the number has never exchanged a message with counts as one new contact toward its day. Pro allows 5 new contacts a day per number; Growth allows 50 a day per number, but no more than 3 in any 15 minutes. So a group of 18 parents who have never texted the number won't fit on either plan in one call: the create call answers 429 new_contact_limit (with retry_after_s) and nothing is sent. People who text the number first never count, so the fix is to have them text first:

  1. Share the number with a reason to text it. In your registration email or sign-up page, put a pre-filled sms: link such as “Text HAWKS to join the team group”. The text-first playbook shows the pattern. Each person who texts is a known contact and has given you their number for this purpose. If the hosted agent is on, it answers each of those first texts 1:1 with your first_message (by default an opener for a sales lead), so set it to a short welcome such as “Thanks! You'll be added to the Hawks parents group this week.” before you share the number.
  2. Start the group with POST /api/imessage/groups: to is a list of 2 to 31 handles (your own number is added automatically, don't list it), text is the first message, and name (up to 60 characters) is optional. Store the chat_id it returns; it never changes, even when the group is renamed. Late joiners go in with POST /api/imessage/groups/update and add; anyone new to the number counts as a new contact on the day you add them.
  3. Or join an existing group. An organizer can add the number to the team's current iMessage group from their own iPhone. Groups the number is added to work the same way as ones it starts, and consent still has to cover every member.

Every member is checked before anything is sent, and one failed check stops the whole call: someone who texted STOP to any of your numbers returns 403 recipient_opted_out, and a new member who isn't on iMessage returns 422 not_on_imessage (both name the member in error.handle). An iMessage group reaches Apple devices only. ZeroSettle's SMS fallback is a limited pilot that ZeroSettle must enable per account, and group chats are not part of it, so members on Android need another channel, such as email or your app.

Make the first message say who is texting and what the group is for:

text
Welcome to the Northside Hawks U10 parents group! This is the team's
automated assistant. I'll post practice and game reminders here, and
you can ask me about times, fields and what to bring. Coach Dana is
in the group for anything about your player.

How does the assistant answer “where is practice?”

The hosted AI agent answers logistics questions in the group from the business context and files you give it, and stays quiet when members are talking to each other. In the docs' words, it “answers only when a message is meant for it or asks something it can help with, keeps it short, and stays silent when people are talking to each other.”

It reads the group's recent messages, each labeled with who wrote it, knows the group's name and members, and replies into the group with its typing bubble there, never in a 1:1 chat. Tapbacks, poll votes and group events (a rename, someone joining or leaving) don't wake it. Switch it on in the console's Messaging tab (step by step) and write a business context like this:

text
You are the assistant for the Northside Hawks U10 soccer team, in the
team parents' iMessage group. Answer questions about practice and game
times, fields, what to bring, and cancellations listed in the schedule
file. Keep answers to one or two short texts.

Practice: Tuesday and Friday, 5:30 to 6:45 PM, Riverbend Park, Field 3.
Bring: shin guards, cleats, a full water bottle, white and blue shirts.
Games: see the schedule file. Arrive 30 minutes early for warmups.

Never share a family's address or phone number. Never discuss a
child's playing time, position or behavior: say Coach Dana will talk
with them directly. Never announce a cancellation that isn't in the
schedule file. If asked, say you are the team's automated assistant.

Put the season schedule in a file instead of the context: the agent reads connected files (PDF with selectable text, Excel, CSV, Word or text, up to 10 MB each, at most 10) before every answer. Add them under Messaging → Connectors. When a field closes for rain, delete the old schedule file and add the updated one first, then post the news, so the agent's answers match.

Two defaults to change for a team number. The default follow-up trigger texts each 1:1 conversation the next morning if the person hasn't replied, which parents who only texted to join don't need: set triggers to [] or edit it. And the default business_context is a sales example for a made-up software business, so replace it before you switch the agent on.

  1. Thu 5:12 PM
  2. Marcus: is practice still at riverbend tomorrow?
  3. Team assistant: Yes, Friday 5:30 to 6:45 PM at Riverbend Park, Field 3. Shin guards and a full water bottle.
  4. Jen: can someone grab Leo tomorrow? stuck at work till 6
  5. Priya: I've got him, we're two streets over
  6. Jen: you're the best
  7. The assistant stays quiet while parents sort it out.
  8. Sam: what time is saturday's game and which field
  9. Team assistant: Saturday 9:00 AM vs. Eastside at Lincoln Field 2. Please arrive by 8:30 for warmups, white shirts.
Illustrative example with a fictional youth soccer team. Gray bubbles are parents; blue bubbles are the hosted AI agent, sent from the team's number. It answers the two schedule questions and says nothing during the pickup exchange.

Each text the agent sends uses one credit, in a group as anywhere else. If two ZeroSettle numbers with the agent on are in one group, only one answers, and the agent never answers another ZeroSettle number. For the judgment behind when an assistant should speak, read When should an AI speak in a group chat?

How do you run RSVPs and availability with polls?

Run RSVPs with a Messages poll sent into the group: every member can vote in the conversation, and the poll's voters list each member's handle per option, so you can see exactly who is in, who is out and who hasn't answered. Send it with POST /api/imessage/send, chat_id and poll:

  • options: 2 to 12 choices, each up to 150 characters, all different. Good RSVP sets: “In / Out / Not sure yet”, or a list of dates for availability.
  • question (optional, up to 300 characters) follows the poll as its own text, as it does when someone makes a poll on an iPhone.
  • A person can pick several options, which suits “which Saturdays can you volunteer?”.
  • Members on iOS 26 or later vote in the conversation. On older iPhones they see “Sent a poll” and can't vote, so add a line like “Can't vote? Reply in or out” to the reminder.

Results come from GET /api/imessage/messages/{id}/poll and arrive as a poll.voted webhook event whenever someone votes, changes their vote or removes it (on a number managed by API, where your webhook receives events). Map handles to your roster and you have an availability list your coach can trust.

Use polls for logistics, not for anything a set of rules governs. An HOA's bylaws or a church's constitution decide how formal votes happen; a group poll is fine for “which evening works for the cleanup day?”.

How do you send scheduled reminders into a group?

Send scheduled reminders from your own code: a job that runs on a schedule (cron, a scheduled cloud function, your app's job queue) and calls POST /api/imessage/send with the group's chat_id. The hosted agent's triggers, the follow-up and daily texts, never fire into a group, and the API sends when you call it, so the timing is yours to run.

This TypeScript job sends an availability poll on Wednesday and, on Friday, a reminder that reads the poll's results and names who hasn't answered. It uses Node 18's built-in fetch:

TypeScript
const BASE = "https://portal.zerosettle.io";
const TOKEN = process.env.ZEROSETTLE_TOKEN!;
const HAWKS = "iMessage;+;chat123456789"; // the chat_id you stored when the group started

async function zs(path: string, init: RequestInit = {}) {
  const res = await fetch(BASE + path, {
    ...init,
    headers: { Authorization: `Bearer ${TOKEN}`, "Content-Type": "application/json" },
  });
  const body = await res.json();
  if (!res.ok) throw Object.assign(new Error(body.error?.code ?? String(res.status)), { body });
  return body;
}

// Wednesday 6 PM: ask who is in for Saturday. Save the returned id.
export async function sendAvailabilityPoll(): Promise<number> {
  const sent = await zs("/api/imessage/send", {
    method: "POST",
    body: JSON.stringify({
      chat_id: HAWKS,
      poll: { question: "Saturday 9 AM vs. Eastside: is your player in?",
              options: ["In", "Out", "Not sure yet"] },
    }),
  });
  return sent.id;
}

// Friday 5 PM: remind everyone and name the families who haven't voted.
export async function sendGameReminder(pollId: number, roster: Map<string, string>) {
  const record = await zs(`/api/imessage/messages/${pollId}/poll`);
  const voted = new Set<string>(record.poll.options.flatMap((o: any) => o.voters));
  const inCount = record.poll.options.find((o: any) => o.text === "In")?.votes ?? 0;
  const waiting = [...roster].filter(([handle]) => !voted.has(handle)).map(([, player]) => player);

  let text = `Reminder: game tomorrow 9:00 AM at Lincoln Field 2, arrive by 8:30. ${inCount} players in so far.`;
  if (waiting.length) text += ` Still need a vote for: ${waiting.join(", ")}. Can't vote? Reply in or out.`;

  try {
    await zs("/api/imessage/send", { method: "POST", body: JSON.stringify({ chat_id: HAWKS, text }) });
  } catch (err: any) {
    if (err.body?.error?.code === "recipient_opted_out") {
      // A member texted STOP: nothing was sent. Tell the organizer who (error.handle).
      await notifyOrganizer(`Group send blocked: ${err.body.error.handle} opted out.`);
    } else throw err;
  }
}

declare function notifyOrganizer(msg: string): Promise<void>;

Three details to get right. First, schedule reminders at reasonable hours in your members' time zone; the docs' consent guidance says nothing promotional before 8 am or after 9 pm, and a team reminder at 5 PM the day before is better than one at 7 AM on game day. Second, a send into a group is refused with 403 recipient_opted_out whenever any member has texted STOP, so handle it as above instead of retrying. Third, if the number is managed by the hosted agent, it reads the reminders your code posts in the thread, so it can answer “wait, which field?” right after. The iMessage group chat API post covers every group endpoint and error.

How should the assistant handle carpools?

Let the assistant start carpool coordination with a poll and let parents arrange the details among themselves. A Wednesday poll such as “Who can drive to the away game Saturday? Driving with 2 seats / Driving with 3 seats / Need a ride” puts every answer in one place instead of a scroll of replies, and voters tells your code who chose what. Your Friday reminder can read the results and post the matchup (“3 drivers, 5 riders: please confirm pickups in the group”).

Keep the assistant out of the private parts. Don't put home addresses or pickup arrangements in the business context or files, and tell the agent never to share a family's address or number. Parents settle those directly, as Jen and Priya did. The same holds for run clubs sharing rides to a trailhead or churches driving older members: the assistant finds who can help; people agree the details.

When should you use broadcast instead of a group?

Use a group when members should see each other and talk; use broadcast when each person should get the message privately. POST /api/imessage/broadcast sends the same message to 1 to 100 handles, each in their own 1:1 conversation. A broadcast never creates or uses a group, and recipients never see each other.

Group chat vs broadcast for a club (ZeroSettle API docs, checked November 2, 2026)
QuestionGroup chatBroadcast
Do members see each other?Yes, and they can reply to everyoneNo, each reply is a private 1:1 thread
How many people?Up to 31 per group1 to 100 handles per call
One person texted STOPThe whole send is refused until they are removedThat person is skipped; the others still get it
What it sendsText, photo, voice message, video or a poll everyone votes inText, photo, voice message or video
Good forA team, a small group, a committeeA league-wide closure notice, a dues reminder, an HOA announcement

Broadcast applies every 1:1 rule to each recipient, including the new-contact limits and at most 2 messages to a contact before their first reply.

A club with 120 members usually needs both: one group per team, small group or committee, and broadcast for the announcements everyone gets. Dues and personal reminders belong in 1:1 messages, never in a group where other parents can read them.

What rules apply to consent, STOP and minors?

Every member of a group must have agreed to hear from you, a STOP from any one of them blocks sends into every group they are in, and for anyone under 18 the consent should come from a parent or guardian. A group message reaches every member, so consent covers everyone in it, not just the organizer who asked for the group.

  • Consent: message only people who gave you their number for this purpose: a registration form, a sign-up sheet, or texting the number themselves. Never import a directory, a scraped list or a purchased list. See iMessage and TCPA consent for what consent means in practice; this is not legal advice.
  • STOP: a STOP blocks that person on every number on your account. Sends into any group they are in return 403 recipient_opted_out until you remove them with POST /api/imessage/groups/update (remove) or they text START. How STOP works on iMessage has the details.
  • Minors: keep youth groups to parents, guardians and coaches. Get consent from the adult, and send anything about a specific child to that child's parent 1:1.
  • Disclosure: say in the welcome message that the group includes an automated assistant. The hosted agent says it is automated if sincerely asked.
  • Sensitive topics: prayer requests, medical needs and disputes between neighbors don't belong in a business context or file. Tell the agent to point those to a named person.

Removing someone is visible

Adding or removing a member happens in the group, and members see it in Messages. When a parent texts STOP, remove them and send them nothing more; if the team still needs to reach that family, the coach can call them.

Also note that group messages are not logged in Close or HubSpot. Errors, limits, and compliance has the full rules.

Which plan does a team or club need?

A single team or small club usually fits Pro; a league, a large church or an app serving many organizations needs Growth or Enterprise. Every plan allows each number 10,000 messages a day, sent and received, with known contacts, and has a 30-day money-back guarantee on the subscription.

  • Pro, $49 a month: one dedicated number, 5 new contacts a day (people who text first never count), and 500 free credits once. Fine for a team whose parents text the number to join.
  • Growth, $199 a month per number: upgrade in the console for 50 new contacts a day per number (and 3 per 15 minutes), team members so co-organizers can share the console, and 1,000 free credits once. From a Growth link it is $599 a month for 3 numbers plus $199 per extra number.
  • Enterprise: custom pricing through sales for high volume and compliance needs, such as a league app running a number for each organization. Book a demo.

Credits pay only for the hosted agent's texts (one credit per text) and for videos. Reminders and polls your own code sends use none. Free credits come once and don't refill; packs are 1,000 for $50 or 5,000 for $200 and never expire. ZeroSettle pricing has the full breakdown, and the group trip planner shows the same pattern for a one-off group.

Frequently asked questions

Can the hosted agent send practice reminders into the group on its own?

No. The hosted agent's triggers, the follow-up and daily texts, never fire into a group. Send reminders from your own code on a schedule with POST /api/imessage/send and the group's chat_id; the agent can still answer questions in the same group.

Can members on Android join the group?

An iMessage group reaches Apple devices only. ZeroSettle's SMS fallback is a limited pilot that ZeroSettle must enable per account, and group chats are not part of it, so give members on Android another channel, such as email or your app.

How many people can be in one group?

Up to 31. When the number starts a group, the to list takes 2 to 31 handles and the number itself is added automatically. For a bigger club, use one group per team or committee and broadcast for club-wide announcements.

What happens if one parent texts STOP?

Every send into every group they are in is refused with 403 recipient_opted_out, with error.handle naming them, until you remove them with POST /api/imessage/groups/update or they text START. The STOP covers every number on your account.

Will the assistant reply to every message in the group?

No. The hosted agent answers only when a message is meant for it or asks something it can help with, and stays silent when members are talking to each other. Tapbacks, poll votes and group events don't wake it, and each text it sends uses one credit.

Can kids be in the group?

Keep youth groups to parents, guardians and coaches. Get consent from the parent or guardian for anyone under 18, and send anything about a specific child to that child's parent 1:1. This is not legal advice.

Sources

  1. ZeroSettle iMessage API docs: “Group chats” (start a group, send, polls, limits and compliance, not covered), “Send a message” (polls, broadcast, SMS fallback), “AI agent” (Managed by AI Agent, in group chats, triggers, connectors, credits), “Your iMessage number” (pricing), “Webhooks, step by step” and “Errors, limits, and compliance”. Checked November 2, 2026.
  2. ZeroSettle iMessage API Terms of Service.

Written by the ZeroSettle team. ZeroSettle is an iMessage API: a real phone number on real iMessage, running on Apple hardware we operate for you, that your code texts customers from and hears back on through a bearer token and signed webhooks.

Product facts on this page come from the ZeroSettle iMessage API docs as of November 2, 2026. The Northside Hawks and everyone in the example are fictional, and this page is not legal advice.

Give your team's group chat an assistant

Get a dedicated iMessage number for your team, club or community, let the hosted agent answer questions in the group, and post reminders and RSVP polls from a few lines of code.

Pro is $49 a month for one number with a 30-day money-back guarantee. Growth is $199 a month per number, or $599 a month for 3 from a Growth link. Enterprise pricing is custom, for high volume and compliance needs.