Frequently Asked Questions
You can send SMS messages programmatically using Node.js, Express, and the Vonage API. Set up an Express server, integrate the Vonage Node.js SDK, create a POST endpoint to handle SMS sending logic, and configure your Vonage API credentials.
The Vonage Node.js SDK (@vonage/server-sdk
) simplifies interaction with the Vonage APIs from your Node.js application. It handles authentication and provides methods for sending SMS messages, making voice calls, and more.
You need a Vonage virtual number to send SMS messages from. This number acts as the sender ID and is required by the Vonage API. Purchase one through the Vonage Dashboard and ensure it's SMS-capable.
While this tutorial uses the simpler vonage.sms.send
method, the Messages API (vonage.messages.send
) is recommended for more advanced use cases. This includes sending MMS, WhatsApp messages, or when you need features like delivery receipts.
Trial accounts can only send SMS to verified test numbers added in your Vonage Dashboard settings. To send to any number, you must upgrade your account by providing billing information.
Create a project directory, initialize npm (npm init -y
), install express
, @vonage/server-sdk
, and dotenv
, configure package.json
for ES modules, set up a .env
file with your API credentials, and create a .gitignore
file.
The .env
file stores your sensitive Vonage API credentials (API Key, API Secret, Virtual Number) and server configuration. It's loaded by the dotenv
package. Never commit this file to version control.
The Vonage API returns a status code ('0' for success). Implement error handling to check for non-zero status codes and provide appropriate feedback to the user. The server logs should record detailed error messages.
The provided example has basic validation. Use a dedicated library like libphonenumber-js
(the Node.js port of google-libphonenumber
) for robust E.164 validation to prevent issues and improve reliability.
Never commit your .env
file to version control. In production, use secure environment variable management provided by your deployment platform (e.g., platform secrets, vault) to prevent unauthorized access.
Use a middleware package like express-rate-limit
to restrict how many requests a user can make within a time period. This protects your application and Vonage account from abuse and unexpected costs.
This is common with Vonage trial accounts. Ensure the recipient number is added to the Test Numbers list in your Vonage Dashboard under Account > Settings > Test Numbers. Upgrading your account removes this limitation.
Check that the VONAGE_FROM_NUMBER
in your .env
file is a valid, SMS-capable Vonage number assigned to your account and is in the correct format (typically E.164 without the leading '+', like '15551234567').
Extend your application by receiving SMS messages (webhooks), implementing delivery receipts, adding more robust error handling and retry logic, using asynchronous sending with queues, or integrating a database for message logging.
Plivo Inbound SMS with Vite, React, and Vue: Two-Way Messaging Tutorial
Build a production-ready full-stack application that receives and responds to inbound SMS messages using Plivo's API. This comprehensive tutorial shows you how to receive SMS in Node.js, handle Plivo webhooks with Express, and create a modern Vite-powered frontend using React or Vue for real-time two-way SMS communication.
Whether you're building customer support systems, appointment reminders, or interactive information services, this guide covers everything from webhook implementation with signature validation to automated SMS responses using Plivo's XML format, frontend integration patterns, security best practices, and production deployment strategies.
Technologies Used
Backend:
express.urlencoded()
andexpress.json()
)..env
files.Frontend:
Development Tools:
System Architecture
The application follows a full-stack architecture for receiving and sending SMS messages:
Prerequisites
Important Trial Account Limitation: Plivo trial accounts can only send SMS to and receive SMS from numbers verified in your Sandbox (Phone Numbers > Sandbox Numbers). You must verify test numbers before development or upgrade to send/receive from any number.
SMS Character Limits and Encoding
Understanding SMS character limits is essential for proper message handling:
E.164 Phone Number Format
All phone numbers must use E.164 international format for reliable SMS delivery:
[+][country code][subscriber number including area code]
+
sign)+12125551234
(country code 1, area code 212, number 5551234)+442071234567
(country code 44, area code 20, number 71234567)+6561234567
(country code 65, no area code, number 61234567)+
followed by 1-9 (no leading zeros).^\+[1-9]\d{1,14}$
Plivo automatically reformats valid variations to E.164, but using correct format from the start ensures reliability and avoids validation errors (Plivo E.164 Guide).
1. Backend Setup: Express Server with Plivo Webhook
Step 1.1: Create Project Structure
Create a new project directory and initialize Node.js:
Step 1.2: Install Backend Dependencies
express
: Web framework for Node.jsplivo
: Official Plivo Node.js SDK (v4.74.0)dotenv
: Environment variable managementnodemon
: Auto-restarts server on file changes (development only)Step 1.3: Configure Environment Variables
Create
.env
in thebackend/
directory:Important: Replace
YOUR_PLIVO_AUTH_ID
andYOUR_PLIVO_AUTH_TOKEN
with actual credentials from your Plivo Console. SetPLIVO_FROM_NUMBER
to your purchased Plivo number in E.164 format.Create
.gitignore
:Step 1.4: Create Express Server with Webhook Handler
Create
backend/server.js
:Step 1.5: Update package.json
Add
"type": "module"
and scripts tobackend/package.json
:Step 1.6: Test Backend Locally
Start the server:
Expected output:
Test the health endpoint:
2. Frontend Setup: Vite with React or Vue
Choose either React or Vue for your frontend. Both integrate identically with the backend.
Option A: React Frontend
Navigate to frontend directory and create Vite + React app:
Create
frontend/src/App.jsx
:Create
frontend/src/App.css
:Update
frontend/vite.config.js
to proxy API requests:Start the frontend:
Option B: Vue Frontend
Alternatively, create a Vue 3 app:
Create
frontend/src/App.vue
:Configure Vite proxy in
frontend/vite.config.js
:3. Configuring Plivo Webhooks with ngrok
Plivo needs a publicly accessible HTTPS URL to send webhook requests. Use ngrok to expose your local server during development.
Step 3.1: Start ngrok
In a new terminal window:
Output will display:
Copy the
https://
URL (e.g.,https://xxxx-xx-xx-xx-xx.ngrok-free.app
).Note: Free ngrok tier includes 1 static domain since August 2023. Configure a static domain at ngrok dashboard to avoid changing URLs between sessions.
Step 3.2: Configure Plivo Application
SMS Webhook Handler
/api/receive_sms
https://xxxx-xx-xx-xx-xx.ngrok-free.app/api/receive_sms
POST
POST
(default)Step 3.3: Assign Application to Your Plivo Number
XML Application
SMS Webhook Handler
Your Express webhook is now connected to your Plivo number. Incoming SMS messages will trigger HTTP POST requests to your server.
4. Testing End-to-End Flow
Test Inbound SMS:
npm run dev
inbackend/
npm run dev
infrontend/
Test Outbound SMS:
Troubleshooting:
PLIVO_AUTH_TOKEN
in.env
matches Plivo Console. Restart backend after changing.env
.vite.config.js
.5. Security Best Practices
5.1 Webhook Signature Validation
Critical security measure: Always validate
X-Plivo-Signature-V3
header to prevent spoofed requests. The providedvalidatePlivoSignature
middleware uses Plivo'svalidateV3Signature
function with SHA256 HMAC (Plivo Signature Validation Guide).How it works:
HMAC-SHA256(Auth Token, URL + Nonce + Body)
X-Plivo-Signature-V3
headerURL Reconstruction Issues: Behind proxies/load balancers,
req.protocol
andreq.get('host')
may differ from actual webhook URL. UseX-Forwarded-Proto
andX-Forwarded-Host
headers as shown in the middleware.5.2 Environment Variables
.env
files to version control5.3 Rate Limiting
Protect
/api/send_sms
endpoint from abuse:5.4 Input Validation and Sanitization
Phone Number Validation: Use
libphonenumber-js
for robust E.164 validation:Message Text Sanitization: Prevent injection attacks if storing messages in database:
5.5 HTTPS in Production
5.6 Opt-Out Compliance
Legal requirement: Honor STOP/UNSUBSCRIBE requests (TCPA compliance in US, similar regulations globally).
The provided webhook handler includes basic keyword detection:
Production implementation:
6. Production Deployment
6.1 Deploy Backend
Option A: Heroku
Option B: Railway
npm i -g @railway/cli
railway login
railway init
railway up
Option C: AWS EC2/Elastic Beanstalk
Deploy as standard Node.js application. Configure environment variables via AWS Systems Manager or
.env
file (ensure proper permissions).6.2 Deploy Frontend
Option A: Vercel
Update API_BASE in
App.jsx
/App.vue
to production backend URL:Option B: Netlify
Configure environment variables in Netlify dashboard.
6.3 Update Plivo Webhook URL
After deployment, update the Message URL in your Plivo Application to your production backend URL:
6.4 Database Integration
Replace in-memory
messages
array with persistent storage:PostgreSQL with Prisma:
Define schema in
prisma/schema.prisma
:Run migrations and update server.js to use Prisma Client.
7. Performance Optimizations
7.1 Async Webhook Processing
For high-volume applications, acknowledge webhook immediately and process asynchronously:
Benefits:
7.2 Frontend: WebSocket for Real-Time Updates
Replace polling with WebSocket for instant message updates:
Backend (add to server.js):
Frontend:
7.3 Caching
Use Redis to cache frequently accessed data:
8. Cost Estimation (Plivo Pricing)
Based on Plivo Pricing (US, as of January 2025):
Example monthly cost (US):
Free trial credits: New accounts receive credits for testing (typically $5-10).
Volume discounts: Available for committed spend agreements ($750+/month minimum).
9. Troubleshooting Common Issues
Issue: Webhook Returns 403 Invalid Signature
Cause: Auth Token mismatch or URL reconstruction error.
Solutions:
PLIVO_AUTH_TOKEN
in.env
matches Plivo Console exactly.env
/api/receive_sms
path)X-Forwarded-Proto
andX-Forwarded-Host
headers are correctly setIssue: No SMS Received on Phone
Causes and solutions:
+
and country codeIssue: Messages Not Appearing in Frontend
Solutions:
vite.config.js
/api/messages
endpoint returns data:Issue: Plivo Retry Loop
Cause: Webhook returns 5xx status code, triggering Plivo's automatic retry mechanism (3 retries: at 60s, 120s, 240s intervals).
Solution: Always return 200 OK with valid XML, even on errors:
Use 5xx statuses only if you want Plivo to retry (e.g., temporary database outage).
Issue: Character Encoding Problems
Cause: Unicode characters exceed GSM-7 character set, switching to UCS-2 (70 char limit).
Solution: Detect encoding and warn users:
Consider removing emoji or using alternative text for longer messages.
10. Advanced Features and Extensions
10.1 Delivery Receipts (DLRs)
Track message delivery status by configuring a callback URL:
Handle DLR webhook:
Possible statuses:
queued
,sent
,failed
,delivered
,undelivered
,rejected
.10.2 MMS Support
Send multimedia messages (images, videos, audio):
Limitations:
10.3 Conversation Threading
Group messages into conversations by phone number pair:
Display grouped conversations in frontend UI.
10.4 Natural Language Processing (NLP)
Integrate AI for intelligent auto-replies:
Use cases: Customer support bots, FAQ automation, appointment scheduling.
11. Testing and Quality Assurance
11.1 Unit Tests with Jest
Create
backend/server.test.js
:Run tests:
11.2 Integration Testing with Plivo
Use Plivo's test credentials (available in Console) to send messages without charges:
11.3 Load Testing
Simulate high-volume webhook traffic with
k6
:Run:
k6 run load-test.js
12. Monitoring and Observability
12.1 Application Performance Monitoring (APM)
Integrate Datadog, New Relic, or Sentry:
12.2 Structured Logging
Replace
console.log
with Winston or Pino:12.3 Health Check Endpoint
Monitor uptime with health checks:
Configure monitoring services (UptimeRobot, Pingdom) to ping
/health
every 5 minutes.13. Compliance and Legal Considerations
13.1 TCPA Compliance (US)
The Telephone Consumer Protection Act regulates automated SMS:
Violation penalties: Up to $1,500 per message.
13.2 GDPR Compliance (EU)
If serving EU users:
13.3 Other Regulations
Recommendation: Consult legal counsel when launching SMS services in new regions.
14. Complete Code Repository
A complete working example of this tutorial is available on GitHub:
Repository: github.com/plivo/plivo-vite-sms-example (adapt URL to actual example repo)
Includes:
Clone and run:
Conclusion
You now have a production-ready full-stack two-way SMS application using Plivo, Node.js/Express, and Vite with React or Vue. This architecture supports:
Next Steps:
Related Resources:
Resources:
For production support and volume pricing, contact Plivo Sales.