API Reference

Integrate HelixPhone with your systems using webhooks, call recording uploads, and CRM screen pops.

Sections

1. Status Change Webhook

Sends a POST request to your configured endpoint on every status change. This is the primary integration point for real-time call monitoring, wallboards, and analytics.

Configuration

  • Settings > Webhook Endpoint URL: The URL to receive POST requests
  • Settings > Webhook API Key: Optional Bearer token for authentication

Request Format

Method: POST
Content-Type: application/json
Authorization: Bearer <API Key>
Timeout: 10 seconds
Retry: 2 attempts with 1-second delay
Shutdown: Synchronous with 3-second timeout

Payload Example

{
  "event":         "status_change",
  "status":        "on_call",
  "direction":     "inbound",
  "remote_number": "4169987587",
  "remote_name":   "John Doe",
  "extension":     "1001",
  "call_id":       "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "timestamp":     "2026-02-17T17:48:16.0000000Z",
  "duration":      0
}

Status Values

Status Direction When
available null Phone registers successfully or call ends
busy null User sets status to Busy
away null User sets status to Away
lunch null User sets status to Lunch
do_not_disturb null User enables Do Not Disturb
ringing inbound/outbound Call arrives or you dial out
on_call inbound/outbound Call is answered
hold inbound/outbound Call placed on hold
offline null Phone unregisters or shuts down

2. Heartbeat

HelixPhone sends a heartbeat POST to the webhook endpoint every 60 seconds. If your server does not receive a heartbeat for over one minute, you can assume the softphone has disconnected.

{
  "event":     "heartbeat",
  "status":    "available",
  "extension": "1001",
  "timestamp": "2026-03-05T14:31:00.0000000Z",
  "duration":  0
}

The heartbeat starts automatically when the application launches and stops when the application exits. An offline status_change webhook is still sent on graceful shutdown.

Webhook Event Flow

Registration:
  App starts → status: "available"
  App shuts down → status: "offline" (synchronous)
User Status Changes:
  Via UI or tray menu → "available" | "busy" | "away" | "lunch" | "do_not_disturb"
DND Toggle:
  DND enabled → status: "do_not_disturb"
  DND disabled → status: <previous user status>
Inbound Call:
  Ringing → Answered ("on_call") → Hold → Resume ("on_call") → Ended ("available" + duration)
  Cancelled/Rejected → "available"
  If user had a custom status before the call, it is re-sent after call ends
Outbound Call:
  Dialing ("ringing") → Answered ("on_call") → Hold → Resume ("on_call") → Ended ("available" + duration)

3. CRM Lookup Integration

Automatically opens a URL in the default browser when an incoming call is answered.

URL Format

Use {phone} as a placeholder for the caller's phone number:

https://crm.company.com/search?phone={phone}

The phone number is URL-encoded automatically. Special characters like +, (, ), and spaces are properly escaped.

4. Call Recording Upload

HelixPhone can automatically upload call recordings to your server via HTTP POST.

Recording Format

  • Format: WAV (16-bit PCM, mono, 8000 Hz)
  • Size: ~960 KB per minute
  • Filename: {TO}_{FROM}_{YYYY}_{MM}_{DD}_{HH}_{mm}_{EPOCH_MS}.wav

Upload Request

Method: POST
Content-Type: multipart/form-data
Authorization: Bearer <API Key>
Field name: file
Timeout: 30 seconds per request
Retry: Up to 3 attempts with 2-second delay

5. Configuration Reference

All settings are stored in: %LOCALAPPDATA%\HelixPhone\settings.json

Full Example

{
  "Sip": {
    "Server": "sip.provider.com",
    "Port": 5060,
    "Transport": "UDP",
    "Username": "1001",
    "Password": "secret"
  },
  "Webhook": {
    "EndpointUrl": "https://your-server.com/webhook",
    "ApiKey": "your-secret"
  },
  "Recording": {
    "Enabled": true,
    "UploadUrl": "https://your-server.com/recordings",
    "ApiKey": "your-secret"
  },
  "Crm": {
    "Enabled": true,
    "LookupUrl": "https://crm.company.com/search?phone={phone}"
  },
  "General": {
    "CloseToTray": true,
    "AutoRegister": true,
    "DoNotDisturb": false
  },
  "SpeedDial": [
    { "Name": "Support", "Number": "1001" }
  ]
}