Skip to main content
ZombieMutex

30 results · ↑ ↓ navigate · Enter open · Esc close

All writing
November 9, 20263 min read

Mobile voice agents: keep the backend in charge

How I connected Swift and Kotlin clients to agent workflows, built Core ML and TensorFlow Lite integration boundaries, and kept authorization on the backend.

By

Share

Send this article to someone or copy its link.

Suggest a correction

Reader tools

3 min remaining · 0% of article

Select a passage and choose Highlight selection to save it. Local browser storage only. Shift+F toggles focus.

In the iOS and Android voice-agent integration I built, the UI owns consent and status presentation; the backend owns case authorization, duplicate suppression and provider credentials. The distinction matters most when the client is compromised, offline or retrying a request whose outcome it never received.

I built the iOS and Android voice-agent integration around a simple operation: request a callback for an existing support case. The Swift client uses URLSession; the Kotlin client uses coroutines and an HTTP connection. Both send an authenticated request to a first-party backend. Neither knows the voice vendor's API key.

The client requests; the server authorizes

The wire contract is intentionally small:

http
POST /api/mobile/callbacks
Authorization: Bearer <first-party-session>
Content-Type: application/json

{"caseId":"case-101","platform":"ios","consent":true,"operationId":"callback-01"}

The backend should derive the account from the signed or opaque session, confirm the case belongs to that account, enforce consent and rate limits, apply quiet-hour/suppression policy where appropriate, and deduplicate requests using an operation key. Only then does a server-side adapter enqueue the provider request.

The response says queued. That's deliberate. A 202 from an internal queue isn't proof a phone rang, was answered, or completed a useful task. I'd model queued, dispatching, ringing, connected, completed, failed and canceled as separate states, each updated from verified provider events. Retry rules need to distinguish an ambiguous network timeout from a definitely rejected request.

Core ML and Android ML aren't authentication

Local inference can be useful for voice activity detection, lightweight intent classification or speech features when device performance and battery justify it. It isn't a reason to trust an operation. Apple App Attest and Google Play Integrity provide additional signals with their own verification requirements; they don't decide whether one account owns another account's support case.

I developed Core ML and TensorFlow Lite integration interfaces so native applications have a clear boundary between model inference and backend authorization. An application can use on-device inference, server inference or a safe fallback. The boundary must include model version, supported OS and hardware, latency, thermal behavior and confidence calibration. Comparisons should be made on real devices with actual evaluation sets, not a diagram that says "Neural Engine" and calls it a benchmark.

Privacy and failure handling should be visible in the UX

An app needs explicit permission for microphone access when it captures audio. A callback-only flow doesn't need it. It does need clear consent for an outbound call, a way to cancel, and a truthful status when offline. Store mobile session credentials using platform-appropriate protection, avoid dumping payloads into logs and keep server-owned voice provider credentials entirely out of the binary.

The local reference deliberately queues callbacks without placing real calls, making the backend boundary and request semantics repeatable in tests. Provider-facing transport and customer calling environments are separate from the published reference; they need their own consent policy, verified delivery events and operational support.

That distinction matters: mobile UI can look effortless, but the backend still has to earn every side effect.

Related: Voice agent mobile integration · Voice agents are distributed systems with microphones · iOS/Android security work.

Related technical notes with overlapping topics.

Discuss a passage

Select a paragraph above, copy it with its article link, then paste into the discussion. Don't include private data.

Jump to discussion ↓

Public conversation / GitHub Discussions

Discuss this article

Read and reply using GitHub Discussions. A GitHub account is needed to post. Comments are public and subject to GitHub moderation.

For privacy, the external giscus widget does not load until you choose to open it. Opening it connects your browser to giscus and GitHub. Do not post credentials or private project data.