late-glass-71191
12/21/2025, 8:17 PMtall-airline-16756
12/21/2025, 8:18 PMtall-airline-16756
12/21/2025, 8:18 PMsip.phoneNumber, sip.callID, sip.callStatus, sip.trunkID).
• Immediately persist the desired fields to your database.
What to listen for (high level)
1. In the agent’s LiveKit room, subscribe to the participant_connected event.
2. When a participant connects, check participant.kind for the SIP participant kind.
3. Pull call metadata from participant.attributes and write it to DB before any agent interaction.
Minimal example (pseudo/Python-style)
def on_participant_connected(participant):
if participant.kind == rtc.ParticipantKind.PARTICIPANT_KIND_SIP:
call_data = {
"call_id": participant.attributes.get("sip.callID"),
"phone_number": participant.attributes.get("sip.phoneNumber"),
"call_status": participant.attributes.get("sip.callStatus"),
"trunk_id": participant.attributes.get("sip.trunkID"),
"room": current_room_name,
"connected_at": now_iso(),
}
save_to_database(call_data)
Twilio setup notes
• Ensure your Twilio number is routed to your LiveKit SIP endpoint (via Twilio SIP trunk/TwiML) so incoming calls create SIP participants in the appropriate room.
• Use explicit agent dispatch (if you need calls routed to specific agents) so the SIP participant arrives in the agent’s room.
Follow-ups I can help with
• Show a full runnable snippet for your language (Node, Python, or Go).
• Recommend which fields to store and DB schema for call records.
• Help with mapping your Twilio SIP attributes to your CRM fields.
Which language are you using for your LiveKit server/handlers and which DB do you want to save into?
Sources: SIP Lifecycle Management Agent | LiveKit docs | Accepting calls overview | LiveKit docs | Agents telephony integration | LiveKit docslate-glass-71191
12/21/2025, 8:19 PMtall-airline-16756
12/21/2025, 8:19 PMparticipant_connected event, check for a SIP participant, read participant.attributes (sip.phoneNumber, sip.callID, sip.callStatus, sip.trunkID), then persist.
Minimal Node.js example (using the LiveKit server-side SDK event hooks pattern):
// Pseudo/illustrative Node.js server code
const { LivekitServer } = require('livekit-server-sdk'); // adapt to actual SDK import
const db = require('./db'); // your DB helper
async function handleRoomSession(room) {
room.on('participant_connected', async (participant) => {
try {
// participant.kind should indicate SIP
if (participant.kind === 'sip' || participant.metadata?.kind === 'sip') {
const attrs = participant.attributes || {};
const callRecord = {
call_id: attrs['sip.callID'] || attrs['callID'] || null,
phone_number: attrs['sip.phoneNumber'] || attrs['from'] || null,
call_status: attrs['sip.callStatus'] || null,
trunk_id: attrs['sip.trunkID'] || null,
room_name: room.name,
connected_at: new Date().toISOString(),
};
// Save to DB (implement saveCall as appropriate for your DB)
await db.saveCall(callRecord);
console.log('Saved incoming SIP call:', callRecord.call_id || callRecord.phone_number);
}
} catch (err) {
console.error('Error handling participant_connected:', err);
}
});
}
Notes and tips
• Attribute keys can vary; check participant.attributes to confirm exact keys your Twilio->LiveKit flow provides.
• Persist as soon as you detect the SIP participant to capture initial call state.
• If you need to correlate agent answers/end status, also listen for participant_updated and participant_disconnected to update the DB record.
• If using dispatch rules, ensure room naming or participant metadata lets you identify the target agent/queue.
If you want, I can:
• Provide a concrete runnable example for Express + the LiveKit Node SDK.
• Show a DB-specific snippet for MongoDB, PostgreSQL, or Firebase. Which database are you using?