Inferensys

Prompt

Phone Number Canonicalization Prompt Template

A practical prompt playbook for normalizing phone numbers from unstructured model outputs into E.164 format with country code inference, extension handling, and type classification.
Developer testing AI inference on mobile phone in hand, laptop with optimization code visible, casual tech review moment.
PROMPT PLAYBOOK

When to Use This Prompt

Define the job-to-be-done, the ideal user, required context, and the boundaries where this prompt should not be applied.

This prompt is designed for identity resolution pipelines, customer data platform (CDP) operators, and CRM integrators who need to ingest phone numbers from unstructured or semi-structured model outputs and convert them into a clean, deduplicatable, E.164-formatted canonical form. The primary job-to-be-done is to take a raw phone number string—potentially containing extensions, vanity characters, country codes, or local formatting—and produce a structured object with a normalized number, a country code, a type classification (mobile, landline, VoIP), and a confidence score. The ideal user is a data engineer or backend developer building an automated data ingestion or identity stitching workflow where downstream systems require strict format compliance.

Use this prompt when you have already extracted a phone number from a larger text but the format is inconsistent. It is not a general-purpose extraction prompt; it assumes a phone number candidate is already isolated. The prompt is most effective when you can provide additional context, such as a default country code for local numbers or a user's locale, to resolve ambiguous cases. It is designed to be wired into a post-processing repair loop, where a validation failure on a phone number field triggers this canonicalization step before the record is written to a system of record. The prompt includes instructions for the model to flag ambiguous numbers for human review rather than guessing, which is critical for high-stakes applications like two-factor authentication or compliance-mandated contact verification.

Do not use this prompt for real-time, sub-millisecond validation where a deterministic regex library like Google's libphonenumber would suffice. The prompt is for repair and disambiguation, not for initial format checking. It is also not a substitute for a full contact deduplication pipeline; it standardizes a single identifier, not a complete record. Avoid using this prompt on raw, multi-line text blobs containing multiple phone numbers—pair it with an extraction prompt first. The next step after reading this section is to review the prompt template, adapt the placeholders to your application's context, and integrate it into a validation harness that can measure false-positive canonicalization rates against a golden dataset of known numbers.

PRACTICAL GUARDRAILS

Use Case Fit

Where the Phone Number Canonicalization Prompt Template works and where it does not. Use these cards to decide if this prompt fits your pipeline before integrating it.

01

Good Fit: Unstructured CRM Ingestion

Use when: phone numbers arrive in free-text fields, chat transcripts, or email signatures with mixed formatting. Guardrail: The prompt expects a raw string input and returns E.164, so ensure your pipeline extracts the candidate string before calling the prompt.

02

Bad Fit: Real-Time Telecom Routing

Avoid when: sub-millisecond latency is required or the number must be validated against a live carrier database. Guardrail: This prompt performs syntactic normalization and inference, not carrier lookup. Pair with a telecom API for routing decisions.

03

Required Inputs

What to watch: The prompt needs a raw phone string and an optional country hint. Missing the hint degrades international disambiguation. Guardrail: Always pass a two-letter ISO country code as a hint when the user's locale is known to reduce ambiguous inference.

04

Operational Risk: Silent Misformatting

What to watch: The model may return a well-formatted but incorrect number for ambiguous local vs. international patterns. Guardrail: Implement a post-processing validator that checks digit count and country code validity before the number enters your system of record.

05

Operational Risk: Extension Loss

What to watch: Extensions after a 'x' or 'ext' delimiter may be dropped or incorrectly merged into the main number. Guardrail: Test with a harness of extension-heavy inputs and add a regex-based fallback to re-attach extensions if the model strips them.

06

Bad Fit: Bulk Telco Data Cleansing

Avoid when: processing millions of records where cost and throughput dominate. Guardrail: Use deterministic libphonenumber-based logic for bulk jobs. Reserve this prompt for records that fail deterministic parsing or come from unstructured text.

PROMPT PLAYBOOK

Copy-Ready Prompt Template

A reusable prompt template with square-bracket placeholders for canonicalizing phone numbers into E.164 format with country code inference and type classification.

This prompt template is designed to be dropped into an identity resolution pipeline, a CRM ingestion workflow, or a post-generation repair loop. It takes a raw phone number string—potentially malformed, missing a country code, or carrying an extension—and produces a structured, E.164-compliant output with explicit reasoning. The template uses square-bracket placeholders for all variable inputs so you can adapt it to your own validation rules, default country, and output schema without rewriting the core instruction.

text
You are a phone number canonicalization engine. Your job is to convert a raw phone number string into a clean, E.164-formatted number with country code inference, extension normalization, and type classification.

## INPUT
Raw phone number: [INPUT]

## CONTEXT
- Default country for inference when no country code is present: [DEFAULT_COUNTRY_CODE]
- Known valid country codes in our system: [VALID_COUNTRY_CODES]
- Extension separator preferences: [EXTENSION_SEPARATORS]

## OUTPUT SCHEMA
Return a JSON object with exactly these fields:
{
  "original": "string (the raw input)",
  "e164": "string (E.164 formatted number or null if unrepairable)",
  "country_code": "string (ISO 3166-1 alpha-2 or null)",
  "national_number": "string (national significant number without country code)",
  "extension": "string or null",
  "type": "string (one of: mobile, fixed_line, voip, toll_free, premium_rate, shared_cost, personal_number, pager, uan, unknown)",
  "is_valid": boolean,
  "confidence": "string (one of: high, medium, low)",
  "repair_actions": ["string (list of transformations applied, e.g., 'added_country_code', 'stripped_formatting', 'normalized_extension')"],
  "warnings": ["string (any concerns about the result, e.g., 'ambiguous_country_code', 'number_too_short')"]
}

## CONSTRAINTS
1. Always strip non-digit characters except the leading '+' and any extension separator specified in [EXTENSION_SEPARATORS].
2. If no country code is present, infer from [DEFAULT_COUNTRY_CODE] and mark confidence as 'medium' with warning 'inferred_country_code'.
3. If the number matches patterns for multiple countries in [VALID_COUNTRY_CODES], mark confidence as 'low' with warning 'ambiguous_country_code' and list the alternatives in warnings.
4. If the number is unrepairable (fewer than 7 digits after stripping, or contains alphabetic characters that aren't extension labels), set e164 to null, is_valid to false, and explain in warnings.
5. For extensions, strip any label like 'ext', 'x', or 'extension' and store only the numeric portion.
6. Do not invent digits. If you cannot determine the correct number, mark it invalid rather than guessing.

## EXAMPLES
Input: "(415) 555-2671"
Default country: "US"
Output: {"original": "(415) 555-2671", "e164": "+14155552671", "country_code": "US", "national_number": "4155552671", "extension": null, "type": "fixed_line", "is_valid": true, "confidence": "medium", "repair_actions": ["stripped_formatting", "added_country_code"], "warnings": ["inferred_country_code"]}

Input: "+44 20 7946 0958"
Default country: "US"
Output: {"original": "+44 20 7946 0958", "e164": "+442079460958", "country_code": "GB", "national_number": "2079460958", "extension": null, "type": "fixed_line", "is_valid": true, "confidence": "high", "repair_actions": ["stripped_formatting"], "warnings": []}

Input: "555-1234 ext. 201"
Default country: "US"
Output: {"original": "555-1234 ext. 201", "e164": "+15551234", "country_code": "US", "national_number": "5551234", "extension": "201", "type": "unknown", "is_valid": true, "confidence": "low", "repair_actions": ["stripped_formatting", "added_country_code", "normalized_extension"], "warnings": ["inferred_country_code", "number_too_short"]}

Input: "not-a-number"
Default country: "US"
Output: {"original": "not-a-number", "e164": null, "country_code": null, "national_number": null, "extension": null, "type": "unknown", "is_valid": false, "confidence": "low", "repair_actions": [], "warnings": ["unrepairable_input"]}

## RISK LEVEL
[RISK_LEVEL]

If RISK_LEVEL is 'high', add an additional field "requires_human_review": boolean to the output and set it to true whenever confidence is 'low' or warnings contains 'ambiguous_country_code'.

To adapt this template, replace each square-bracket placeholder with your pipeline's configuration. For a CRM ingestion workflow, set [DEFAULT_COUNTRY_CODE] to your primary market, [VALID_COUNTRY_CODES] to the ISO codes you accept, and [EXTENSION_SEPARATORS] to ["ext", "x", "extension"]. If you are running in a high-risk identity resolution pipeline, set [RISK_LEVEL] to "high" to enable the mandatory human-review flag. For batch processing, wrap this prompt in a loop that feeds one raw number per call and validates each JSON response against the schema before writing to your canonical data store. Always log the repair_actions and warnings fields to your observability system so you can monitor how often the model is inferring country codes or flagging ambiguous numbers.

IMPLEMENTATION TABLE

Prompt Variables

Placeholders required by the Phone Number Canonicalization prompt template. Replace each placeholder with concrete values before sending the prompt to the model. Validation notes describe how to check that the supplied input is well-formed before execution.

PlaceholderPurposeExampleValidation Notes

[INPUT_PHONE_NUMBER]

The raw phone number string extracted from the model output, which may include formatting, extensions, or missing country code

+1 (555) 123-4567 ext. 890

Must be a non-empty string. Null or zero-length input should short-circuit before the prompt is sent. Check for obviously invalid inputs like '000-000-0000' or strings with no digits.

[DEFAULT_COUNTRY_CODE]

The ISO 3166-1 alpha-2 country code to assume when the input number lacks an explicit country prefix

US

Must be a valid two-letter uppercase country code from an allowed list. Reject unknown or unsupported codes. This value drives the E.164 country prefix inference and must match the deployment region or user context.

[ALLOWED_EXTENSION_FORMATS]

A list of acceptable extension separator patterns the model should recognize and normalize

["ext.", "x", "#", "extension"]

Must be a non-empty array of lowercase strings. Validate that each entry is a known separator pattern. Missing entries cause the model to treat extensions as part of the main number.

[OUTPUT_SCHEMA]

The expected JSON schema describing the canonicalized output fields

{"type": "object", "properties": {"e164": {"type": "string"}, "extension": {"type": ["string", "null"]}, "number_type": {"type": "string", "enum": ["mobile", "landline", "voip", "unknown"]}, "country_code": {"type": "string"}, "is_valid": {"type": "boolean"}, "confidence": {"type": "number"}}, "required": ["e164", "number_type", "country_code", "is_valid", "confidence"]}

Must be a valid JSON Schema object parseable by a schema validator. Confirm that required fields match downstream consumer expectations. Schema drift between prompt and validator causes silent failures.

[COUNTRY_CODE_MAPPING]

A mapping from ISO country codes to E.164 dialing prefixes for disambiguation when multiple countries share number patterns

{"US": "1", "CA": "1", "GB": "44", "AU": "61"}

Must be a valid JSON object where keys are ISO alpha-2 codes and values are numeric dialing prefixes as strings. Validate that every key appears in the allowed country code list. Missing entries cause incorrect prefix assignment for NANP-sharing countries.

[AMBIGUITY_THRESHOLD]

The confidence score below which the model should flag the result for human review rather than auto-accepting the canonicalization

0.85

Must be a float between 0.0 and 1.0. Values above 0.95 may cause excessive human review requests. Values below 0.5 risk accepting incorrect canonicalizations. Calibrate against a labeled test set before production use.

[MAX_RETRIES]

The maximum number of repair attempts allowed when the output fails schema validation or confidence thresholds

3

Must be a positive integer. Set to 1 for latency-sensitive pipelines. Values above 5 rarely add value and increase cost. Track retry exhaustion rate in production to detect systemic canonicalization failures.

PROMPT PLAYBOOK

Implementation Harness Notes

How to wire the phone number canonicalization prompt into an application with validation, retries, logging, and model choice.

The phone number canonicalization prompt is designed to be called as a stateless function inside a data pipeline or API handler. It accepts a raw phone number string and optional context (such as a default country code or user locale) and returns a structured E.164 payload. The prompt should be treated as a post-extraction repair step, not a real-time user-facing feature. Wire it after your initial extraction or generation step, and before any downstream CRM write, identity resolution match, or SMS send operation. The prompt expects the model to reason about ambiguous cases (e.g., a 10-digit number that could be local in multiple countries), so always provide a [DEFAULT_COUNTRY] hint when available to reduce disambiguation errors.

Validation and retry logic must sit outside the prompt. After the model returns a JSON payload, validate the e164 field against a strict E.164 regex (e.g., ^\+[1-9]\d{1,14}$). If validation fails, retry once with the error message injected into the prompt's [PREVIOUS_ERROR] placeholder. If the second attempt also fails, log the raw input, the model's output, and the validation error, then route the record to a human review queue. Do not silently drop invalid numbers—they often represent edge cases worth fixing. For high-throughput pipelines, implement a circuit breaker that halts processing if the failure rate exceeds 5% over a rolling window of 100 calls, preventing cascading bad outputs from polluting your canonical data store.

Model choice matters. Use a model with strong instruction-following and JSON output discipline, such as GPT-4o, Claude 3.5 Sonnet, or a fine-tuned variant if you have sufficient training data. Avoid smaller or older models that struggle with the structured output format and country code inference simultaneously. Enable structured output mode (JSON mode or function calling with a strict schema) to reduce parsing failures. Log every call with the prompt_version, model_id, input_hash, output_e164, confidence_score, and validation_passed fields. This audit trail is essential for debugging disambiguation errors and proving data quality to downstream consumers. For batch processing, implement rate limiting and exponential backoff to handle API throttling gracefully.

When to escalate beyond a prompt: If your pipeline processes more than 10,000 numbers per day, the latency and cost of LLM-based canonicalization may become prohibitive. In that case, use the prompt to build a labeled dataset of raw-to-canonical pairs, then train a lightweight classifier or deterministic rule engine for the common cases, reserving the LLM prompt only for ambiguous or low-confidence inputs. Similarly, if your use case requires real-time canonicalization (e.g., during live call routing), the prompt's latency is too high; pre-compute canonical forms or use a deterministic library like Google's libphonenumber for the fast path, falling back to the LLM prompt only when the library returns an invalid or ambiguous result. Never use this prompt as the sole validation step before sending SMS or making phone calls—always confirm the number is reachable through a separate verification channel.

IMPLEMENTATION TABLE

Expected Output Contract

Fields, types, and validation rules for the canonicalized phone number object returned by the prompt. Use this contract to build a post-processing validator before the output enters your identity resolution pipeline.

Field or ElementType or FormatRequiredValidation Rule

canonical_number

string (E.164)

Must match ^+[1-9]\d{1,14}$ regex. No spaces, hyphens, or parentheses.

original_input

string

Must equal the raw [PHONE_INPUT] value exactly. Null not allowed.

country_code

integer

Must be 1-3 digits. Must match the leading digits of canonical_number after the + sign.

national_number

string

Must be the digits following country_code in canonical_number. Length must be valid for the inferred country.

extension

string or null

If present, must be digits only. Null if no extension detected in input. Must not appear inside canonical_number.

number_type

enum

Must be one of: mobile, fixed_line, voip, toll_free, premium_rate, shared_cost, personal_number, pager, uan, unknown. Unknown allowed only when classification is genuinely ambiguous.

inferred_country

string (ISO 3166-1 alpha-2)

Must be a valid two-letter country code. Must be the country used for E.164 formatting when no explicit country code was in the input.

confidence

float

Must be between 0.0 and 1.0 inclusive. Values below 0.7 should trigger human review in high-assurance pipelines.

PRACTICAL GUARDRAILS

Common Failure Modes

Phone number canonicalization fails in predictable ways. These are the most common production failure modes and the guardrails that catch them before they corrupt downstream systems.

01

Country Code Ambiguity

What to watch: Numbers without explicit country codes are assigned to the wrong country when multiple countries share numbering patterns. A 10-digit number could be US (+1), India (+91), or China (+86) depending on context. Guardrail: Require a [DEFAULT_COUNTRY] parameter and flag ambiguous numbers with a confidence score. When confidence is below threshold, route to human review rather than guessing.

02

Leading Zero Truncation Errors

What to watch: National numbers with leading zeros (common in Europe, Australia, and many Asian countries) lose those zeros during E.164 conversion, producing invalid numbers. An Italian number like 02 1234 5678 becomes +39012345678 instead of +390212345678. Guardrail: Validate against known national number length patterns for each country code. Reject outputs where the national significant number length doesn't match the expected range for the claimed country.

03

Extension Misclassification

What to watch: Extension digits are either stripped entirely or merged into the main number, producing invalid E.164. A number like +1-555-123-4567 x123 becomes +15551234567123. Guardrail: Explicitly separate extension parsing from main number canonicalization. Output extensions in a dedicated field, never concatenated. Validate that the main number field contains only digits matching E.164 length constraints.

04

Vanity Number Literal Conversion

What to watch: Vanity numbers like 1-800-FLOWERS are converted to E.164 by treating letters as literal characters rather than mapping them to keypad digits. Guardrail: Pre-process inputs with a keypad mapping step before canonicalization. Add eval cases specifically for alphanumeric phone representations. Flag outputs where the resulting digit string doesn't match expected length for the country.

05

Special Service Number Misrouting

What to watch: Emergency numbers (911, 112), premium-rate numbers, and short codes are incorrectly formatted as standard geographic numbers or silently dropped. Guardrail: Classify number type before canonicalization. Route special service numbers to a separate handling path. Never apply geographic country code inference to numbers shorter than 7 digits. Maintain an allowlist of known short codes per country.

06

Format Drift Under High Volume

What to watch: When processing batches, the model gradually drifts from strict E.164 output to mixed formats—some numbers with parentheses, some with dashes, some with spaces. This breaks downstream parsers that expect consistent formatting. Guardrail: Add a post-processing validation step that rejects any output not matching the exact E.164 regex pattern. Use a retry loop with format reinforcement in the retry prompt. Log format drift rate per batch for monitoring.

IMPLEMENTATION TABLE

Evaluation Rubric

Use this rubric to test the quality of phone number canonicalization outputs before integrating them into production identity resolution pipelines. Each criterion targets a specific failure mode observed in model-generated E.164 formatting.

CriterionPass StandardFailure SignalTest Method

E.164 Format Compliance

Output matches +[country_code][national_number] with no spaces, hyphens, or parentheses

Output contains formatting characters, leading zeros after country code, or missing + prefix

Regex validation against ^+[1-9]\d{1,14}$

Country Code Inference Accuracy

Inferred country code matches ground truth for ambiguous numbers when context is provided

US +1 assigned to non-US numbers or incorrect code chosen when multiple countries share a number pattern

Compare against labeled test set with known country origins and context clues

Extension Normalization

Extension separated with ;ext= prefix and preserved digits only

Extension appended with x, ext., or comma separators; extension digits truncated or merged into main number

String contains ;ext= followed by digits; no legacy extension separators present

Type Classification Correctness

Number classified as mobile, fixed, voip, toll-free, or unknown with confidence flag

All numbers classified as mobile; toll-free numbers misclassified; type field missing when number is ambiguous

Assert type field is one of allowed enum values; spot-check toll-free and voip ranges

Null Handling for Unparseable Inputs

Returns null or empty output with reason when input cannot be parsed as a phone number

Model hallucinates a plausible number from non-phone text; returns partial digits without flagging uncertainty

Test with non-phone strings, empty inputs, and severely truncated digit sequences

Local vs. International Disambiguation

Correctly distinguishes local numbers from international when context provides region hints

Treats all 10-digit numbers as US; ignores locale context; defaults to +1 without evidence

Test ambiguous 10-digit patterns with explicit locale context and verify country code selection

Confidence Flag Calibration

Low-confidence flag set when country code inferred without explicit context or number pattern is ambiguous

High confidence assigned to inferred codes; confidence flag always true or always false

Check confidence field distribution across test set; verify low confidence correlates with ambiguous cases

Input Preservation Fidelity

Digits preserved exactly as provided; no digits added, removed, or reordered

Model corrects perceived digit errors; drops leading digits; adds missing digits without flagging

Compare input digit sequence to output digit sequence after stripping formatting

ADAPTATION OPTIONS

Adapt This Prompt

How to adapt

Start with the base prompt and a small set of test numbers. Remove strict schema enforcement and focus on E.164 formatting logic. Use a lightweight eval script that checks output format without full validation.

code
Normalize this phone number to E.164 format: [INPUT_NUMBER]
If you cannot determine the country code, return the number as-is with a confidence flag.

Watch for

  • Missing country code inference when context is absent
  • Over-confident local number assumptions (defaulting to US)
  • Extension numbers being silently dropped
Prasad Kumkar

About the author

Prasad Kumkar

CEO & MD, Inference Systems

Prasad Kumkar is the CEO & MD of Inference Systems and writes about AI systems architecture, LLM infrastructure, model serving, evaluation, and production deployment. Over 5+ years, he has worked across computer vision models, L5 autonomous vehicle systems, and LLM research, with a focus on taking complex AI ideas into real-world engineering systems.

His work and writing cover AI systems, large language models, AI agents, multimodal systems, autonomous systems, inference optimization, RAG, evaluation, and production AI engineering.