LiteNet Developer API Release
All checks were successful
Deploy to Server / deploy (push) Successful in 1m55s

This commit is contained in:
rocord01 2026-06-19 11:07:06 -04:00
parent 70e12bf4fe
commit e7a7839f26
9 changed files with 4144 additions and 6 deletions

View file

@ -115,10 +115,10 @@ importers:
version: 0.468.0(react@19.1.0) version: 0.468.0(react@19.1.0)
next: next:
specifier: ^15.1.1 specifier: ^15.1.1
version: 15.1.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) version: 15.1.1(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next-plausible: next-plausible:
specifier: ^3.12.4 specifier: ^3.12.4
version: 3.12.4(next@15.1.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0) version: 3.12.4(next@15.1.1(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
next-themes: next-themes:
specifier: ^0.4.6 specifier: ^0.4.6
version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0) version: 0.4.6(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@ -480,6 +480,10 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'} engines: {node: '>=12.4.0'}
'@opentelemetry/api@1.9.0':
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
engines: {node: '>=8.0.0'}
'@pkgjs/parseargs@0.11.0': '@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'} engines: {node: '>=14'}
@ -1618,6 +1622,9 @@ packages:
csstype@3.1.3: csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
d3-array@3.2.4: d3-array@3.2.4:
resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==}
engines: {node: '>=12'} engines: {node: '>=12'}
@ -3483,6 +3490,9 @@ snapshots:
'@nolyfill/is-core-module@1.0.39': {} '@nolyfill/is-core-module@1.0.39': {}
'@opentelemetry/api@1.9.0':
optional: true
'@pkgjs/parseargs@0.11.0': '@pkgjs/parseargs@0.11.0':
optional: true optional: true
@ -4232,7 +4242,7 @@ snapshots:
'@types/react@19.1.8': '@types/react@19.1.8':
dependencies: dependencies:
csstype: 3.1.3 csstype: 3.2.3
'@types/unist@2.0.11': {} '@types/unist@2.0.11': {}
@ -4637,6 +4647,8 @@ snapshots:
csstype@3.1.3: {} csstype@3.1.3: {}
csstype@3.2.3: {}
d3-array@3.2.4: d3-array@3.2.4:
dependencies: dependencies:
internmap: 2.0.3 internmap: 2.0.3
@ -5789,9 +5801,9 @@ snapshots:
natural-compare@1.4.0: {} natural-compare@1.4.0: {}
next-plausible@3.12.4(next@15.1.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0): next-plausible@3.12.4(next@15.1.1(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0))(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
next: 15.1.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0) next: 15.1.1(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
react: 19.1.0 react: 19.1.0
react-dom: 19.1.0(react@19.1.0) react-dom: 19.1.0(react@19.1.0)
@ -5800,7 +5812,7 @@ snapshots:
react: 19.1.0 react: 19.1.0
react-dom: 19.1.0(react@19.1.0) react-dom: 19.1.0(react@19.1.0)
next@15.1.1(react-dom@19.1.0(react@19.1.0))(react@19.1.0): next@15.1.1(@opentelemetry/api@1.9.0)(react-dom@19.1.0(react@19.1.0))(react@19.1.0):
dependencies: dependencies:
'@next/env': 15.1.1 '@next/env': 15.1.1
'@swc/counter': 0.1.3 '@swc/counter': 0.1.3
@ -5820,6 +5832,7 @@ snapshots:
'@next/swc-linux-x64-musl': 15.1.1 '@next/swc-linux-x64-musl': 15.1.1
'@next/swc-win32-arm64-msvc': 15.1.1 '@next/swc-win32-arm64-msvc': 15.1.1
'@next/swc-win32-x64-msvc': 15.1.1 '@next/swc-win32-x64-msvc': 15.1.1
'@opentelemetry/api': 1.9.0
sharp: 0.33.5 sharp: 0.33.5
transitivePeerDependencies: transitivePeerDependencies:
- '@babel/core' - '@babel/core'

3
pnpm-workspace.yaml Normal file
View file

@ -0,0 +1,3 @@
allowBuilds:
sharp: true
unrs-resolver: true

1456
public/api-spec/openapi.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,781 @@
openapi: "3.0.3"
info:
title: LiteNet API
description: |
LiteNet is a free community PBX based on FreePBX. This API allows you to
manage your extension, access voicemails, view conferences, and interact
with the LiteNet PBX programmatically.
**Authentication:** Most endpoints require a Bearer token obtained via
Discord OAuth. Pass it in the `Authorization` header:
`Authorization: Bearer *** version: "1.0.0"
contact:
name: LiteNet
url: https://litenet.tel
servers:
- url: https://api.litenet.tel
description: Production API
- url: http://localhost:3001
description: Local development
paths:
/extensions/me:
get:
summary: Get current extension
description: Returns the authenticated user's extension details,
including their Discord profile and PBX device configuration.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: Extension details
content:
application/json:
schema:
$ref: "#/components/schemas/ExtensionDetails"
"401":
description: Unauthorized
/extensions/me/devicestatus:
get:
summary: Get device registration status
description: Returns whether the user's SIP device is currently
registered with the PBX. Polled every 5 seconds on the dashboard.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: Device status
content:
application/json:
schema:
type: object
properties:
extension:
type: string
description: The extension number
example: "1010"
deviceState:
type: string
description: Human-readable state (e.g. "Registered", "In use")
example: In use
activeChannels:
type: string
nullable: true
description: Active channel info or null if none
example: null
/extensions/me/calls:
get:
summary: List active calls
description: Returns all currently active calls for the authenticated
user's extension. Polled every 5 seconds on the dashboard.
tags:
- Calls
security:
- BearerAuth: []
responses:
"200":
description: List of active calls
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ActiveCall"
delete:
summary: Hangup all calls
description: Hangs up every active call for the user's extension.
tags:
- Calls
security:
- BearerAuth: []
responses:
"200":
description: All calls hung up
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Successfully requested termination for 1 call(s) for extension 1010."
terminatedChannels:
type: array
description: List of terminated channel IDs
items:
type: string
example: ["PJSIP/1010-00000002"]
"401":
description: Unauthorized
/extensions/me/callme:
post:
summary: Call me
description: Triggers the PBX to call the user's extension. Supports
music on hold and echo test modes.
tags:
- Extensions
security:
- BearerAuth: []
parameters:
- in: query
name: mode
required: true
schema:
type: string
enum: [hold, echo]
description: |
`hold` — play music on hold
`echo` — echo test (play back what you say)
- in: query
name: callerId
required: false
schema:
type: string
description: Custom caller ID to display (defaults to the extension number)
- in: query
name: autoAnswerMode
required: false
schema:
type: string
description: Auto-answer mode for the call
responses:
"200":
description: Call initiated
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Successfully initiated hold call to extension 1010."
/extensions/me/resetsecret:
post:
summary: Reset SIP secret
description: Resets the SIP password for the extension. Returns the
new secret once — it cannot be retrieved again.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: Secret reset
content:
application/json:
schema:
type: object
properties:
newSecret:
type: string
description: The new SIP secret (displayed once)
example: "aB3xK9mP2qR7"
/extensions/me/dnd:
get:
summary: Get Do Not Disturb status
description: Returns whether Do Not Disturb is currently enabled.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: DND status
content:
application/json:
schema:
type: object
properties:
extension:
type: string
description: The extension number
example: "1010"
dndStatus:
type: boolean
description: Whether DND is enabled
example: false
post:
summary: Toggle Do Not Disturb
description: Enables or disables Do Not Disturb for the extension.
tags:
- Extensions
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- dndStatus
properties:
dndStatus:
type: boolean
description: true to enable, false to disable
responses:
"200":
description: DND updated
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "DND status for extension 1010 set to true."
extension:
type: string
description: The extension number
example: "1010"
dndStatus:
type: boolean
description: Updated DND state
example: true
/extensions/me/endpoint:
get:
summary: List registered endpoints
description: Returns all SIP endpoints/devices registered to the
user's extension. Polled every 10 seconds on the dashboard.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: List of registered devices
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/RegisteredDevice"
/extensions/me/voicemails:
get:
summary: List voicemails
description: Returns voicemail messages for the authenticated user.
tags:
- Voicemail
security:
- BearerAuth: []
responses:
"200":
description: List of voicemails
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Voicemail"
/extensions/me/voicemails/{messageId}/download:
get:
summary: Download voicemail audio
description: Downloads the WAV audio file for a specific voicemail.
tags:
- Voicemail
security:
- BearerAuth: []
parameters:
- in: path
name: messageId
required: true
schema:
type: string
responses:
"200":
description: WAV audio file
content:
audio/wav:
schema:
type: string
format: binary
/extensions/me/voicemails/{messageId}/move:
patch:
summary: Move voicemail to folder
description: Moves a voicemail into a different folder for organization.
tags:
- Voicemail
security:
- BearerAuth: []
parameters:
- in: path
name: messageId
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- targetFolder
properties:
targetFolder:
type: string
enum: [INBOX, Family, Friends, Old, Work, Urgent]
responses:
"200":
description: Voicemail moved
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Voicemail moved from Old to Friends."
messageId:
type: string
description: The voicemail message ID
example: "849c9236"
sourceFolder:
type: string
description: Original folder
example: Old
targetFolder:
type: string
description: Destination folder
example: Friends
newMessageNumber:
type: string
description: New message number after move
example: msg0001
/extensions/me/voicemails/{messageId}:
delete:
summary: Delete voicemail
description: Permanently deletes a voicemail message.
tags:
- Voicemail
security:
- BearerAuth: []
parameters:
- in: path
name: messageId
required: true
schema:
type: string
responses:
"200":
description: Voicemail deleted
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Voicemail msg0033 deleted permanently from Old."
messageId:
type: string
description: The voicemail message ID
example: "37aca380"
folder:
type: string
description: The folder the voicemail was in
example: Old
originalMessageId:
type: string
description: The original message number
example: msg0033
/conferences:
get:
summary: List conference rooms
description: Returns all currently active conference rooms and
their participant counts.
tags:
- Conferences
responses:
"200":
description: List of conference rooms
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ConferenceRoom"
/conferences/{conferenceId}:
get:
summary: Get conference participants
description: Returns the list of participants currently in a
specific conference room.
tags:
- Conferences
parameters:
- in: path
name: conferenceId
required: true
schema:
type: string
responses:
"200":
description: List of participants
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Participant"
/conferences/{conferenceId}/connectme:
post:
summary: Connect to conference
description: Dials the authenticated user's extension and bridges
them into the specified conference room.
tags:
- Conferences
parameters:
- in: path
name: conferenceId
required: true
schema:
type: string
security:
- BearerAuth: []
responses:
"200":
description: Connected to conference
/system/records:
get:
summary: Get call statistics
description: Returns aggregate call statistics for the LiteNet PBX.
Public endpoint — no authentication required.
tags:
- System
responses:
"200":
description: Call statistics
content:
application/json:
schema:
$ref: "#/components/schemas/CallRecords"
/system/survey:
get:
summary: Get hardware survey data
description: Returns aggregated hardware survey data showing device
types, brands, and devices needing categorization.
Public endpoint — no authentication required.
tags:
- System
responses:
"200":
description: Survey data
content:
application/json:
schema:
$ref: "#/components/schemas/SurveyData"
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: UUID
description: |
Obtain a token via Discord OAuth at `/auth/discord`.
Pass it as `Authorization: Bearer ***
schemas:
ExtensionDetails:
type: object
properties:
status:
type: boolean
description: Whether the request was successful
example: true
message:
type: string
description: Status message
example: "Extension found successfully"
id:
type: string
description: Base64-encoded extension identifier
example: "ZXh0ZW5zaW9uOjEwMTA="
extensionId:
type: string
description: The 4-digit extension number
example: "1010"
user:
type: object
description: User profile and PBX settings
properties:
name:
type: string
description: Discord display name
example: rocord
outboundCid:
type: string
description: Outbound caller ID override
example: ""
voicemail:
type: string
description: Voicemail context
example: default
ringtimer:
type: integer
description: Ring time in seconds before voicemail
example: 0
noanswer:
type: string
description: No-answer destination
example: ""
noanswerDestination:
type: string
description: No-answer destination context
example: ""
noanswerCid:
type: string
description: Caller ID on no-answer
example: ""
busyCid:
type: string
description: Caller ID on busy
example: ""
sipname:
type: string
description: SIP display name
example: ""
extPassword:
type: string
description: SIP secret (masked in dashboard)
example: "REDACTED"
coreDevice:
type: object
description: PBX device configuration
properties:
deviceId:
type: string
description: Device identifier
example: "1010"
dial:
type: string
description: Asterisk dial string
example: PJSIP/1010
devicetype:
type: string
description: Device type (fixed, adhoc, etc.)
example: fixed
description:
type: string
description: Human-readable device description
example: rocord
emergencyCid:
type: string
description: Emergency caller ID override
example: ""
tech:
type: string
description: SIP technology driver
example: pjsip
ActiveCall:
type: object
properties:
channel:
type: string
description: Asterisk channel identifier
example: PJSIP/1010-00000002
uniqueId:
type: string
description: Unique call identifier
example: "1781687772.6"
caller:
type: object
properties:
number:
type: string
description: Caller number
example: "1010"
name:
type: string
description: Caller display name
example: "Call Me Test (MusicOnHold)"
connectedLine:
type: object
properties:
number:
type: string
description: Connected line number
example: "1010"
name:
type: string
description: Connected line display name
example: "Call Me Test (MusicOnHold)"
state:
type: string
description: Call state (e.g. "Up", "Ring")
example: Up
duration:
type: string
description: Call duration in HH:MM:SS format
example: "00:01:49"
application:
type: string
description: Asterisk application name
example: MusicOnHold
applicationData:
type: string
description: Application data/arguments
example: ""
RegisteredDevice:
type: object
properties:
uri:
type: string
description: SIP contact URI
example: sip:1010@192.168.1.100:5060
useragent:
type: string
description: User-Agent header from the device
example: Linphone/4.4.0
ip:
type: string
description: Client IP address
example: 192.168.1.100
port:
type: string
description: Client port
example: "5060"
pingMs:
type: string
description: Round-trip latency in milliseconds
example: "12.34"
Voicemail:
type: object
properties:
messageId:
type: string
description: Unique voicemail identifier
callerIdNum:
type: string
description: Caller's phone number
callerIdName:
type: string
description: Caller's name (if available)
date:
type: string
description: Timestamp of the voicemail
example: "Wed Mar 18 11:57:09 PM UTC 2026"
duration:
type: number
description: Duration in seconds
fileSize:
type: integer
description: Audio file size in bytes
hasAudio:
type: boolean
description: Whether audio is available for playback
folder:
type: string
enum: [INBOX, Family, Friends, Old, Work, Urgent]
description: Current folder
originalMessageId:
type: string
description: Original message ID before any moves
ConferenceRoom:
type: object
properties:
conferenceId:
type: string
description: Conference room identifier
example: "400"
parties:
type: integer
description: Number of participants
example: 1
marked:
type: integer
description: Number of marked participants
example: 0
locked:
type: boolean
description: Whether the room is locked
example: false
Participant:
type: object
properties:
channel:
type: string
description: Asterisk channel identifier
callerIdNum:
type: string
description: Participant's extension number
callerIdName:
type: string
description: Participant's display name
muted:
type: boolean
description: Whether the participant is muted
admin:
type: boolean
description: Whether the participant is a conference admin
talking:
type: boolean
description: Whether the participant is currently speaking
CallRecords:
type: object
properties:
records:
type: object
properties:
total_calls_ever_placed:
type: integer
description: Total calls since launch
example: 5324
record_calls:
type: object
description: Single-day call record
properties:
count:
type: integer
date:
type: string
format: date
last_updated:
type: string
format: date-time
additionalProperties:
type: integer
description: Monthly call totals (e.g. monthly_total_2025-01)
SurveyData:
type: object
properties:
phoneTypes:
type: object
description: Device types and their counts
additionalProperties:
type: integer
example:
softphone: 45
ip_phone: 23
ata: 8
brands:
type: object
description: Device brands and their counts
additionalProperties:
type: integer
example:
Polycom: 12
Cisco: 8
Yealink: 7
needsCategorization:
type: array
description: Devices that couldn't be automatically categorized
items:
type: object
properties:
ua:
type: string
description: User-Agent string
lastUpdated:
type: string
format: date-time
description: When the survey data was last refreshed

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,24 @@
import Header from '@/components/header';
import Footer from '@/components/footer';
import DevelopersClient from './DevelopersClient';
import { Suspense } from 'react';
function DevelopersPageContent() {
return (
<>
<Header />
<main className="flex-grow">
<DevelopersClient />
</main>
<Footer />
</>
);
}
export default function DevelopersPage() {
return (
<Suspense fallback={<div>Loading...</div>}>
<DevelopersPageContent />
</Suspense>
);
}

View file

@ -50,6 +50,10 @@ export default function Footer() {
Ban Appeal Ban Appeal
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-blue-400 transition-all duration-300 group-hover:w-full" /> <span className="absolute bottom-0 left-0 w-0 h-0.5 bg-blue-400 transition-all duration-300 group-hover:w-full" />
</Link> </Link>
<Link href="/developers" className="hover:text-blue-400 transition-colors duration-300 relative group">
Developers
<span className="absolute bottom-0 left-0 w-0 h-0.5 bg-blue-400 transition-all duration-300 group-hover:w-full" />
</Link>
</nav> </nav>
{/* Legal links */} {/* Legal links */}

View file

@ -38,6 +38,9 @@ export default function Header() {
<Link href="/conferences" className="text-gray-300 hover:text-white" onClick={() => plausible('Nav Click', {props: {section: 'Conferences'}})}> <Link href="/conferences" className="text-gray-300 hover:text-white" onClick={() => plausible('Nav Click', {props: {section: 'Conferences'}})}>
Conferences Conferences
</Link> </Link>
<Link href="/developers" className="text-gray-300 hover:text-white" onClick={() => plausible('Nav Click', {props: {section: 'Developers'}})}>
Developers
</Link>
</nav> </nav>
</div> </div>
@ -151,6 +154,13 @@ export default function Header() {
> >
Conferences Conferences
</Link> </Link>
<Link
href="/developers"
className="text-gray-300 hover:text-white transition-colors px-2 py-2 rounded-md hover:bg-gray-800/50"
onClick={() => { plausible('Nav Click', {props: {section: 'Developers'}}); setMobileMenuOpen(false); }}
>
Developers
</Link>
<div className="pt-4 border-t border-gray-800 space-y-3"> <div className="pt-4 border-t border-gray-800 space-y-3">
<div onClick={() => setMobileMenuOpen(false)}> <div onClick={() => setMobileMenuOpen(false)}>

View file

@ -0,0 +1,781 @@
openapi: "3.0.3"
info:
title: LiteNet API
description: |
LiteNet is a free community PBX based on FreePBX. This API allows you to
manage your extension, access voicemails, view conferences, and interact
with the LiteNet PBX programmatically.
**Authentication:** Most endpoints require a Bearer token obtained via
Discord OAuth. Pass it in the `Authorization` header:
`Authorization: Bearer *** version: "1.0.0"
contact:
name: LiteNet
url: https://litenet.tel
servers:
- url: https://api.litenet.tel
description: Production API
- url: http://localhost:3001
description: Local development
paths:
/extensions/me:
get:
summary: Get current extension
description: Returns the authenticated user's extension details,
including their Discord profile and PBX device configuration.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: Extension details
content:
application/json:
schema:
$ref: "#/components/schemas/ExtensionDetails"
"401":
description: Unauthorized
/extensions/me/devicestatus:
get:
summary: Get device registration status
description: Returns whether the user's SIP device is currently
registered with the PBX. Polled every 5 seconds on the dashboard.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: Device status
content:
application/json:
schema:
type: object
properties:
extension:
type: string
description: The extension number
example: "1010"
deviceState:
type: string
description: Human-readable state (e.g. "Registered", "In use")
example: In use
activeChannels:
type: string
nullable: true
description: Active channel info or null if none
example: null
/extensions/me/calls:
get:
summary: List active calls
description: Returns all currently active calls for the authenticated
user's extension. Polled every 5 seconds on the dashboard.
tags:
- Calls
security:
- BearerAuth: []
responses:
"200":
description: List of active calls
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ActiveCall"
delete:
summary: Hangup all calls
description: Hangs up every active call for the user's extension.
tags:
- Calls
security:
- BearerAuth: []
responses:
"200":
description: All calls hung up
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Successfully requested termination for 1 call(s) for extension 1010."
terminatedChannels:
type: array
description: List of terminated channel IDs
items:
type: string
example: ["PJSIP/1010-00000000"]
"401":
description: Unauthorized
/extensions/me/callme:
post:
summary: Call me
description: Triggers the PBX to call the user's extension. Supports
music on hold and echo test modes.
tags:
- Extensions
security:
- BearerAuth: []
parameters:
- in: query
name: mode
required: true
schema:
type: string
enum: [hold, echo]
description: |
`hold` — play music on hold
`echo` — echo test (play back what you say)
- in: query
name: callerId
required: false
schema:
type: string
description: Custom caller ID to display (defaults to the extension number)
- in: query
name: autoAnswerMode
required: false
schema:
type: string
description: Auto-answer mode for the call
responses:
"200":
description: Call initiated
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Successfully initiated hold call to extension 1010."
/extensions/me/resetsecret:
post:
summary: Reset SIP secret
description: Resets the SIP password for the extension. Returns the
new secret once — it cannot be retrieved again.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: Secret reset
content:
application/json:
schema:
type: object
properties:
newSecret:
type: string
description: The new SIP secret (displayed once)
example: "aB3xK9mP2qR7"
/extensions/me/dnd:
get:
summary: Get Do Not Disturb status
description: Returns whether Do Not Disturb is currently enabled.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: DND status
content:
application/json:
schema:
type: object
properties:
extension:
type: string
description: The extension number
example: "1010"
dndStatus:
type: boolean
description: Whether DND is enabled
example: false
post:
summary: Toggle Do Not Disturb
description: Enables or disables Do Not Disturb for the extension.
tags:
- Extensions
security:
- BearerAuth: []
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- dndStatus
properties:
dndStatus:
type: boolean
description: true to enable, false to disable
responses:
"200":
description: DND updated
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "DND status for extension 1010 set to true."
extension:
type: string
description: The extension number
example: "1010"
dndStatus:
type: boolean
description: Updated DND state
example: true
/extensions/me/endpoint:
get:
summary: List registered endpoints
description: Returns all SIP endpoints/devices registered to the
user's extension. Polled every 10 seconds on the dashboard.
tags:
- Extensions
security:
- BearerAuth: []
responses:
"200":
description: List of registered devices
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/RegisteredDevice"
/extensions/me/voicemails:
get:
summary: List voicemails
description: Returns voicemail messages for the authenticated user.
tags:
- Voicemail
security:
- BearerAuth: []
responses:
"200":
description: List of voicemails
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Voicemail"
/extensions/me/voicemails/{messageId}/download:
get:
summary: Download voicemail audio
description: Downloads the WAV audio file for a specific voicemail.
tags:
- Voicemail
security:
- BearerAuth: []
parameters:
- in: path
name: messageId
required: true
schema:
type: string
responses:
"200":
description: WAV audio file
content:
audio/wav:
schema:
type: string
format: binary
/extensions/me/voicemails/{messageId}/move:
patch:
summary: Move voicemail to folder
description: Moves a voicemail into a different folder for organization.
tags:
- Voicemail
security:
- BearerAuth: []
parameters:
- in: path
name: messageId
required: true
schema:
type: string
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- targetFolder
properties:
targetFolder:
type: string
enum: [INBOX, Family, Friends, Old, Work, Urgent]
responses:
"200":
description: Voicemail moved
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Voicemail moved from INBOX to Work."
messageId:
type: string
description: The voicemail message ID
example: "849c9236"
sourceFolder:
type: string
description: Original folder
example: Old
targetFolder:
type: string
description: Destination folder
example: Friends
newMessageNumber:
type: string
description: New message number after move
example: msg0000
/extensions/me/voicemails/{messageId}:
delete:
summary: Delete voicemail
description: Permanently deletes a voicemail message.
tags:
- Voicemail
security:
- BearerAuth: []
parameters:
- in: path
name: messageId
required: true
schema:
type: string
responses:
"200":
description: Voicemail deleted
content:
application/json:
schema:
type: object
properties:
message:
type: string
description: Status message
example: "Voicemail msg0033 deleted permanently from Old."
messageId:
type: string
description: The voicemail message ID
example: "37aca380"
folder:
type: string
description: The folder the voicemail was in
example: Old
originalMessageId:
type: string
description: The original message number
example: msg0033
/conferences:
get:
summary: List conference rooms
description: Returns all currently active conference rooms and
their participant counts.
tags:
- Conferences
responses:
"200":
description: List of conference rooms
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/ConferenceRoom"
/conferences/{conferenceId}:
get:
summary: Get conference participants
description: Returns the list of participants currently in a
specific conference room.
tags:
- Conferences
parameters:
- in: path
name: conferenceId
required: true
schema:
type: string
responses:
"200":
description: List of participants
content:
application/json:
schema:
type: array
items:
$ref: "#/components/schemas/Participant"
/conferences/{conferenceId}/connectme:
post:
summary: Connect to conference
description: Dials the authenticated user's extension and bridges
them into the specified conference room.
tags:
- Conferences
parameters:
- in: path
name: conferenceId
required: true
schema:
type: string
security:
- BearerAuth: []
responses:
"200":
description: Connected to conference
/system/records:
get:
summary: Get call statistics
description: Returns aggregate call statistics for the LiteNet PBX.
Public endpoint — no authentication required.
tags:
- System
responses:
"200":
description: Call statistics
content:
application/json:
schema:
$ref: "#/components/schemas/CallRecords"
/system/survey:
get:
summary: Get hardware survey data
description: Returns aggregated hardware survey data showing device
types, brands, and devices needing categorization.
Public endpoint — no authentication required.
tags:
- System
responses:
"200":
description: Survey data
content:
application/json:
schema:
$ref: "#/components/schemas/SurveyData"
components:
securitySchemes:
BearerAuth:
type: http
scheme: bearer
bearerFormat: UUID
description: |
Obtain a token via Discord OAuth at `/auth/discord`.
Pass it as `Authorization: Bearer ***
schemas:
ExtensionDetails:
type: object
properties:
status:
type: boolean
description: Whether the request was successful
example: true
message:
type: string
description: Status message
example: "Extension found successfully"
id:
type: string
description: Base64-encoded extension identifier
example: "S3BlY2lhbFZvaWNlbWFpbE1lc3NhZ2U="
extensionId:
type: string
description: The 4-digit extension number
example: "1010"
user:
type: object
description: User profile and PBX settings
properties:
name:
type: string
description: Discord display name
example: rocord
outboundCid:
type: string
description: Outbound caller ID override
example: ""
voicemail:
type: string
description: Voicemail context
example: default
ringtimer:
type: integer
description: Ring time in seconds before voicemail
example: 0
noanswer:
type: string
description: No-answer destination
example: ""
noanswerDestination:
type: string
description: No-answer destination context
example: ""
noanswerCid:
type: string
description: Caller ID on no-answer
example: ""
busyCid:
type: string
description: Caller ID on busy
example: ""
sipname:
type: string
description: SIP display name
example: ""
extPassword:
type: string
description: SIP secret (masked in dashboard)
example: "REDACTED"
coreDevice:
type: object
description: PBX device configuration
properties:
deviceId:
type: string
description: Device identifier
example: "1010"
dial:
type: string
description: Asterisk dial string
example: PJSIP/1010
devicetype:
type: string
description: Device type (fixed, adhoc, etc.)
example: fixed
description:
type: string
description: Human-readable device description
example: rocord
emergencyCid:
type: string
description: Emergency caller ID override
example: ""
tech:
type: string
description: SIP technology driver
example: pjsip
ActiveCall:
type: object
properties:
channel:
type: string
description: Asterisk channel identifier
example: PJSIP/1010-00000002
uniqueId:
type: string
description: Unique call identifier
example: "00000000.0"
caller:
type: object
properties:
number:
type: string
description: Caller number
example: "1010"
name:
type: string
description: Caller display name
example: "Call Me Test (Example)"
connectedLine:
type: object
properties:
number:
type: string
description: Connected line number
example: "1010"
name:
type: string
description: Connected line display name
example: "Call Me Test (Example)"
state:
type: string
description: Call state (e.g. "Up", "Ring")
example: Up
duration:
type: string
description: Call duration in HH:MM:SS format
example: "00:01:49"
application:
type: string
description: Asterisk application name
example: MusicOnHold
applicationData:
type: string
description: Application data/arguments
example: ""
RegisteredDevice:
type: object
properties:
uri:
type: string
description: SIP contact URI
example: sip:1010@192.168.1.100:5060
useragent:
type: string
description: User-Agent header from the device
example: Linphone/4.4.0
ip:
type: string
description: Client IP address
example: 192.168.1.100
port:
type: string
description: Client port
example: "5060"
pingMs:
type: string
description: Round-trip latency in milliseconds
example: "12.34"
Voicemail:
type: object
properties:
messageId:
type: string
description: Unique voicemail identifier
callerIdNum:
type: string
description: Caller's phone number
callerIdName:
type: string
description: Caller's name (if available)
date:
type: string
description: Timestamp of the voicemail
example: "Wed Mar 18 11:57:09 PM UTC 2026"
duration:
type: number
description: Duration in seconds
fileSize:
type: integer
description: Audio file size in bytes
hasAudio:
type: boolean
description: Whether audio is available for playback
folder:
type: string
enum: [INBOX, Family, Friends, Old, Work, Urgent]
description: Current folder
originalMessageId:
type: string
description: Original message ID before any moves
ConferenceRoom:
type: object
properties:
conferenceId:
type: string
description: Conference room identifier
example: "400"
parties:
type: integer
description: Number of participants
example: 1
marked:
type: integer
description: Number of marked participants
example: 0
locked:
type: boolean
description: Whether the room is locked
example: false
Participant:
type: object
properties:
channel:
type: string
description: Asterisk channel identifier
callerIdNum:
type: string
description: Participant's extension number
callerIdName:
type: string
description: Participant's display name
muted:
type: boolean
description: Whether the participant is muted
admin:
type: boolean
description: Whether the participant is a conference admin
talking:
type: boolean
description: Whether the participant is currently speaking
CallRecords:
type: object
properties:
records:
type: object
properties:
total_calls_ever_placed:
type: integer
description: Total calls since launch
example: 5324
record_calls:
type: object
description: Single-day call record
properties:
count:
type: integer
date:
type: string
format: date
last_updated:
type: string
format: date-time
additionalProperties:
type: integer
description: Monthly call totals (e.g. monthly_total_2025-01)
SurveyData:
type: object
properties:
phoneTypes:
type: object
description: Device types and their counts
additionalProperties:
type: integer
example:
softphone: 45
ip_phone: 23
ata: 8
brands:
type: object
description: Device brands and their counts
additionalProperties:
type: integer
example:
Polycom: 12
Cisco: 8
Yealink: 7
needsCategorization:
type: array
description: Devices that couldn't be automatically categorized
items:
type: object
properties:
ua:
type: string
description: User-Agent string
lastUpdated:
type: string
format: date-time
description: When the survey data was last refreshed