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.
Prompt
Phone Number Canonicalization Prompt Template

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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
textYou 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.
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.
| Placeholder | Purpose | Example | Validation 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. |
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.
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 Element | Type or Format | Required | Validation 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. |
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.
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.
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.
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.
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.
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.
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.
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.
| Criterion | Pass Standard | Failure Signal | Test 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 |
Enabling Efficiency, Speed & Accuracy
Intelligent Analysis, Decision & Execution
We build AI systems for teams that need search across company data, workflow automation across tools, or AI features inside products and internal software.
Talk to Us
Search across company data
Give teams answers from docs, tickets, runbooks, and product data with sources and permissions.
Useful when people spend too long searching or get different answers from different systems.

Automate internal workflows
Use AI to route work, draft outputs, trigger actions, and keep approvals and logs in place.
Useful when repetitive work moves across multiple tools and teams.

Add AI to products and internal tools
Build assistants, guided actions, or decision support into the software your team or customers already use.
Useful when AI needs to be part of the product, not a separate tool.
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.
codeNormalize 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

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.
Partnered with leading AI, data, and software stack.
How We Work
Custom AI workflows for your Business
One-fit-all AI don't work for modern businesses. At Inferensys, we aim to understand your business & custom requirements; which we use to define most efficient agentic workflows, the data, and the tools for your business.
01
Review the use case
We understand the task, the users, and where AI can actually help.
Read more02
Pick the right approach
We define what needs search, automation, or product integration.
Read more03
Build the first useful version
We implement the part that proves the value first.
Read more04
Improve from there
We add the checks and visibility needed to keep it useful.
Read moreThe first call is a practical review of your use case and the right next step.
Talk to Us