Auto-text missed callers (free n8n workflow)

Sharing a workflow I built after seeing workflows here for a missed-call auto-responder a couple of weeks back. With a similar core idea built my own version with a few different choices, figured it’s worth sharing back.

What it does:
A missed-call webhook fires, caller data gets normalised across providers, then it checks two things before texting - is it a weekend, and is it inside business hours. Sends one of three distinct messages depending on the answer, then logs the call to a Google Sheet.

Compatible with: Twilio, Telnyx, OpenPhone, JustCall, RingCentral, or anything that fires a webhook on a missed call.

Nodes :

  • Webhook trigger

  • Normalise caller fields across provider formats

  • Guard check for empty/malformed payloads

  • Weekend check → distinct “back Monday” message

  • Business hours check → during-hours vs after-hours message

  • Google Sheets log (phone, call ID, timestamp)

  • Here’s the JSON workflow for the same. Please leave feedback.

    Miscall workflow n8n.json (14.1 KB)

2 Likes

Two things that will bite this once it’s live. If the missed call came from a landline or a VoIP number that can’t receive SMS, the send returns an error code but the row still logs as sent — branch on the delivery status callback, not on the response to the send. And add a per-number cooldown, or the repeat caller who tries you three times in ten minutes gets three texts.

The bigger one for US numbers is A2P 10DLC. An unregistered brand and campaign gets filtered at the carrier, not at Twilio, so everything looks like it’s working right up until nobody ever replies.

Thanks for the feedback!! I looked all these up. On A2P 10DLC, you’re right that it’s the bigger issue for anyone going live with real US numbers. There’s a real cost to getting compliant, though, so is paying for registration upfront the right sequence, or is there a smarter way to approach it?

Landline/VoIP, also fair, same root issue really, branching on send response instead of delivery status callback. Have you built that pattern before? Curious how you’d structure it.

On sequencing: register first, and it’s cheaper than people expect. The scary numbers floating around are for Standard brands with secondary vetting. For a single-location business texting missed callers, you’re looking at roughly $4-5 one-time for a Low Volume Standard or Sole Proprietor brand, a $15 campaign vetting fee, and then $1.50-$10/month for the campaign depending on use case. Call it about $20 up front and a couple bucks a month. Worth confirming current numbers in the Trust Hub before you quote it to anyone, since TCR adjusts them.

The reason it has to come first is that there’s no way to test around it. Unregistered traffic gets filtered at the carrier, so Twilio returns a clean sent, your Sheet logs a success, and the message just never arrives. You’d be debugging your workflow for a week over a problem that isn’t in your workflow. Sole Proprietor caps you at one number and one campaign, which is usually fine for this use case, but it needs OTP verification on a personal mobile and takes a few days.

If you want to skip 10DLC entirely for a demo or a pilot, a toll-free number with toll-free verification is free to submit and has no monthly campaign fee. Different caller ID feel, so it’s not right for every business, but it’s a legitimate path while a 10DLC brand is pending.

On the delivery status pattern — yes, I’ve built it, and the shape that holds up is treating the send and the outcome as two separate executions.

Set statusCallback on the send (easiest at the Messaging Service level so every message inherits it) pointing at a second n8n webhook. The response to your send only tells you Twilio accepted the request; it’s queued or accepted and it means nothing about delivery. Log the row at that point with the MessageSid as your key and status queued, and stop there. No “sent” in the sheet yet.

Twilio then POSTs to your callback as the message moves: sending, sent, delivered, undelivered, failed. Second workflow receives those and upserts on MessageSid. Two things to guard:

Callbacks can arrive out of order. Rank the statuses and only write if the incoming rank is higher than what’s stored, or a late sent will overwrite a delivered.

Some messages never reach a terminal state. Landlines and dead numbers often sit at sent forever. So run a sweeper on a schedule — anything non-terminal after 15 or 20 minutes gets marked unknown and escalated the same way a failure would.

The error codes worth branching on are 30003, 30005 and 30006 for unreachable or non-mobile destinations, and 30007 for carrier filtering. 30007 climbing is your 10DLC canary. Landline hits should not retry as SMS; route those to a “call them back” queue instead, since retrying is just burning money on a number that physically can’t receive it.

One upstream option that kills a chunk of this: Twilio Lookup with line_type_intelligence before you send. Roughly half a cent per lookup, tells you mobile vs landline vs VoIP, and lets you branch before spending a message and a carrier fee on something undeliverable. Doesn’t replace the callback, but it cleans up the obvious cases.