He’s up a ladder. His phone rings. He can’t answer. The caller tries the next electrician on Google. That’s roughly £200 gone, and it happens dozens of times a month. Trades commonly lose 30–40% of calls this way - not because they’re bad at the job, but because they’re doing the job. We built a fix in 48 hours. Here’s the honest account of how it went.

What we actually built

An AI receptionist that picks up every call, answers as the business, and handles the whole intake conversation with no human involved. By the time the call ends, the electrician has a proper job card sitting in his calendar: name, phone, email, full address and postcode, job type (rewire, fault-find, inspection), urgency, access notes (“dog in garden, side gate open”), and preferred contact method. He can price the job before he even calls back.

The stack was three pieces:

  • A voice AI platform with sub-second latency - fast enough that callers dont notice they’re talking to a machine
  • n8n as the booking middleware, handling the logic between the voice layer and the calendar
  • An open-source booking engine as the calendar back-end

We already had a master template from previous builds. Cloning it to a new named business with its own phone number took about 30 minutes. The template handles the call flow; the intelligence layer - the specific questions, the field collection, the job card format - is where the real work lives.

What surprised us

Two things caught us off guard, both good.

First: the demo sells itself. Once someone calls the number and books a fake appointment, they get it immediately. No slide deck needed. Thats a better sales tool than anything we could write.

Second: one-time pricing landed far better than a monthly model. Trades hate subscriptions. A monthly fee feels like another bill. A one-off feels like buying a tool - a van ramp, a new drill. Worth keeping in mind if you’re selling automation to this audience.

What broke (the useful part)

Four things went wrong. Each one took about ten minutes to find and two to fix - but only because we’d built this before. If it was your first time, you’d be staring at it for hours.

Bug 1: the booking API lied about its own field name

The docs said available slots would come back under data.slots. They came back under data. That’s it. One level of nesting missing, so our n8n expression was pulling nothing and the AI was telling callers there were no available times - for every single slot.

The fix was to inspect the raw response and update the expression:

{{ $json.data }} // not $json.data.slots as documented

Always log the raw API response before you trust the docs.

Bug 2: toolCallId had to match exactly

The voice platform routes tool results back to the right point in the conversation using a toolCallId. If the ID you return doesn’t match the one the platform sent, the call flow fails silently - no error, no log entry, the AI just stalls. We were generating a new ID in n8n instead of passing the original one back.

{
  "toolCallId": "{{ $json.toolCallId }}", // echo back exactly what the platform sent
  "result": "{{ $json.result }}"
}

Silent failures are the worst kind. When nothing happens and nothing errors, check your IDs first.

Bug 3: two assistants, one workflow, wrong business name

During testing we had two assistants pointing at the same n8n workflow. Bookings started appearing with the wrong business name in the calendar event. The workflow was pulling the business name from whichever assistant had last written to a shared variable.

Fix: one workflow per business, full stop. The extra ten minutes to duplicate it is not optional.

Bug 4: job context buried where nobody could see it

The AI was collecting all the right information - address, access notes, urgency - but pushing it into event metadata rather than the visible notes field. The electrician would open the calendar event and see nothing useful. The data existed; it just wasn’t where a human would look.

We updated the n8n node to write the full job summary into the booking engine’s notes field explicitly:

{
  "title": "Electrical job - {{ $json.jobType }}",
  "notes": "{{ $json.callerName }} | {{ $json.phone }} | {{ $json.address }}\nJob: {{ $json.jobType }}\nUrgency: {{ $json.urgency }}\nAccess: {{ $json.accessNotes }}"
}

If the information isn’t visible at a glance, it might as well not exist.

The actual lesson

The AI is not the product. Missed calls turning into booked jobs is the product. The voice model, the latency, the stack - none of that matters to an electrician. What matters is that he comes down the ladder, opens his calendar, and sees three new jobs he’d have lost six months ago.

The bugs above are not embarrassing edge cases. They’re the normal cost of connecting real systems together. Document them, fix them fast, and the next build is 30 minutes instead of 48 hours.

If you’re losing calls while you’re working, let’s talk about what a build like this looks like for your business.