v2.1: docs + boot_session sms_enabled + legacy api header: README.md

This commit is contained in:
Zac Gaetano 2026-05-12 00:14:28 -04:00
parent 43bc705c35
commit 78f69d8a88

188
README.md
View file

@ -1,15 +1,36 @@
# Voxtelesys Integration for ERPNext Helpdesk # Voxtelesys Integration for ERPNext / Frappe Helpdesk
Minimal Frappe app that receives an HTTP webhook from **3CX** when an inbound Frappe app that wires the **Voxtelesys** voice + SMS platform into ERPNext —
call arrives (via a Voxtelesys SIP trunk) and automatically creates an giving Helpdesk agents click-to-call, inbound call popups, agent routing,
**HD Ticket** in Frappe Helpdesk. call recording, SMS send/receive, and auto-ticketing on missed calls.
Two architectures are supported and can run side by side:
| Path | Use when | Endpoint |
| --- | --- | --- |
| **Direct API** (v2.x) — ERPNext talks to Voxtelesys directly | You want click-to-call, agent routing, SMS, and recording driven from the desk UI | `api.voxtelesys.handle_inbound_call`, `api.sms.handle_inbound_sms` |
| **3CX bridge** (v1.x, legacy) — 3CX brokers calls, ERPNext just auto-creates tickets | Your 3CX PBX already routes inbound calls and you only want ticketing on the ERPNext side | `api.inbound_call` |
--- ---
## Architecture ## Architecture overview
### Direct API path
``` ```
Voxtelesys SIP trunk → 3CX PBX → CF_URLFetch (Call Flow) → ERPNext webhook → HD Ticket Caller ── PSTN ──→ Voxtelesys ──webhook──→ ERPNext
├─ writes Voxtelesys Call Log
├─ creates HD Ticket on missed call
├─ rings agent (Round Robin / Availability)
└─ returns VoXML <Dial> → call connects to agent's phone
```
### 3CX bridge path
```
Caller ── PSTN ──→ Voxtelesys SIP trunk ──→ 3CX PBX
├─ rings extensions normally
└─ CF_URLFetch ─→ ERPNext (creates HD Ticket only)
``` ```
--- ---
@ -24,67 +45,136 @@ bench --site erp.broadcastmgmt.cloud migrate
bench restart bench restart
``` ```
--- After install, three custom fields are added via fixtures:
## Webhook Endpoint - `User.custom_voxtelesys_number` — E.164 number to ring for inbound routing
- `HD Ticket.custom_voxtelesys_call_sid` — dedup for direct-API missed-call tickets
``` - `HD Ticket.custom_3cx_call_id` — dedup for 3CX-bridge tickets
POST https://erp.broadcastmgmt.cloud/api/method/voxtelesys_integration.api.inbound_call
```
### Parameters (POST body or query string)
| Parameter | Required | Description |
|---|---|---|
| `caller_id` | Yes | Inbound caller number e.g. `+12025551234` |
| `called_did` | No | DID that was dialled |
| `call_id` | No | 3CX internal call ID (for deduplication) |
### Response
```json
{ "ok": true, "ticket": "HD-TICKET-00001" }
```
--- ---
## 3CX Call Flow Setup ## Configuration (direct API path)
1. Open **3CX Management Console → Call Flow Designer** 1. **Get a Voxtelesys API token** from the [Voxtelesys developer portal](https://developer.voxtelesys.com/apis/authorization/).
2. Create a new Call Flow (or edit your inbound DID's flow) 2. Open **Voxtelesys Settings** in ERPNext and fill in:
3. Add a **CF_URLFetch** block with these settings: - **Voxtelesys API Token** (Bearer token)
- **Default Caller ID** (E.164, used for outbound voice and SMS)
- **Public Base URL** (e.g. `https://erp.broadcastmgmt.cloud`)
- **Webhook Signing Secret** (optional but recommended — HMAC-SHA256)
- **Enable Call Recording** if desired
- **Inbound Call Routing** (`Round Robin`, `Availability-Based`, or `Direct (no routing)`)
3. Copy the two **Webhook URLs** shown in Voxtelesys Settings and paste them into:
- Voice API Profile → Answer URL: `…/api/method/voxtelesys_integration.api.voxtelesys.handle_inbound_call`
- SMS Profile → Inbound Webhook: `…/api/method/voxtelesys_integration.api.sms.handle_inbound_sms`
4. Tick **Enabled** and save.
5. Test with the **Test API Connection** button on Voxtelesys Settings.
### Agent routing setup
For Round Robin / Availability-Based routing to work, each agent's **User**
record needs a `Voxtelesys Number` set (the field is added automatically by
the fixture). This is the actual phone number Voxtelesys will dial — usually
the agent's cell or desk phone DID, in E.164.
---
## Configuration (3CX bridge path)
1. **3CX → Management Console → Call Flow Designer**
2. Create or edit the Call Flow for your inbound DID
3. Add a **CF_URLFetch** block:
- **URL**: `https://erp.broadcastmgmt.cloud/api/method/voxtelesys_integration.api.inbound_call` - **URL**: `https://erp.broadcastmgmt.cloud/api/method/voxtelesys_integration.api.inbound_call`
- **Method**: POST - **Method**: POST
- **Parameters**: - **Parameters**:
- `caller_id` = `[caller_id]` (3CX variable for inbound caller number) - `caller_id` = `[caller_id]`
- `called_did` = `[called_did]` (optional) - `called_did` = `[called_did]` (optional)
- `call_id` = `[call_id]` (optional, enables deduplication) - `call_id` = `[call_id]` (recommended — enables dedup)
4. Connect the block in your call flow — it can run in parallel with ringing, no need to wait for the response 4. Optional secret token: `bench --site … set-config voxtelesys_webhook_secret yourtoken` and append `?secret=yourtoken` to the URL.
--- ---
## Optional: Webhook Secret ## Usage
To prevent unauthorized calls to the endpoint, add this to your site config: ### Click-to-call
- **HD Ticket form**: a "Voxtelesys → Call ..." button appears in the
toolbar whenever the ticket's linked Contact has a mobile / phone number.
- **Lead / Contact forms**: same button group; works on any Phone field via
the `frappe.phone_call.handler` override.
- A floating call bar appears at the bottom of the screen showing live call
status. Clicking "Open Log" jumps to the Call Log entry.
### Inbound calls
When a call hits the inbound webhook, the agent on shift gets a popup with
the caller's number and a "Ringing…" indicator. If no agent answers, a
**missed-call HD Ticket** is auto-created (toggle via Voxtelesys Settings →
*Auto-create Helpdesk Ticket on Missed Call*).
### SMS
- **Send**: "Voxtelesys → Send SMS" button on HD Ticket and Lead forms.
- **Receive**: inbound MO messages from a known Contact with an open HD
Ticket are automatically appended as a `Communication` row on the ticket
thread (toggle via Voxtelesys Settings → *Auto-attach Inbound SMS to Open
Ticket*).
- All messages are persisted to the **Voxtelesys SMS Log** doctype with
Dynamic Link entries for cross-referencing.
---
## DocTypes
| Name | Purpose |
| --- | --- |
| **Voxtelesys Settings** | Single — global config |
| **Voxtelesys Call Log** | One row per call (in or out) with status, duration, recording URL, links |
| **Voxtelesys SMS Log** | One row per SMS (in or out) with body, status, delivery receipt, links |
---
## Scheduled jobs
- `sync_pending_call_logs` runs every 5 minutes to reconcile any Call Log
rows stuck in `Ringing` or `In Progress` because a status webhook was
missed. Configured in `hooks.py:scheduler_events`.
---
## Whitelisted API surface
| Method | Auth | Purpose |
| --- | --- | --- |
| `voxtelesys_integration.api.voxtelesys.handle_inbound_call` | guest | Voxtelesys voice webhook |
| `voxtelesys_integration.api.voxtelesys.handle_call_status` | guest | Voxtelesys status callback |
| `voxtelesys_integration.api.voxtelesys.make_outbound_call` | user | Click-to-call from desk UI |
| `voxtelesys_integration.api.voxtelesys.test_connection` | sysmgr | Settings → Test button |
| `voxtelesys_integration.api.voxtelesys.get_linked_call_logs` | user | Form sidebar history |
| `voxtelesys_integration.api.sms.send_sms` | user | Send SMS from desk UI |
| `voxtelesys_integration.api.sms.handle_inbound_sms` | guest | Voxtelesys SMS webhook |
| `voxtelesys_integration.api.sms.get_linked_sms_logs` | user | Form sidebar SMS history |
| `voxtelesys_integration.api.inbound_call` | guest | Legacy 3CX CF_URLFetch entrypoint |
Guest endpoints verify a HMAC-SHA256 signature in the
`X-Voxtelesys-Signature` header against the **Webhook Signing Secret** in
settings (if configured). The legacy 3CX endpoint uses a query-string
`?secret=` token from `site_config.json` instead.
---
## Development
```bash ```bash
bench --site erp.broadcastmgmt.cloud set-config voxtelesys_webhook_secret "yourtoken" cd ~/frappe-bench/apps/voxtelesys_integration
git remote -v # should point at forge.wilddragon.net
bench --site erp.broadcastmgmt.cloud clear-cache && bench restart
``` ```
Then append `?secret=yourtoken` to the 3CX webhook URL. To export updated fixtures after editing custom fields in the UI:
--- ```bash
bench --site erp.broadcastmgmt.cloud export-fixtures --app voxtelesys_integration
## Optional: Custom Field for Deduplication ```
To prevent duplicate tickets if 3CX retries the webhook, add a custom field
to HD Ticket:
- **DocType**: HD Ticket
- **Field Name**: `custom_3cx_call_id`
- **Field Type**: Data
This can be done via **ERPNext → Customize Form → HD Ticket**.
--- ---