VoiceFlux API
Internal developer reference. The evidence baseline is the complete audit package indocs/voiceflux/, especially documents 01, 04, 07, 09, 11, and 12 plusvoiceflux-audit-manifest.json.
Route Map
All profile IDs and agent IDs supplied by clients are revalidated against the active organization. Job diagnostics select only status, provider/model metadata, attempt counts, duration, safe failure code, and timestamps. They never return message text,
failureDetail, audioStorageKey, or audioUrl.
VoiceFluxSettingsUpdateSchema intentionally excludes includedAudioSeconds; tenants cannot grant themselves provider allowance.
Persistence
Core models:OrganizationVoiceFluxSettings: entitlement activation, Stripe subscription state, default profile, retention, included allowance.VoiceFluxProfile: organization/agent-scoped structured style.VoiceFluxSynthesisJob: idempotent lifecycle and safe diagnostics.VoiceFluxUsagePeriod: UTC monthly included, purchased, and used audio seconds.
Agent.voiceRepliesEnabled and Conversation.voiceFluxEnabled. The queue requires both fields plus Conversation.isAiEnabled.
Profile resolution performs separate indexed queries and applies agent profile > organization default > built-in defaults. Do not replace direct organizationId, agentId, conversationId, or messageId filters with relation filters.
Runtime Flow
handle-chat-message/handler.tspersists the normal text answer.enqueueVoiceFluxForMessage(messageId)validates emergency/provider state, three-layer activation, channel support, commercial entitlement, and available allowance.- A deterministic SHA-256 idempotency key includes message, selected profile/style, and fixed model policy.
- BullMQ queue
voiceflux-synthesizerunsprocessVoiceFluxJobinapps/workers-services. - The worker synthesizes OGG/Opus, measures actual duration, reserves usage atomically, uploads privately, and delivers through the existing channel adapter.
- Any safe failure delivers the already-persisted original text. An uncertain
DELIVERINGretry favors text over duplicate audio.
sendVoice, Messenger audio attachment, and Instagram audio attachment.
Fixed Model Policy
The worker calls the official Google Gemini Interactions REST endpoint directly:- endpoint:
https://generativelanguage.googleapis.com/v1beta/interactions - auth:
x-goog-api-keywith server-onlyGOOGLE_AI_API_KEY - provider fallback: none; OpenRouter is never used by VoiceFlux
- Google Cloud project/location variables and ADC are not required
gemini-3.1-flash-tts-preview is treated as stable and operational and is the sole pricing/capacity baseline. No model branch beyond the two IDs listed above is permitted. Changes require updating the complete docs/voiceflux audit package and provider policy tests.
Metering and Retention
Duration is measured from generated OGG/Opus output and rounded up to a whole second.meterVoiceFluxAudioSeconds uses a transaction and conditional updateMany to reserve allowance atomically. Provider consumption is still metered if synthesis completed after another concurrent request exhausted the delivery allowance.
Uploaded objects receive expiresAt. The VoiceFlux worker scans the indexed expiration column hourly, deletes expired S3 objects in bounded 100-row batches, and clears storage references. A Redis ownership lock prevents cleanup overlap across replicas. Missing storage configuration disables cleanup without deleting job audit records.
Worker Resilience
The VoiceFlux entrypoint follows the same operational contract as the mature workers-services workers:- separate Redis connections isolate BullMQ blocking work from health, queue inspection, cleanup locks, and realtime logs;
- reconnect uses bounded backoff with connect, reconnect, error, and end telemetry;
- concurrency, rate limiting, Bull locks, stalled recovery, health cadence, cleanup cadence, and shutdown timeout are validated environment-tunable integers;
- health includes active/waiting/delayed work, failures, stalls, real average latency, cleanup outcomes, Redis connection states, memory, and uptime;
- retention cleanup is non-overlapping within a process and uses a distributed token-checked lock across replicas;
- shutdown is idempotent, drains with a timeout, force-closes only after the deadline, and closes the queue, both Redis connections, and Prisma;
- uncaught exceptions and unhandled rejections enter the same fatal shutdown path.
VoiceFluxSynthesisJob before the external request. A worker restart resumes from primaryAttempts and fallbackUsed; exhausted jobs never restart the model sequence. This conservative reservation also prevents concurrent replicas from issuing the same attempt.
Billing and Stripe
VoiceFlux is alevel_2+ growth module. Checkout copies organizationId and growthModuleKey into subscription metadata. Checkout completion and subscription webhook events synchronize the base subscription module list and OrganizationVoiceFluxSettings.stripeSubscriptionId/status. Inactive or deleted add-on subscriptions disable organization VoiceFlux.
The webhook remains the commercial source of truth. The UI cannot activate VoiceFlux when plan eligibility or add-on state is missing.
Frontend Contract
The localized Pages Router surface is/voiceflux. ExpandedNavigation and the collapsed Navigation place VoiceFlux immediately after Livia and before ZappFlux. The page reads the settings, usage, profiles, and agent-table APIs; it does not duplicate backend state or introduce a client-only profile contract.
Permissions remain intentionally split: agents.read controls visibility, agents.write controls profile CRUD, and billing.manage controls organization policy. Voice names and all style option arrays are exported from @zappway/lib/voiceflux/contracts and shared by the dedicated page, agent editor, and Zod schemas.
Required Playwright targets:
Gotchas
- Never suppress the normal text response unless the VoiceFlux job was successfully queued.
- Never log raw reply text, credentials, provider payloads, audio URLs, or internal error details.
- Do not retry BullMQ synthesis jobs independently of the provider adapter; the adapter owns the exact model-attempt ceiling.
- Do not expose model IDs as product settings.
- Do not add allowance writes to the public settings schema.
- Keep Stripe cancellation handling synchronized with organization activation.

