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

# Format a phone number as E.164 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/)

E.164 formatting gives you a plus sign, country calling code and number without display punctuation.

```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;

var phone = PhoneNumber.Parse(
    "(202) 555-0123", Region.US);
Console.WriteLine(phone.E164);
```

```text
+12025550123
```

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

## Full program

```csharp
using RecursiveAI.OneContact;

var phone = PhoneNumber.Parse("(202) 555-0123 ext. 42", Region.US);
Console.WriteLine($"E.164: {phone.E164}");
Console.WriteLine($"Extension: {phone.Extension}");
Console.WriteLine($"Canonical: {phone.Canonical}");
Console.WriteLine($"National: {phone.Format(PhoneFormat.National)}");
```

`dotnet run` prints:

```text
E.164: +12025550123
Extension: 42
Canonical: +12025550123;ext=42
National: (202) 555-0123 ext. 42
```

The extension stays available on the parsed value, but `E164` leaves it out. “Canonical” is the E.164 number plus `;ext=` and the extension, when present. If input cannot be parsed, `Parse` throws `ContactParseException`.

## Variations

Print a grouped international number and a dialing URI:

```csharp
using RecursiveAI.OneContact;

var phone = PhoneNumber.Parse("+44 20 7946 0123 ext. 42");
Console.WriteLine(phone.Format(PhoneFormat.International));
Console.WriteLine(phone.Format(PhoneFormat.Rfc3966));
```

```text
+44 20 7946 0123 x42
tel:+44-20-7946-0123;ext=42
```

## Related recipes

- [Validate a phone number in C#](https://recursiveai.org/onecontact/cookbook/validate-phone-number/)
- [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

Parse the input with `PhoneNumber.Parse`, then read `phone.E164`. It returns the plus sign, country calling code and national significant number without display punctuation or an extension. This is different from `Canonical`, which appends `;ext=` when the phone value has an extension.

The full program deliberately uses an extension. It prints the E.164 number and extension on separate lines, then prints the canonical and national forms. That makes it clear which value to put into a field that accepts only the international number.

## How do you format a phone number as E.164 in C#?

Start with country context rather than string replacement. The example parses a US national number with `Region.US`. For an input that already starts with a plus sign and calling code, you can omit the default region. For a national input, supply the region in which the number was written.

Don’t just delete punctuation and prepend a plus sign. A national prefix is not necessarily part of the national significant number. Parsing applies the region’s prefix rules; formatting then uses the parsed parts. The British example starts with `020` nationally but uses `20` after the international calling code.

Formatting and validation are separate decisions. If your application only accepts valid numbers, check `IsValid` after parsing and before storing the formatted value. A successfully parsed phone value is not by itself a valid subscriber number, and producing a formatted string does not test whether a call would connect.

Use `TryParse` instead of `Parse` when handling ordinary form input. It lets the form take a rejection path without catching an exception. The [parsing recipe](https://recursiveai.org/onecontact/cookbook/parse-phone-number/) includes that version as runnable code. Decide what a missing region means in your UI: ask for a country or require an international number, rather than guessing one from punctuation.

## How do I format a phone number internationally in C#?

Choose the representation for the destination. `E164` is the compact international number. `PhoneFormat.International` is a grouped, readable international form. `PhoneFormat.National` is the display form within the region. `PhoneFormat.Rfc3966` produces a `tel:` URI with the extension parameter when present. The variation prints the latter two international representations for the same value.

Store an extension in its own field if your downstream API accepts only E.164. Otherwise you risk losing information when you replace the original string with `E164`. Use `Canonical` when you need OneContact’s complete normalized phone value, including the extension, and the receiver understands that representation.

A phone’s calling code also isn’t a substitute for its region. Several regions can share a calling code. Leave parsing and region lookup to the metadata-backed phone type rather than splitting a fixed number of characters from the beginning. The [phone documentation](https://recursiveai.org/onecontact/docs/phones/) lists the supported formats and explains how the canonical form and comparison key differ. Choose deliberately between a display string, a dialing URI and a comparison value; they serve different purposes even when they refer to the same phone.
