# How to Integrate Retool with Bandwidth

- Tool: Retool
- Difficulty: Intermediate
- Time required: 20 minutes
- Last updated: April 2026

## TL;DR

Connect Retool to Bandwidth using a REST API Resource with API token and secret authentication. Configure the base URL for Bandwidth's messaging and voice APIs, then build a telephony operations dashboard that lets your team send SMS messages, manage phone numbers, view call logs, and monitor message delivery status — all through Retool's visual query builder.

## Why Build a Retool Bandwidth Dashboard?

Enterprise communications teams using Bandwidth's API for voice, SMS, and MMS workflows need an internal operations panel that goes beyond Bandwidth's web portal. A Retool Bandwidth dashboard gives NOC engineers, operations managers, and customer success teams the ability to monitor message delivery status, investigate failed calls, send operational notifications, and manage phone number inventories — all without requiring API access or developer involvement for routine operational tasks.

Bandwidth is commonly used by enterprises running mission-critical communications: appointment reminders for healthcare systems, two-factor authentication for financial applications, and emergency notifications for public safety organizations. These use cases generate high message and call volumes that operations teams need to monitor continuously. A Retool dashboard can surface delivery failure rates, carrier rejection patterns, and latency metrics in real time, combined with data from your internal CRM or ticketing systems for full operational context.

Bandwidth's API design is clean and REST-based with straightforward Basic Auth, making the Retool integration relatively simple compared to more complex OAuth flows. Since Retool proxies all API calls server-side, your Bandwidth credentials never reach the browser — critical for an enterprise telecom platform where API access can trigger billable actions. Using Retool's configuration variables to store credentials and Retool's permission system to restrict query access ensures only authorized team members can trigger messaging or voice operations from the dashboard.

## Before you start

- A Retool account (Cloud or self-hosted) with permission to add Resources
- A Bandwidth account with API access enabled — Bandwidth accounts require a formal signup process; trial/sandbox accounts are available
- Your Bandwidth API credentials: Account ID, API Token, and API Secret — found in the Bandwidth Dashboard under Account → API Credentials
- A Bandwidth phone number configured for messaging or voice (required to send messages; can be a long code or toll-free number)
- Your Bandwidth messaging application ID if using the v2 Messaging API (applications are configured in Bandwidth Dashboard → Applications)

## Step-by-step guide

### 1. Locate your Bandwidth API credentials and configure the Resource

Bandwidth uses a straightforward Basic Auth scheme with your API Token and API Secret as the credentials. Navigate to the Bandwidth Dashboard (dashboard.bandwidth.com) and go to Account → API Credentials.

You will find three key values:
- Account ID: your numeric Bandwidth account identifier (used in API URL paths)
- API Token: the username component for Basic Auth
- API Secret: the password component for Basic Auth

Copy all three values. Note your Account ID separately — it appears in every Bandwidth API endpoint URL in the format /api/v2/accounts/{accountId}/.

Open Retool and navigate to the Resources tab. Click Add Resource and select REST API. Configure:
- Name: 'Bandwidth API'
- Base URL: https://messaging.bandwidth.com (for messaging operations) or https://voice.bandwidth.com (for voice operations) — you may need two resources if building a combined messaging + voice dashboard
- Authentication: Basic Auth
- Username: your API Token
- Password: your API Secret

Add a default header:
- Content-Type: application/json

Store your Account ID as a Retool configuration variable (Settings → Configuration Variables, name it BANDWIDTH_ACCOUNT_ID, mark as secret) so query paths can reference {{ retoolContext.configVars.BANDWIDTH_ACCOUNT_ID }} rather than hardcoding it.

Click Save Changes. Click Test Connection — a successful response confirms the credentials are valid.

**Expected result:** The Bandwidth API resource appears in the Resources list. Test Connection returns a successful response confirming the API token and secret are valid.

### 2. Query message history and build the delivery monitoring table

Create a query to retrieve outbound message history from Bandwidth's Messaging API v2. In your Retool app, go to the Code panel and create a new query. Select the Bandwidth API (messaging) resource.

Configure the message list query:
- Method: GET
- Path: /api/v2/accounts/{{ retoolContext.configVars.BANDWIDTH_ACCOUNT_ID }}/messages
- URL parameters:
  - sourceTn: {{ sourceNumberSelect.value || '' }} (filter by source number if selected)
  - messageDirection: outbound
  - messageStatus: {{ statusFilter.value || '' }} (filter by delivery status: DELIVERED, FAILED, etc.)
  - fromDateTime: {{ fromDate.value || '' }} (ISO 8601 format: 2024-01-01T00:00:00Z)
  - toDateTime: {{ toDate.value || '' }}
  - limit: 100

Bandwidth's message response includes: messageId, to, from, text (content), messageStatus, carrierName, errorCode, and receiveTime. Add a JavaScript transformer to format timestamps, extract delivery status badges, and map error codes to human-readable descriptions.

Drag a Table component onto the canvas. Bind its data to {{ messagesQuery.data }}. Add column settings to display: From, To, Message preview (first 50 chars), Status (with conditional color coding: green for DELIVERED, red for FAILED), Carrier, Error Code, and Received Time. Enable row selection so clicking a row loads the full message detail in a side panel.

```
// Transformer for Bandwidth message list response
// Maps Bandwidth message objects to display-ready table rows
const messages = data.messages || data || [];
const errorCodeMap = {
  '4720': 'Carrier rejected — spam/content filter',
  '4750': 'Invalid destination number',
  '4770': 'Carrier timeout',
  '9902': 'Rate limit exceeded',
  '9999': 'Unknown carrier error'
};
return messages.map(msg => ({
  message_id: msg.messageId,
  from: msg.from || msg.sourceTn || '',
  to: Array.isArray(msg.to) ? msg.to.join(', ') : (msg.to || msg.destinationTn || ''),
  text_preview: (msg.text || '').substring(0, 60) + ((msg.text || '').length > 60 ? '...' : ''),
  status: msg.messageStatus || msg.currentStatus || '',
  carrier: msg.carrierName || '',
  error_code: msg.errorCode || '',
  error_description: errorCodeMap[String(msg.errorCode)] || '',
  segment_count: msg.segmentCount || 1,
  received_time: msg.receiveTime
    ? new Date(msg.receiveTime).toLocaleString()
    : (msg.sendingTime ? new Date(msg.sendingTime).toLocaleString() : '')
}));
```

**Expected result:** A table populates with recent outbound messages showing delivery status, carrier, and error codes. Filters for date range and status narrow results. Clicking a message row opens a detail panel with the full message content and metadata.

### 3. Build the phone number management panel

Create queries to list and manage phone numbers in your Bandwidth account. In the Code panel, create a new query:
- Method: GET
- Path: /api/account/{{ retoolContext.configVars.BANDWIDTH_ACCOUNT_ID }}/tns
- URL parameters:
  - size: 100
  - page: {{ pagination.page || 0 }}

This query returns your owned Telephone Numbers (TNs). The response includes: fullNumber, status, type (local, toll-free), features, and assignedApplicationId. Add a transformer to clean up the number format and extract key fields.

For searching available numbers, create a second query:
- Method: GET
- Path: /api/account/{{ retoolContext.configVars.BANDWIDTH_ACCOUNT_ID }}/availableNumbers
- URL parameters:
  - areaCode: {{ areaCodeInput.value }}
  - quantity: 10
  - type: local

This returns up to 10 available numbers in the specified area code that can be ordered.

Drag two Table components onto a tabbed Container: one for 'Owned Numbers' bound to the TNs query, one for 'Available Numbers' bound to the search results. Add an 'Order Number' button in the Available Numbers table that triggers a POST query to provision the selected number into your account:
- Method: POST
- Path: /api/account/{{ retoolContext.configVars.BANDWIDTH_ACCOUNT_ID }}/orders
- Body: JSON with the selected number and order details

Add a confirmation dialog before submitting the order since phone number provisioning incurs monthly charges.

```
// Transformer for owned Bandwidth phone numbers
// Handles Bandwidth's XML-like nested response structure
const tnList = data.TelephoneNumberResponse?.TelephoneNumberDetail || [];
const numbers = Array.isArray(tnList) ? tnList : [tnList];
return numbers.map(tn => ({
  number: tn.FullNumber || tn.TelephoneNumber || '',
  formatted: tn.FullNumber
    ? `+1 (${tn.FullNumber.substring(0,3)}) ${tn.FullNumber.substring(3,6)}-${tn.FullNumber.substring(6)}`
    : '',
  status: tn.Status || 'Active',
  type: tn.Type || 'local',
  city: tn.City || '',
  state: tn.State || '',
  application_id: tn.MessagingSettings?.ApplicationId || '',
  features: [
    tn.Features?.Feature
      ? (Array.isArray(tn.Features.Feature) ? tn.Features.Feature.join(', ') : tn.Features.Feature)
      : ''
  ].filter(Boolean).join(', ')
}));
```

**Expected result:** The Owned Numbers table displays all phone numbers in the account with their type, assigned application, and status. The Available Numbers search returns numbers in the specified area code. Order and release buttons are wired with confirmation dialogs.

### 4. Add an SMS compose panel with send functionality

Build a message composition panel for operations teams to send SMS messages through Bandwidth. Add form components to the canvas:
- A Select component 'From Number' populated from the owned numbers query (filtered to messaging-capable numbers)
- A Text Input 'To Number' with a phone number format validator
- A Textarea 'Message Body' with a character count indicator (show segment count: Math.ceil(chars/160))
- A Button 'Send Message' with a confirmation step enabled

Create the send message query:
- Method: POST
- Path: /api/v2/accounts/{{ retoolContext.configVars.BANDWIDTH_ACCOUNT_ID }}/messages
- Body:
```json
{
  "applicationId": "{{ applicationIdInput.value }}",
  "to": ["{{ toNumberInput.value }}"],
  "from": "{{ fromNumberSelect.value }}",
  "text": "{{ messageBodyInput.value }}"
}
```

Set the query to Manual trigger. Add event handlers: On Success → run the messages list query to refresh the delivery table, show a success notification with the messageId, and clear the compose form. On Failure → show an error notification with the error message.

Add an audit log INSERT query that runs on success: write the sender ({{ retoolContext.currentUser.email }}), recipient number, message preview, and timestamp to an internal sms_send_log database table. This creates an audit trail for operational SMS activity.

```
// POST body configuration for sending an SMS via Bandwidth v2 Messaging API
// Wire this as a JSON body in the send message query
{
  "applicationId": "{{ applicationIdSelect.value }}",
  "to": ["{{ toNumberInput.value.startsWith('+') ? toNumberInput.value : '+1' + toNumberInput.value.replace(/\D/g, '') }}"],
  "from": "{{ fromNumberSelect.value }}",
  "text": "{{ messageBodyTextarea.value }}",
  "tag": "{{ 'retool-ops-' + retoolContext.currentUser.email }}"
}
```

**Expected result:** The compose panel allows selecting a from-number, entering a recipient, composing a message, and sending it with a confirmation dialog. Successful sends refresh the delivery monitoring table and show the new message in the log.

### 5. Add call detail records and build a unified dashboard layout

Combine messaging monitoring with voice call detail records (CDRs) for a complete telephony operations dashboard. Create a voice CDR query using the Bandwidth Voice resource:
- Method: GET
- Base URL resource: your Bandwidth Voice resource (voice.bandwidth.com)
- Path: /api/v2/accounts/{{ retoolContext.configVars.BANDWIDTH_ACCOUNT_ID }}/calls
- URL parameters:
  - fromDateTime: {{ dateRange.start }}
  - toDateTime: {{ dateRange.end }}

The calls response includes: callId, direction (inbound/outbound), from, to, startTime, endTime, duration, and disconnect reason. Add a transformer to calculate call duration in minutes and format timestamps.

Organize the dashboard into three tabs using a Tabs component:
1. Message Monitoring — the delivery table with filters and compose panel
2. Call Records — the CDR table with filters by direction and outcome
3. Number Management — the owned/available numbers panels

Add a dashboard header with key metrics displayed as Statistics components:
- Messages sent today (count from messages query filtered to today)
- Message delivery rate (percentage of DELIVERED vs total from today)
- Total active numbers (count from TNs query)
- Failed messages in last 24h (count from messages query filtered to FAILED status)

For complex dashboards combining multiple Bandwidth API resources, carrier-level routing analysis, and automated monitoring workflows, RapidDev's team can help architect and build your Retool solution.

```
// CDR transformer for Bandwidth Voice calls response
const calls = data.calls || data || [];
return calls.map(call => {
  const start = call.startTime ? new Date(call.startTime) : null;
  const end = call.endTime ? new Date(call.endTime) : null;
  const durationSec = start && end ? Math.floor((end - start) / 1000) : 0;
  const durationMin = (durationSec / 60).toFixed(1);
  return {
    call_id: call.callId || '',
    direction: call.direction || '',
    from: call.from || '',
    to: call.to || '',
    start_time: start ? start.toLocaleString() : '',
    end_time: end ? end.toLocaleString() : '',
    duration_sec: durationSec,
    duration_display: durationSec > 60 ? durationMin + ' min' : durationSec + ' sec',
    disconnect_reason: call.disconnectCause || call.disconnectReason || '',
    answered: call.answeredTime ? 'Yes' : 'No'
  };
});
```

**Expected result:** A three-tab dashboard shows message delivery monitoring, call detail records, and phone number management. The header metrics update based on real Bandwidth API data. Operations teams can send messages, review CDRs, and manage numbers from a single panel.

## Best practices

- Store your Bandwidth Account ID, API Token, and API Secret as secret configuration variables in Retool Settings → Configuration Variables — never hardcode them in query paths or body fields
- Create separate Retool resources for Bandwidth's messaging API (messaging.bandwidth.com) and voice API (voice.bandwidth.com) since they have different base URLs and separate quota limits
- Require Retool user confirmation dialogs for all outbound message sends and number ordering operations — these are billable actions that cannot be easily reversed
- Add phone number format validation before send queries — Bandwidth requires E.164 format (+1XXXXXXXXXX for US) and will reject malformed numbers with a 400 error
- Use Retool Workflows with webhook triggers to capture Bandwidth's delivery receipt callbacks and store DLR events in an internal database, enabling accurate real-time delivery tracking in your dashboard
- Implement rate limit awareness in your bulk messaging workflows — Bandwidth enforces per-number throughput limits (typically 1 MPS for long codes) and will return 429 errors if exceeded; add delay or batching logic via Retool Workflows
- For production SMS operations, always include a unique tag value in message requests to make it easier to correlate sent messages with delivery receipts and troubleshoot delivery issues

## Use cases

### Build a message delivery monitoring dashboard

Create a Retool panel that queries Bandwidth's messaging API for recent outbound messages, showing delivery status (delivered, failed, undeliverable), carrier rejection reasons, and latency metrics. Add filters by date range, status, and source phone number. Wire failed message rows to a re-send button that triggers a new message to the same destination number.

Prompt example:

```
Build a message delivery dashboard with a date range picker and status filter (All, Delivered, Failed, Undeliverable). Query Bandwidth's messaging API for messages matching the filter criteria. Display results in a table with columns for message ID, to/from numbers, content preview, status, carrier rejection code, and delivery timestamp. Add a row action button 'Retry Send' that sends a new message to the failed recipient's number.
```

### Build a phone number inventory management panel

Create a Retool panel for managing your Bandwidth phone number inventory — browsing owned numbers, searching for available numbers in a specific area code, assigning numbers to applications or campaigns, and releasing numbers that are no longer needed. Add a usage report view that shows message and call volume per number for the past 30 days.

Prompt example:

```
Build a phone number management panel with two tabs: Owned Numbers and Search Available. The Owned Numbers tab shows all numbers in the account with their assigned application ID, type (local/toll-free), and last 30-day message count. Add a Release Number button with a confirmation dialog. The Search Available tab has an area code input and a Search button that queries Bandwidth for available numbers in that area code and allows ordering them.
```

### Build an operational SMS sender for notifications

Create a Retool tool for operations teams to send bulk or individual SMS notifications through Bandwidth — for incident alerts, appointment reminders, or campaign messages. Include a compose panel with recipient input (single or CSV upload for bulk), message template selection from an internal database, and a send history log that records who sent what message and when.

Prompt example:

```
Create an SMS operations panel with a 'New Message' form showing: From Number dropdown (populated from Bandwidth account numbers), To Number input (with CSV upload for bulk sending), message body textarea with character counter (160 chars = 1 SMS segment), and a Send button. Below the form, show a send history table from the internal sms_send_log database showing sender, recipient count, message preview, timestamp, and delivery success rate.
```

## Troubleshooting

### API returns 401 Unauthorized for all queries

Cause: The API Token or API Secret is incorrect, or the credentials were copied with trailing whitespace. Bandwidth uses Basic Auth with the API Token as the username and API Secret as the password — these are easy to swap.

Solution: In the Bandwidth Dashboard, navigate to Account → API Credentials and verify you are copying the correct values. In Retool, edit the resource and clear both the Username and Password fields before re-entering the values. Test by clicking Test Connection immediately after saving. If 401 persists, generate new API credentials in Bandwidth Dashboard and update the resource.

### Messaging API returns 403 Forbidden when sending messages

Cause: The application ID in the request body does not exist in the Bandwidth account, or the phone number being used to send is not associated with a messaging-enabled application.

Solution: Navigate to Bandwidth Dashboard → Applications and verify the application ID exists and is configured for messaging. Confirm the from phone number in the request is assigned to the messaging application (in Dashboard → Numbers, the number's messaging settings should show the application ID). If using the v2 Messaging API, the applicationId field is required in the request body.

### Phone number list query returns XML instead of JSON, breaking the transformer

Cause: Bandwidth's Dashboard API (for account management operations like number listing) returns XML by default. Some endpoints under dashboard.bandwidth.com use a different content negotiation than the messaging/voice APIs.

Solution: Add an Accept: application/json header to the specific query if the endpoint supports JSON responses. If the endpoint only returns XML (common for Bandwidth's legacy Dashboard API), use DOMParser in your transformer to parse the XML manually, similar to the approach used for B2's S3-compatible API. Check Bandwidth's API documentation for whether the endpoint you are using is the newer REST API (JSON) or the older Dashboard API (XML).

```
// XML parser fallback for Bandwidth Dashboard API responses
if (typeof data === 'string' && data.trim().startsWith('<')) {
  const parser = new DOMParser();
  const xmlDoc = parser.parseFromString(data, 'application/xml');
  // Then extract elements from xmlDoc
}
```

### Message delivery status shows as 'SENT' but never updates to 'DELIVERED'

Cause: Bandwidth's message API returns the initial SENT status synchronously, but delivery confirmations (DLRs) are delivered asynchronously via webhooks — the REST API does not push status updates, it only shows the last known status.

Solution: For real-time delivery status, Bandwidth sends delivery receipts to the callback URL configured in your messaging application. To track DLR data in Retool, configure Bandwidth to send delivery callbacks to a Retool Workflow webhook URL, store incoming DLR events in your database, and query that database from Retool rather than polling Bandwidth's message API repeatedly.

## Frequently asked questions

### Does Bandwidth have a Retool native connector like Twilio does?

No. Bandwidth does not have a native connector in Retool's Resources catalog. You connect via a REST API Resource with Basic Auth using your API Token and Secret. This approach requires manually configuring endpoint paths and query parameters, but provides full access to all of Bandwidth's messaging, voice, and account management APIs.

### How do I monitor incoming messages and calls in Retool?

Bandwidth delivers inbound messages and call events to webhook endpoints configured in your Bandwidth Application settings — Retool does not automatically receive inbound traffic. To monitor inbound activity from Retool, set up a Retool Workflow with a webhook trigger URL and configure Bandwidth to POST inbound message events to that URL. Store incoming events in your database and query that database from your Retool dashboard for a near-real-time inbound monitoring view.

### Can I use Retool to manage Bandwidth's emergency (911) services?

Bandwidth provides Dynamic Location Routing for 911 services through separate E911 API endpoints. While these endpoints are technically accessible via a REST API Resource in Retool, we recommend extreme caution — 911 service configuration errors have serious safety implications. Test all E911 operations thoroughly in a Bandwidth sandbox environment and add multiple confirmation steps before allowing any production E911 configuration changes from Retool.

### How do I handle Bandwidth's rate limits in a high-volume messaging dashboard?

Bandwidth enforces throughput limits per phone number (typically 1 message per second for standard long codes, higher for registered 10DLC numbers). For bulk messaging from Retool, implement a batched send approach using Retool Workflows: create a Schedule or Webhook-triggered Workflow that reads recipients from your database in batches, sends each message with a delay block between sends, and logs results. This avoids 429 rate limit errors that occur when sending too many messages simultaneously from the Retool UI.

### What is the difference between Bandwidth's Dashboard API and the messaging/voice REST API?

Bandwidth has two distinct API surfaces: the Dashboard API (dashboard.bandwidth.com) for account management operations like phone number ordering, provisioning, and account settings — this API returns XML responses and uses different URL patterns. The Messaging API (messaging.bandwidth.com) and Voice API (voice.bandwidth.com) are the runtime APIs for sending messages and managing calls — these return JSON. You may need separate Retool resources and transformer strategies for each API surface in a comprehensive Bandwidth dashboard.

---

Source: https://www.rapidevelopers.com/retool-integrations/bandwidth
© RapidDev — https://www.rapidevelopers.com/retool-integrations/bandwidth
