itu-e164

itu-e164 is a dependency-free Ruby utility for strict, auditable validation of canonical geographic-area numbers against Recommendation ITU-T E.164 (02/2026). It is deliberately not a Rails validator and does not contact a carrier.

Installation

Add the gem to your bundle:

gem "itu-e164"

Then run bundle install.

Usage

require "itu/e164"

result = ITU::E164.check("+393331234567")

result.conformant?       # => true
result.country_code      # => "39"
result.national_number   # => "3331234567"
result.category          # => :geographic
result.standard_version  # => "02/2026"
result.dataset_version   # => "itu-t-e164-2026-07-15"

For a boolean:

ITU::E164.conformant?("+393331234567") # => true

For exception-based control flow:

result = ITU::E164.check!("+393331234567")

begin
  ITU::E164.check!("0039 333 123 4567")
rescue ITU::E164::InvalidNumber => error
  error.result.error_codes # => [:invalid_representation]
end

The accepted representation is intentionally strict: a String containing + followed by ASCII decimal digits. Spaces, punctuation, 00, URI parameters, and extensions are rejected. Normalize user input before this boundary and store extensions separately.

Existing validation layers

The result is designed to be consumed without an Active Record dependency:

result = ITU::E164.check(value)

unless result.conformant?
  errors.add(:phone_number, result.errors.map(&:message).join(", "))
end

With Twilio Verify, use this gem before sending a verification:

result = ITU::E164.check(candidate)
return validation_failure(result.errors) unless result.conformant?

twilio_verify(candidate)

The responsibilities stay separate:

  • itu-e164 checks canonical representation, E.164 length and field structure, and the assigned geographic country-code snapshot.
  • Twilio Verify checks whether a user controls a reachable endpoint.

Exact scope

For profile: :geographic (the only profile in 0.1), a conformant result means:

  • the input is canonical leading-plus notation;
  • the E.164 digit sequence contains at most 15 digits;
  • it starts with an assigned one-, two-, or three-digit geographic country code;
  • at least one digit remains as the national (significant) number.

This is the complete E.164-level structure for the geographic category. E.164 leaves national destination-code and subscriber-number details to national numbering authorities.

Accordingly, this gem does not claim that:

  • the national number range is allocated or currently active;
  • the number is mobile, SMS-capable, reachable, or owned by a user;
  • a national trunk prefix was correctly removed;
  • one of E.164's seven non-geographic categories satisfies its service-specific numbering recommendation.

Assigned non-geographic country codes are recognized, but fail the geographic profile with :profile_mismatch. Spare or unknown codes fail with :country_code_unassigned.

Results and errors

ITU::E164.check always returns an immutable ITU::E164::Result. Invalid input has one or more immutable ITU::E164::ValidationError values:

result = ITU::E164.check("+80012345678")

result.conformant? # => false
result.category    # => :global_service
result.error_codes # => [:profile_mismatch]
result.to_h

Current error codes are:

  • :not_a_string
  • :invalid_representation
  • :too_long
  • :country_code_unassigned
  • :missing_national_number
  • :profile_mismatch

Branch on error codes, not English messages.

Versioning and updates

The recommendation version and assignment dataset are exposed separately because a stable numbering structure can coexist with changing assignments. See SOURCES.md for provenance and the update procedure.

License

The gem is available under the MIT License.