Pet care updates over iMessage: photos, voice notes and pickup texts
ZeroSettle lets a vet clinic, groomer or doggy daycare send owners photo updates during the visit, a voice-message discharge summary they can play at home, and a “ready for pickup” text, all in one iMessage thread from the business's own number. Owners start the thread by scanning a QR code at drop-off, so those threads never count against the 5 new contacts a day that ZeroSettle's $49-a-month Pro plan allows, and returning owners keep the same thread visit after visit. Staff send photos from the ZeroSettle console; voice messages go out through the API.
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.
- For pet care: photo updates from the console, a recorded discharge note sent with
audio_b64, owners' photos back in the same thread, and the pickup text. - 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 contacts a day per number on Pro (50 on Growth). Owners who text first, and ongoing threads, are never limited.
- What it does not do: no video, no SMS fallback for Android owners, and the console does not send voice messages.
Who uses iMessage for pet care updates?
iMessage pet care updates suit vet clinics, groomers, doggy daycares and boarding kennels whose owners mostly carry iPhones. Their front desks field “is he ready?” and “how is she doing?” calls all day, and discharge instructions given at a busy counter are forgotten by the time the owner gets home. Practices with many Android owners, or that need video, should read when ZeroSettle is not a fit; other workflows are in 50 ways businesses use iMessage.
How iMessage for pet care updates works, step by step
The owner opens the thread at drop-off, staff post into it during the visit, and the pickup text closes it.
- Drop-off. The owner scans the QR code on the check-in slip, which opens Messages with “Drop-off: Biscuit” filled in, and taps Send. Your webhook gets a signed
message.receivedevent about 1–2 seconds later, and your code matches the number to the pet. Owners who opt in on the intake form instead get a first text from you. - During the visit. Staff send a photo from the console (camera button, paste or drop), the dog mid-bath or the cat waking up after surgery, with the caption in the same bubble (photo limits).
- Discharge. The vet records a 30-second summary and your code sends it with
POST /api/imessage/sendandaudio_b64; the console sends text and photos only. It arrives as Messages' audio bubble with a waveform and the transcript the owner's phone generates. A voice bubble has no caption, so doses follow as a text. - Owner questions. Replies and incision photos show in the console and arrive as
message.received, a photo with animageobject forGET /api/imessage/messages/{id}/image. Only the first of several photos in one message is delivered, and a video arrives with no file, so ask for “one photo per text”. - Pickup. “Ready for pickup at 4:00” goes in the same thread; an owner's ❤️ arrives as
reaction.received. The thread stays open for the next visit.
Tell owners to tap Keep
Apple's guide says a recipient can play an audio message any time, but must tap Keep within 2 minutes of listening to save it, unless audio messages are set never to expire. Say so in the written follow-up. ZeroSettle keeps the recording, so if an owner loses it, GET /api/imessage/messages/{id}/audio returns the file for your code to send again.
Example conversation: pet care updates
A Saturday groom at a fictional shop, as the front desk sees it in the ZeroSettle console:
- Sat 8:04 AM
- Customer: Drop-off: Biscuit
- Business: Got him! Full groom today. We'll text you when he's ready 🐶
- Sat 10:41 AM
- Business: [Photo: Biscuit in the tub]
Mid-bath and very proud of himself.❤️ - Sat 1:15 PM
- Business: Biscuit is ready for pickup! We're open until 6.
- Customer: omw, 15 min
Dana sent the first message, so the thread cost Wag Society nothing against its daily allowance.
Setup: console photos and API voice notes
Photo updates and pickup texts need no code: staff use the console. The discharge note and filing owners' photos follow the attachments and webhook docs.
The QR code encodes a prefilled sms: link (how to get customers to text you first): sms:+15555550100&body=Drop-off%3A%20Biscuit, printed on the check-in slip. The discharge note is one call, with the written version sent as a text after it:
BASE=https://portal.zerosettle.io # export ZEROSETTLE_TOKEN=... in the environment, never in source
# 30 s of audio is too long for one command-line argument on Linux, so build the body in a file
AUDIO=$(base64 < mochi-discharge.m4a | tr -d '\n') # same on macOS and Linux
printf '{"to":"+15555550147","audio_b64":"%s","audio_format":"m4a"}' "$AUDIO" > discharge.json
curl -s -X POST -H "Authorization: Bearer $ZEROSETTLE_TOKEN" -H 'Content-Type: application/json' \
--data-binary @discharge.json $BASE/api/imessage/send
Owners' photos go to a receiver that verifies ZeroSettle's signature and answers 2xx before filing, since ZeroSettle allows 10 seconds for an answer and then retries 3 more times, after 1, 5 and 20 seconds.
# owner_photos.py: run with uvicorn owner_photos:app --port 8100
import 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, seen = FastAPI(), set() # keep seen ids in your database
def verify(secret: str, header: str, raw_body: 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_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, v1)
def add_to_chart(handle: str, name: str, data: bytes) -> None: ... # your practice software
def file_photo(m: dict) -> None:
img = requests.get(BASE + m["image"]["url"], headers=AUTH, timeout=30) # HEIC arrives as JPEG
img.raise_for_status()
ext = m["image"]["content_type"].split("/")[-1]
add_to_chart(m["handle"], f"owner-photo-{m['id']}.{ext}", img.content)
@app.post("/webhook")
async def webhook(req: Request, tasks: BackgroundTasks):
raw = await req.body()
if not verify(SECRET, req.headers.get("X-ZeroSettle-Signature", ""), raw):
return Response(status_code=401)
ev = json.loads(raw)
m = ev.get("message") or {}
if ev["event"] == "message.received" and m.get("kind") == "image" and m.get("image"):
if m["id"] not in seen: # retries carry the same id
seen.add(m["id"])
tasks.add_task(file_photo, m)
return {"ok": True}
Register the receiver with PUT /api/imessage/webhook and store the signing secret; it is shown only once.
Limits and consent for pet care updates
Pet care threads rarely touch ZeroSettle's new-contact limit: an owner who texts at drop-off is never counted, and your first text after an intake opt-in counts once per owner. The limits cover the console too.
| Limit | Pro | Growth |
|---|---|---|
| New contacts per day (3 AM to 3 AM Eastern) | 5 | 50 |
| New contacts per rolling 15 minutes | No separate cap (the daily 5 binds first) | 3 |
| Unanswered messages to one owner | 2, then 403 awaiting_reply | |
| Photos or voice to an owner who has never replied | Refused (403 attachment_before_reply) | |
| Owners who texted first, ongoing threads | Not limited | Not limited |
| Photo / voice message size | 5 MB / 6 MB | 5 MB / 6 MB |
Source: ZeroSettle iMessage API docs, “Errors, limits, and compliance” and “Attachments”. The docs put a minute of speech well under 1 MB.
The limit math for a busy Saturday
Take a groomer with 40 dogs booked: 26 regulars with an existing thread and 14 first-timers.
- Regulars, and first-timers who scan the QR code: never counted.
- If all 14 first-timers opt in on the intake form instead and you text each one during the 8:00–8:15 check-in: Pro allows 5 new contacts a day per number, so the 6th returns
429 new_contact_limitwithretry_after_s. Growth allows 50 a day but only 3 per 15 minutes per number. Hand those owners the QR code, which costs nothing against either limit, or space the welcome texts out. Photos and voice notes to them wait until they reply. - A week of boarding with a daily photo: one ongoing thread. On either plan the third update to a silent owner returns
403 awaiting_replyuntil they send anything, a ❤️ included. Updates within 5 minutes count as one, so send each day's photos together.
Consent comes first
The owner's drop-off text, or a dated opt-in on the intake form, is your record that they asked for visit updates. A promotion such as “20% off nail trims” likely needs a separate yes. ZeroSettle's docs say “Marketing texts need written consent”, and the FCC's TCPA rule generally requires prior express written consent for autodialed advertising to mobile numbers. The docs also rule out anything promotional before 8 am or after 9 pm in the owner's time zone. This isn't legal advice; have counsel review your consent flow.
A post-op trap: any text with the word STOP, or a clear request like “take me off your list”, opts the owner out, so “he won't stop licking his stitches” does too. Sends to them then return 403 recipient_opted_out from every number on your account (how STOP works). Their texts still reach you, so call them, and if they still want updates, ask them to text START.
Keep card numbers and billing details out of the thread: ZeroSettle's terms say content sent through the service “may not be encrypted”.
When ZeroSettle is not a fit for pet care updates
ZeroSettle is the wrong tool for pet care updates in these cases:
- You need to send video of the pet. Photos and voice messages are the only attachments.
- You would run promotions in the same thread without a separate yes. ZeroSettle's docs warn against automated marketing in a support thread: “It is a different consent, and it is how support lines get reported as spam.”
- Many owners use Android. There is no SMS fallback: iMessage reaches Apple devices, and other phones get SMS or RCS, as Apple explains. On Android the drop-off QR code opens the SMS app, so keep a phone call or email for those owners. You can check whether a number is on iMessage first; the check sends nothing.
- You want updates inside your practice-management software but have no developer. There is no built-in integration; without code, the console covers text and photos.
- You need proof the owner heard the discharge note. The API reports
message.sentandmessage.failed, not read status.
Recheck and vaccine reminders are a separate flow: appointment reminders customers confirm with a tapback.
How much does iMessage for pet care updates cost?
Pet care updates cost the plan price: ZeroSettle charges no per-message fees, and messages are unlimited (counted).
| Plan | Price | Fits |
|---|---|---|
| Pro | $49/month | One clinic or shop: one number to start, 5 new contacts a day, unlimited messages with people who message you first, self-serve, no setup fee |
| Growth | From $599/mo | 3+ numbers working as one, 50 new contacts a day per number, after a demo |
Both carry a 30-day money-back guarantee on the subscription; this flow uses no AI credits. See ZeroSettle pricing, get a number, or read the API docs.
Frequently asked questions
Do pet records fall under HIPAA?
Generally not, as we read the rule: HIPAA defines health care as care “related to the health of an individual”, and an individual as “the person who is the subject of protected health information” (45 CFR 160.103). Check your state veterinary board's rules on records too. This isn't legal advice; ask counsel about your practice.
Will owners see my clinic's name?
Usually. ZeroSettle shares your name and photo with your first message in each conversation, including threads the owner started, shown as “Maybe: Your Clinic” until the owner saves the number; the exact display depends on their device and contact settings. See what customers see.
Can owners answer with a voice message?
Yes. It reaches your webhook as message.received with an audio object; ZeroSettle converts it to an .m4a file with duration_ms filled in, which you fetch with GET /api/imessage/messages/{id}/audio and the same bearer token.
Can the hosted AI agent answer “is he ready?” texts?
Not on the number staff post from. The hosted AI agent (Beta) is either-or per line group: while it manages a line, inbound texts skip your webhook, and sends from your code and the console composer return 403 managed_by_zerosettle. It also answers only from the business context you write, so it could not know whether a given pet is ready.
Sources
- ZeroSettle iMessage API docs: “Send a message”, “Attachments”, “Customer support”, “AI agent”, “Webhooks, step by step” and “Errors, limits, and compliance”. Checked October 8, 2026.
- ZeroSettle homepage: plans and the FAQ on how a business name appears. Checked October 8, 2026.
- ZeroSettle iMessage API Terms of Service, section 13 (engagement privacy disclaimer). Last modified September 28, 2026.
- Send and receive audio messages in Messages on iPhone, iPhone User Guide, Apple Support. Checked October 8, 2026.
- What is the difference between iMessage, RCS, and SMS/MMS?, Apple Support. Checked October 8, 2026.
- 47 CFR § 64.1200, Delivery restrictions, paragraph (a)(2), the FCC's TCPA rule (Legal Information Institute, Cornell Law School). Checked October 8, 2026.
- 45 CFR § 160.103, Definitions, HIPAA Administrative Simplification (Legal Information Institute, Cornell Law School). Checked October 8, 2026.