Session Checker
A skill for checking if CircleTel customer PPPoE/RADIUS sessions are active using the Interstellio (NebularStack) Telemetry API. Analyzes CDR (Call Detail Records) to determine real-time connection status.
When This Skill Activates
This skill automatically activates when you:
- Need to check if a customer's internet session is active
- Want to view session history for a subscriber
- Debug connection issues or troubleshoot "not connected" complaints
- Analyze session patterns and terminate causes
- Check PPPoE connection status
Keywords: session active, session status, connection status, PPPoE session, check session, CDR records, subscriber online, is connected, client session, terminate cause
Core Concepts
Session States
| State | terminate_cause | Meaning |
|---|
| Active | null | Session is currently connected |
| Disconnected | Lost-Carrier | Connection lost (modem/router issue) |
| User Ended | User-Request | User initiated disconnect |
| Idle Timeout | Idle-Timeout | Session timed out due to inactivity |
| Session Timeout | Session-Timeout | Max session duration reached |
| Admin Disconnect | Admin-Reset | Administratively disconnected |
| Port Error | Port-Error | NAS/BNG port issue |
| NAS Error | NAS-Error | Network access server error |
CDR Record Fields
| Field | Description |
|---|
id | Unique session identifier |
start_time | When session started (ISO 8601) |
update_time | Last accounting update |
username | PPPoE username (e.g., customer@circletel.co.za) |
calling_station_id | Customer's IP address assigned by BRAS |
called_station_id | BRAS/BNG IP address |
nas_ip_address | NAS that authenticated the session |
duration | Session duration in seconds |
terminate_cause | Why session ended (null if active) |
Quick Check Methods
Method 1: Using the Interstellio Client (Programmatic)
typescript
1import { getInterstellioClient } from '@/lib/interstellio'
2
3// Set token first (get from Interstellio dashboard or auth)
4const client = getInterstellioClient()
5client.setToken(process.env.INTERSTELLIO_API_TOKEN!, 'circletel.co.za')
6
7// Quick check - just returns true/false
8const isActive = await client.isSessionActive('subscriber-uuid-here')
9console.log('Session active:', isActive)
10
11// Detailed analysis
12const analysis = await client.analyzeSessionStatus('subscriber-uuid-here')
13console.log('Analysis:', {
14 isActive: analysis.isActive,
15 lastSession: analysis.lastSession?.username,
16 sessionsToday: analysis.totalSessionsToday,
17 terminateCauses: analysis.terminateCauses
18})
19
20// Get raw CDR records for custom analysis
21const records = await client.getCDRRecords('subscriber-uuid', {
22 start_time: '2025-12-19T00:00:00+02:00',
23 end_time: '2025-12-19T23:59:59+02:00'
24})
Method 2: Using PowerShell (Quick CLI Check)
powershell
1# Run the session checker script
2powershell -File .claude/skills/session-checker/check-session.ps1 -SubscriberId "23ffee86-dbe9-11f0-9102-61ef2f83e8d9"
Method 3: Direct API Call (cURL/PowerShell)
powershell
1$headers = @{
2 "X-Auth-Token" = $env:INTERSTELLIO_API_TOKEN
3 "X-Tenant-ID" = "circletel.co.za"
4 "X-Domain" = "circletel.co.za"
5 "X-Timezone" = "Africa/Johannesburg"
6 "Content-Type" = "application/json"
7}
8
9$body = @{
10 start_time = (Get-Date).Date.ToString("yyyy-MM-ddT00:00:00+02:00")
11 end_time = (Get-Date).ToString("yyyy-MM-ddTHH:mm:ss+02:00")
12} | ConvertTo-Json
13
14$response = Invoke-RestMethod `
15 -Uri "https://telemetry-za.nebularstack.com/v1/subscriber/{subscriber_id}/cdr/records" `
16 -Method POST `
17 -Headers $headers `
18 -Body $body
19
20# Check if session is active
21if ($response.terminate_cause -eq $null) {
22 Write-Host "Session is ACTIVE" -ForegroundColor Green
23 Write-Host "Username: $($response.username)"
24 Write-Host "Connected since: $($response.start_time)"
25 Write-Host "Duration: $([math]::Round($response.duration / 60, 1)) minutes"
26} else {
27 Write-Host "Session is DISCONNECTED" -ForegroundColor Red
28 Write-Host "Last terminate cause: $($response.terminate_cause)"
29}
Finding Subscriber IDs
From Supabase (CircleTel Database)
sql
1-- Find subscriber by customer email
2SELECT
3 cs.interstellio_subscriber_id,
4 cs.radius_username,
5 c.email,
6 c.first_name,
7 c.last_name
8FROM customer_services cs
9JOIN customers c ON cs.customer_id = c.id
10WHERE c.email = 'customer@example.com';
11
12-- Find subscriber by account number
13SELECT
14 cs.interstellio_subscriber_id,
15 cs.radius_username,
16 cs.status
17FROM customer_services cs
18JOIN customers c ON cs.customer_id = c.id
19WHERE c.account_number = 'CT-2025-00001';
From Interstellio API
typescript
1// Search by username
2const subscribers = await client.listSubscribers({
3 username: 'customer@circletel.co.za'
4})
5const subscriberId = subscribers.payload[0]?.id
Common Troubleshooting Scenarios
Scenario 1: Customer Reports "No Internet"
-
Check session status:
typescript
1const analysis = await client.analyzeSessionStatus(subscriberId)
-
Interpret results:
isActive: true → Session is up, issue is elsewhere (DNS, routing, etc.)
isActive: false with Lost-Carrier → Customer's router lost connection
isActive: false with Session-Timeout → Session expired, needs reconnect
-
Check session history for patterns:
typescript
1// Multiple Lost-Carrier in short time = unstable line
2if (analysis.terminateCauses['Lost-Carrier'] > 5) {
3 console.log('Line appears unstable - recommend technician check')
4}
Scenario 2: Checking Before Service Activation
typescript
1// Ensure no orphaned sessions before provisioning
2const existingSessions = await client.listSessions(subscriberId)
3if (existingSessions.payload.length > 0) {
4 // Disconnect existing sessions first
5 await client.disconnectAllSessions(subscriberId)
6}
Scenario 3: Usage Monitoring Dashboard
typescript
1// Get today's session stats for dashboard
2const analysis = await client.analyzeSessionStatus(subscriberId)
3
4const dashboardData = {
5 connectionStatus: analysis.isActive ? 'Online' : 'Offline',
6 currentSessionDuration: analysis.lastSession?.duration || 0,
7 reconnectsToday: analysis.terminateCauses['Lost-Carrier'] || 0,
8 totalOnlineTime: analysis.totalDurationSeconds
9}
API Reference
Endpoint
POST https://telemetry-za.nebularstack.com/v1/subscriber/{subscriber_id}/cdr/records
| Header | Value |
|---|
X-Auth-Token | JWT from Interstellio identity service |
X-Tenant-ID | circletel.co.za |
X-Domain | circletel.co.za |
X-Timezone | Africa/Johannesburg |
Content-Type | application/json |
Request Body
json
1{
2 "start_time": "2025-12-19T00:00:00+02:00",
3 "end_time": "2025-12-19T23:59:59+02:00"
4}
Note: Maximum query window is 32 days.
Response Example
json
1{
2 "id": "4d81f126-dcd1-11f0-9e13-a59eec990c99::2025-12-01",
3 "start_time": "2025-12-19T13:53:15.000+02:00",
4 "update_time": "2025-12-19T14:20:50.132+02:00",
5 "acct_unique_id": "4d81f126-dcd1-11f0-9e13-a59eec990c99",
6 "username": "customer@circletel.co.za",
7 "calling_station_id": "100.125.57.136",
8 "called_station_id": "100.127.1.229",
9 "nas_ip_address": "41.198.130.3",
10 "client_ip_address": "13.247.40.35",
11 "duration": 1655,
12 "terminate_cause": "Lost-Carrier"
13}
Environment Variables Required
env
1INTERSTELLIO_API_TOKEN=your_jwt_token_here
2INTERSTELLIO_TENANT_ID=circletel.co.za
3INTERSTELLIO_DOMAIN=circletel.co.za
| File | Purpose |
|---|
lib/interstellio/client.ts | Interstellio API client |
lib/interstellio/types.ts | TypeScript types including CDR records |
docs/api/INTERSTELLIO_API.md | Full API documentation |
.claude/skills/session-checker/check-session.ps1 | PowerShell quick-check script |
Best Practices
- Always check session status before disconnecting - Don't blindly disconnect active sessions
- Use timezone-aware dates - Always include
+02:00 for South Africa
- Handle empty results - API may return empty if no sessions in time window
- Cache tokens - Interstellio tokens are valid for 12 months
- Monitor terminate causes - High
Lost-Carrier counts indicate line issues
Version: 1.0.0
Last Updated: 2025-12-20
Maintained By: CircleTel Development Team
API Source: https://docs.interstellio.io/