Skip to content

Repository files navigation

NetSuite Click-to-Call with AI Call Analysis

SuiteScript 2.1 Twilio Voice SDK UIF v9 TypeScript Jest SDF SuiteApp License: MIT

A NetSuite SuiteApp that adds browser-to-phone calling directly from CRM records. Sales reps click a phone icon on Customer, Contact, or Lead records; a softphone popup opens; calls place via Twilio. Recordings transcribe automatically and are analyzed by NetSuite's N/llm module to produce Phone Call activity records with AI summaries, satisfaction scores, tone keywords, and action items.

Zero external hosting required — every script runs on NetSuite SuiteScript 2.1; everything else is Twilio's managed platform. No middleware, no Node.js server, no external services.

Important

SuiteApp — verify in your account before production use

This repository is an open-source example of a NetSuite + Twilio click-to-call integration with AI call analysis. It is provided for educational and demonstration purposes only. There is no warranty of any kind; use it at your own risk. The code is not certified for quality, security, correctness, or production readiness in your environment.

Twilio usage incurs real costs (Voice, Recording, Conversational Intelligence) and calls are recorded — ensure you meet consent and data-handling requirements for your jurisdiction. Configure the CTC Configuration record, test with the same roles that will place calls, and review execution logs in a sandbox before relying on this in production.

Screenshots

Admin Console

The Click-to-Call Admin Console (Setup Wizard SPA) — deployment status, provisioned phone numbers, assigned reps, preflight checks, and recent call activity with a per-rep breakdown.

Click-to-Call Admin Console

Softphone

The softphone popup launched from a Customer record — contact info, dialpad, and one-click calling via Twilio Voice, all same-origin with NetSuite.

Softphone popup on a Customer record

Phone Call Activities

Completed calls land as Phone Call activity records, enriched with AI briefs, tone keywords, satisfaction scores, and duration.

Phone Call activity records with AI fields

Call Intelligence

The Call Intelligence panel on a Phone Call record — an N/llm-generated summary, satisfaction score, full transcript, and extracted action items.

Call Intelligence panel on a Phone Call record

Features

  • One-click calling from Customer, Contact, and Lead records
  • Softphone popup — dial, mute, hold, contact-info side panel
  • Sales Rep Central portlet — recent calls + rollups at-a-glance
  • Setup Wizard SPA — UIF-based 5-step onboarding + multi-section Admin Console
  • Automatic recording with two-party consent disclosure
  • AI transcription + analysis — Twilio Conversational Intelligence + N/llm (Cohere Command A)
  • Phone Call activity records with full transcript, summary, score, tone keywords, action items
  • Recording cleanup — Twilio recordings auto-deleted after transcript extraction
  • Multi-role support — Admin + Sales Rep custom roles

How It Works

CALL FLOW (synchronous)
    User Event (phone icon)
            │
    Suitelet (softphone popup HTML + Twilio Voice JS SDK 2.x)
            │
    RESTlet (mints Twilio JWT via N/crypto HMAC-SHA256)
            │
    Browser  ───  Twilio Voice  ───  PSTN

ENRICHMENT (async, polled every 15 min)
    Scheduled Script
            │
    Twilio Recordings API + Conversational Intelligence
            │
    N/llm (Cohere Command A)
            │
    Phone Call record updated with transcript + AI fields
            │
    Twilio recording deleted (cost containment)

Architecture

Layer Technology
Phone icon injection UserEvent Script (beforeLoad on Customer/Contact/Lead)
Softphone UI Suitelet-served HTML + Twilio Voice JS SDK 2.7.3
Setup wizard + admin console UIF SPA (@uif-js/core + @uif-js/component)
Auth RESTlet mints Twilio JWTs using N/crypto HMAC-SHA256
Transcription Twilio Conversational Intelligence (async, $0.035/min)
AI analysis N/llm (Cohere Command A, free tier ~1000 req/mo)
Polling Scheduled Script every 15 min on weekdays
Sales Rep dashboard Portlet (Sales Rep Central)
Packaging SDF SuiteApp (com.netsuite.clicktocall)

Project Structure

src/
├── FileCabinet/SuiteApps/com.netsuite.clicktocall/
│   ├── ctc_pl_dashboard.js              Portlet — Sales Rep Central
│   ├── ctc_rl_token.js                  RESTlet — JWT mint + softphone actions
│   ├── ctc_sl_softphone.js              Suitelet — softphone popup HTML
│   ├── ctc_sl_wizard_api.js             Suitelet — setup wizard JSON API
│   ├── ctc_ss_poll_transcripts.js       Scheduled Script — poll Twilio
│   ├── ctc_ue_phone_button.js           UserEvent — phone icon
│   ├── ctc_ue_transcript_viewer.js      UserEvent — Call Intelligence panel
│   ├── lib/                             Shared SuiteScript modules + Twilio SDK
│   └── setup_wizard/                    SPA bundle output (generated, see below)
│       ├── SpaClient.js
│       └── SpaServer.js
├── SuiteApps/com.netsuite.clicktocall/
│   └── setup_wizard/                    SPA TypeScript source
│       ├── SpaClient.tsx                Entry point (5-line, mounts <App />)
│       ├── SpaServer.ts                 Server endpoints
│       ├── App.tsx                      Root PureComponent — subscribes to Store
│       ├── AppController.tsx            Imperative builders + handlers + loaders
│       ├── app/                         State machinery (Action, Reducer, InitialState, Store)
│       ├── components/                  UI building blocks (matches airport360 canonical)
│       │   ├── shared/                  Cross-feature primitives (was render/)
│       │   ├── sections/                Admin Console sections (overview/phones/voice/...)
│       │   └── steps/                   Onboarding wizard step forms
│       └── services/                    Server data fetching (wizardApi)
├── Objects/
│   ├── Records/                         customrecord_*.xml
│   ├── Scripts/                         customscript_*.xml + custspa_*.xml
│   ├── Fields/                          custevent_*.xml (Phone Call CRM fields)
│   └── Lists/                           customlist_*.xml
├── manifest.xml
└── deploy.xml

Prerequisites

  • NetSuite account with SuiteScript 2.1, SDF, and UIF (2025.1+)
  • Twilio account with:
    • Voice-capable phone number
    • API Key + Secret
    • TwiML App pointing to a TwiML Bin
    • Conversational Intelligence service enabled
  • Node.js 20+ (for local development, testing, and the bundle pipeline)
  • @oracle/suitecloud-cli configured with M2M auth (see Deploy below)

Setup

npm install
npm test           # 524 jest tests
npm run lint       # eslint-plugin-suitescript
npm run typecheck  # tsc --noEmit (TS source validation)
npm run bundle     # gulp + rollup — regenerate SPA bundle from TS source

Deploy

# Set up M2M credentials once (one-time per machine):
suitecloud account:setup:ci --account <accountId> --authid <id> \
    --certificateid <certId> --privatekeypath ./private-key.pem

# Deploy (bundles SPA + pushes to NetSuite):
npm run deploy

The npm run deploy script chains gulp bundle (TS → AMD JS) then suitecloud project:deploy. The SPA bundle output (SpaClient.js, SpaServer.js) is committed to git alongside its TypeScript source so a fresh git clone + npm run deploy works without an extra bundle step.

Twilio Configuration

Before the first deploy, set up Twilio:

  1. Purchase a phone number with Voice capability
  2. Create an API Key (Standard) — save the SID and Secret
  3. Create a TwiML Bin with call recording and consent disclosure
  4. Create a TwiML App pointing to the TwiML Bin URL
  5. Enable Conversational Intelligence with auto-transcribe

NetSuite Configuration

After first deploy:

  1. CTC Configuration record — create a singleton instance with Twilio credentials (Account SID, API Key SID, API Secret pointer)
  2. API Secret — store the Twilio API Key Secret value as a custsecret_* NetSuite API Secret; reference its script ID in the config record
  3. Setup Wizard — admins open the Setup Wizard SPA from the Click-to-Call deployment to complete configuration

Testing

npm test                  # 524 tests across 15 suites
npm test -- --watch       # watch mode

Tests use @oracle/suitecloud-unit-testing for SuiteScript module stubs, plus a custom N/llm mock at __mocks__/llm.js. The __tests__/ and __mocks__/ folders are kept local-only and are not included in the published repository.

CI

GitHub Actions runs on every PR + push to main:

  • ESLint (eslint-plugin-suitescript)
  • TypeScript typecheck (tsc --noEmit)
  • Bundle drift gate (regenerates SPA and fails if committed bundle is stale)

The Jest suite runs locally (npm test), not in CI — the test files are kept local-only (see Testing). See .github/workflows/ci.yml.

Cost Estimate

For 10 reps making ~20 calls/day (5 min avg):

Component Monthly
Twilio Phone Number $1.15
Outbound Voice $42.00
Recording Storage $1.50
Conversational Intelligence $105.00
N/llm (free tier) $0.00
Total ~$150/mo

License

MIT

About

NetSuite Click-to-Call with AI Call Analysis — SuiteApp

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages