Validating Phone Numbers Using Twilio Lookup API in Rust

December 09, 2025
Written by
Jesuleye Marvellous Oreoluwa
Contributor
Opinions expressed by Twilio contributors are their own
Reviewed by

Validating Phone Numbers Using Twilio Lookup API in Rust

Validating phone numbers is important for many applications like sign-ups, messaging, and customer support. It helps to make sure the phone numbers are real and can be contacted.

In this project, we will build a small command-line tool in Rust that checks if a phone number is valid using the Twilio Lookup API. Twilio is a popular service that provides reliable information about phone numbers.

We choose Rust because it is fast, safe, and easy to use for building small command-line apps. By the end, you will have a tool that takes a phone number as input and tells you if it is valid and some extra details like the phone type or country.

Prerequisites

  • Basic knowledge of Rust and CLI applications
  • A Twilio account (free or paid). Create one if you don't already have one.
  • Rust and Cargo

Configure the required environment variables

To avoid hardcoding your Twilio credentials in your Rust code, it’s best to use environment variables. Specifically, you need to store your Account SID and Auth Token. In your project root, create a new file named .env, which is not shared publicly. Then, paste the code below into the new file:

TWILIO_ACCOUNT_SID=<your_account_sid_here>
TWILIO_AUTH_TOKEN=<your_auth_token_here>

Using the rust-dotenv crate, your Rust app will load these variables at runtime automatically. This way, you can easily change credentials without touching your source code.

Make sure to add .env to your .gitignore file to prevent it from being committed to version control.

Retrieve your Twilio credentials

With your .env file in place, the next step is to retrieve your Twilio credentials. Go to the Twilio Console and sign in to your account. On the console dashboard, locate the Account Info section. There, you’ll see your Account SID and Auth Token. These credentials authenticate your requests to Twilio services, including the Lookup API.

Twilio account dashboard with a welcome message for new user Jesulaye and an option to get a phone number.

Copy both values and paste them into the .env file you created earlier, replacing the <your_account_sid_here> and <your_auth_token_here> placeholders, respectively.

The Lookup API includes features like carrier and caller name lookups, but some of these may have usage limits depending on your plan. You can review Twilio’s pricing and limits for full details.

Set up the Rust project

Now that you have your Twilio credentials, let’s set up the Rust project where we will build the CLI app.

Open your terminal and run the command below to create a new Rust project named "phone_validator" (though, you can choose any name that you prefer) using Cargo:

cargo new phone_validator
cd phone_validator

This creates a new folder named "phone_validator" with the basic Rust project files.

Add the required dependencies

We need a few libraries (called “crates” in Rust) to help us:

  • reqwest: To make HTTP requests to Twilio API
  • serdeand serde_json: To handle JSON data
  • clap: To parse command-line arguments
  • dotenv (optional): To load environment variables

To add them, open the Cargo.toml file in the project's top-level directory and add the following in the "dependencies" section:

reqwest = { version = "0.11", features = ["blocking", "json"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
clap = { version = "4.0", features = ["derive"] }
dotenv = "0.15"

Create the application logic

The main part of your Rust CLI app is the logic that takes a phone number from the user, sends it to the Twilio Lookup API, and handles the response.

It uses the clap crate to read the phone number input on the command line. Then, it creates an HTTP request with the reqwest crate, including your Twilio credentials for authenticated access. After sending the request to the Twilio Lookup API, it receives a JSON response with details about the phone number. It then uses Serde to turn this JSON into Rust structs, making it easy to get information like whether the number is valid, its country code, and its type (such as mobile or landline).

Open main.rs in the project's top-level directory and paste the code below into the file.

use std::env;
use reqwest::Client;
use serde::Deserialize;
use dotenv::dotenv;
#[derive(Debug, Deserialize)]
struct PhoneLookup {
    phone_number: String,
    national_format: Option<String>,
    country_code: Option<String>,
    carrier: Option<CarrierInfo>,
}
#[derive(Debug, Deserialize)]
struct CarrierInfo {
    name: Option<String>,
    r#type: Option<String>,
    mobile_country_code: Option<String>,
    mobile_network_code: Option<String>,
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    dotenv().ok();
    let sid = env::var("TWILIO_ACCOUNT_SID")?;
    let token = env::var("TWILIO_AUTH_TOKEN")?;
    let phone_number = std::env::args()
        .nth(1)
        .expect("Usage: cargo run <phone_number>");
    let url = format!(
        "https://lookups.twilio.com/v1/PhoneNumbers/{}?Type=carrier",
        phone_number
    );
    let client = Client::new();
    let res = client
        .get(&url)
        .basic_auth(&sid, Some(&token))
        .send()
        .await?;
    match res.status().as_u16() {
        200 => {
            let body: PhoneLookup = res.json().await?;
            println!(" Valid number!");
            println!("Phone: {}", body.phone_number);
            println!("National Format: {:?}", body.national_format);
            println!("Country Code: {:?}", body.country_code);
            println!("Carrier Info: {:?}", body.carrier);
        }
        404 => {
            println!(" Invalid number: {} not found.", phone_number);
        }
        code => {
            let error_text = res.text().await?;
            eprintln!(" Error {}: {}", code, error_text);
        }
    }
    Ok(())
}

The code above checks if the phone number provided is valid using the Twilio Lookup API. It loads your Twilio credentials from environment variables using rust-dotenv, reads the phone number from the command line, and sends a GET request using reqwest.

The JSON response is parsed into Rust structs with Serde. If the number is valid, it prints details like the national format, country code, and carrier info. It also handles errors such as missing numbers or API issues, based on the response status.

Test that the application works

To test the application, run the command below after replacing <Your Phone Number> with your phone number in E.164 format.

cargo run <Your Phone Number>

This will trigger a request to the Twilio Lookup API and display the result in the terminal. You can also test with invalid or incomplete numbers to check if error handling works as expected.

The image below shows the result of the output if it's successful, given that the mobile number supplied is valid:

Terminal output showing the result of a Rust program that validates and provides details about a phone number.

Else, if the mobile number is invalid, the output below shows the result

Screenshot of terminal showing Rust project output with a warning, error message, and execution info.

That is how to validate phone numbers using Twilio's Lookup API in Rust

That is how to validate phone numbers using the Twilio Lookup API in Rust — by securely loading your Twilio credentials, accepting a phone number through a simple CLI, and making an authenticated HTTP request to the API.

With proper error handling and clear output, this app not only helps ensure accurate phone data, but also serves as a great starting point for building more powerful Rust tools that interact with external APIs.

Jesuleye Marvellous Oreoluwa is a software engineer who is passionate about teaching technology and enjoys making music.