Workflow AutomationOperationsSchema

Phone Number Format Wrong After Sync: Three Fields

Phone numbers come out wrong after a sync because a phone number is three fields, country code, national number, and extension, and every system in the stack stores a different subset and normalizes at a different moment. Salesforce rewrites a 10 or 11 digit number on save and drops the leading 1, HubSpot stores E.164 but formats only on display, Airtable formats any 10 digit string as US, Google Sheets executes a leading plus sign as a formula, and Zapier's formatter leaves an invalid number untouched without failing the step. The SMS gateway is the only strict stop, so the failure shows up there, hops after the damage was done. The fix is to normalize once at the boundary into two fields, an E.164 number and a separate extension, and to treat the pretty display format as each receiver's job.

Alexey YushkinFounder, GENERAL INFORMATICS4 min read

After a sync, the phone number is wrong in one of four ways: the plus sign is gone, the country code is gone, the extension is gone, or the SMS tool rejects a number the CRM displays perfectly. All four have the same cause. A phone number is not a string. It is three fields, a country code, a national number, and an extension, and every system in the stack stores a different subset of the three and normalizes at a different moment. Salesforce rewrites the value on save. HubSpot stores one form and displays another. Airtable formats anything with ten digits as a US number. Google Sheets executes a leading plus sign as a formula. Zapier's formatter leaves an invalid number untouched and reports success. The only strict stop is the SMS gateway, which is why the failure appears there, three hops after the damage was done.

Why the plus sign and the country code go missing

Most operators find this when a texting workflow starts failing for a subset of contacts, and the subset turns out to be everyone whose number passed through a particular system. The number was fine at the form. It was fine in the webhook payload. Somewhere between there and the SMS send, one hop rewrote it, and no hop logged that it had.

Salesforce is the most common rewriter. Its knowledge article on phone field formatting says that when the user locale is English (United States) or English (Canada), "Salesforce formats 10-digit and 11-digit phone numbers starting with '1'." A 10 digit number is saved with parentheses, so 1234567890 becomes (123) 456-7890. An 11 digit number starting with 1 loses its leading digit: "the number 12345678901 is saved as (234) 567-8901." That is the country code, deleted on save, by design. The same article gives the escape: "enter a '+' before the number" and the value is preserved in that exact format. Zendesk's article on why numbers synced from Salesforce lose their country code says the same thing from the receiving side and recommends the same plus sign.

So a Twilio inbound that delivers the caller as +15551234567 survives Salesforce. The same number after a Zap that stripped non-digits, 15551234567, comes out of Salesforce as (555) 123-4567 with the 1 gone. It reads as a valid US number to every human. It is missing the one character the next API needs.

Spreadsheets are the second rewriter, and they are worse because they do not tell you. Google Sheets treats a leading plus sign as the start of a formula, the same as an equals sign, which its support community has explained to a decade of people asking why their phone numbers changed. A cell that receives +15551234567 evaluates to the number 15551234567. A cell that receives +1-800-555-1234 evaluates the arithmetic and stores -2588. Excel does the same thing with the plus sign, and both tools then render a long number in scientific notation the moment it leaves the cell. If your sync ever passes through a sheet, and a surprising number of "temporary" syncs do, that sheet is where the plus sign died. The CSV import failure modes that mangle IDs and ZIP codes are the same mechanism applied to phone numbers.

What each system does to a phone number

The field is called Phone everywhere. What it does underneath differs on three questions: when does it normalize (on write, on display, or never), what does it do with a value it cannot parse, and where does the extension go. Each row was checked against the vendor's current documentation in September 2026.

SystemWhen it normalizesWhat it storesExtensionBad or unparseable value
Salesforce (standard Phone)On save, for US and Canada locales only, and only when the input is pure digitsThe formatted string: 10 digits become (XXX) XXX-XXXX, 11 digits starting with 1 lose the 1. Values with a plus, dash, period, or parenthesis are stored as typed. Maximum 40 charactersNo slot. Whatever you type stays in the textStored as typed. There is no validation on the standard field
HubSpot (phone property with validation on)On write, then formats only for displayE.164 without formatting. The documentation's example: "+1 (888) 482-7768 would be saved as +18884827768 but displayed as +1 (888) 482-7768"Appended in the value as "ext [number]", e.g. +18884827768 ext 123Rejected as invalid. A default country code can be added to values that lack one, but "currently only applies to phone number property updates made via import"
HubSpot (validation off)NeverWhatever arrivedIn the text, if at allStored as typed
Airtable (phone number field)On a 10 digit stringA string. "A phone number field will format a 10-digit string of numbers as a US/Canada phone number: (XXX) XXX-XXXX." Anything else is kept as isIn the textStored as typed. Airtable also warns that formatting "may not be preserved consistently" when the field is read through lookups in automations
Google Sheets and ExcelOn entry, as a formula or a numberA number, if the cell parses as one. The plus sign is consumed as a formula prefixLost with everything after the digitsSilently converted. A number that does not parse as a formula may error or be stored as text depending on the separators
Zapier Formatter (Format Phone Number)In the stepThe chosen output: E164, National, International, RFC3966, and several no-symbol variantsNot mentioned in the documentationNot transformed. Zapier's article says invalid numbers "will not be transformed" when validation is on. The step succeeds and passes the original through
Twilio Messages API (To)Never. It validates and refusesNothing. It is an API parameter, not a storeNot supported for SMSError 21211, Invalid 'To' Phone Number. The documentation requires "no spaces, dashes, or parentheses"

Read the table down the second column. Salesforce normalizes on write into a display format. HubSpot normalizes on write into a machine format and displays a different one. Airtable normalizes on write into a US display format regardless of where the number is from. Sheets normalizes on entry into the wrong data type. Zapier normalizes in flight and lets failures through. Twilio does not normalize at all. Five systems, five different answers to when, and only one of them will tell you it disagreed.

Two rows deserve a second look. HubSpot's stored form, +18884827768, is exactly what Twilio wants, and its displayed form, +1 (888) 482-7768, is exactly what Twilio rejects. Which one your sync reads depends on the endpoint. An API read returns the stored form. A CSV export or a workflow that copies the displayed value into a text property can carry the formatted one. And Airtable's rule applies to any 10 digit string, so a UK number typed without its leading zero or plus, or a German number that happens to be 10 digits long, is displayed as a US number with parentheses. The data is not corrupted, but a downstream parser that trusts the parentheses as a US signal will add +1 to a number that was never in the US.

Where the extension goes

The extension is the field nobody designs for, and it is the one that quietly disappears in every sync we have audited for a multi-location operation. Front desks, dispatch lines, and property management offices live on extensions. The number without it reaches a phone tree, not a person.

E.164 has no place for it. Twilio's glossary defines the format as a plus sign, country code, and subscriber number, limited to 15 digits total. RFC 3966, the tel URI standard, is the one format that carries an extension explicitly, in its own parameter, which is why Zapier's formatter offers RFC3966 as an output and why libphonenumber can format to it. Almost nothing downstream reads RFC 3966.

So each system improvises. HubSpot's validation accepts "ext 123" appended to the E.164 value, which is a reasonable convention that no other vendor in the table shares. Salesforce, Airtable, and an unvalidated HubSpot property keep whatever text you type, so "555-123-4567 x204" and "(555) 123-4567 ext. 204" and "5551234567,204" are all valid and all different. A formatter step that strips non-digits turns the last one into 5551234567204, a 13 digit number that a validator may accept as a possible international number and an SMS gateway will fail to route. That is how an extension becomes a wrong number rather than a missing one.

The rule that survives all of this is short. The extension is its own field. It never travels inside the number. When a receiving system has no extension field, the sync writes it to a text property named for the purpose, and the display layer, not the data layer, decides how to show the two together.

Why the failure shows up at the SMS gateway

Look at the last column of the table again. Salesforce stores a bad value. Airtable stores a bad value. Sheets converts it. Zapier passes it through. Every system except Twilio treats a phone number as text that a human will read. Twilio treats it as an address it has to route, and error 21211 is the first moment in the chain that a machine actually tries to use the number.

That ordering is why phone problems are diagnosed late and blamed on the wrong tool. The texting platform gets the ticket. The texting platform is often innocent, and the fix people reach for, a Formatter step just before the send, is a patch on the last hop. It works for the numbers that reach it intact. It does nothing for the number Salesforce already turned into (555) 123-4567, because the formatter cannot know whether the missing country code was 1 or 44, and with validation on it may simply hand the value back untransformed.

The second place the failure lands is matching. A dedup or cross-system match keyed on phone compares strings, and +15551234567, 15551234567, (555) 123-4567, and 555.123.4567 are four strings for one line.Most CRMs compare them literally. The duplicate contacts that appear after a migration, with the same person under two phone formats, are the same failure as the SMS rejection, surfacing in a different report.

Normalize once at the boundary, into two fields

The fix is to stop asking six systems to agree on a format and instead normalize once, at the point where the number enters your automation, and carry a machine form from there. This is a design decision, not a formatter step, and it has five parts.

Parse with a real library, at the entry point. Google's libphonenumber, and its ports such as libphonenumber-js, parse a raw string plus a default region into a structured number and then format it as E.164, international, national, or RFC 3966. Run the parse on the webhook that receives the form, the call, or the import row, before any system stores the value. In n8n, that means a Code node; note that n8n's documentation says n8n Cloud cannot import external npm modules in the Code node, so on Cloud you either self-host, call a small HTTP endpoint you control, or use the HubSpot or Zapier formatter upstream. In Zapier, the Format Phone Number transform with E164 output does the parse, with the caveat in the next paragraph.

Treat "not transformed" as a failure. Zapier's formatter and any lenient parser will return an unformatted value for input it cannot resolve. Add a check immediately after: the output must start with a plus sign and match the digit count for its country. libphonenumber distinguishes isPossibleNumber, a length check, from isValidNumber, a full length and prefix check for the region, and the second is the one to gate on. A number that fails goes to a review queue with the raw input attached, not to the CRM and not to the SMS send. The logging you already keep for every run should record the raw input, the parsed result, and which check failed.

Store two fields, both text. The first holds the E.164 number, +15551234567. The second holds the extension, 204, or nothing. Never a numeric type, which drops the plus and any leading zero, and never a single field that combines them. Salesforce's own knowledge article on normalizing phone numbers takes this approach from the other end, recommending a separate formula field that strips separators and prepends +1 rather than touching the standard Phone field. If the receiving system rewrites its native phone field on save, as Salesforce does for bare digits, write the plus-prefixed E.164 form and it is preserved as typed.

Get the default region from the record, not from a setting. A parser needs to know that 020 7946 0958 is a London number and 555-123-4567 is not. The country comes from the record: the billing address, the form's country field, the inbound caller ID's country code. HubSpot's Validate and format phone number workflow action has a Dynamic option that references each record's Country/Region Code property for exactly this reason, and Zapier's formatter defaults to the United States when nothing is set, which is correct until the first international lead. A single static default is fine for a one-state contractor and wrong for a multi-location operation the first time a Canadian franchisee's contacts come through.

Let each receiver display its own way. Once the stored value is E.164, Salesforce will keep it as typed, HubSpot will render its regional format on top of it, and the SMS API will accept it unchanged. Do not write the display format back. The only formatting a sync should ever apply is to the E.164 field, once, at the boundary. When someone wants parentheses in a report, that is a formula or a view, not a stored value.

For an operation that texts customers, routes calls, or matches leads across systems, this is the schema decision that determines whether the acquisition workflows work for every contact or only for the ones whose number happened to arrive clean.

What to do next

Export the phone column from each system your automations write to and count the values by shape: starts with a plus, starts with 1 and has 11 digits, has 10 digits and parentheses, has letters. The shape distribution tells you which hop has been rewriting numbers, and the one with the most 10 digit parenthesized values is almost always the one that dropped the country code. Re-parse that whole set once with a real library and a per-record default region, split off the extensions into their own field, and write the E.164 form back with the plus sign in front so no receiver reformats it again.

If the sync is not built yet, decide the two-field schema before the first contact moves, and put the parse on the entry webhook rather than in front of the send. It is the same discipline as the owner map and the picklist map: the receiver's version of the value is correct from its own point of view, and the sync has to carry yours. We build this normalization step into every workflow automation system that touches a phone number, and if yours already has a texting failure you cannot trace, send us the shape counts and we will tell you which hop it was.

Frequently Asked Questions

SOURCES & CITATIONS

  1. Standard Phone Field Length and Automatic Formatting Rules in Salesforce CRM (Knowledge Article 000385963) Salesforcehttps://help.salesforce.com/s/articleView?id=000385963&language=en_US&type=1
  2. Set up phone number property validation HubSpothttps://knowledge.hubspot.com/properties/phone-number-property-validation
  3. Error 21211: Invalid 'To' Phone Number Twiliohttps://www.twilio.com/docs/api/errors/21211
  4. Formatter Features: formatting phone numbers Zapierhttps://community.zapier.com/featured-articles-65/formatter-features-formatting-phone-numbers-11391

About Alexey Yushkin

Alexey is the founder of GENERAL INFORMATICS LLC. He designs and ships AI and automation systems for businesses and operators across the US.

Connect on LinkedIn

Related reading

Want this kind of system in your business?

We build practical AI and automation systems for operators. Send us your current workflow and we will show you what to automate first.