Skip to content

Story No. 13Communications & workflow automation

Inbound texts that trigger Zapier workflows, without duplicate runs or silent gaps

The client wanted text messages arriving through RingCentral to start workflows in Zapier, dependably and without supervision. We built a small async FastAPI service that sits between the two. It accepts each SMS event, fetches the details RingCentral leaves out, masks sensitive fields and passes a clean, structured payload on to Zapier. It also renews its own webhook subscriptions, retries failed deliveries with backoff and screens out resent events so one message doesn’t start the same workflow twice.

Client
RingCentral SMS Integration
Sector
Communications & workflow automation
Our role
Designed and built end to end
Context
API middleware · internal service

The challenge

On paper, linking a phone system to an automation tool means pointing one webhook at one URL. The real requirements were less tidy. RingCentral’s SMS event doesn’t contain everything the Zapier workflows use, so each one has to be followed by REST calls to fill in the gaps. Message data also includes personal details, and those should reach as few systems as possible.

The service also had to be easy to look after: shipped as a container, configured through the environment instead of code edits, open to inspection when something goes wrong, and able to feed downstream compliance and do-not-call (DNC) checks. Middleware that behaves like a black box gets blamed for every misbehaving workflow, whether it caused the trouble or not.

The larger business risk lay in failures that make no noise. Automations run unattended, so a fault that raises no error can go unnoticed until someone asks why a workflow stopped. We planned around four of them:

  • RingCentral webhook subscriptions expire unless renewed, and when one lapses nothing complains: messages simply stop coming in
  • Retries at the transport level can resend an event that was already handled, which would start the same Zap again
  • Zapier or the network can drop a delivery part-way, so a single attempt isn’t enough
  • Each field forwarded to a third party widens the spread of personal data

Our approach

We chose Python and FastAPI and made the service async throughout. Nearly all of its time is spent waiting: on RingCentral’s webhook, on the follow-up REST calls and on Zapier. Async I/O lets one lightweight process hold many of those waits open together, and HTTPX supplies the async client for outbound calls to Zapier.

Subscription expiry got a background task of its own. A renewer keeps the RingCentral webhook subscriptions current, so the integration doesn’t run happily for a while and then go quiet. We see this as the most important safeguard in the service, because it covers the failure that is hardest to notice.

For duplicates we added an idempotency filter held in memory. When a transport retry presents a message that was already passed on, the filter recognises it and drops it before Zapier is called. Memory is the right place for that record while the service runs as a single container. Our advice if it ever scales out to several replicas: move the filter into a shared store, or each copy will only know about its own events.

Delivery to Zapier retries with backoff. A short outage on either side gets time to clear instead of costing the message, and the widening gap between attempts avoids piling pressure on a service that is already struggling.

Masking happens before any data leaves the service. Sensitive fields are hidden in what Zapier receives, so the automation layer sees only what its steps use. That is data minimisation designed in from the start, and it gives the compliance and DNC hooks further along a predictable, trimmed payload.

Day-to-day running is deliberately unremarkable. Pydantic settings read credentials and endpoints from the environment and validate them at start-up, so a missing value stops the service at once instead of surfacing on the first live text. Health endpoints let the container platform confirm it is up, and structured logs record each stage so anyone can trace what happened to a given message.

Every inbound message takes one fixed route:

  • Accept the SMS event from RingCentral on the active webhook subscription
  • Call RingCentral’s REST API for the metadata the event lacks
  • Mask the sensitive fields
  • Discard the event if the idempotency filter has seen it before
  • Send the structured payload to Zapier, with retries and backoff if delivery fails

Architecture & stack

Service
Python, FastAPI, Pydantic settings, HTTPX
Integrations
RingCentral, Zapier, Webhooks
Operations
Container deployment, Health endpoints, Structured logging

The outcome

The client now has a compact, single-purpose bridge between RingCentral and Zapier. Texts reach Zapier already enriched and with sensitive fields masked, subscriptions look after themselves, failed deliveries are retried and resent events are filtered out.

It is also simple to hand over. It ships as a container, reports its own health and writes structured logs, and because it forwards only what the Zapier steps need, later compliance and DNC checks always receive data in the same shape.

Our advice for anyone wiring a phone system into workflow automation: plan for the failures that make no sound. Renew subscriptions automatically, make delivery idempotent, retry with backoff, and decide which fields may leave your systems before the first message goes through. Building those in at the start costs far less than working out, after the fact, why the automation went quiet.

  • Webhook subscriptions renewed automatically, so messages keep arriving
  • Resent events filtered out before they reach Zapier
  • Personal fields masked before data reaches a third party
  • Container deploys with health endpoints and searchable, structured logs

Last updated

All 13 stories

Tell us what you’re building.

Book a free one-hour call, or send a short brief and we’ll reply within two working days.