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...
Settings voicemail plays a FreePBX message from its paired upload
Settings -> Phone -> Voicemails plays each row through /voicemails/{id}/audio, which asked the provider for the audio. FreePBX serves no voicemail audio over an...
Phone OAuth hops return the platform's members to internal.kamouniverse.com
kamouniverse.com is the platform's primary apex (kamo-shared-library 0e8cf90f). Sign-in ranks it first for the platform organization, the one organization holdi...
Read JustCall voicemail with INCOMING_VOICEMAIL, and file each under its agent
JustCall answers call_type=VOICEMAIL with 400 ("call_type must be one of ... INCOMING_VOICEMAIL"), so not one of the 241 voicemails on the JustCall account ever...
A PBX ring event rings only members of the key's own org
APIService vouches for the API key's org in X-Org-Id and takes the phone server id from a header the key holder writes. The ring seam ignored the org, so any ke...
Store inbound RingCentral texts, and stop re-registering live JustCall webhooks
RingCentral: the SMS subscription was the bare /message-store filter, whose notifications are a change summary with no message in it, and the reader looked for ...
Read a FreePBX sweep's mailboxes over one manager session
The voicemail sweep runs inside syncInstance's database transaction and asked FreePBX extension by extension, each over a fresh AMI connect and login. A manager...
Read FreePBX voicemail over the Asterisk Manager Interface
FreePBX's API has no voicemail messages: its voicemail module serves mailbox settings only. FreePBXProvider.getVoicemails GET /admin/api/api/rest/voicemail, a r...
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...
Mint a RingCentral webhook verificationToken RingCentral accepts
RingCentral refuses a deliveryMode.verificationToken longer than 32 characters with CMN-101 "Parameter **************** value is invalid" (measured against the ...
Only verified RingCentral webhooks are processed; calling needs a seat
The legacy path that processed a RingCentral call or SMS event with no instanceId, trusting the payload's own to-number, is removed together with its 2026-10-13...
Pin kamo-shared-library 1.6.1, the only version that exists
The library moved to 1.6.1 and this service still asked for 1.6.0. There is no window in which both resolve: the library is never published to a remote, so the ...
Right checks, SSRF/credential guards and cross-org fixes across VOIP
Findings 2-6 from the phone-system audit, fixed together because several share files. 2. HIGH — VoipInstanceController had no right check on any mutating endpo...
Verify RingCentral webhooks before trusting them
RingCentral's inbound call/SMS webhooks were processed with zero verification: WebhookController routed telephony/message-store events straight into ***********...
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's owner travels as exact text, so saving it no longer re-owns it
GET /api/voip/numbers wrote ownerMemberId as the entity's Long. A member id is an INT8 past 2^53, so the settings page read it rounded: the owner was never foun...
Liveness probe on /actuator/health/liveness, not the DB-aware aggregate
The aggregate /actuator/health includes the DataSource indicator, so restarting the database failed liveness on every pod at once and restarted the whole platfo...
Release idle Hikari connections now that YSQL pooling is shared
The connection manager no longer pins sessions **************** so idle app connections no longer each hold a database backend. Keep the pool maximum, but stop ...
Accept OCI image indexes when resolving the built digest [skip ci]
The images are pushed as OCI image indexes, so asking the registry for a single image manifest only answered 404, the digest came back empty and the check faile...
Restart when a same-commit rebuild leaves pods on the old digest [skip ci]
The rollout step tried to detect a same-commit rebuild by comparing the Deployment's image reference before and after `set image`. "Apply manifests" has already...
Put the stream in the config the pod actually reads
The previous commit set nats.jetstream.stream in **************** shipped, deployed — and the new pod still logged NATS stream 'CHAT_MESSAGES' already exis...
Give voip.* a stream to live in, and stop lying about who sent the text
There was no VOIP_MESSAGES stream in NATS at all. Every `voip.*` publish answered 503 No Responders Available and both media pods logged, once, at boot: [V...
Record what the carrier says happened to a text, and check 10DLC before it matters
Sending now succeeds and nothing arrives. Telnyx accepts the message, returns an id, and Verizon then refuses to deliver it: status delivery_failed code ...
Normalise the sender at the gateway, and stop calling a refusal retryable
The previous commit normalised the sender number where it is stored in the number inventory and on the carrier, and the send still failed with the same carrier ...
Normalise sender numbers to E.164 before they reach a carrier
Sending a text failed with "The message could not be sent. Try again in a moment.". Telnyx's own answer, from the voipservice log, was specific: Telnyx POST ...
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...
Stop telling people to add the text provider they already added
Reported from a real setup, and the report was right. An organization running FreePBX added Telnyx as a text provider, opened the SMS window, and was shown Free...
Tell a member the number is missing, not that their PBX cannot text
Reported from a real setup: an organization added Telnyx as a text provider, opened the SMS window, and was told "This phone server is a FreePBX PBX, which carr...
A frozen CHECK blocked every Telnyx AND JustCall provider from being created
Adding a Telnyx text provider 500'd. The log named it plainly and the screen said nothing useful: constraint **************** Failing row contains (..., 6)...
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...
Ask whether THIS NUMBER can text, not whether the org can
SmsGateway grew a number-aware availability() when routing moved onto the number, and then nothing called it with a number — both SmsController call sites used ...
Delete the Telnyx code nothing calls
Three methods I added that no caller reaches, removed while the reason is still fresh — this feature's worst bug was TelnyxProvider.provision() being defined an...
The "you cannot text" message stopped one step short of the fix
FreePBX and Teams told a member to add an SMS provider under Phone → Providers. That was complete advice until numbers gained their own text route; now adding a...
Only the carrier that owns a webhook URL may verify its posts
The phone-server inbound path added in the previous commit verified against whatever provider carried the number. That is a forgery surface, and not hypothetica...
A Telnyx phone server could send texts and never receive one
Telnyx is both a phone server and a carrier, and a Telnyx messaging profile has exactly one webhook URL. So an organization that added Telnyx as a PHONE SERVER ...
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...
Populate a new number before persisting it, not after
save() built an empty OrgPhoneNumber, persisted it, and then filled in E164 and PHONE_CANON — both NOT NULL. It works today because the UUID generator needs no ...
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...
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.
