How would you convert phone numbers to E.164 format

I need to pull the phone number of contacts in Pipedrive, and then query the phone numbers via another 3rd party API. The 3rd party API demands phone numbers must be passed in E.164 format, without the leading +

E.164 numbers have a maximum of 15 digits and are structured as follows:

  • +: (a plus sign)
  • Country code: This identifies the country (e.g., +1 for the US, +44 for the UK).
  • Subscriber number: This includes the area code and the local number.
  • **No spaces

Examples
077 123 11120
+44 77 123 11120
for both examples would be: 447712311120

I am new to n8n, who can I transform the data in this way?

Thanks for the advice.

Hello, hope all is well. Here is an AI Agent which could help you with formatting your numbers:

And there is a result of our conversation:

So one solution could be to use an AI agent (possibly not the AI Agent, but a node, which could just “message a model”, for example an OpenAI node, with a similar system prompt

Hi, many thanks for the reply only 2 out of the example 9 are correct in the picture. In all honesty I wasn’t thinking of using AI, as the on-going costs would be too much.

I thought there would be a way in N8N to user regex or something to reformat the strings?

you can use code node here is implementation:

My understanding is that this needs to work for any country code and with arbitrary input format, but I could have misunderstood.

As in

  • US number: (555) 123-4567 → 15551234567
  • UK number: 020 7123 4567 → 442071234567
  • German number: 030 12345678 → 493012345678

Here is another solution, I can propose:

You build a rest wrapper around

https://github.com/google/libphonenumber

for example in python. Conveniently there are SDKs for this library in different language. For example in python it would be

https://github.com/daviddrysdale/python-phonenumbers

So you create something like this:

app.py
from flask import Flask, request, jsonify
import phonenumbers

app = Flask(__name__)

@app.route('/parse', methods=['POST'])
def parse():
    data = request.json
    number = data.get('number')
    region = data.get('region', None)

    try:
        parsed = phonenumbers.parse(number, region)
        e164 = phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.E164)

        return jsonify({
            'input_number': number,
            'input_region': region,
            'country_code': parsed.country_code,
            'national_number': parsed.national_number,
            'is_valid': phonenumbers.is_valid_number(parsed),
            'is_possible': phonenumbers.is_possible_number(parsed),
            'international_format': phonenumbers.format_number(parsed, phonenumbers.PhoneNumberFormat.INTERNATIONAL),
            'e164_format': e164,
            'e164_format_no_plus': e164.lstrip('+')
        })
    except Exception as e:
        return jsonify({'error': str(e)}), 400

@app.route('/validate', methods=['POST'])
def validate():
    data = request.json
    number = data.get('number')
    region = data.get('region', None)

    try:
        parsed = phonenumbers.parse(number, region)
        valid = phonenumbers.is_valid_number(parsed)
        return jsonify({'valid': valid})
    except Exception as e:
        return jsonify({'error': str(e)}), 400

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8080)
requirements.txt
flask
phonenumbers
Dockerfile
FROM python:3.12-slim

WORKDIR /app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

EXPOSE 8080
CMD ["python", "app.py"]

You build an image:

docker build -t phone-api .

Validate you have the image:

$ docker images | grep phone
phone-api                       latest      132288ef6b69   25 minutes ago   180MB

to your compose file (and I assume you use docker compose), add another service:

  phone-api:
    image: phone-api:latest
    container_name: phone-api
    hostname: phone-api
    restart: unless-stopped
    networks:
      - whatever_your_n8n_network_is

Then you bring up your infra.

Next in n8n: