---
title: "Validate a phone number in C#"
url: https://recursiveai.org/onecontact/cookbook/validate-phone-number/
description: "Validate a phone number in C# with OneContact: free, open-source .NET code, a runnable example and real output."
version: "1.0.0"
---

# Validate a phone number in C#

**OneContact** is a free, open-source contact data library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies, no network access.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneContact) · [GitHub](https://github.com/recursive-ai-oss/onecontact-csharp) · [Docs](https://recursiveai.org/onecontact/docs/)

Check a phone number against its region’s numbering rules before accepting it in a form.

```shell
dotnet add package RecursiveAI.OneContact
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneContact;

bool valid = PhoneNumber.TryParse(
    "(202) 555-0123", Region.US, out var phone)
    && phone.IsValid;
Console.WriteLine(valid);
```

```text
True
```

**[Download this example (.zip)](https://recursiveai.org/onecontact/cookbook/validate-phone-number/validate-phone-number.zip)**: unzip, then `dotnet run`.

## Full program

```csharp
using RecursiveAI.OneContact;

foreach (string input in new[] { "(202) 555-0123", "123", "not a phone" })
{
    if (!PhoneNumber.TryParse(input, Region.US, out var phone))
    {
        Console.WriteLine($"{input}: cannot parse");
        continue;
    }
    Console.WriteLine($"{input}: valid={phone.IsValid}, possibility={phone.GetPossibility()}");
}
```

`dotnet run` prints:

```text
(202) 555-0123: valid=True, possibility=IsPossible
123: valid=False, possibility=TooShort
not a phone: cannot parse
```

The full program distinguishes an invalid number from text that cannot be parsed. `TryParse` returns false for rejected input; `Parse` instead throws `ContactParseException`.

## Variations

Check validity for a particular region and read the number type:

```csharp
using RecursiveAI.OneContact;

var phone = PhoneNumber.Parse("+44 20 7946 0123");
Console.WriteLine(phone.IsValidForRegion(Region.Parse("GB")));
Console.WriteLine(phone.Type);
```

```text
True
FixedLine
```

## Related recipes

- [Format a phone number as E.164 in C#](https://recursiveai.org/onecontact/cookbook/format-phone-number-e164/)
- [Validate an email address in C#](https://recursiveai.org/onecontact/cookbook/validate-email-address/)
- [Parse a phone number in C#](https://recursiveai.org/onecontact/cookbook/parse-phone-number/)
- [Extract email addresses from text in C#](https://recursiveai.org/onecontact/cookbook/extract-emails-from-text/)

## The short answer

Use `PhoneNumber.TryParse` with a default region, then check `IsValid`. Those are separate tests: a string can parse into a phone value without matching a valid number type in its region. The full program makes that difference visible. The string `123` parses, but it is too short and isn’t valid. Unreadable text fails parsing altogether.

“Valid” here means valid against the numbering metadata, not that a subscriber answers the phone. The library does not contact the number or a carrier. Use this check to catch malformed input, not to establish account ownership. If ownership matters to your application, make confirmation a separate step.

## Is there a way to validate a phone number?

There are three useful questions to ask in order:

- Can the input be parsed? `TryParse` answers this without throwing for rejected input.
- Is its length possible? `GetPossibility()` distinguishes cases such as too short, too long and possible.
- Does it match a recognized number type? `IsValid` answers this using the region’s numbering rules.

Use the last test when accepting a complete number. Use the possibility result when explaining an incomplete number to someone still typing. A possible length alone is not the same as a valid number.

The region is not a formatting preference. A national number needs the country context in which it was entered. `Region.US` supplies that context for the example; `Region.Parse("GB")` supplies it for Britain. A plus-prefixed international number can be parsed without a default region. Without a plus sign or a default region, parsing fails with `phone.region-required`.

`IsValidForRegion` asks a narrower question than `IsValid`: does the number belong to the specified region’s plan? The variation demonstrates this for a British fixed line. Don’t impose that narrower test unless your form actually requires a number from that region. An international customer can legitimately supply a foreign number.

## Can you provide a regex to validate phone numbers?

No single regex over the input covers real numbering plans. Use OneContact’s parser to apply the region’s numbering rules instead. It accepts punctuation, national and international prefixes, extensions and vanity input under the documented parsing rules. A digit-count check would miss the distinction between a plausible length and a recognized number type.

Keep presentation separate from validation. Preserve what the user typed if you need it for editing, validate the parsed value, and use `E164` for an unpunctuated international representation. If the input has an extension, keep that separately: E.164 output omits it. The canonical form includes it as a `;ext=` parameter.

The numbering data is bundled with this package release. It is not a live carrier directory, and changing your application’s acceptance policy is separate from updating that data. The [phone documentation](https://recursiveai.org/onecontact/docs/phones/) describes metadata loading, reason codes and supported operations. For example, a rejected national input may need a region rather than different punctuation. Showing that specific problem is more useful than telling everyone to remove every non-digit character.

As the [OneContact release overview](https://recursiveai.org/onecontact/docs/overview/) states: “Version 1.0 runs on rules and markup alone.”
