Why We Left Zenoti: The Hidden Cost of Off-the-Shelf SaaS
We ran a spa on Zenoti for $6,516 a year — $318/month plus $225/month in SMS credits at 3–4× market rate. A post-mortem on what vertical SaaS actually costs, why the worst damage was the part we couldn't measure, and how to evaluate a platform before you sign.
We operated a spa on Zenoti — a vertical SaaS platform for spas, salons, and wellness businesses — for several years, at $318/month. Over that time we opened dozens of support tickets, built custom integrations against their API, and invested a meaningful chunk of engineering time working around platform limitations. Eventually we moved off it.
This isn't a "Zenoti is bad" post. Zenoti is a mature product that plenty of large operators run happily, and much of what follows is a story about a mismatch between a platform's assumptions and ours. It's a post-mortem on a more general failure: we evaluated a SaaS platform on its subscription price and feature checklist, and paid for it everywhere else. That's a mistake I've now watched play out at more than one company, and it's worth writing down.
The $318 was the number we budgeted for. The number we actually paid was $543 a month — $6,516 a year — and even that only counts what appeared on an invoice.
The core mismatch
Vertical SaaS is priced and designed around a median customer. The further you sit from that median, the more of the gap you backfill yourself — and the gap is invisible during evaluation, because demos are built on the median.
We were unusual in one specific way: we had an engineer. That sounds like an advantage. It was actually the trap. Because we could build around limitations, we did — repeatedly, and each time it felt locally cheaper than switching platforms. A business without in-house engineering would have hit a hard wall in month two and made a decision. We had a soft wall, and we kept paying to climb it.
Where the time actually went
The subscription was a line item we noticed every month. These were the costs we didn't:
- Opening and shepherding support tickets — not the filing, the follow-up
- Waiting on engineering investigations while an operational issue stayed live
- Building manual workarounds and then maintaining them
- Writing custom software for things we assumed were product features
- Exporting and reconciling data
- Troubleshooting integrations we'd built ourselves
Individually, each of these is a normal cost of doing business on someone else's platform. Aggregated over several years, they exceeded the subscription. That's the finding. The subscription wasn't the expensive part; the metered add-ons and the gaps around the software were.
The clearest number: SMS credits at 3–4× market
Most of this post is a judgment call. This part isn't — it's arithmetic.
Zenoti sells SMS in credit packs. The pack we bought:
- 5,000 SMS credits — $225.00, one-time purchase, valid 180 days
That's $0.045 per SMS. Here's what the same message costs if you send it yourself through Twilio, the infrastructure provider a platform like this sits on top of:
| Per SMS | 5,000 SMS | |
|---|---|---|
| Zenoti credits | $0.045 | $225.00 |
| Twilio (base rate) | $0.0083 | $41.50 |
| Twilio (incl. carrier fees) | ~$0.011–$0.015 | ~$54–$77 |
Twilio's US outbound base rate is $0.0083 per segment, and US carriers add roughly $0.0025–$0.007 on top depending on which network delivers it. I'm using the all-in figure, because it's the fair comparison — the honest markup is about 3–4×, not the 5.4× you'd get by quoting the base rate alone. On the pack we actually bought, that's roughly $150–170 of margin per 5,000 messages.
Some margin here is legitimate. Zenoti is carrying the deliverability, the compliance surface, the 10DLC registration, and the support burden of running messaging for thousands of businesses. That's real work and it should be priced. I'm not arguing SMS should be at cost.
But then there's the 180-day expiry. Unused credits don't roll over — they evaporate.
That one didn't bite us, and I'll say so plainly: we went through a pack a month, so we never got near the deadline. But it's worth naming for anyone smaller, because it means $0.045 is a best case, not a price. A quieter salon that buys the same pack and uses 3,000 of it paid $0.075 a message and never saw a line item explaining why. The expiry turns a usage-based charge into a subscription with extra steps, and it transfers the forecasting risk to the customer least equipped to carry it.
What it added up to
Two line items, both of which we paid every month:
| Per month | Per year | |
|---|---|---|
| Subscription | $318 | $3,816 |
| SMS credits (5,000) | $225 | $2,700 |
| Total | $543 | $6,516 |
We bought a 5,000-credit pack every month. So the SMS add-on was not a rounding error next to the subscription — it was about 41% of what we paid Zenoti, for a service that is a thin wrapper over an SMS gateway.
Run the same 60,000 messages a year through Twilio directly and you'd pay roughly $660–$900 all-in. We paid $2,700. That's about $1,800–$2,000 a year of pure markup — on a channel we couldn't route around, sending messages we couldn't edit.
To be clear about what that number is and isn't: it's not a claim that Zenoti should sell SMS at cost. It's the price of not being allowed to bring your own gateway. A platform that let me point my own Twilio credentials at it would have cost me $700 a year for the identical traffic, and I'd have written the templates myself.
Where the pricing and the rigidity compound
The SMS markup on its own is a line item you can swallow. What made it actually expensive was that we couldn't control what went into the messages.
We send booking notifications to our own service providers — our staff. What those people need to know is short: who's booked, what service, what time. What Zenoti's template sends is that, plus the salon address, plus the cancellation policy, plus instructions on how to cancel.
Every one of those lines is dead weight. Our providers know where they work. They are not going to cancel the appointment as if they were the client. This is boilerplate written for a customer-facing confirmation, being sent to staff, because the template wasn't ours to change.
The problem is that SMS bills by segment, not by message. A GSM-7 message fits 160 characters in one segment; past that it splits, and concatenated segments only carry 153 characters each. An address and a cancellation policy will blow through 160 characters without effort. So a notification that should have been one segment goes out as two or three — and each one bills.
That's the compounding. A rigid template doesn't just annoy you; it multiplies your unit cost against a rate that's already at 3–4× market. Paying $0.045 for a segment you needed is a pricing decision you can accept. Paying $0.090 or $0.135 to tell an employee the address of the building they're standing in is the platform's inflexibility showing up on your invoice, every single booking, forever.
And the fix was unavailable at every level. We couldn't edit the template. We couldn't route provider notifications through our own Twilio account, which would have cost us roughly a fifth as much for a message we'd have controlled completely. The API let us build a great deal — but not this.
This is the whole thesis of the post in one line item: the platform decided what we sent, and then charged us 3–4× market to send it.
Integration surface was ours to build
The clearest example: we ended up building our own synchronization layer for appointments, invoices, payments, tips, providers, packages, guests, and appointment deletions.
That's not a small integration. That's a distributed systems problem — bidirectional sync, conflict resolution, idempotency, reconciliation for the cases where the two sides disagree. Appointment deletion alone is genuinely hard, because a deletion is the one event a polling-based sync can't observe by looking at what exists.
To be fair to Zenoti: they publish a real API and they explicitly encourage customers to build custom functionality when the core product doesn't cover a need. That's an honest and reasonable position, and the flexibility has genuine value. But "the platform has an API" and "the platform does this" are not the same sentence, and during evaluation we heard them as the same sentence. An API is a permission to build, not a feature. It moves work to you.
Support latency compounds differently than you'd expect
Our ticket history has a recognizable shape: repeated follow-ups, tickets moving between teams, long investigations, requests for additional logs, and issues that stayed open for extended periods.
The frustrating part wasn't the raw latency. It was that latency on an operationally-live issue is not linear in cost. If a booking flow is broken, every day it stays broken is a day of manual workaround by staff who should be serving customers — and that workaround itself has to be built, explained, and then unwound later. A ticket open for three weeks isn't three weeks of waiting; it's three weeks of parallel manual process. Instead of fixing problems once, we kept following up.
Configuration complexity is a real, recurring tax
Many workflows required a tour through numerous configuration screens. Finding the right setting meant reading documentation, contacting support, testing configurations, and repeating. This isn't unique to us — it's a common complaint about deeply configurable vertical platforms, and it's arguably the direct cost of the flexibility that makes them viable for large operators in the first place.
The tradeoff is legible once you name it: configurability is a transfer of complexity from the vendor to you. Enterprises absorb that transfer with an ops team. We absorbed it with my evenings.
Owning your data is not the same as accessing it
As an owner, I wanted our data to be ours. In practice we regularly needed support involvement for exports, reporting, payment information, gift card data, and API questions.
API access helps, and I don't want to undersell it — a platform with no API is far worse. But extracting business data in a usable shape still took real technical effort. There's a meaningful distance between "your data is accessible" and "your data is usable without an engineer," and that distance is where a lot of switching cost quietly accumulates. The day you want to leave is the day you find out how far apart those two things are.
The costs I can't put a number on — and why that's the point
Everything above this line is arithmetic. What follows isn't, and I want to be honest about the difference rather than dress up impressions as data.
These are real, and they cost us money. I can't tell you how much:
- Group booking consistently showed no available dates. Guests trying to book two people together were told there was nothing available. How many of them gave up and called a competitor instead, I have no idea.
- The booking form demands the guest's home address, and there is no way to switch it off. We are a spa. We don't ship anything. Nobody needs to hand over their home address to book a facial — but every guest was asked for one, mid-booking, at precisely the moment they were deciding whether this was worth the bother. Asking for data you don't need is a conversion tax, and it was ours to pay and not ours to remove.
- The login form isn't built to web standards, so browsers can't generate or autofill a password. Every returning guest hit friction at exactly the moment they were trying to give us money.
- Rigid required fields elsewhere in the flow. Being forced to specify a room, a piece of equipment, or a named provider on bookings that didn't need one — annoying for staff, and one more wall between a guest and a confirmed appointment.
- Support that answered without testing. Increasingly AI-generated replies, from agents who hadn't checked whether the fix worked.
- We lost a payment dispute because not all of the evidence we supplied was attached to the case.
Two of those are the same failure as the SMS templates, pointed the other way. We couldn't choose what our booking form asked, exactly as we couldn't choose what our notifications said. On the outbound side that cost us $0.045 a segment. On the inbound side it cost us guests — and unlike the SMS, nobody sends you an invoice for the ones who didn't finish booking.
You'll notice there isn't a single figure in that list. That is not me being coy. I genuinely do not have the numbers, and the reason I don't have them is itself one of the complaints.
We could not set up enhanced conversion tracking. The booking funnel ran inside Zenoti, and Zenoti did not give us the instrumentation to see where guests fell out of it. So when I tell you the password bug cost us bookings, I'm inferring from a broken form — not reading it off a dashboard, because there was no dashboard to read it off.
Sit with that for a second, because it's the whole post in miniature. A platform that owns your funnel and won't let you measure it has made its own failures unfalsifiable. I can't prove the group-booking bug cost us $10,000, and I can't prove it cost us nothing. Neither could Zenoti. Neither of us could, which is exactly the problem — you cannot manage what the vendor won't let you see, and you cannot escalate what you cannot quantify.
That asymmetry is worth more than any number I could have put in this section. It's why the pricing analysis above is the part I lead with: the $6,516 is the only part of this relationship I could actually measure. Everything else, I had to take on faith.
What I'd do differently
The lesson isn't "avoid Zenoti," and it definitely isn't "build it yourself" — building a spa platform from scratch would have been vastly worse. It's that the evaluation was wrong. If I were choosing a vertical SaaS platform again, I'd price these explicitly before signing:
- Estimate the integration surface up front. List every entity you'll need to sync and ask, concretely, which ones you'd be building yourself. Treat every answer of "you can do that via the API" as a line item with an engineering estimate attached, not as a yes.
- Ask about support latency on business-critical paths specifically. Not average response time — resolution time on issues that block daily operations, and what the escalation path actually looks like.
- Test the exit on day one. Try to export your data before you depend on the platform, not after. If you need support's help to get your data out during evaluation, you'll need it under worse conditions later.
- Price the metered add-ons against the underlying provider. Take every usage-based charge — SMS, email, storage, payments — and divide it by what Twilio, SES, or Stripe would charge you directly. A 3–4× markup on a channel you're forced to use is a permanent tax, and it's the easiest thing to check before signing and the hardest to escape after. Ask what expires, too.
- Check whether you control the content of what you're metered on. A markup you can't avoid is bad. A markup on messages whose length someone else decides is worse, because the two multiply.
- Price the total cost of ownership, not the subscription. Developer hours, staff training, support meetings, troubleshooting, and the projects that don't happen because you're doing the above. For us this dominated, and it never appeared on an invoice.
- Be honest about whether you're the median customer. If you're not, you're paying the difference in labor.
Would I recommend Zenoti?
Genuinely, it depends, and I think the split is fairly clean.
For large enterprises with dedicated IT teams and developers, the extensive customization is a real asset. You have the staff to absorb the complexity transfer, and in exchange you get a platform that bends to your process rather than the other way around. That's a good trade.
For small and medium spas, med spas, salons, and wellness businesses without in-house engineering resources, our experience was that the operational overhead outweighed the benefits. Not because the software is bad, but because the model assumes an engineering capacity you may not have — and if you do have it, you'll spend it here instead of on your business.
We wanted software that simply worked, so we could spend our time serving customers, marketing, and growing the business — not opening support tickets. That's ultimately why we left.
If you're weighing the same decision, I wrote up both halves of what comes next:
- Export your Zenoti data with Claude Code → — eight copy-paste prompts that get your whole history into a database you own, in a couple of evenings, without writing the code yourself.
- How to export your data out of Zenoti → — the technical version: the auth problem, every endpoint and its limits, and the five bugs that cost us duplicate guests, duplicate invoices, and a calendar full of $0 totals.
- Build a Zenoti clone → — a complete implementation prompt for the platform you'd move to, including the rules that keep a sync from destroying your billing history.