Use cases

Fitness studio intro-offer follow-up over iMessage: a welcome, a voice note, then the membership link

ZeroSettle lets a boutique fitness studio follow up with intro-offer visitors over iMessage from the studio's own number: a welcome the evening before the first class, the instructor's 20-second voice note once the client has replied, and the membership link when they ask. Each new visitor counts once against the Pro plan's 5 new contacts a day per number, so a studio that welcomes up to 5 first-timers a day fits on one $49-a-month number. When a client doesn't answer, stop: every plan allows at most two unanswered messages.

Key takeaways

  • What it is: 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.
  • The studio flow: a link-free welcome the evening before class that invites a reply, the instructor's voice note after class once the client has replied (up to 6 MB, arriving as Messages' own audio bubble), and the membership link when they ask for it.
  • Price: Pro is $49/month for one number. Growth, for several numbers working as one, is from $599/mo. Messaging is unlimited on both.
  • Main limit: 5 new contacts a day per number on Pro; 50 a day and 3 per 15 minutes on Growth. Voice notes go only to clients who have replied. The voice note and later texts to the same client never count again.
  • What it does not do: no SMS fallback for Android clients, and the API does not schedule sends; your booking system decides when to call it.

Who uses iMessage for intro-offer follow-up?

iMessage intro-offer follow-up fits Pilates, yoga, indoor cycling, climbing and HIIT studios that sell a first-timer offer, such as an intro week. An automated email after the first class reads as generic, and the front desk rarely has time to call every first-timer; a short voice note from the coach who taught the class is personal and takes a minute.

It is a weaker fit for old visitor lists, Android-heavy client bases and drip campaigns (see when ZeroSettle is not a fit). Ongoing clients fit coaching client check-ins over iMessage, software trials fit founder-led SaaS onboarding over iMessage, and more workflows are in 50 ways businesses use iMessage.

How iMessage for intro-offer follow-up works, step by step

Your booking system sends a welcome that invites a reply and, after class, a voice note to clients who answered; everything after that waits for the client's reply. ZeroSettle carries the messages; the timing stays in your booking system.

  1. A first-timer books the intro offer and ticks a box agreeing to texts from the studio. Store the wording and a timestamp.
  2. The evening before class, your system calls POST https://portal.zerosettle.io/api/imessage/send with a link-free welcome that names the studio and ends on an easy question. That is the client's one new contact, and ZeroSettle shares the studio's name and photo with it once you have set them.
  3. After class, your system sends the instructor's 20-second voice note ("Great job today, how are the legs?") as audio_b64: m4a, mp3, wav and other formats, up to 6 MB. It arrives as Messages' native audio bubble with a waveform, a play button and the transcript the client's phone generates. ZeroSettle sends voice messages only to contacts who have replied (403 attachment_before_reply otherwise), so if the client never answered the welcome, send the coach's line as a text instead.
  4. The client replies. A signed message.received event reaches your webhook about 1–2 seconds later, and staff answer in the ZeroSettle console and send the membership link, tappable now.
  5. No answer to the welcome or the follow-up means stop. ZeroSettle refuses a third unanswered message with 403 awaiting_reply on every plan.

Hold a voice note from a 6 am class until after 8 am: ZeroSettle's docs ask that nothing promotional go out before 8 am or after 9 pm in the recipient's time zone. Put the offer's end date in a text, too: Apple's iPhone User Guide says transcription works only in select languages, and unless audio messages are set never to expire, a listener must tap Keep within 2 minutes to save one.

Example conversation: intro-offer follow-up

This thread shows the order that keeps the membership link tappable: a link-free welcome, the client's reply, the instructor's voice note, and the link only after the client asks for it.

  1. Wed 6:30 PM
  2. Studio: Hi Tyler, it's Corestone Pilates! Excited for your first reformer class tomorrow at 7. Grip socks help if you have them 🧦 Any questions before class?
  3. Client: nope, see you there!
  4. Thu 8:05 AM
  5. Studio: Voice message, 0:22 (Coach Mia)
  6. Thu 12:41 PM
  7. Client: sore lol but loved it
  8. Studio: That means it worked 😄 Your intro week ends Sunday, and members save 30% on classes. Want the details?
  9. Client: yes
  10. Studio: Here you go: example.com/join
  11. Client: doing the unlimited
Illustrative example with a fictional studio and offer. Blue bubbles come from the studio's number (the welcome and voice note through the API, the rest from the console); gray bubbles are the client's. The voice note and the link go out after Tyler has replied, so the voice note is allowed and the link is tappable.

The welcome says who is texting, and the offer ends in a question, so the link answers a request. The reasoning is in how to write a first iMessage customers actually reply to.

Setup: a booking-system trigger plus a voice note

One small service covers the flow: a send function your booking system calls twice, and a webhook receiver that counts unanswered messages and alerts the front desk. It follows the send docs, the voice message docs and the webhook steps.

python
# intro_followup.py: run with  uvicorn intro_followup:app --port 8100
import base64, hashlib, hmac, json, os, time
import requests
from fastapi import BackgroundTasks, FastAPI, Request, Response

BASE = "https://portal.zerosettle.io"
AUTH = {"Authorization": f"Bearer {os.environ['ZEROSETTLE_TOKEN']}"}
SECRET = os.environ["ZEROSETTLE_WEBHOOK_SECRET"]
app = FastAPI()
unanswered: dict[str, int] = {}          # use your database in production
seen: set[tuple[int, str]] = set()

def alert_front_desk(m: dict) -> None: ...

def send(to: str, **fields) -> dict:     # to in E.164, like the webhook's handle
    if unanswered.get(to, 0) >= 2:       # a third would be 403 awaiting_reply
        return {"skipped": "awaiting reply"}
    r = requests.post(f"{BASE}/api/imessage/send", headers=AUTH,
                      json={"to": to, **fields}, timeout=120)
    return r.json()   # line_busy: retry in 2 s; new_contact_limit: after retry_after_s

def on_intro_booked(b: dict) -> dict:    # the evening before class
    if not b["text_consent"]:
        return {"skipped": "no consent"}
    return send(b["mobile"], text=f"Hi {b['first_name']}, it's Corestone Pilates! "
                f"Excited for your first class tomorrow at {b['starts']}. "
                "Any questions before class?")

def on_class_finished(b: dict, path: str) -> dict:   # not before 8 am
    with open(path, "rb") as f:
        audio = base64.b64encode(f.read()).decode()
    r = send(b["mobile"], audio_b64=audio, audio_format=path.rsplit(".", 1)[-1])
    if r.get("error", {}).get("code") == "attachment_before_reply":   # no reply yet
        r = send(b["mobile"], text="Great job today, how are the legs? - Coach Mia")
    return r

def verify(header: str, raw: bytes, tolerance: int = 300) -> bool:
    try:
        parts = dict(p.split("=", 1) for p in header.split(","))
        t, v1 = int(parts["t"]), parts["v1"]
    except Exception:
        return False
    if abs(time.time() - t) > tolerance:
        return False
    expected = hmac.new(SECRET.encode(), f"{t}.".encode() + raw, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, v1)

@app.post("/webhook")
async def webhook(req: Request, tasks: BackgroundTasks):
    raw = await req.body()
    if not verify(req.headers.get("X-ZeroSettle-Signature", ""), raw):
        return Response(status_code=401)
    ev = json.loads(raw)
    m = ev.get("message")
    if m is None or (m["id"], ev["event"]) in seen:
        return {"ok": True}              # retries repeat the id and event
    seen.add((m["id"], ev["event"]))
    if ev["event"] == "message.sent":    # API and console sends
        unanswered[m["handle"]] = unanswered.get(m["handle"], 0) + 1
    elif ev["event"] in ("message.received", "reaction.received"):
        unanswered[m["handle"]] = 0
        if ev["event"] == "message.received":
            tasks.add_task(alert_front_desk, m)
    return {"ok": True}

Register the receiver with PUT /api/imessage/webhook and store the signing secret; it is shown once. The counter runs on message.sent, so console texts count too. The console doesn't send voice messages, so the recording goes through the API (formats in what an iMessage API can send). A booking tool that only connects through Zapier, n8n or Make can still send the text welcome with one HTTP request step (iMessage automations with Zapier, n8n or Make).

Limits and consent for intro-offer follow-up

Each intro-offer client uses one new contact, the welcome; the voice note, the replies and the membership link belong to an ongoing conversation and never count again.

ZeroSettle limits for intro-offer follow-up, per number (API docs, checked October 12, 2026)
LimitProGrowth
New contacts per day (3 AM to 3 AM Eastern)550
New contacts per rolling 15 minutes—3
Unanswered messages to one client2, then 403 awaiting_reply2, then 403 awaiting_reply
Voice notes and photosOnly after the client repliesOnly after the client replies
Voice note, replies and the membership link to that clientNever a new contactNever a new contact

Source: ZeroSettle iMessage API docs, “Errors, limits, and compliance”. On every plan, messages sent within 5 minutes of the first count as one, and any reply, photo, voice note or tapback from the client resets the count.

The limit math for a Saturday of intro classes

Take 16 first-timers booked into Saturday's classes, welcomed at 6 PM on Friday.

  • On Pro: 16 is more than the 5-a-day cap. Five welcomes go out Friday; the sixth returns 429 new_contact_limit with retry_after_s, pointing at the reset at 3 AM Eastern (midnight Pacific). Send welcomes when each client books, rather than all the evening before, or ask clients to text the studio first: a client who texts first never counts. Saturday's voice notes don't count.
  • The rest of Friday: once five welcomes are out, any other first text, such as a same-day booking, waits for the reset.
  • On Growth, which comes with several numbers, each number takes 3 new contacts per 15 minutes and a new contact goes to the number with the most room left. Three numbers send 9 per window, so the 16 welcomes also finish in about 15 minutes.

Membership offers are marketing

In the US, texting a consumer without prior express consent carries TCPA statutory damages of $500 to $1,500 per message, and marketing texts need written consent (ZeroSettle's docs); the FCC's rule, 47 CFR 64.1200, also bars telephone solicitations before 8 a.m. or after 9 p.m. local time. Collect consent on the booking form, send between 8 am and 9 pm in the client's time zone, and stop after one follow-up. More in iMessage marketing and TCPA consent; this is not legal advice.

ZeroSettle enforces STOP: a text with the word STOP in it, or a clear request like “take me off your list”, blocks every number on your account from reaching that client, and a send to them returns 403 recipient_opted_out until they text START.

When ZeroSettle is not a fit for intro-offer follow-up

ZeroSettle is the wrong tool for a studio in these cases:

  • You want to text every past visitor a promotion. That needs written consent first, and ZeroSettle suspends lines used for unsolicited messaging.
  • Most of your clients use Android. There is no SMS fallback, so keep email or SMS for them. ZeroSettle checks every first message with Apple and refuses one to a number not on iMessage (422 not_on_imessage) without sending it or using a new-contact slot.
  • Your booking platform has no API, webhook or Zapier step. Staff can text from the console, but the voice note needs the API.
  • You want an automated drip sequence. The API doesn't schedule sends, and every plan refuses a third unanswered message.
  • You need to know who played the voice note. The API reports message.sent and message.failed, not delivered, read or played status.

How much does iMessage for intro-offer follow-up cost?

Intro-offer follow-up costs the plan price: messaging is unlimited on both plans, voice notes included, and only new contacts are capped.

ZeroSettle plans for intro-offer follow-up (zerosettle.io, checked October 12, 2026)
PlanPriceFits
Pro$49/monthOne number, up to 5 first-timers a day, unlimited messages with people who message you first, self-serve, no setup fee
GrowthFrom $599/moSeveral numbers working as one, 50 new contacts a day per number, set up after a demo

Both plans bill monthly with a 30-day money-back guarantee on the subscription. Pro includes 1,000 AI credits a month, used only if the hosted AI agent (Beta) replies instead of staff. See ZeroSettle pricing, get a number, or book a Growth demo.

Frequently asked questions

How do instructors record a voice note for each client?

On their own phone with any voice-memo app; they hand the file to your system (an upload form works), which sends it as audio_b64. Keep it short: ZeroSettle's docs say two or three sentences land best.

How many follow-ups are okay?

One after the welcome, which here is the after-class voice note (or text). If neither gets an answer, stop: ZeroSettle's docs say repeated messages to people who never answer are the fastest way to get a number flagged by Apple. Once the client replies, the count starts again.

Can I include the membership link in the welcome?

Wait for a reply: until then an iPhone shows the link as plain text they can't tap, and the API's response adds warning.code: "link_not_tappable". See why links in a first iMessage aren't tappable.

Do I need written consent?

For membership offers in the US, generally yes: they're marketing, and ZeroSettle's docs note marketing texts need written consent. Collect it on the booking form with a timestamp, in its own checkbox rather than inside the liability waiver. This isn't legal advice.

Can the client text the studio first instead?

Yes: a “Text us” link on the booking confirmation opens Messages with a prefilled text. A client who texts first never counts as a new contact, links work at once, and Apple's Screen Unknown Senders filter, which files unknown senders' texts without a notification, can't hide your welcome. See how to get customers to text you first.

Sources

  1. ZeroSettle iMessage API docs: “Send a message”, “Attachments”, “Webhooks, step by step” and “Errors, limits, and compliance”. Checked October 8, 2026.
  2. Send and receive audio messages in Messages on iPhone, Apple Support (iPhone User Guide). Checked October 8, 2026.
  3. Screen and filter text messages on iPhone, Apple Support (iPhone User Guide). Checked October 8, 2026.
  4. 47 CFR § 64.1200, Delivery restrictions, the FCC's rules under the TCPA (Legal Information Institute, Cornell Law School). Checked October 8, 2026.

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 and zerosettle.io as of October 12, 2026. Apple's and the FCC's rules come from the pages listed under Sources, checked October 8, 2026. Corestone Pilates is a fictional studio, and this page is not legal advice.

Text your customers from your own iMessage number

ZeroSettle gives your business its own phone number on real iMessage, running on Apple hardware we operate for you in a server facility. Your code sends with one API call and hears every reply on a signed webhook.

Pro is $49 a month with a 30-day money-back guarantee. Growth, for several numbers working as one, is from $599/mo.