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.

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.