The DDL file for the phone server's team line
SP95 Task 2. **************** a nullable VARCHAR(20) that holds the extension an AI's unnamed transfer rings (the team line, 8200 on the k1m1 FreePBX). Hand-app...
Teams calling connects send the api.kamouniverse.com redirect
The owner has added **************** to the platform Microsoft app, keeping the api.kamocrm.com one. Both hosts serve the path. Completes aa7b608, which moved R...
RingCentral connects send the api.kamouniverse.com redirect
The owner added **************** to the platform RingCentral app and kept the api.kamocrm.com one; both hosts serve the path. Teams calling uses the same path o...
PBX policy feed and AI voice admin endpoints
V7 GET /internal/voip/pbx-config (cluster secret) answers kamo-asterisk-support's policy pull through APIService and records the helper's heartbeat; a Redis fai...
Provision, retire and resolve AI voice lines
Retire deletes the PBX extension only when it is still there, and a phone server in use that refuses the delete keeps the line and answers 502, so the minute SI...
AI voice lines on FreePBX, KamoPBX and Telnyx
A refused FreePBX addExtension (status false, no GraphQL error) now fails the AI line instead of recording one that rings nothing. Telnyx number lookups send th...
KamoAI internal surface guarded by its own secret
/api/voip/internal/** (SP13: AI lines, SIP credentials for LiveKit) takes KAMOAI_INTERNAL_SECRET, not the cluster secret; the cluster prefixes keep theirs. The ...
AI voice lines, per-server AI voice settings, outbound allow-list as data
Announce new voicemails — live panel, phone push and a card
A voicemail the sweep writes for the first time, on an extension with an assigned member and received in the last 24 hours (spec D17), now publishes voip.voicem...
Pre-assign JustCall phone server id for callback URL
The new-phone form generates a UUID before create so the member can paste the webhook callback URL into JustCall while requesting API credentials. Create accept...
Serve JustCall callback URL for phone server setup
Adds GET /api/voip/setup so the settings UI can show the exact per-instance webhook URL without hardcoding the deployment host.
A number can be shared by several members, and one of them receives it
A single OWNER_MEMBER_ID could say "this number belongs to Sarah" and nothing else. Real desks are not shaped like that: a support line is answered by four peop...
Serve the inbound webhook URL, from one definition
An administrator adding a text provider has to paste Kamo's inbound URL into the carrier's own console, and nothing told them what it was. Missing that step has...
Actually create the Telnyx account setup, carry MMS, and let a carrier-only org hold threads
Three gaps, and the first was the feature not working at all. TELNYX PROVISIONING WAS DEFINED AND CALLED BY NOTHING TelnyxProvider.provision(), ensureMemberCr...
Route texts by NUMBER, and add Telnyx on both sides of it
An organization can buy its DIDs and its texting from one company and answer the calls with another. Kamo could not express that: a member's texting was a prope...
Fall back to the org's own hostname for the Teams redirect
A redirect the org typed into its own registration still wins outright — Microsoft requires the URI replayed on the token exchange to match the authorization by...
Lock the shared sweeps, and run two pods
Every @Scheduled sweep here whose effect is shared now takes a named distributed lease through SingletonTaskRunner before it does anything, so it runs once acro...
Teams Phone falls back to the org's own Entra app
The per-phone-server credentials still win — that is the most specific source. What changes is the fallback underneath them: the org's own MICROSOFT_TEAMS regis...
Let an on-premise PBX report a ringing extension
RingCentral and JustCall publish INBOUND_RINGING from their webhooks. FreePBX and KamoPBX publish nothing -- they are the customer's own Asterisk and nothing wa...
Wire JustCall in through the phone provider abstraction
JustCall (api.justcall.io/v2.1) as a full PhoneProvider: call history, texts, voicemail, recordings, the agent directory and availability, plus signed account w...
Keyword interception at step 0 on the RingCentral rail (MS1 Task 4)
Today a STOP to a number no MEMBER_VOIP_CONFIG row owns hits the "No member found for to-number" branch and vanishes — and that branch is EXACTLY where an opted...
SmsKeywordService — the one writer for inbound keywords (MS1 Task 3)
Closes the TODO Task 2 left behind. Until this commit a verified inbound STOP reached BulkTextInboundController, was recognised, was logged, and was then DROPPE...
Carrier-facing inbound SMS webhook (MS1 Task 2)
POST **************** -- form-encoded or JSON, guarded by the CARRIER'S OWN SIGNATURE. Why a new endpoint. /api/voip/webhook cannot receive a STOP and fails si...
Implement KamoPBX extension, user and device management
The provider advertised extensionManagement, userManagement and deviceManagement as true while implementing none of them, so the UI would have shown buttons tha...
Decrypt the KamoPBX credential; test the refusal path
The master credential is stored as ciphertext by the platform settings UI, so it must be decrypted before use — handing ciphertext to the API as a password woul...
Read KamoPBX platform config from the database
Adding a KamoPBX phone server failed with a raw Kubernetes DNS error — 'I/O error on PUT ... **************** — shown to an organization admin who can neither r...
Provision a KamoPBX account when a phone server is created
Adding a KamoPBX phone server now creates the underlying account and writes the account id and realm back to configJson. Any configJson the client sent is DISCA...
Implement the KamoPBX provider
Replaces the stub. KamoPBX is Kamo's own platform, so the organization holds no credential at all: KamoPBXAccountProvisioner creates the account when a phone se...
Read and write the line-window gate
GET surfaces lineWindowEnabled; PUT accepts it as a nullable Boolean so that absent means "not mentioned" and preserves the stored value. Every existing caller ...
Authenticate RingCentral with a JWT, per phone server
RingCentral was the last provider whose credentials came from a Kamo-wide registration plus two browser consent hops — one for the org, one per member. Both are...
Missed-call and voicemail counts for the softphone indicator
Reported as separate lines rather than a total: the icon shows the sum and its dropdown shows the breakdown, so a pre-summed wire value would make the dropdown ...
An unread snapshot, a mark-read, and a live frame
Its own NATS subject rather than the existing message one: the browser's handler for /topic/voip/message/ plays the arrival sound and opens a tool window for ev...
The blocked capability now outranks the right, and god mode
PhiPlaybackAuthorizer gated PHI call playback on VIEW_CALL_LOGS. That was the whole check because ServiceType.VOIP mapped to the blocked VOIP_RECORDING module, ...
Point at YugabyteDB and use PostgreSQLDialect
CockroachDB has been replaced by YugabyteDB. Connection strings move from cockroachdb-public:26257 to yb-tserver-service:5433, and the Hibernate dialect from **...
Persist calls and associate calls, texts and voicemail with leads
Calls were never recorded anywhere — VoipCallEventService published a NATS event for the browser and kept nothing, and RECORDINGS only exists when audio was cap...
Microsoft Teams Phone as a provider
Teams is not one API, so the provider glues three control planes together: • Graph, app-only — call history (getPstnCalls), presence reads, directory and...
Persist the VOIP PHI trail to phi_access_log
Call recordings, voicemail audio and transcripts were audited into the log stream, which keeps 14 days against a six-year §164.528 obligation and cannot be quer...
Require VIEW_CALL_LOGS for call playback in PHI-handling orgs
Recording and voicemail playback checked tenancy and nothing else: any member of the owning org could pull any call in it, transcript included, on extensions th...
Record call recording, voicemail and transcript access
Recording playback left no trace. A recorded call is the densest PHI the platform stores — the unredacted conversation — and "who listened to this call" was una...
TURN-REST credentials endpoint for the mobile softphone
GET /api/voip/turn/credentials mints ephemeral coturn creds (HMAC-SHA1 over "<expiry>:<memberId>" with the shared static-auth-secret) so native/cellular WebRTC ...
Accept X-***-Token on REST + signed ?st= stream tokens on audio endpoints
OTKValidationFilter precedence: X-OTK → X-***-Token → ?st= (GET, audio streaming paths only, verified via shared StreamTokenCodec with internal.auth.secret; cla...
Allow admins to connect RingCentral on a member's behalf
The per-member RingCentral flow was self-serve only, so an admin managing another member's profile saw "they must connect it themselves". Sysadmins commonly cre...
Per-member RingCentral OAuth identity + softphone SIP fixes
Softphone SIP credential fixes: - getSipCredentials: map outboundProxyBackup + stunServers (web-phone v2 needs them for WSS failover + ICE/media); throw Provi...
Doc-07 SMS template system — /api/voip/sms/templates + GSM-7/UCS-2 segment guard
**************** over the shared-lib SmsTemplate entities: renders {{var}} and sends via the EXISTING BulkTextProvider primitive (no second carrier path); SmsSe...
Like what you see shipping?
All of it arrives in your workspace on its own. Start on the free plan and read this page again in a month.
