# Web Responder & Click-to-Call — How-To Guide

This service powers two customer-facing features, both set up through a **Zoho
form** — you normally don't need server access:

1. **SMS Responder** — a caller reaches a treatment and gets texted back
   hours/address info. Submitting the SMS form also **auto-builds the NetSapiens
   routing** (system user + dial rule + answer rule) for you.
2. **Click-to-Call widget** — a "Call Us" button you embed on a website; a
   visitor enters their number and NetSapiens calls them into a queue.

Both are keyed by a **Config ID** of the form `<ns-domain>-<suffix>`
(e.g. `pressone.net-sms`, `pressone.net-sales`). One NS domain can have many
configs.

---

## Prerequisites

- Access to the **Zoho forms** (SMS form → `/update-sms`, Click-to-Call form → `/update-domain`).
- The **form secret** is already baked into each form as a hidden field — you don't enter it.
- Only for verifying NS objects or reading SMS inventory: access to `ucportal.pressone.net`.
- SSH to `ns-scripts.pressone.net` is only needed for troubleshooting (password in 1Password).

---

## How to Add an SMS Responder

### Step 1 — Gather the values

| Field | What it is | Example |
|---|---|---|
| Config ID | `<ns-domain>-<suffix>`, your unique key | `pressone.net-sms` |
| NS Domain (`api_domain`) | the customer's real NS domain | `pressone.net` |
| SMS Number Owner (`user`) | extension that **owns the SMS DID** (see below) | `2000` |
| NS System User (`ns_system_user`) | the routing user to be auto-created | `8001` |
| From Number | the SMS DID, digits only | `19294873999` |
| Auto-Reply Message | the text the caller receives | `Our hours are Mon–Fri 9am–5pm…` |

**Finding the SMS Number Owner (`user`):** look up which extension owns the DID:
```bash
curl -s -H "Authorization: Bearer $(grep NS_TOKEN /opt/ns-scripts/webresponder/.env | cut -d= -f2)" \
  "https://ucportal.pressone.net/ns-api/v2/domains/pressone.net/smsnumbers"
```
Find the row where `number` matches your from-number — the `dest` field is the `user`.

> **Pick a free `ns_system_user` extension.** It must not already be a real user.
> The auto-provisioning creates it as a Simple User dedicated to routing this
> responder (`service-code=system-webresponder`).

### Step 2 — Submit the SMS Zoho form

Fill the fields above and submit. On success the form returns:
```json
{"status":"ok","id":"pressone.net-sms",
 "provisioning":{"user":"ok","dial_rule":"ok","answer_rule":"ok"}}
```
- All three `provisioning` values should be `"ok"`.
- If any reads `"error: ..."`, the config still saved but that NS step failed —
  see **Troubleshooting** below.

Behind the scenes this saves the config **and** builds the NS routing:
`call → {ns_system_user}@{api_domain} → answer rule forward-always →
webresponder{ns_system_user} → dial rule (To Web) → webhook → SMS sent`.

### Step 3 — Point the treatment at the responder

The auto-created dial rule already routes `webresponder{ns_system_user}` to the
webhook. In the customer's NS portal, route the inbound treatment (Auto
Attendant digit, etc.) to the **NS System User** extension (e.g. `8001`).

### Step 4 — Test

Call the number/treatment and confirm you receive the SMS.

---

## How to Add a Click-to-Call Widget

### Step 1 — Gather the values

| Field | What it is | Example |
|---|---|---|
| Config ID | `<ns-domain>-<suffix>` | `pressone.net-sales` |
| NS Domain (`api_domain`) | the customer's real NS domain | `pressone.net` |
| Queue | call queue in **`EXT@DOMAIN`** format | `9002@pressone.net` |
| Button Text | label on the button | `Call Us Now` |
| Button Color | hex color | `#1a73e8` |
| Company Name | shown in the widget | `PressONE` |
| Logo URL | optional | *(blank)* |

> **The queue MUST include `@domain`** (e.g. `9002@pressone.net`). A bare
> extension silently fails with "Call Queue not found".

### Step 2 — Submit the Click-to-Call Zoho form

On success it returns `{"status":"ok","id":"pressone.net-sales"}`.

### Step 3 — Embed the widget on the customer site

```html
<script src="https://ns-scripts.pressone.net/widget.js?id=pressone.net-sales"></script>
```

### Step 4 — Test

Load the page, click the button, enter a phone number, and confirm the callback
rings and bridges into the queue.

---

## How to Update Hours / Message / Branding

Just **re-submit the same form** with the same Config ID and changed values.
- SMS re-submit: provisioning re-runs but is **idempotent** — existing NS objects
  are left in place (a 409 / "already exists" counts as success), so editing the
  message text won't error.
- The two forms preserve each other's fields, so an SMS submit won't wipe a
  widget's `queue`/branding on the same `id`, and vice-versa.

---

## How to Change the Voice/SMS Wording in Code

The confirmation message callers hear (and other in-code strings) live in
`webresponder/app.py` (`_XML_SUCCESS`). To change it, follow the **deploy
process** in the reference doc (edit local → test → commit → push → pull on
server → restart). Do **not** hand-edit files on the server.

---

## How to Remove a Customer Config

Edit `domains.json` on the server to delete the entry (it's re-read on every
request, no restart needed):
```bash
ssh root@ns-scripts.pressone.net
nano /opt/ns-scripts/webresponder/domains.json
```
For an SMS responder, also remove the NS objects (system user, dial rule, answer
rule) in the NS portal if you want them gone — the app doesn't delete them.

---

## How to Check If It's Working

**Service status:**
```bash
ssh root@ns-scripts.pressone.net
systemctl status ns-webresponder
```

**Watch live logs during a test:**
```bash
journalctl -u ns-webresponder -f
```
A successful SMS call logs:
```
INFO webresponder: caller=+19734321440 id=pressone.net-sms digits=1 call_id=...
INFO SMS sent to +19734321440 via 19294873999
```

**Probe the SMS webhook from the command line:**
```bash
curl -s "https://ns-scripts.pressone.net/webresponder?id=pressone.net-sms&NmsAni=%2B19734321440&Digits=1"
```
Should return XML containing `texted you`.

---

## Troubleshooting

| Symptom | Likely cause | Fix |
|---|---|---|
| Form returns `403 Forbidden` | Wrong/missing form secret | Check the hidden `update_secret` field matches the server's `UPDATE_SECRET` |
| Form returns `400 Missing fields` | A required field was blank | Fill all required fields for that form |
| `provisioning.user = error` | NS API auth or bad `api_domain` | Check `NS_TOKEN`; confirm the domain exists |
| `provisioning.dial_rule = error` | Dial plan / domain issue | Confirm the api-domain's dial plan; check logs |
| `provisioning.answer_rule = error` | System user not ready | Re-submit (idempotent); check logs |
| Call to SMS number does nothing | Treatment not pointed at `ns_system_user` | Route the treatment to that extension |
| Caller hears "could not send" | Config ID not in `domains.json` | Re-submit the form |
| Caller hears "could not send" | Wrong `user`/`from_number` | Re-check SMS inventory |
| Widget shows "Something went wrong" | Bad/empty queue, or `queue` missing `@domain` | Use `EXT@DOMAIN` |
| New endpoint 404s publicly | Caddy not routing it | Add the route to `server-config/Caddyfile` |

---

## Quick Reference

| Task | Where |
|---|---|
| Add/edit SMS responder | SMS Zoho form → `/update-sms` |
| Add/edit click-to-call | Click-to-Call Zoho form → `/update-domain` |
| Widget embed | `<script src="https://ns-scripts.pressone.net/widget.js?id=<ID>"></script>` |
| SMS webhook URL | `https://ns-scripts.pressone.net/webresponder?id=<ID>` |
| View logs | `journalctl -u ns-webresponder -f` |
| Restart service | `systemctl restart ns-webresponder` |
| Full deploy / config detail | `docs/webresponder-reference.md` and runbook |
