Prerequisites
- Node.js 18+ (native
fetchis available without any packages) - A free VeriRouteIntel API key — get yours here (10 free lookups included, no credit card)
Step 1: Get Your API Key
Sign up at verirouteintel.com/signup. After confirming your email, your API key appears on the dashboard under API Keys. Copy it — you'll pass it as a Bearer token in every request.
Store it as an environment variable rather than hardcoding it:
export VRI_API_KEY="your_key_here"
Or add it to a .env file if you're using dotenv.
Step 2: Make Your First Lookup (JavaScript)
No npm packages needed for the request itself. Node.js 18+ ships fetch natively.
// carrier-lookup.js
const API_KEY = process.env.VRI_API_KEY;
const BASE_URL = 'https://verirouteintel.com/api/v1';
async function lookupCarrier(phoneNumber) {
const response = await fetch(`${BASE_URL}/lrn`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
phone_number: phoneNumber,
include_enhanced_lrn: true,
messaging_lookup: true,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Lookup failed [${response.status}]: ${error.error || response.statusText}`);
}
return response.json();
}
// Usage
(async () => {
const result = await lookupCarrier('14155550100');
console.log(result);
})();
Run it:
VRI_API_KEY=your_key_here node carrier-lookup.js
Step 3: TypeScript Version
The same function with full type coverage:
// carrier-lookup.ts
interface EnhancedLRN {
carrier: string;
carrier_type: 'mobile' | 'landline' | 'voip' | 'unknown';
city: string;
zip_code: string;
}
interface MessagingInfo {
provider: string | null;
enabled: boolean;
country: string;
country_code: string;
reference_id: string;
}
interface CarrierLookupResult {
phone_number: string;
lrn: string;
lrn_activated_at: string | null;
enhanced_lrn: EnhancedLRN;
messaging: MessagingInfo;
}
const API_KEY = process.env.VRI_API_KEY!;
const BASE_URL = 'https://verirouteintel.com/api/v1';
async function lookupCarrier(phoneNumber: string): Promise<CarrierLookupResult> {
const response = await fetch(`${BASE_URL}/lrn`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
phone_number: phoneNumber,
include_enhanced_lrn: true,
messaging_lookup: true,
}),
});
if (!response.ok) {
const error = await response.json();
throw new Error(`Lookup failed [${response.status}]: ${error.error || response.statusText}`);
}
return response.json() as Promise<CarrierLookupResult>;
}
export { lookupCarrier, CarrierLookupResult, MessagingInfo, EnhancedLRN };
Step 4: Parse the Response
A successful lookup returns:
{
"phone_number": "14155550100",
"lrn": "14153000000",
"lrn_activated_at": "2018-03-15T00:00:00Z",
"enhanced_lrn": {
"carrier": "T-Mobile USA",
"carrier_type": "mobile",
"city": "San Francisco",
"zip_code": "94102"
},
"messaging": {
"provider": "Twilio",
"enabled": true,
"country": "United States",
"country_code": "US",
"reference_id": "MSG-ref-abc123"
}
}
| Field | What it tells you |
|---|---|
lrn |
Line Routing Number — reflects number porting |
lrn_activated_at |
When this LRN was last activated; a recent date signals a recent port |
enhanced_lrn.carrier |
The voice network: AT&T, Verizon, T-Mobile, or regional MVNO |
enhanced_lrn.carrier_type |
mobile, landline, or voip — essential for TCPA scoping |
messaging.provider |
The SMS aggregator: Twilio, Bandwidth, Sinch, Telnyx, Vonage, etc. |
messaging.enabled |
Whether the number can receive SMS at all |
Step 5: Error Handling
The API uses standard HTTP status codes. Here's a production-ready error handler:
async function lookupCarrierSafe(phoneNumber) {
try {
const response = await fetch(`${BASE_URL}/lrn`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
phone_number: phoneNumber,
include_enhanced_lrn: true,
messaging_lookup: true,
}),
});
const data = await response.json();
switch (response.status) {
case 200:
return { success: true, data };
case 400:
return { success: false, error: 'Invalid phone number format', code: 'INVALID_NUMBER' };
case 401:
return { success: false, error: 'Invalid or missing API key', code: 'AUTH_ERROR' };
case 402:
return { success: false, error: 'Insufficient account balance', code: 'INSUFFICIENT_BALANCE' };
case 429:
return { success: false, error: 'Rate limit exceeded — retry after delay', code: 'RATE_LIMITED' };
default:
return { success: false, error: data.error || 'Unknown error', code: 'API_ERROR' };
}
} catch (err) {
return { success: false, error: 'Network error', code: 'NETWORK_ERROR' };
}
}
Retry strategy: retry on 429 with exponential backoff. Do not retry on 400 (bad input) or 402 (account balance) — those require action before retrying.
Bulk Lookups for High-Volume Use Cases
For campaign pre-flight, lead list validation, or contact center hygiene, use the /api/v1/lrn/bulk endpoint. It accepts up to 1,000 numbers per request, deduplicates automatically, and bills only for unique numbers.
const response = await fetch(`${BASE_URL}/lrn/bulk`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
phone_numbers: ['14155550100', '12125550199', '13105550177'],
include_messaging: true,
}),
});
const { results, summary, billing } = await response.json();
// summary.duplicates_removed shows how many numbers were deduplicated
// billing.actual_cost shows the final charge
Copy the code — free API key. VeriRouteIntel includes 10 free lookups on signup. No credit card required.
Get your free API keyFrequently Asked Questions
What's the difference between a carrier and a messaging provider?
The carrier is the voice network — AT&T, Verizon, T-Mobile, or a regional MVNO. The messaging provider is the SMS aggregator sitting between the carrier and the sender: Twilio, Bandwidth, Sinch, Telnyx, Vonage, and others. A Verizon subscriber can have their SMS traffic routed through Bandwidth. Most carrier lookup APIs return only the voice carrier; VeriRouteIntel returns both in a single call.
Does this work for ported numbers?
Yes. The API uses LRN (Line Routing Number) data, which reflects the current routing state of a number including porting events. The lrn_activated_at field shows when the current LRN was activated — a recent date indicates a recent port.
What phone number formats does the API accept?
The API accepts NANP (North American Numbering Plan) numbers in any common format: 10-digit (4155550100), E.164 (+14155550100), or punctuated (415-555-0100). The API normalizes the number before lookup.
What's the rate limit on the free tier?
Free accounts include 10 free lookups and are subject to standard API rate limits. For high-volume throughput requirements, see the pricing page for plan options.