Inspiration

I live in Richards Bay, South Africa, where the plumber, the electrician and the appliance technician all run their business from the phone in their pocket. They lose work for one reason above every other: nobody answered. Not through carelessness — because they are physically under someone's sink when the call comes in. Replying in five minutes instead of thirty transforms the odds of winning a job, and five minutes is impossible for a two-person business. A receptionist costs more than the jobs they would save.

The enquiries these businesses actually receive are not tidy forms. They are six words and a photo: "this is leaking, can you help?" That is precisely the shape of problem a multimodal model handles well and a rules engine cannot touch at all. So I built the front desk instead of the receptionist.

What it does

IntakeArc is an AI-operated front desk for small service businesses. Enquiries arrive by email, WhatsApp or phone — or from any web form that posts to the workspace's ingest URL — and Gemini runs every one of them in production:

  • Reads the photo, not just the words. Image bytes go to Gemini's vision, so the appliance type and the brand on the badge come from the picture even when the customer typed nothing useful. It does not diagnose the fault — that is the technician's job when they arrive. It gets the right job to the right person, fast.
  • Decides. Intent, priority, a completeness score, which job details are still missing, the service it belongs to, and whether the message is even a real customer rather than a newsletter.
  • Drafts the reply inside rules the owner has written down, asking only for what is genuinely still missing — not for the photo it already has, or the brand it already read.
  • Answers the phone. Calls are taken by an AI receptionist, transcribed, and triaged into the same desk as everything else.
  • Sets itself up. Gemini extracts a business's details from its own website during onboarding, and reads uploaded documents such as a price list so replies match what the business actually offers.

The owner approves each reply, or switches on guarded autopilot and lets routine ones send themselves.

The part I care most about: what the AI is not allowed to do

The interesting engineering problem in an AI product is not what you let the model do. It is what you refuse to let it do, and how you make that refusal impossible to bypass.

Every model decision passes through a chain of deterministic validators before anything reaches a customer:

  • enforceSafetyFloor — smoke, gas, sparking, injury force human review. The model cannot override this however confident it is.
  • enforceOwnerEscalation — the owner's own "always send this to me" rules.
  • enforceCommercialClaims — any reply that mentions money is discarded and rebuilt from the owner's approved price book. A model that invents a price does real commercial damage.
  • enforceConversationMemory — stops a follow-up being treated as a brand-new enquiry.

A send schedule can narrow automation but can never switch it on. That rule is one line, and it is the line I am most confident about in the whole codebase.

Every decision writes a receipt: model, real latency, token usage, whether the image was actually read, and which guardrails fired.

How I built it

  • Gemini 3.1 Flash Lite via the Generative Language API, with image attachments sent as inlineData parts and a longer timeout on vision calls (20s) than text-only ones (14s).
  • Cloudflare Workers for the whole backend, KV for workspaces and D1 for the outreach pipeline.
  • Vite single-page app in vanilla JavaScript — no framework, because the bundle is the product's first impression on a phone over a South African mobile connection.
  • Cron Triggers driving held-reply release and the outreach queue.
  • Zoho SMTP through worker-mailer for outbound, Vapi + Deepgram for voice.
  • 208 tests under node --test, plus a repo safety scanner that blocks a commit if anything private is about to become public.

Total spend to get this into production was R370 — about twenty US dollars — for the company registration and one year of a domain. Recurring monthly cost is zero. Everything runs on free tiers.

Challenges I ran into

Gemini's free tier was failing two thirds of my production calls. I only found this while investigating a lead that never appeared — the API was returning 503 "overloaded" in bursts and my code treated one failure as final. Three attempts with a 400ms/1200ms backoff took it to 7 out of 7 successful.

A single phone call created about eighty junk leads. My Vapi webhook parser failed open: when it could not understand a payload it created a lead anyway, and Vapi sends many events per call. Fixing it meant failing closed, requiring actual content, and de-duplicating on the call ID. Failing open is a reasonable instinct for a parser and a terrible one for anything that writes records.

Cloudflare Queues is a paid feature. Rather than take the plan, I rebuilt the same behaviour on a Cron Trigger and a D1 table. It cost an afternoon and R0 a month.

The AI asked a customer for a photo they had already attached. Embarrassing, and it taught me that "what is missing" has to be computed against what has actually arrived across the whole thread, not against the current message.

Consent, not cold pitches. POPIA is South Africa's privacy law, and I write to prospective customers asking permission to contact them rather than pitching. When a third of my outreach list turned out to be dead addresses, I paused sending rather than push through and damage the domain my future customers' mail would depend on.

Getting the demo footage safe to publish. My phone screen recordings had other people's emails and my own photo library in them. Blurring that turned out to be genuinely hard: Gmail's Compose button moves when a send toast appears, and each position uncovered text a fixed blur box had missed. I ended up detecting the toast's exact on-screen windows from its own pixel brightness and gating the blur regions on that.

Accomplishments that I'm proud of

A product that genuinely runs itself, in production, on a live domain, built solo with no funding and no cash buffer — and a set of refusals I would defend in front of anyone. I also declined the paid path twice when a free one existed.

I want to be straight about the other side of it: no customers and no revenue yet. The company was registered in July 2026. What exists is a working product, a registered company and a consent-based pipeline — not traction.

What I learned

AI is not a feature of this business; it is most of the staff. It wrote much of this codebase alongside me, reviewed my security posture, and pushed back when I was about to do something unwise — twice this month, arguing against a security control I had asked for, and insisting I verify an email list before sending to it. Both times it was right, and I was wrong.

The technical lesson is the one above: build the model a cage before you build it a job.

What's next for IntakeArc

Getting the first paying business onto it. IntakeArc is R99 a month. A typical South African appliance job runs about R650 — a R500 flat call-out plus parts and labour, which is my own field data, not an industry guess. So a single recovered job in a month returns roughly 6.5× the fee, and recovered work — the jobs that would otherwise have leaked away to silence — is the entire mechanism. There are hundreds of thousands of these operators in South Africa alone, and the same shape of business in every emerging market.

Live now: https://intakearc.originarclabs.com

Built With

Share this project:

Updates