Grandstream Phones
The Grandstream adapter is beta-tier . It communicates with Grandstream GXP/GXV SIP desk phones over CGI/HTTP using challenge-response authentication and browser-style cookies. The adapter includes credentials encrypted at rest, an SSRF guard on phone IP, role gates on factory-reset and firmware push, and HMAC-signed provisioning.
What works
Section titled “What works”| Feature | Details |
|---|---|
| Fleet view | Per-phone: model, firmware, MAC, registration status |
| Templated XML provisioning | Account, codec order, BLF keys, DND, time zone, NTP, VLAN tag |
| Bulk reboot | Trigger a reboot across all selected phones (site_admin+ required) |
| Per-phone factory-reset | Wipe a single phone to factory defaults (voip.manage_phones required) |
| Firmware push | Push a firmware URL to a phone or fleet (site_admin+ required) |
| Per-phone status polling | SIP registration state, IP address, uptime |
GXV touchscreen-only video features and DECT base-station + handset roaming orchestration (beyond single-base provisioning) are not supported.
Authentication model
Section titled “Authentication model”Grandstream phones use a challenge-response authentication scheme:
- FreeSDN posts
sha256_hex(username)to/cgi-bin/access; the phone returns atoken. - FreeSDN hashes
sha256_hex(password + token)and posts it to/cgi-bin/dologinalong with the username. - The phone sets
session-identityandsession-rolecookies at login time (Set-Cookieon the/cgi-bin/dologinresponse). aiohttp carries these automatically for all subsequent/cgi-bin/api-*calls - cookies are the primary authentication mechanism andinclude_sid=Falseis the default. Additionally,/cgi-bin/config_getand/cgi-bin/config_updaterequire thesid(also returned in the login JSON body) appended as a query parameter (?sid=<sid>); those two endpoints passinclude_sid=Trueexplicitly. TheCookieJar(unsafe=True)is required because aiohttp’s default cookie jar rejects cookies from IP-literal hosts.
The adapter uses aiohttp with CookieJar(unsafe=True) because Grandstream phones are addressed by IP, and the standard cookie jar rejects cookies for IP-literal hosts.
Passwords are stored encrypted at rest. They are never written to logs.
Prerequisites
Section titled “Prerequisites”- Grandstream phone running firmware 1.0.7.x or later (GXP21xx/GXP16xx series tested)
- HTTP access from the FreeSDN host to the phone management port (default 80)
- A phone admin account (default username:
admin) - Source-IP allowlist: the FreeSDN host IP must be in the phone’s Access Control list, or requests must carry a valid HMAC signature
Adding phones
Section titled “Adding phones”Single phone
Section titled “Single phone”# Add the phonecurl -X POST https://freesdn.example.com/api/v1/voip/phones \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{ "name": "Reception", "ip_address": "10.0.1.101", "mac_address": "00:0b:82:ab:cd:ef", "vendor": "grandstream", "site_id": "<site-uuid>" }'
# Store the admin password on the phone record (encrypted at rest in the phone's settings)curl -X PUT https://freesdn.example.com/api/v1/voip/phones/<phone-uuid>/credentials \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{ "username": "admin", "password": "admin123" }'Fleet discovery
Section titled “Fleet discovery”If phones are on the same subnet as the FreeSDN agent, use the discovery scan to find all Grandstream devices:
curl -X POST https://freesdn.example.com/api/v1/voip/discovery/scan \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{ "subnet": "10.0.1.0/24", "scan_type": "http" }'Discovered phones appear in VoIP → Discovery for manual adoption.
Provisioning
Section titled “Provisioning”FreeSDN uses templated XML provisioning - you define a provisioning template (account parameters, codec order, BLF keys, etc.) and push it to one or more phones.
Create a template
Section titled “Create a template”curl -X POST https://freesdn.example.com/api/v1/voip/templates/ \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{ "name": "Standard Office", "vendor": "grandstream", "site_id": "<site-uuid>", "sip_settings": { "sip_server": "pbx.example.com", "sip_port": 5060, "codec_order": ["PCMU", "PCMA", "G722"] }, "network_settings": { "ntp_server": "pool.ntp.org", "time_zone": "US/Eastern" }, "feature_settings": { "dnd_enabled": false } }'Apply a template to a phone
Section titled “Apply a template to a phone”curl -X POST https://freesdn.example.com/api/v1/voip/phones/<phone-uuid>/provision \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{"force": false, "reboot_after": true}'The adapter renders the template to Grandstream P-code XML, extracts the P-value map, and writes it to the phone via HTTP PUT to /cgi-bin/config_update (POST returns 501 on modern GXP/GRP firmware). The phone reboots to apply the new config.
Bulk operations
Section titled “Bulk operations”Bulk reboot
Section titled “Bulk reboot”curl -X POST https://freesdn.example.com/api/v1/voip/fleet/bulk/reboot \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{"phone_ids": ["<uuid-1>", "<uuid-2>"]}'Per-phone factory-reset
Section titled “Per-phone factory-reset”Requires the voip.manage_phones permission. Factory-reset is a per-phone operation - there is no bulk fleet endpoint for factory-reset.
curl -X POST https://freesdn.example.com/api/v1/voip/phones/<phone-uuid>/factory-reset \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>"Firmware push
Section titled “Firmware push”Requires site_admin role. Provide the target firmware version string; FreeSDN schedules the upgrade across the selected phones via the fleet bulk endpoint:
curl -X POST https://freesdn.example.com/api/v1/voip/fleet/bulk/firmware \ -H "Cookie: freesdn_access=<token>" \ -H "X-CSRF-Token: <csrf>" \ -H "Content-Type: application/json" \ -d '{ "phone_ids": ["<uuid-1>"], "target_version": "1.0.11.16" }'P-code configuration
Section titled “P-code configuration”Grandstream phones use a numeric P-code system for all settings. FreeSDN’s provisioning templates map human-readable fields to P-codes. If you need to set a P-code that is not in the template schema, use the raw_pconfig field:
{ "raw_pconfig": { "P271": "1", "P272": "3" }}Values in raw_pconfig are merged with the rendered template before being pushed to the phone.
Frontend pages
Section titled “Frontend pages”- PhonesListPage - fleet overview with registration status badges
- PhoneDetailPage - per-phone detail, provisioning, BLF configuration
- FleetDashboardPage - aggregate fleet health
- TemplatesPage - provisioning template management
- FirmwarePage (VoIP) - firmware push history
- DiscoveryPage (VoIP) - newly discovered phones awaiting adoption
Backend route prefix
Section titled “Backend route prefix”/api/v1/voip/phones/*- phone CRUD + lifecycle/api/v1/voip/templates/*- provisioning template management/api/v1/voip/provisioning/cfg{MAC}.xml- phone-pull config serving. Access is restricted: the source IP must be in the site’s configured subnet(s), or the request URL must include a valid HMAC signature (?sig=<hex>). No JWT/cookie auth is required (phones pull directly), but unauthenticated external requests from unlisted IPs return 404./api/v1/voip/fleet/bulk/*- bulk reboot + firmware push/api/v1/voip/firmware/*- firmware tracking + compliance/api/v1/voip/discovery/*- scan triggers
Adapter tier
Section titled “Adapter tier”| CB | RR | TS | SSRF | RG |
|---|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ | ✓ |
Dual-gate (DG) is not applicable - phone configuration writes are applied immediately (not staged), because the phone itself is the authority. Every write is logged in the FreeSDN audit trail.
All product names, logos, and brands are property of their respective owners. FreeSDN is an independent project and is not affiliated with or endorsed by the vendors it integrates with. See Trademarks.