Use cases

Thank first-time donors with a voice message over iMessage

ZeroSettle lets a nonprofit text each first-time donor who opted in a short thank-you from the executive director and, once the donor replies, send a voice message in that director’s voice, which arrives as a native iMessage voice bubble, followed by a photo of the program the gift supports. On the $49-a-month Pro plan, one number reaches 5 new donors a day, about 150 a month. Replies land in the ZeroSettle console, and later impact updates in the same thread never count against that limit.

Key takeaways

  • What it is: a short thank-you text from your executive director and, after the donor replies, a voice thank-you and a program photo with the donor’s name in the caption, sent from your organization’s own iMessage number by a daily script and a webhook.
  • Who it fits: small and mid-size nonprofits whose donors tick a “text me a thank-you and updates” box on the donation form.
  • Price: Pro is $49/month for one number. Growth, for several numbers working as one, is from $599/mo. No per-message fees.
  • Main limit: 5 new donors a day per number on Pro, about 150 a month, and voice and photos only after the donor replies. Replies and later updates to a donor you already thanked don’t count against it.
  • What it does not do: reach donors on Android (there is no SMS fallback), or replace the written acknowledgment IRS rules call for on gifts of $250 or more.

Who uses iMessage for donor thank-yous?

This workflow is for development and executive directors at small and mid-size nonprofits who want each first-time donor who opted in to texts to hear a personal thank-you the morning after the gift. 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 problem is the second gift, and the thank-you is where it starts. A first-time donor may get only an emailed receipt, and a thank-you call takes staff time and can end in voicemail. A 30-second message in the executive director’s voice needs no one to pick up. Year-end volume and Android donors are covered under when ZeroSettle is not a fit.

How iMessage for donor thank-yous works, step by step

A donor ticks a box, a script runs the next morning with a short thank-you text, and when the donor replies they get two more messages from your number: the executive director’s voice, then a photo of the work the gift funds.

  1. Add an optional, unticked “Text me a thank-you and updates” checkbox beside the mobile number on your donation form, and store the consent with the gift.
  2. The executive director records a thank-you on their own phone, one per program, under a minute, opening with their name and the organization’s; the docs say two or three sentences land best. ZeroSettle accepts m4a, mp3, wav, aiff, caf, flac, aac, mp4 and amr files up to 6 MB, and voice messages for language-learning apps covers audio prep.
  3. Each morning, after 8 am in your donors’ time zones, a script takes yesterday’s opted-in first-time donors and calls POST https://portal.zerosettle.io/api/imessage/send with a short, link-free text from the executive director that invites a reply. ZeroSettle sends photos and voice messages only to contacts who have replied (403 attachment_before_reply otherwise), so the recording waits for that reply.
  4. When the donor’s reply arrives on your webhook, your server sends the recording with audio_b64. The donor gets Messages’ native voice bubble with a waveform, a play button and a transcript their iPhone generates.
  5. A second send carries image_b64 and a caption with the donor’s first name, because a voice message can’t carry a caption.
  6. Once you set your name and logo in the console, they travel with the first message, so the donor sees “Lanternfield Food Bank shared a name and photo with you”.
  7. Replies land in the ZeroSettle console, where staff answer from the same number. Months later, an impact update in the same thread is an ongoing conversation, with no new-contact limit.

The same leader-to-newcomer pattern drives founder-led SaaS onboarding over iMessage; here the recording does the personal part.

Example conversation: a donor thank-you

This thread shows the thank-you text, the donor’s reply, the voice message and photo, a tapback from the donor and an impact update three months later, all on one number.

  1. Wed 10:04 AM
  2. Food bank: Hi Mark, it’s Angela, Executive Director at Lanternfield Food Bank. Thank you for your first gift! Can I send you a 30-second thank-you?
  3. Donor: oh nice, sure
  4. Food bank: Voice message, 0:31 (Angela, Executive Director)
  5. Food bank: Photo: volunteers stocking pantry shelves
    Your gift helps stock these shelves. Thank you, Mark.❤️
  6. Wed, Jan 13, 11:00 AM
  7. Food bank: Mark, quick update: we served 1,240 families this quarter, our most ever.
Illustrative example with a fictional food bank. Blue bubbles are sent from Lanternfield Food Bank’s number; gray bubbles are the donor’s replies. The voice message and the photo are two separate sends, made after Mark replied.

Setup: a morning script with voice and photo sends

The integration is one daily script that texts each opted-in first-time donor, plus a webhook handler that sends the voice message, then the captioned photo, when that donor replies, all through POST /api/imessage/send. Request shapes follow the Attachments section of the ZeroSettle docs, and what an iMessage API can send sums up photo and voice limits.

python
# thank_donors.py: run each morning:  python3 thank_donors.py new_donors.csv
# Your webhook handler calls send_thanks() when a donor's first reply arrives.
import base64, csv, os, sys, time
import requests

BASE = "https://portal.zerosettle.io"
TOKEN = os.environ["ZEROSETTLE_TOKEN"]
FIRST = ("Hi {name}, it's Angela, Executive Director at Lanternfield Food Bank. "
         "Thank you for your first gift! Can I send you a 30-second thank-you?")
PROGRAMS = {"pantry": ("thanks-pantry.m4a", "shelves.jpg",
                       "Your gift helps stock these shelves. Thank you, {name}.")}

RETRY = ("new_contact_limit", "line_busy", "phone_offline", "phone_timeout")
SKIP = ("recipient_opted_out", "not_on_imessage", "send_failed",
        "awaiting_reply", "attachment_before_reply")   # this donor only

class DailyCap(Exception):
    pass

class Skip(Exception):
    pass

def b64(path):
    with open(path, "rb") as f:
        return base64.b64encode(f.read()).decode()

def send(body):
    for attempt in range(8):
        r = requests.post(f"{BASE}/api/imessage/send", json=body,
                          headers={"Authorization": f"Bearer {TOKEN}"}, timeout=120)
        if r.ok:
            return r.json()
        err = r.json()["error"]
        if err["code"] == "new_contact_limit" and err.get("window") == "day":
            raise DailyCap()
        if err["code"] in SKIP:
            raise Skip(f"{err['code']}: {err['message']}")
        if err["code"] not in RETRY:
            break                              # bad token, unpaid, bad input
        time.sleep(err.get("retry_after_s", 2 * (attempt + 1)))
    sys.exit(f"stopping: {r.status_code} {err['code']}: {err['message']}")

def send_thanks(phone, first_name, program):   # after the donor replies
    audio, photo, caption = PROGRAMS[program]
    send({"to": phone, "audio_b64": b64(audio), "audio_format": "m4a"})
    send({"to": phone, "image_b64": b64(photo), "image_format": "jpg",
          "text": caption.format(name=first_name)})

if __name__ == "__main__":
    done = set(open("thanked.txt").read().split()) if os.path.exists("thanked.txt") else set()
    for d in csv.DictReader(open(sys.argv[1])):  # phone, first_name, program
        if d["phone"] in done:
            continue
        try:
            send({"to": d["phone"], "text": FIRST.format(name=d["first_name"])})
        except DailyCap:
            break                                  # the rest go out tomorrow
        except Skip as e:
            print(d["phone"], e)                   # opted out or not on iMessage: email instead
        with open("thanked.txt", "a") as f:
            f.write(d["phone"] + "\n")

Only the morning text can hit the new-contact limit; by the time the voice message and photo go out, the donor has replied. A refusal about one donor is logged and skipped; anything else, like a bad token, stops the run with nobody marked thanked. Send the recording to your own number once before the first run. Register a webhook and verify each message.received before calling send_thanks or logging the reply against the donor record: the X-ZeroSettle-Signature header carries an HMAC-SHA256 of "<t>." plus the raw body, checked with a constant-time compare as in the webhook steps in the docs. Keep the number “Managed by API”: while the hosted AI agent manages it, your script’s sends are refused with 403 managed_by_zerosettle.

Limits and consent for donor thank-yous

On Pro, one number reaches 5 new donors a day, about 150 a month. Replies are never limited, and later messages to a donor you already thanked never count as new contacts, though every plan caps unanswered messages at 2.

ZeroSettle limits that apply to donor thank-yous, per number (API docs, checked October 12, 2026)
LimitProGrowth
New donors per day (3 AM to 3 AM Eastern)550
New donors per rolling 15 minutes—3
Unanswered messages to one donor2, then 403 awaiting_reply2, then 403 awaiting_reply
Voice messages and photosOnly after the donor repliesOnly after the donor replies
Replies and later messages count as new contactsNoNo

Source: ZeroSettle iMessage API docs, “Errors, limits, and compliance”.

The year-end math

  • 400 first-time gifts on December 31: at 5 a day on Pro, the last donor hears from you 80 days later. On Growth each number allows 50 a day, so three numbers finish in three days. Or thank the surge by email.
  • Donors who text first are never limited. A prefilled sms: link on the donation confirmation page lets donors start the thread (on Android it opens the SMS app, so keep email for those donors); see how to get customers to text you first.
  • Quiet donors: a donor who never answers the thank-you text gets no voice message or photo. The thank-you is one unanswered message and the next impact update is the second; a third waits for a reply.

Consent comes first

Text only donors who ticked the box, and keep the record; the iMessage TCPA consent guide covers what to store. Lead with thank-yous and impact. Keep fundraising asks rare, and send them only between 8 am and 9 pm in the donor’s time zone. This isn’t legal advice; check consent rules with counsel.

A text with the word STOP, or a clear request like “take me off your list”, opts the donor out across every number on your account, including a donor’s “I’ll stop by Saturday.” Sends to them return 403 recipient_opted_out, and only START opts them back in.

When ZeroSettle is not a fit for donor thank-yous

ZeroSettle is the wrong tool for donor thank-yous in these cases:

  • Hundreds of new donors a day on one Pro number, as at year-end. Plan Growth numbers or email for the surge.
  • Donors who didn’t opt in to texts. A gift is not consent to be texted, and ZeroSettle suspends lines used for unsolicited messaging.
  • Donors on Android or another phone without iMessage. There is no SMS fallback, so they get nothing; thank them by email.
  • Fundraising appeals to your whole list. ZeroSettle’s terms prohibit high-volume marketing.
  • The message as the tax receipt. Under IRS rules, a contribution of $250 or more is substantiated by a written acknowledgment with your organization’s name, the amount of a cash gift (or a description of a non-cash one) and a statement about goods or services. A voice message is not one, so keep sending receipts. This isn’t tax advice.

How much does iMessage for donor thank-yous cost?

Donor thank-yous cost the plan price: ZeroSettle charges no per-message fees, and messages in both directions are unlimited (counted).

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

Both are billed monthly with a 30-day money-back guarantee. See ZeroSettle pricing, more iMessage use cases, or get a number.

Frequently asked questions

What if a donor replies with a voice message or a photo?

It arrives with the file, in the console and as message.received on your webhook. ZeroSettle converts a voice reply to .m4a with its length in duration_ms, and a HEIC photo to JPEG, so staff can play or open either in a browser.

Can the donor replay the message later?

Only if they keep it. Apple says a recipient can play an audio message any time after it arrives, but must tap Keep within 2 minutes of listening to save it, unless they set audio messages never to expire. Your copy stays in ZeroSettle: GET /api/imessage/messages/{id}/audio returns the bytes you sent.

Can we ask for another gift by text?

Only if their consent covers it. ZeroSettle’s docs define consent as a number given for this purpose, with a record you can show, and note that US marketing texts need written consent. A box offering “a thank-you and updates” may not cover appeals, so name them in the checkbox if you plan to ask. How to write a first iMessage that gets replies covers wording. This isn’t legal advice.

Sources

  1. ZeroSettle iMessage API docs: “Send a message”, “Name and photo”, “Attachments”, “Webhooks, step by step” and “Errors, limits, and compliance”. Checked October 8, 2026.
  2. ZeroSettle iMessage API Terms of Service, section 13 (opt-in consent and prohibited uses). Last modified September 28, 2026.
  3. Send and receive audio messages in Messages on iPhone, Apple Support. Checked October 8, 2026.
  4. Charitable contributions: Written acknowledgments, Internal Revenue Service. 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, zerosettle.io and the iMessage API Terms as of October 12, 2026. Outside facts come from the pages listed under Sources, checked October 8, 2026. Lanternfield Food Bank is fictional, and this page is not legal or tax 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.