Skip to content

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.

FeatureDetails
Fleet viewPer-phone: model, firmware, MAC, registration status
Templated XML provisioningAccount, codec order, BLF keys, DND, time zone, NTP, VLAN tag
Bulk rebootTrigger a reboot across all selected phones (site_admin+ required)
Per-phone factory-resetWipe a single phone to factory defaults (voip.manage_phones required)
Firmware pushPush a firmware URL to a phone or fleet (site_admin+ required)
Per-phone status pollingSIP registration state, IP address, uptime

GXV touchscreen-only video features and DECT base-station + handset roaming orchestration (beyond single-base provisioning) are not supported.

Grandstream phones use a challenge-response authentication scheme:

  1. FreeSDN posts sha256_hex(username) to /cgi-bin/access; the phone returns a token.
  2. FreeSDN hashes sha256_hex(password + token) and posts it to /cgi-bin/dologin along with the username.
  3. The phone sets session-identity and session-role cookies at login time (Set-Cookie on the /cgi-bin/dologin response). aiohttp carries these automatically for all subsequent /cgi-bin/api-* calls - cookies are the primary authentication mechanism and include_sid=False is the default. Additionally, /cgi-bin/config_get and /cgi-bin/config_update require the sid (also returned in the login JSON body) appended as a query parameter (?sid=<sid>); those two endpoints pass include_sid=True explicitly. The CookieJar(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.

  • 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
Terminal window
# Add the phone
curl -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"
}'

If phones are on the same subnet as the FreeSDN agent, use the discovery scan to find all Grandstream devices:

Terminal window
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.

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.

Terminal window
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
}
}'
Terminal window
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.

Terminal window
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>"]}'

Requires the voip.manage_phones permission. Factory-reset is a per-phone operation - there is no bulk fleet endpoint for factory-reset.

Terminal window
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>"

Requires site_admin role. Provide the target firmware version string; FreeSDN schedules the upgrade across the selected phones via the fleet bulk endpoint:

Terminal window
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"
}'

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.

  • 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
  • /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
CBRRTSSSRFRG

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.