← Back to the blog

MyMusicStaff has no Zapier, no API, and no public roadmap to add either

What that gap costs a studio that wants to push lesson events into Slack, Notion, or a spreadsheet. The 9-event webhook pattern Segnoly ships, with a worked Zapier example.

9 min readBy Paul Fink
XLinkedIn

There's a March 13, 2026 review of MyMusicStaff on Capterra that's been stuck in my head for a month. The reviewer is laying out, in order, the integration ceiling of the product:

"no open APIs and functions through Zapier are so limited."

Capterra review of MyMusicStaff, Mar 2026

The same review's bottom line: "AVOID AT ALL COSTS if you want a software that you can scale and grow with." That second sentence is louder than the first, but the first is the one that explains the second. A studio doesn't outgrow a billing tool because the billing got worse. It outgrows it because the data is trapped — the events are happening inside the tool, and there is no clean way to get them to Slack, to Notion, to a Google Sheet, to the bookkeeper's reconciliation script, to anywhere the studio is actually doing work.

I want to do two things in this post. First, take apart why MyMusicStaff is in this position — not just describe it. Second, walk through a concrete worked example of what a studio with a webhook-shaped product gets that a studio with no API doesn't. The example is what I'd actually do at a real studio, with the real JSON shape Segnoly emits, and the real Zapier step that consumes it.

Why "no Zapier" is structural, not strategic

The phrase that does the most work in the March 13 review is "no open APIs." Zapier connectors don't appear out of nowhere. A Zapier connector exists because the underlying product exposes an API or a webhook that the connector code can read or subscribe to. If the underlying product has no public API, the Zapier integration is either non-existent or a hand-built scrape — limited to whatever the vendor chose to wire up, with no path for the studio to extend.

So when MyMusicStaff users say "the Zapier integration is limited," what they're really describing is a downstream symptom of the upstream choice: there is no public API for Zapier (or anyone else) to build on. The Zapier surface is whatever MyMusicStaff hand-shipped, and the gaps in it can't be filled by a third-party developer because there's no API to fill them with.

There are two reasons a SaaS product ends up here.

Architectural reason. The product was built before "let third parties read our event stream" was a design priority. Adding it later means designing an event bus, deciding on a versioning strategy, signing every payload, building a delivery-and-retry system, exposing it through a developer dashboard, and supporting it forever. That's a substantial engineering investment for a feature that's invisible to 90% of customers — the ones who don't ever want to wire MyMusicStaff to a Google Sheet.

Business reason. Once the data is locked in the tool, the lock-in is itself a competitive moat. The studio that has three years of lesson history in MyMusicStaff is harder to convert to a competitor than the studio that has the same three years synced to a Google Sheet. From the vendor's perspective, "no API" is a retention feature.

I don't know which of those two reasons drove the MyMusicStaff decision and I'm not going to speculate. What I know is that the reviewer who wrote "AVOID AT ALL COSTS if you want a software that you can scale and grow with" was naming the consequence: the moment your studio gets big enough to want events flowing into Slack or your bookkeeper's spreadsheet, the lack of a webhook surface is the wall.

What Segnoly's webhook layer actually ships

The relevant files in Segnoly are lib/webhooks.ts (delivery, signing, retry) and lib/dispatch-hooks.ts (the call-site wrapper). The schema is db/schema.ts:webhookEndpoints and db/schema.ts:webhookDeliveries. Studios add an endpoint via the settings UI; each endpoint has a URL, a secret, and a list of events to subscribe to.

The events Segnoly fires are a closed set of nine, taken straight from lib/webhooks.ts:

  • lesson.attended
  • lesson.no_show
  • lesson.late_cancel
  • invoice.issued
  • invoice.paid
  • invoice.overdue
  • payment.recorded
  • payment.refunded
  • student.created

I want to defend the choice to keep this list short. Every event in the list is one a studio wants to act on outside the tool — to Slack a teacher, to log to a spreadsheet, to trigger a thank-you note, to start a re-engagement drip. Events that don't have an obvious external use case (like lesson.scheduled, which fires hundreds of times a week and is mostly internal noise) are intentionally not in the list. The wrong shape of webhook surface is one that fires on every internal state change; the right shape fires on the events that have a downstream consumer.

Each delivery is HMAC-signed using the endpoint's secret. The signature is in the X-Segnoly-Signature header, formatted as sha256=<hex>, computed over the JSON body. Receivers verify the signature before trusting the payload — this is the same pattern Stripe uses, and the same pattern any Zapier connector built against Segnoly will use. The relevant code in lib/webhooks.ts:deliver:

const signature = createHmac("sha256", secret).update(body).digest("hex");
const res = await fetch(url, {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Segnoly-Event": event,
    "X-Segnoly-Signature": `sha256=${signature}`,
  },
  body,
  signal: AbortSignal.timeout(5000),
});

The 5-second timeout is intentional. A receiver that hangs for 30 seconds would block the whole delivery queue; we'd rather record a failure and retry than let a slow webhook backpressure the studio's billing flow.

Every delivery — successful or failed — is recorded in db/schema.ts:webhookDeliveries with the status, the response code, the response body (truncated to 500 chars), and the duration in milliseconds. Studios can see the delivery log in the settings UI, replay any failed delivery, and audit exactly what was sent to which URL and when. The "no audit trail" failure mode that haunts hand-rolled integrations doesn't apply.

The worked example: invoice.paid → Google Sheets

Concretely. A studio wants every paid invoice to land as a row in a Google Sheet, with the date, the family name, the amount, the lesson type, and the payment method. A common reason: the bookkeeper does monthly reconciliation in Sheets and doesn't want to log into the studio tool.

Here's the actual setup, end to end.

Step 1: register the webhook endpoint in Segnoly.

In the Segnoly settings UI, the studio adds a new endpoint:

  • URL: https://hooks.zapier.com/hooks/catch/123456/abcdef/ (Zapier's catch-hook URL for this Zap)
  • Events: invoice.paid
  • Secret: auto-generated, copied to clipboard

The settings handler runs lib/webhooks.ts:generateSecret, persists the row in webhookEndpoints, and shows the secret once.

Step 2: build the Zap.

In Zapier, the studio creates a Zap with two steps:

  1. Trigger: Webhooks by Zapier → Catch Hook. Zapier provides the URL the studio just pasted into Segnoly. Zapier listens.
  2. Action: Google Sheets → Create Spreadsheet Row. The studio maps fields from the incoming payload (which Zapier shows after the first test fires) to columns in the sheet.

The Zap is live the moment the studio saves it.

Step 3: a real invoice gets paid in Segnoly.

A parent pays invoice INV-1042 for $240 on the parent portal. Segnoly's payment handler records the payment, marks the invoice paid, and calls fireAndForget("invoice.paid", { ... }) from lib/dispatch-hooks.ts. That function calls dispatch in lib/webhooks.ts, which finds every active endpoint subscribed to invoice.paid (in this case, the studio's Zapier hook), signs the body, and POSTs.

The actual JSON body that hits Zapier:

{
  "event": "invoice.paid",
  "occurredAt": "2026-06-16T18:42:11.082Z",
  "data": {
    "invoiceId": "inv_01HZ6X4...",
    "invoiceNumber": "INV-1042",
    "studentId": "stu_01HZ6X1...",
    "studentName": "Lena Khoury",
    "familyName": "Khoury",
    "totalCents": 24000,
    "currency": "USD",
    "paymentMethod": "stripe_card",
    "paidAt": "2026-06-16T18:42:10.998Z",
    "lessonTypeName": "60-min Piano",
    "lessonsIncluded": 4
  }
}

The X-Segnoly-Event header is invoice.paid and the X-Segnoly-Signature header is sha256= followed by 64 hex characters. Zapier doesn't verify the signature by default (that's a Code-step away if the studio cares; for a private Zap, signature verification is optional), so the catch-hook accepts the body and Zapier presents the fields to the studio for mapping.

Step 4: the row appears in the sheet.

A new row writes to the bookkeeper's Google Sheet. Date column: 2026-06-16. Family: Khoury. Amount: $240.00. Lesson type: 60-min Piano. Method: stripe_card. The bookkeeper opens the sheet on the first of next month and the entire June reconciliation is pre-populated.

The studio touched the data zero times. The teacher touched the data zero times. The integration runs for the lifetime of the Zap. Because it's a webhook (push) rather than a poll (pull), there's no "every 15 minutes" lag — the row appears within seconds of payment.

This is the thing the March 13 reviewer is naming when she says "scale and grow with." It's not a feature. It's an integration capability. Once it exists, the studio invents uses for it that the vendor never imagined. Push every late-cancel into a Slack channel for the lead teacher to see. Push every new student into Notion to trigger an onboarding template. Push every overdue invoice into a Trello board for the office manager to triage. All of them are one Zap each. None of them require Segnoly to ship a Slack integration, a Notion integration, or a Trello integration.

Why I shipped a webhook layer before a "Zapier app"

A reasonable next question: why hasn't Segnoly built a first-class Zapier connector?

It will. The webhook surface is the foundation; the Zapier app is the polish on top. Building a Zapier connector against your own webhooks is roughly a week's work if the webhooks already exist. Building it without webhooks means inventing a polling API, which is the wrong primitive — push beats pull on every dimension that matters for studio events. So the order is: webhooks first, Zapier app second, Make.com app third, n8n template fourth.

The reason I'm shipping in that order rather than the reverse is that the webhook layer is what gives a studio agency today. A studio that wants invoice.paid → Google Sheets can wire it up in fifteen minutes using Zapier's catch-hook, without waiting for me to build a branded connector. The connector, when it ships, is a UX improvement over the catch-hook flow. It doesn't add capability — the capability is already there, in lib/webhooks.ts:dispatch.

MyMusicStaff didn't take this path. Whether that's because they got their architecture in the wrong order, or because the lock-in was the point, the consequence for studios on the platform is the same: when you want events out of the tool, you can't get them, and the workaround is the spreadsheets the March 13 reviewer described as "hours of work … using formulas and pivot tables."

What this means if you're shopping

The fifteen-second test that surfaces the underlying integration model: ask the vendor for the list of events their tool emits as webhooks. If the answer is a list of 5–15 named events with documented payload shapes, the tool has a foundation you can build on. If the answer is "we have a Zapier integration" without naming the events, the integration is whatever the vendor hand-wired and the gaps will surface the moment you want something specific. If the answer is "no API," you're in the position the March 13 reviewer named, and the spreadsheet hours are your future.

Segnoly's nine-event list lives in lib/webhooks.ts:WebhookEvent, the signing logic is lib/webhooks.ts:deliver, the call sites are lib/dispatch-hooks.ts:fireAndForget, and every delivery is logged in webhookDeliveries. The shape of the integration is small enough to read in one sitting and stable enough to build on.

That's the entire integration layer. The "scale and grow with" property the March 13 reviewer named as missing in MyMusicStaff is what those four files exist to provide.


Building Segnoly — billing and automation for independent music teachers. The webhook code in this post is real, lives at lib/webhooks.ts, and the waitlist is open for the first cohort.

mymusicstaff alternativeintegrationswebhooks

Start free. Stay quiet.

Segnoly is free to start — billing, scheduling, and reminders for independent music teachers.