# How to Integrate Bolt.new with Vonage (formerly Nexmo)

- Tool: Bolt.new
- Difficulty: Intermediate
- Time required: 20 minutes
- Last updated: April 2026

## TL;DR

Vonage (formerly Nexmo) is a CPaaS alternative to Twilio offering SMS, voice calls, and 2FA — often cheaper for international SMS. In Bolt.new, use the @vonage/server-sdk in a Next.js API route to send messages. Outbound SMS works in Bolt's WebContainer preview; inbound webhooks for receiving messages require deployment to Netlify or Bolt Cloud first.

## Vonage as a Twilio Alternative: SMS, Voice, and 2FA for Bolt Apps

Vonage (formerly Nexmo) is one of the major CPaaS platforms alongside Twilio and Sinch. It covers SMS, voice, video, 2FA, and number verification. For international SMS especially — Europe, Southeast Asia, Latin America — Vonage pricing is often more competitive than Twilio.

The @vonage/server-sdk is the modern unified npm package for TypeScript/JavaScript. It communicates over HTTPS, making it fully compatible with Bolt's WebContainer. Outbound SMS and voice calls work in the Bolt preview. Inbound webhooks require deployment — Bolt's browser-based runtime cannot receive incoming HTTP calls.

Vonage's Messages API v1 is the current standard for sending SMS (replacing the older SMS API). It uses JWT authentication for the most secure implementation, though Basic Auth with API key/secret is simpler to set up and sufficient for most applications.

## Before you start

- A Bolt.new account with a Next.js project created
- A Vonage API account at dashboard.nexmo.com (free trial includes test credits)
- A Vonage virtual phone number (required as sender for SMS in most countries)
- Your Vonage API Key and API Secret from the dashboard
- Understanding that inbound webhook testing requires deployment to a live URL

## Step-by-step guide

### 1. Set Up Your Vonage Account and Get a Virtual Number

Sign up at dashboard.nexmo.com for a free trial account. Vonage provides €2 in free credits on signup, which is enough to send approximately 20-30 test SMS messages depending on destination country. The dashboard shows your API Key and API Secret on the home page — copy both immediately.

For sending SMS, you need a virtual phone number as the 'from' sender in most countries. Navigate to Numbers → Buy Numbers in the dashboard, choose your target country (United States numbers start around €0.90/month), and complete the purchase. The number appears in Your Numbers and should be in E.164 format (e.g., +14155550100).

For the Messages API (the recommended modern API), you also need to set your inbound and status webhook URLs in the Vonage dashboard. These are used when messages are received or delivery receipts arrive. You can use placeholder URLs now and update them after deployment. Go to API Settings → Default SMS setting and switch from 'SMS API' to 'Messages API' — this affects which SDK methods work correctly.

**Expected result:** You have your API Key, API Secret, and a virtual phone number from the Vonage dashboard. The Messages API is set as your default SMS API.

### 2. Install the Vonage SDK and Configure Environment Variables

The @vonage/server-sdk is the modern unified SDK for all Vonage APIs. It replaces the older nexmo npm package and provides TypeScript types for all API responses. Install it in your Bolt.new project along with its peer dependencies.

The SDK supports both Basic Auth (API key + secret) and JWT authentication. For simplicity, Basic Auth is sufficient for sending SMS and most use cases. JWT is required for Voice API calls and provides better security for production apps. Start with Basic Auth and upgrade if you need Voice API functionality.

Store all Vonage credentials in your .env file with no NEXT_PUBLIC_ prefix — they are server-side only secrets that must never be included in client bundles. The Vonage API secret especially should never appear in browser-accessible code.

```
# .env file additions
# Vonage credentials — server-side only, never NEXT_PUBLIC_
VONAGE_API_KEY=your_api_key_here
VONAGE_API_SECRET=your_api_secret_here
VONAGE_FROM_NUMBER=+14155550100
# For Voice API (optional — needed for making/receiving calls)
# VONAGE_APPLICATION_ID=your_application_id
# VONAGE_PRIVATE_KEY_PATH=./vonage_private_key.pem
```

**Expected result:** The @vonage/server-sdk package is installed. lib/vonage.ts initializes the client without TypeScript errors. Environment variables are configured in .env.

### 3. Create the SMS Sending API Route

Build the core API route that sends SMS messages using the Vonage Messages API. The Messages API v1 is the modern endpoint that supports SMS, MMS, WhatsApp, Viber, Facebook Messenger, and RCS from a single consistent interface — unlike the legacy SMS API which only handles basic SMS.

The API route should validate the input (phone number in E.164 format, non-empty message text), call the Vonage Messages API via the SDK, and return the message UUID on success. Vonage returns a unique message_uuid for each sent message, which you can use to track delivery status via webhooks later.

Phone numbers must be in E.164 format (international format with + prefix, e.g., +14155550123 for a US number). A common source of send failures is locally formatted numbers without the country code — validate and normalize numbers before sending.

```
// app/api/send-sms/route.ts
import { NextResponse } from 'next/server';
import { Vonage } from '@vonage/server-sdk';
import { Auth } from '@vonage/auth';

const vonage = new Vonage(
  new Auth({
    apiKey: process.env.VONAGE_API_KEY ?? '',
    apiSecret: process.env.VONAGE_API_SECRET ?? '',
  })
);

const E164_REGEX = /^\+[1-9]\d{6,14}$/;

export async function POST(request: Request) {
  try {
    const { to, text, from } = await request.json();

    if (!to || !E164_REGEX.test(to)) {
      return NextResponse.json(
        { error: 'Invalid phone number. Use E.164 format (e.g., +14155550123)' },
        { status: 400 }
      );
    }
    if (!text || text.trim().length === 0) {
      return NextResponse.json({ error: 'Message text is required' }, { status: 400 });
    }
    if (text.length > 1600) {
      return NextResponse.json({ error: 'Message exceeds 1600 character limit' }, { status: 400 });
    }

    const fromNumber = from ?? process.env.VONAGE_FROM_NUMBER;
    if (!fromNumber) {
      return NextResponse.json({ error: 'No sender number configured' }, { status: 500 });
    }

    const response = await vonage.messages.send({
      message_type: 'text',
      to,
      from: fromNumber,
      channel: 'sms',
      text: text.trim(),
    });

    return NextResponse.json({
      success: true,
      message_uuid: response.message_uuid,
    });
  } catch (error: unknown) {
    console.error('Vonage SMS error:', error);
    const vonageError = error as { response?: { data?: { title?: string; detail?: string } } };
    const detail = vonageError.response?.data?.detail ?? 'Failed to send SMS';
    return NextResponse.json({ error: detail }, { status: 500 });
  }
}
```

**Expected result:** The /api/send-sms endpoint accepts POST requests and sends SMS via Vonage. Test with a curl or Postman request using a verified phone number during development.

### 4. Add Inbound Webhook Handling (Deployment Required)

To receive incoming SMS messages or delivery receipts, you need webhook endpoints that Vonage can call when events occur. Vonage sends a POST request to your registered webhook URL with the message content or delivery status.

During development in Bolt's WebContainer, these webhooks cannot be tested — Bolt's browser-based runtime cannot receive incoming HTTP connections from external servers like Vonage. This is a fundamental WebContainer limitation: the runtime virtualizes networking within the browser but cannot expose ports to the public internet.

Build the webhook handler routes now, but register the webhook URLs in the Vonage dashboard only after deploying. After deployment, go to Vonage Dashboard → API Settings → Default SMS Setting → Messages webhooks, and update the Inbound URL and Status URL to your deployed endpoint URLs.

For local development testing before deploying, you can use tools like ngrok to expose a local port — but that requires running Next.js outside Bolt. The practical approach is to deploy early and test webhooks on the deployed URL.

```
// app/api/webhooks/vonage-inbound/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  try {
    const payload = await request.json();
    // Vonage Messages API inbound SMS payload shape
    const {
      from,        // sender phone number
      to,          // your Vonage virtual number
      text,        // message content
      timestamp,   // ISO timestamp
      message_uuid,
    } = payload;

    console.log('Inbound SMS:', { from, to, text, timestamp, message_uuid });

    // Process the message here:
    // - Save to database
    // - Trigger auto-reply
    // - Route to support ticket

    // IMPORTANT: Always return 200 quickly
    // Vonage retries delivery if no 200 within 10 seconds
    return NextResponse.json({ status: 'received' }, { status: 200 });
  } catch (error) {
    console.error('Inbound webhook error:', error);
    // Still return 200 to prevent Vonage from retrying
    return NextResponse.json({ status: 'error' }, { status: 200 });
  }
}
```

**Expected result:** Webhook routes are created. After deploying and registering the URLs in the Vonage dashboard, incoming SMS messages appear in your server logs.

## Best practices

- Store VONAGE_API_KEY and VONAGE_API_SECRET in server-side environment variables only — never in NEXT_PUBLIC_ prefixed variables or client-side code
- Validate phone numbers in E.164 format before sending — locally formatted numbers without country codes are a common source of delivery failures
- Return HTTP 200 from webhook handlers immediately, then process asynchronously — Vonage retries webhooks that don't receive 200 within 10 seconds
- Test outbound SMS in Bolt's WebContainer preview (it works), but register and test inbound webhooks only after deploying to a live URL
- Use Vonage's Sandbox environment for development testing — it supports test numbers without purchasing credits
- For production apps, implement idempotency by storing message_uuid in your database to detect and ignore duplicate webhook deliveries
- Compare Vonage vs Twilio pricing per country for your target markets — Vonage is often 30-50% cheaper for European and Asian numbers

## Use cases

### International SMS Notifications for SaaS Apps

Send order confirmations, shipping alerts, or account notifications to users in international markets where SMS delivery rates are high and email open rates are low. Vonage's international routing can be cheaper than Twilio for European and Asian phone numbers.

Prompt example:

```
Add Vonage SMS notifications to my Next.js app. Create an API route at /api/send-sms that accepts a 'to' phone number (E.164 format), a 'message' text, and sends it using the Vonage Messages API with @vonage/server-sdk. Store VONAGE_API_KEY, VONAGE_API_SECRET, and VONAGE_FROM_NUMBER in environment variables. Return the message UUID on success.
```

### Two-Factor Authentication via SMS OTP

Implement SMS-based 2FA using Vonage Verify API, which handles OTP generation, delivery, retries, and verification in a single API with built-in fraud protection. This is faster to build than rolling your own OTP logic and handles carrier-level delivery optimization automatically.

Prompt example:

```
Implement two-factor authentication using the Vonage Verify API. Create two API routes: /api/auth/send-otp that takes a phone number and starts a Vonage Verify v2 workflow, and /api/auth/verify-otp that takes the request_id and the code entered by the user and verifies it. Show appropriate error messages for incorrect codes and expired verification requests.
```

### Outbound Voice Calls for Appointment Reminders

Make automated voice calls to remind customers of upcoming appointments, using text-to-speech to read the appointment details. Vonage's Voice API accepts NCCO (Nexmo Call Control Objects) — JSON arrays defining what the call should do — enabling complex call flows without recording audio files.

Prompt example:

```
Build an appointment reminder system using the Vonage Voice API. Create an API route that makes an outbound call to a phone number, uses text-to-speech to say the appointment details, and returns the call UUID. The NCCO should say 'This is a reminder for your appointment tomorrow at [time]. Press 1 to confirm or 2 to cancel.' Handle the keypress webhook to update the appointment status.
```

## Troubleshooting

### 'Non-Whitelisted Destination' error when sending SMS

Cause: Vonage trial accounts can only send SMS to verified phone numbers (numbers you've explicitly added to a whitelist in the dashboard). Attempting to send to unverified numbers fails with this error.

Solution: Go to Vonage Dashboard → Settings → Test Numbers and add the phone number you want to test with. Alternatively, upgrade to a paid account to send to any number.

### Messages API returns 'Authentication failed' despite correct API key and secret

Cause: The Messages API requires a different authentication method than the legacy SMS API. If you have a Vonage Application with JWT auth configured, the Messages API expects JWT, not Basic Auth credentials.

Solution: For Basic Auth, ensure you have NOT configured a Vonage Application ID in your SDK initialization. Use only apiKey and apiSecret. For JWT auth (required for Voice API), use the applicationId and privateKey fields instead.

```
// Basic Auth only (for SMS):
const vonage = new Vonage(new Auth({
  apiKey: process.env.VONAGE_API_KEY ?? '',
  apiSecret: process.env.VONAGE_API_SECRET ?? '',
}));
```

### Inbound webhooks not being received on deployed app

Cause: The webhook URL is not registered in the Vonage dashboard, or the URL was registered with http:// instead of https://, or the webhook URL points to the Bolt preview instead of the deployed URL.

Solution: Go to Vonage Dashboard → API Settings → Default SMS setting (or your Application settings for Voice). Update both the Inbound URL and Status URL to use your exact deployed HTTPS URL. Verify the routes return 200 by calling them manually first.

### 'The request body is invalid' when calling the Messages API

Cause: The Messages API v1 requires a specific JSON shape with message_type, channel, to, from, and the content field matching the message_type. Mixing up field names from the legacy SMS API causes this error.

Solution: Ensure your message object includes all required fields: message_type: 'text', channel: 'sms', to, from, and text. The text field name is specific to SMS — other channels use different content field names.

```
await vonage.messages.send({
  message_type: 'text', // required
  channel: 'sms',      // required
  to: '+14155550123',  // E.164 format
  from: '+14155550100', // your Vonage number
  text: 'Your message', // the content
});
```

## Frequently asked questions

### How do I connect Bolt.new to Vonage (Nexmo)?

Install @vonage/server-sdk, add your VONAGE_API_KEY and VONAGE_API_SECRET to your .env file (server-side only), and create a Next.js API route that initializes the Vonage client and calls vonage.messages.send(). Outbound SMS works immediately in Bolt's WebContainer preview. For inbound messages and delivery receipts, deploy to Netlify or Bolt Cloud and register your webhook URLs in the Vonage dashboard.

### Is Vonage cheaper than Twilio for international SMS?

It depends on the destination country. Vonage is frequently cheaper than Twilio for European Union countries, Southeast Asia, and Latin America. Twilio is sometimes cheaper for US and Canadian numbers. Always compare current pricing on both dashboards for your specific target countries before committing — prices change frequently.

### Can I receive inbound SMS in Bolt's WebContainer preview?

No. Receiving inbound SMS requires Vonage to POST to a webhook URL on your server. Bolt's WebContainer runs inside a browser and cannot receive incoming HTTP connections from external services. You must deploy to Netlify or Bolt Cloud, register the deployed HTTPS URL in the Vonage dashboard, and test inbound messaging on the live site.

### What's the difference between the Vonage SMS API and Messages API?

The SMS API is the legacy endpoint — simpler but limited to SMS only. The Messages API v1 is the modern endpoint supporting SMS, MMS, WhatsApp, Facebook Messenger, Viber, and RCS from a single consistent interface. Use the Messages API for new integrations. The @vonage/server-sdk's vonage.messages.send() method uses the Messages API. Ensure your Vonage dashboard is set to 'Messages API' (not 'SMS API') in the default settings.

### Does Bolt.new work with Vonage Voice API for phone calls?

Yes. The Voice API uses JWT authentication instead of Basic Auth, requiring a Vonage Application with a private key. Create a Vonage Application in the dashboard, download the private key, and initialize the SDK with applicationId and privateKey. Making outbound calls works in Bolt's WebContainer preview, but receiving inbound calls requires a registered answer URL on a deployed server.

---

Source: https://www.rapidevelopers.com/bolt-ai-integrations/nexmo-vonage-api
© RapidDev — https://www.rapidevelopers.com/bolt-ai-integrations/nexmo-vonage-api
