Lead Validation C# Rest Code Snippet

using System.Web;

namespace lead_validation_dot_net.REST
{
    /// <summary>
    /// Provides functionality to call the ServiceObjects Lead Validation (LV) REST API's ValidateLead_V3 endpoint,
    /// retrieving lead validation information for a given US or Canada lead with fallback to a backup endpoint for reliability in live mode.
    /// </summary>
    public static class ValidateLeadV3Client
    {
        // Base URL constants: production, backup, and trial
        private const string LiveBaseUrl = "https://sws.serviceobjects.com/lv/api.svc/json/";
        private const string BackupBaseUrl = "https://swsbackup.serviceobjects.com/lv/api.svc/json/";
        private const string TrialBaseUrl = "https://trial.serviceobjects.com/lv/api.svc/json/";

        /// <summary>
        /// Synchronously calls the ValidateLead_V3 REST endpoint to retrieve lead validation information,
        /// attempting the primary endpoint first and falling back to the backup if the response is invalid
        /// (Error.TypeCode == "3") in live mode.
        /// </summary>
        /// <param name="input">The input parameters including name, address, phone, email, and other lead details.</param>
        /// <returns>Deserialized <see cref="LVResponse"/> containing lead validation data or an error.</returns>
        public static LVResponse Invoke(ValidateLeadV3Input input)
        {
            // Use query string parameters so missing/optional fields don't break the URL
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            LVResponse response = Helper.HttpGet<LVResponse>(url, input.TimeoutSeconds);

            // Fallback on error in live mode
            if (input.IsLive && !IsValid(response))
            {
                string fallbackUrl = BuildUrl(input, BackupBaseUrl);
                LVResponse fallbackResponse = Helper.HttpGet<LVResponse>(fallbackUrl, input.TimeoutSeconds);
                return fallbackResponse;
            }

            return response;
        }

        /// <summary>
        /// Asynchronously calls the ValidateLead_V3 REST endpoint to retrieve lead validation information,
        /// attempting the primary endpoint first and falling back to the backup if the response is invalid
        /// (Error.TypeCode == "3") in live mode.
        /// </summary>
        /// <param name="input">The input parameters including name, address, phone, email, and other lead details.</param>
        /// <returns>Deserialized <see cref="LVResponse"/> containing lead validation data or an error.</returns>
        public static async Task<LVResponse> InvokeAsync(ValidateLeadV3Input input)
        {
            // Use query string parameters so missing/optional fields don't break the URL
            string url = BuildUrl(input, input.IsLive ? LiveBaseUrl : TrialBaseUrl);
            LVResponse response = await Helper.HttpGetAsync<LVResponse>(url, input.TimeoutSeconds).ConfigureAwait(false);

            // Fallback on error in live mode
            if (input.IsLive && !IsValid(response))
            {
                string fallbackUrl = BuildUrl(input, BackupBaseUrl);
                LVResponse fallbackResponse = await Helper.HttpGetAsync<LVResponse>(fallbackUrl, input.TimeoutSeconds).ConfigureAwait(false);
                return fallbackResponse;
            }

            return response;
        }

        // Build the full request URL, including URL-encoded query string
        public static string BuildUrl(ValidateLeadV3Input input, string baseUrl)
        {
            // Construct query string with URL-encoded parameters
            string qs = $"ValidateLead_V3?" +
                        $"FullName={Helper.UrlEncode(input.FullName)}" +
                        $"&Salutation={Helper.UrlEncode(input.Salutation)}" +
                        $"&FirstName={Helper.UrlEncode(input.FirstName)}" +
                        $"&LastName={Helper.UrlEncode(input.LastName)}" +
                        $"&BusinessName={Helper.UrlEncode(input.BusinessName)}" +
                        $"&BusinessDomain={Helper.UrlEncode(input.BusinessDomain)}" +
                        $"&BusinessEIN={Helper.UrlEncode(input.BusinessEIN)}" +
                        $"&Address1={Helper.UrlEncode(input.Address1)}" +
                        $"&Address2={Helper.UrlEncode(input.Address2)}" +
                        $"&Address3={Helper.UrlEncode(input.Address3)}" +
                        $"&Address4={Helper.UrlEncode(input.Address4)}" +
                        $"&Address5={Helper.UrlEncode(input.Address5)}" +
                        $"&Locality={Helper.UrlEncode(input.Locality)}" +
                        $"&AdminArea={Helper.UrlEncode(input.AdminArea)}" +
                        $"&PostalCode={Helper.UrlEncode(input.PostalCode)}" +
                        $"&Country={Helper.UrlEncode(input.Country)}" +
                        $"&Phone1={Helper.UrlEncode(input.Phone1)}" +
                        $"&Phone2={Helper.UrlEncode(input.Phone2)}" +
                        $"&Email={Helper.UrlEncode(input.Email)}" +
                        $"&IPAddress={Helper.UrlEncode(input.IPAddress)}" +
                        $"&Gender={Helper.UrlEncode(input.Gender)}" +
                        $"&DateOfBirth={Helper.UrlEncode(input.DateOfBirth)}" +
                        $"&UTCCaptureTime={Helper.UrlEncode(input.UTCCaptureTime)}" +
                        $"&OutputLanguage={Helper.UrlEncode(input.OutputLanguage)}" +
                        $"&TestType={Helper.UrlEncode(input.TestType)}" +
                        $"&LicenseKey={Helper.UrlEncode(input.LicenseKey)}";
            return baseUrl + qs;
        }

        private static bool IsValid(LVResponse response) => response?.Error == null || response.Error.TypeCode != "3";

        /// <summary>
        /// Input parameters for the ValidateLead_V3 API call. Represents lead details for validation in the US or Canada.
        /// </summary>
        /// <param name="FullName">The contact’s full name. Optional.</param>
        /// <param name="Salutation">Salutation of the contact. Optional.</param>
        /// <param name="FirstName">First name of the contact. Optional.</param>
        /// <param name="LastName">Last name of the contact. Optional.</param>
        /// <param name="BusinessName">The contact’s company. Optional.</param>
        /// <param name="BusinessDomain">Website domain associated with the business. Optional.</param>
        /// <param name="BusinessEIN">Company Tax Number for US leads. Optional.</param>
        /// <param name="Address1">Address line 1 of the contact or business address. Optional.</param>
        /// <param name="Address2">Address line 2 of the contact or business address. Optional.</param>
        /// <param name="Address3">Address line 3 of the contact or business address. Optional.</param>
        /// <param name="Address4">Address line 4 of the contact or business address. Optional.</param>
        /// <param name="Address5">Address line 5 of the contact or business address. Optional.</param>
        /// <param name="Locality">The city of the contact’s postal address. Optional.</param>
        /// <param name="AdminArea">The state or province of the contact’s postal address. Optional.</param>
        /// <param name="PostalCode">The zip or postal code of the contact’s postal address. Optional.</param>
        /// <param name="Country">The country of the contact’s postal address. Optional.</param>
        /// <param name="Phone1">The contact’s primary phone number. Optional.</param>
        /// <param name="Phone2">The contact’s secondary phone number. Optional.</param>
        /// <param name="Email">The contact’s email address. Optional.</param>
        /// <param name="IPAddress">The contact’s IP address in IPv4. Optional.</param>
        /// <param name="Gender">The contact’s gender ("Male", "Female", "Neutral"). Optional.</param>
        /// <param name="DateOfBirth">The contact’s date of birth. Optional.</param>
        /// <param name="UTCCaptureTime">The time the lead was submitted. Optional.</param>
        /// <param name="OutputLanguage">Language for some output information. Optional.</param>
        /// <param name="TestType">The type of validation to perform. Required.</param>
        /// <param name="LicenseKey">The license key to authenticate the API request. Required.</param>
        /// <param name="IsLive">Indicates whether to use the live service (true) or trial service (false).</param>
        /// <param name="TimeoutSeconds">Timeout duration for the API call, in seconds.</param>
        public record ValidateLeadV3Input(
            string FullName = "",
            string Salutation = "",
            string FirstName = "",
            string LastName = "",
            string BusinessName = "",
            string BusinessDomain = "",
            string BusinessEIN = "",
            string Address1 = "",
            string Address2 = "",
            string Address3 = "",
            string Address4 = "",
            string Address5 = "",
            string Locality = "",
            string AdminArea = "",
            string PostalCode = "",
            string Country = "",
            string Phone1 = "",
            string Phone2 = "",
            string Email = "",
            string IPAddress = "",
            string Gender = "",
            string DateOfBirth = "",
            string UTCCaptureTime = "",
            string OutputLanguage = "",
            string TestType = "",
            string LicenseKey = "",
            bool IsLive = true,
            int TimeoutSeconds = 15
        );
    }
}



    public class LVResponse
{
        public string OverallCertainty { get; set; }
        public string OverallQuality { get; set; }
        public string LeadType { get; set; }
        public string LeadCountry { get; set; }
        public string NoteCodes { get; set; }
        public string NoteDesc { get; set; }
        public string NameCertainty { get; set; }
        public string NameQuality { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string FirstNameClean { get; set; }
        public string LastNameClean { get; set; }
        public string NameNoteCodes { get; set; }
        public string NameNoteDesc { get; set; }
        public string AddressCertainty { get; set; }
        public string AddressQuality { get; set; }
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public string Address3 { get; set; }
        public string Address4 { get; set; }
        public string Address5 { get; set; }
        public string AddressLocality { get; set; }
        public string AddressAdminArea { get; set; }
        public string AddressPostalCode { get; set; }
        public string AddressCountry { get; set; }
        public string AddressNoteCodes { get; set; }
        public string AddressNoteDesc { get; set; }
        public string EmailCertainty { get; set; }
        public string EmailQuality { get; set; }
        public string EmailCorrected { get; set; }
        public string EmailNoteCodes { get; set; }
        public string EmailNoteDesc { get; set; }
        public string IPAddressCertainty { get; set; }
        public string IPAddressQuality { get; set; }
        public string IPCountry { get; set; }
        public string IPLocality { get; set; }
        public string IPAdminArea { get; set; }
        public string IPNoteCodes { get; set; }
        public string IPNoteDesc { get; set; }
        public string Phone1Certainty { get; set; }
        public string Phone1Quality { get; set; }
        public string Phone1Locality { get; set; }
        public string Phone1AdminArea { get; set; }
        public string Phone1Country { get; set; }
        public string Phone1NoteCodes { get; set; }
        public string Phone1NoteDesc { get; set; }
        public string Phone2Certainty { get; set; }
        public string Phone2Quality { get; set; }
        public string Phone2Locality { get; set; }
        public string Phone2AdminArea { get; set; }
        public string Phone2Country { get; set; }
        public string Phone2NoteCodes { get; set; }
        public string Phone2NoteDesc { get; set; }
        public PhoneContact PhoneContact { get; set; }
        public InformationComponent[] InformationComponents { get; set; }
        public Error Error { get; set; }
        public override string ToString()
        {
            string Output = $"\n{{OverallCertainty: {OverallCertainty} " +
                $"\nOverallQuality: {OverallQuality} " +
                $"\nLeadType: {LeadType} " +
                $"\nLeadCountry: {LeadCountry} " +
                $"\nNoteCodes:  {NoteCodes} " +
                $"\nNoteDesc: {NoteDesc} " +
                $"\nNameCertainty:  {NameCertainty} " +
                $"\nNameQuality:   {NameQuality} " +
                $"\nFirstName: {FirstName} " +
                $"\nLastName: {LastName} " +
                $"\nFirstNameClean: {FirstNameClean} " +
                $"\nLastNameClean: {LastNameClean} " +
                $"\nNameNoteCodes: {NameNoteCodes} " +
                $"\nNameNoteDesc: {NameNoteDesc} " +
                $"\nAddressCertainty: {AddressCertainty} " +
                $"\nAddressQuality: {AddressQuality} " +
                $"\nAddress1: {Address1} " +
                $"\nAddressLine2: {Address2} " +
                $"\nAddressLine3: {Address3} " +
                $"\nAddressLine4: {Address4} " +
                $"\nAddressLine5: {Address5} " +
                $"\nAddressLocality: {AddressLocality} " +
                $"\nAddressAdminArea: {AddressAdminArea} " +
                $"\nAddressPostalCode: {AddressPostalCode} " +
                $"\nAddressCountry: {AddressCountry} " +
                $"\nAddressNoteCodes: {AddressNoteCodes} " +
                $"\nAddressNoteDesc: {AddressNoteDesc} " +
                $"\nEmailCertainty: {EmailCertainty} " +
                $"\nEmailQuality: {EmailQuality} " +
                $"\nEmailCorrected: {EmailCorrected} " +
                $"\nEmailNoteCodes: {EmailNoteCodes} " +
                $"\nEmailNoteDesc: {EmailNoteDesc} " +
                $"\nIPAddressCertainty: {IPAddressCertainty} " +
                $"\nIPAddressQuality: {IPAddressQuality} " +
                $"\nIPCountry: {IPCountry} " +
                $"\nIPLocality: {IPLocality} " +
                $"\nIPAdminArea: {IPAdminArea} " +
                $"\nIPCountry: {IPCountry} " +
                $"\nIPNoteCodes: {IPNoteCodes} " +
                $"\nIPNoteDesc: {IPNoteDesc} " +
                $"\nPhone1Certainty: {Phone1Certainty} " +
                $"\nPhone1Quality: {Phone1Quality} " +
                $"\nPhone1Locality: {Phone1Locality} " +
                $"\nPhone1AdminArea: {Phone1AdminArea} " +
                $"\nPhone1Country: {Phone1Country} " +
                $"\nPhone1NoteCodes: {Phone1NoteCodes} " +
                $"\nPhone1NoteDesc: {Phone1NoteDesc} " +
                $"\nPhone2Certainty: {Phone2Certainty} " +
                $"\nPhone2Quality: {Phone2Quality} " +
                $"\nPhone2Locality: {Phone2Locality} " +
                $"\nPhone2AdminArea: {Phone2AdminArea} " +
                $"\nPhone2Country: {Phone2Country} " +
                $"\nPhone2NoteCodes: {Phone2NoteCodes} " +
                $"\nPhone2NoteDesc: {Phone2NoteDesc} " +
                $"\nPhoneContact: {{{PhoneContact}}} " +
                $"\nInformationComponents: [";
            if (InformationComponents != null && InformationComponents.Length > 0)
            {
                foreach (InformationComponent A in InformationComponents)
                {
                    Output += "{" + A.ToString() + "}\n";
                }
            }
            Output += "]" +
            $"\nError: {{{Error}}}\n";
            return Output;
        }
    }

    public class Error
    {
        public string Type { get; set; }
        public string TypeCode { get; set; }
        public string Desc { get; set; }
        public string DescCode { get; set; }
        public override string ToString()
        {
            return $"{{Type: {Type} " +
                $"\nTypeCode: {TypeCode} " +
                $"\nDesc: {Desc} " +
                $"\nDescCode: {DescCode}}}";
        }
    }

    public class PhoneContacts
    {
        public PhoneContact[] PhoneContact { get; set; }
        public override string ToString()
        {
            string Output = "PhoneContacts: [";
            if (PhoneContact != null && PhoneContact.Length > 0)
            {
                foreach (PhoneContact A in PhoneContact)
                {
                    Output += "{" + A.ToString() + "}\n";
                }
            }
            return Output += "]\n";
        }
    }

    public class PhoneContact
    {
        public string Name { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Zip { get; set; }
        public string Type { get; set; }
        public override string ToString()
        {
            return $"Name: {Name} " +
                $"\nAddress: {Address} " +
                $"\nCity: {City} " +
                $"\nState: {State} " +
                $"\nZip: {Zip} " +
                $"\nType: {Type}\n";
        }
    }

    public class InformationComponent
    {
        public string Name { get; set; }
        public string Value { get; set; }
        public override string ToString()
        {
            return $"Name: {Name} " +
                $"\nValue: {Value}\n";
        }
    }


using System.Text.Json;
using System.Web;

namespace lead_validation_dot_net.REST
{
    public class Helper
    {
        public static T HttpGet<T>(string url, int timeoutSeconds)
        {
            using var httpClient = new HttpClient
            {
                Timeout = TimeSpan.FromSeconds(timeoutSeconds)
            };
            using var request = new HttpRequestMessage(HttpMethod.Get, url);
            using HttpResponseMessage response = httpClient
                .SendAsync(request)
                .GetAwaiter()
                .GetResult();
            response.EnsureSuccessStatusCode();
            using Stream responseStream = response.Content
                .ReadAsStreamAsync()
                .GetAwaiter()
                .GetResult();
            var options = new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true
            };
            object? obj = JsonSerializer.Deserialize(responseStream, typeof(T), options);
            T result = (T)obj!;
            return result;
        }

        // Asynchronous HTTP GET and JSON deserialize
        public static async Task<T> HttpGetAsync<T>(string url, int timeoutSeconds)
        {
            HttpClient HttpClient = new HttpClient();
            HttpClient.Timeout = TimeSpan.FromSeconds(timeoutSeconds);
            using var httpResponse = await HttpClient.GetAsync(url).ConfigureAwait(false);
            httpResponse.EnsureSuccessStatusCode();
            var stream = await httpResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);
            return JsonSerializer.Deserialize<T>(stream)!;
        }

        public static string UrlEncode(string value) => HttpUtility.UrlEncode(value ?? string.Empty);
    }
}

Lead Validation Python Rest Code Snippet

from lv_response import LVResponse, PhoneContact, InformationComponent, Error
import requests

# Endpoint URLs for ServiceObjects Lead Validation (LV) API
primary_url = "https://sws.serviceobjects.com/lv/api.svc/json/ValidateLead_V3?"
backup_url = "https://swsbackup.serviceobjects.com/lv/api.svc/json/ValidateLead_V3?"
trial_url = "https://trial.serviceobjects.com/lv/api.svc/json/ValidateLead_V3?"

def validate_lead_v3(full_name: str,
                    salutation: str,
                    first_name: str,
                    last_name: str,
                    business_name: str,
                    business_domain: str,
                    business_ein: str,
                    address1: str,
                    address2: str,
                    address3: str,
                    address4: str,
                    address5: str,
                    locality: str,
                    admin_area: str,
                    postal_code: str,
                    country: str,
                    phone1: str,
                    phone2: str,
                    email: str,
                    ip_address: str,
                    gender: str,
                    date_of_birth: str,
                    utc_capture_time: str,
                    output_language: str,
                    test_type: str,
                    license_key: str,
                    is_live: bool) -> LVResponse:
    """
    Call ServiceObjects Lead Validation (LV) API's ValidateLead_V3 endpoint
    to retrieve lead validation information for a given US or Canada lead.

    Parameters:
        full_name: The contacts full name. Optional.
        salutation: Salutation of the contact. Optional.
        first_name: First name of the contact . Optional.
        last_name: Last name of the contact . Optional.
        business_name: The contacts company . Optional.
        business_domain: Website domain associated with the business. Optional.
        business_ein: Company Tax Number for US leads. Optional.
        address1: Address line 1 of the contact or business address. Optional.
        address2: Address line 2 of the contact or business address. Optional.
        address3: Address line 3 of the contact or business address. Optional.
        address4: Address line 4 of the contact or business address. Optional.
        address5: Address line 5 of the contact or business address. Optional.
        locality: The city of the contacts postal address. Optional.
        admin_area: The state or province of the contacts postal address. Optional.
        postal_code: The zip or postal code of the contacts postal address. Optional.
        country: The country of the contacts postal address . Optional.
        phone1: The contacts primary phone number. Optional.
        phone2: The contacts secondary phone number. Optional.
        email: The contacts email address. Optional.
        ip_address: The contacts IP address in IPv4. Optional.
        gender: The contacts gender. Optional.
        date_of_birth: The contacts date of birth. Optional.
        utc_capture_time: The time the lead was submitted. Optional.
        output_language: Language for some output information. Optional.
        test_type: The type of validation to perform. Required.
        license_key: Your ServiceObjects license key.
        is_live: Use live or trial servers.

    Returns:
        LVResponse: Parsed JSON response with lead validation results or error details.

    Raises:
        RuntimeError: If the API returns an error payload.
        requests.RequestException: On network/HTTP failures (trial mode).
    """
    params = {
        "FullName": full_name,
        "Salutation": salutation,
        "FirstName": first_name,
        "LastName": last_name,
        "BusinessName": business_name,
        "BusinessDomain": business_domain,
        "BusinessEIN": business_ein,
        "Address1": address1,
        "Address2": address2,
        "Address3": address3,
        "Address4": address4,
        "Address5": address5,
        "Locality": locality,
        "AdminArea": admin_area,
        "PostalCode": postal_code,
        "Country": country,
        "Phone1": phone1,
        "Phone2": phone2,
        "Email": email,
        "IPAddress": ip_address,
        "Gender": gender,
        "DateOfBirth": date_of_birth,
        "UTCCaptureTime": utc_capture_time,
        "OutputLanguage": output_language,
        "TestType": test_type,
        "LicenseKey": license_key,
    }
    # Select the base URL: production vs trial
    url = primary_url if is_live else trial_url

    try:
        # Attempt primary (or trial) endpoint
        response = requests.get(url, params=params, timeout=10)
        response.raise_for_status()
        data = response.json()

        # If API returned an error in JSON payload, trigger fallback
        error = data.get('Error')
        if not (error is None or error.get('TypeCode') != "3"):
            if is_live:
                # Try backup URL
                response = requests.get(backup_url, params=params, timeout=10)
                data = response.json()

                # If still error, propagate exception
                if 'Error' in data:
                    raise RuntimeError(f"LV service error: {data['Error']}")
            else:
                # Trial mode error is terminal
                raise RuntimeError(f"LV trial error: {data['Error']}")

        # Convert JSON response to LVResponse for structured access
        error = Error(**data.get("Error", {})) if data.get("Error") else None
        phone_contact = PhoneContact(**data.get("PhoneContact", {})) if data.get("PhoneContact") else None

        return LVResponse(
            OverallCertainty=data.get("OverallCertainty"),
            OverallQuality=data.get("OverallQuality"),
            LeadType=data.get("LeadType"),
            LeadCountry=data.get("LeadCountry"),
            NoteCodes=data.get("NoteCodes"),
            NoteDesc=data.get("NoteDesc"),
            NameCertainty=data.get("NameCertainty"),
            NameQuality=data.get("NameQuality"),
            FirstName=data.get("FirstName"),
            LastName=data.get("LastName"),
            FirstNameClean=data.get("FirstNameClean"),
            LastNameClean=data.get("LastNameClean"),
            NameNoteCodes=data.get("NameNoteCodes"),
            NameNoteDesc=data.get("NameNoteDesc"),
            AddressCertainty=data.get("AddressCertainty"),
            AddressQuality=data.get("AddressQuality"),
            Address1=data.get("Address1"),
            Address2=data.get("Address2"),
            Address3=data.get("Address3"),
            Address4=data.get("Address4"),
            Address5=data.get("Address5"),
            AddressLocality=data.get("AddressLocality"),
            AddressAdminArea=data.get("AddressAdminArea"),
            AddressPostalCode=data.get("AddressPostalCode"),
            AddressCountry=data.get("AddressCountry"),
            AddressNoteCodes=data.get("AddressNoteCodes"),
            AddressNoteDesc=data.get("AddressNoteDesc"),
            EmailCertainty=data.get("EmailCertainty"),
            EmailQuality=data.get("EmailQuality"),
            EmailCorrected=data.get("EmailCorrected"),
            EmailNoteCodes=data.get("EmailNoteCodes"),
            EmailNoteDesc=data.get("EmailNoteDesc"),
            IPAddressCertainty=data.get("IPAddressCertainty"),
            IPAddressQuality=data.get("IPAddressQuality"),
            IPCountry=data.get("IPCountry"),
            IPLocality=data.get("IPLocality"),
            IPAdminArea=data.get("IPAdminArea"),
            IPNoteCodes=data.get("IPNoteCodes"),
            IPNoteDesc=data.get("IPNoteDesc"),
            Phone1Certainty=data.get("Phone1Certainty"),
            Phone1Quality=data.get("Phone1Quality"),
            Phone1Locality=data.get("Phone1Locality"),
            Phone1AdminArea=data.get("Phone1AdminArea"),
            Phone1Country=data.get("Phone1Country"),
            Phone1NoteCodes=data.get("Phone1NoteCodes"),
            Phone1NoteDesc=data.get("Phone1NoteDesc"),
            Phone2Certainty=data.get("Phone2Certainty"),
            Phone2Quality=data.get("Phone2Quality"),
            Phone2Locality=data.get("Phone2Locality"),
            Phone2AdminArea=data.get("Phone2AdminArea"),
            Phone2Country=data.get("Phone2Country"),
            Phone2NoteCodes=data.get("Phone2NoteCodes"),
            Phone2NoteDesc=data.get("Phone2NoteDesc"),
            PhoneContact=phone_contact,
            InformationComponents=[
                InformationComponent(Name=comp.get("Name"), Value=comp.get("Value"))
                for comp in data.get("InformationComponents", [])
            ] if "InformationComponents" in data else [],
            Error=error
        )

    except requests.RequestException as req_exc:
        # Network or HTTP-level error occurred
        if is_live:
            try:
                # Fallback to backup URL
                response = requests.get(backup_url, params=params, timeout=10)
                response.raise_for_status()
                data = response.json()
                if "Error" in data:
                    raise RuntimeError(f"LeadValidation backup error: {data['Error']}") from req_exc

                error = Error(**data.get("Error", {})) if data.get("Error") else None
                phone_contact = PhoneContact(**data.get("PhoneContact", {})) if data.get("PhoneContact") else None

                return LVResponse(
                    OverallCertainty=data.get("OverallCertainty"),
                    OverallQuality=data.get("OverallQuality"),
                    LeadType=data.get("LeadType"),
                    LeadCountry=data.get("LeadCountry"),
                    NoteCodes=data.get("NoteCodes"),
                    NoteDesc=data.get("NoteDesc"),
                    NameCertainty=data.get("NameCertainty"),
                    NameQuality=data.get("NameQuality"),
                    FirstName=data.get("FirstName"),
                    LastName=data.get("LastName"),
                    FirstNameClean=data.get("FirstNameClean"),
                    LastNameClean=data.get("LastNameClean"),
                    NameNoteCodes=data.get("NameNoteCodes"),
                    NameNoteDesc=data.get("NameNoteDesc"),
                    AddressCertainty=data.get("AddressCertainty"),
                    AddressQuality=data.get("AddressQuality"),
                    Address1=data.get("Address1"),
                    Address2=data.get("Address2"),
                    Address3=data.get("Address3"),
                    Address4=data.get("Address4"),
                    Address5=data.get("Address5"),
                    AddressLocality=data.get("AddressLocality"),
                    AddressAdminArea=data.get("AddressAdminArea"),
                    AddressPostalCode=data.get("AddressPostalCode"),
                    AddressCountry=data.get("AddressCountry"),
                    AddressNoteCodes=data.get("AddressNoteCodes"),
                    AddressNoteDesc=data.get("AddressNoteDesc"),
                    EmailCertainty=data.get("EmailCertainty"),
                    EmailQuality=data.get("EmailQuality"),
                    EmailCorrected=data.get("EmailCorrected"),
                    EmailNoteCodes=data.get("EmailNoteCodes"),
                    EmailNoteDesc=data.get("EmailNoteDesc"),
                    IPAddressCertainty=data.get("IPAddressCertainty"),
                    IPAddressQuality=data.get("IPAddressQuality"),
                    IPCountry=data.get("IPCountry"),
                    IPLocality=data.get("IPLocality"),
                    IPAdminArea=data.get("IPAdminArea"),
                    IPNoteCodes=data.get("IPNoteCodes"),
                    IPNoteDesc=data.get("IPNoteDesc"),
                    Phone1Certainty=data.get("Phone1Certainty"),
                    Phone1Quality=data.get("Phone1Quality"),
                    Phone1Locality=data.get("Phone1Locality"),
                    Phone1AdminArea=data.get("Phone1AdminArea"),
                    Phone1Country=data.get("Phone1Country"),
                    Phone1NoteCodes=data.get("Phone1NoteCodes"),
                    Phone1NoteDesc=data.get("Phone1NoteDesc"),
                    Phone2Certainty=data.get("Phone2Certainty"),
                    Phone2Quality=data.get("Phone2Quality"),
                    Phone2Locality=data.get("Phone2Locality"),
                    Phone2AdminArea=data.get("Phone2AdminArea"),
                    Phone2Country=data.get("Phone2Country"),
                    Phone2NoteCodes=data.get("Phone2NoteCodes"),
                    Phone2NoteDesc=data.get("Phone2NoteDesc"),
                    PhoneContact=phone_contact,
                    InformationComponents=[
                        InformationComponent(Name=comp.get("Name"), Value=comp.get("Value"))
                        for comp in data.get("InformationComponents", [])
                    ] if "InformationComponents" in data else [],
                    Error=error
                )
            except Exception as backup_exc:
                raise RuntimeError("LeadValidation service unreachable on both endpoints") from backup_exc
        else:
            raise RuntimeError(f"LeadValidation trial error: {str(req_exc)}") from req_exc


from dataclasses import dataclass
from typing import Optional, List


@dataclass
class InformationComponent:
    """Information Component for API responses."""
    Name: Optional[str] = None
    Value: Optional[str] = None

    def __str__(self) -> str:
        return f"Name={self.Name}, Value={self.Value}"


@dataclass
class PhoneContact:
    """Phone Contact for lead validation responses."""
    Name: Optional[str] = None
    Address: Optional[str] = None
    City: Optional[str] = None
    State: Optional[str] = None
    Zip: Optional[str] = None
    Type: Optional[str] = None

    def __str__(self) -> str:
        return (f"PhoneContact: Name={self.Name}, Address={self.Address}, City={self.City}, "
                f"State={self.State}, Zip={self.Zip}, Type={self.Type}")


@dataclass
class Error:
    """Error object for API responses."""
    Type: Optional[str] = None
    TypeCode: Optional[str] = None
    Desc: Optional[str] = None
    DescCode: Optional[str] = None

    def __str__(self) -> str:
        return (f"Error: Type={self.Type}, TypeCode={self.TypeCode}, "
                f"Desc={self.Desc}, DescCode={self.DescCode}")


@dataclass
class LVResponse:
    """Response from ValidateLead_V3 API, containing lead validation information."""
    OverallCertainty: Optional[str] = None
    OverallQuality: Optional[str] = None
    LeadType: Optional[str] = None
    LeadCountry: Optional[str] = None
    NoteCodes: Optional[str] = None
    NoteDesc: Optional[str] = None
    NameCertainty: Optional[str] = None
    NameQuality: Optional[str] = None
    FirstName: Optional[str] = None
    LastName: Optional[str] = None
    FirstNameClean: Optional[str] = None
    LastNameClean: Optional[str] = None
    NameNoteCodes: Optional[str] = None
    NameNoteDesc: Optional[str] = None
    AddressCertainty: Optional[str] = None
    AddressQuality: Optional[str] = None
    Address1: Optional[str] = None
    Address2: Optional[str] = None
    Address3: Optional[str] = None
    Address4: Optional[str] = None
    Address5: Optional[str] = None
    AddressLocality: Optional[str] = None
    AddressAdminArea: Optional[str] = None
    AddressPostalCode: Optional[str] = None
    AddressCountry: Optional[str] = None
    AddressNoteCodes: Optional[str] = None
    AddressNoteDesc: Optional[str] = None
    EmailCertainty: Optional[str] = None
    EmailQuality: Optional[str] = None
    EmailCorrected: Optional[str] = None
    EmailNoteCodes: Optional[str] = None
    EmailNoteDesc: Optional[str] = None
    IPAddressCertainty: Optional[str] = None
    IPAddressQuality: Optional[str] = None
    IPCountry: Optional[str] = None
    IPLocality: Optional[str] = None
    IPAdminArea: Optional[str] = None
    IPNoteCodes: Optional[str] = None
    IPNoteDesc: Optional[str] = None
    Phone1Certainty: Optional[str] = None
    Phone1Quality: Optional[str] = None
    Phone1Locality: Optional[str] = None
    Phone1AdminArea: Optional[str] = None
    Phone1Country: Optional[str] = None
    Phone1NoteCodes: Optional[str] = None
    Phone1NoteDesc: Optional[str] = None
    Phone2Certainty: Optional[str] = None
    Phone2Quality: Optional[str] = None
    Phone2Locality: Optional[str] = None
    Phone2AdminArea: Optional[str] = None
    Phone2Country: Optional[str] = None
    Phone2NoteCodes: Optional[str] = None
    Phone2NoteDesc: Optional[str] = None
    PhoneContact: Optional['PhoneContact'] = None
    InformationComponents: Optional[List['InformationComponent']] = None
    Error: Optional['Error'] = None

    def __post_init__(self):
        if self.InformationComponents is None:
            self.InformationComponents = []

    def __str__(self) -> str:
        info_components_string = ', '.join(str(component) for component in self.InformationComponents) if self.InformationComponents else 'None'
        phone_contact = str(self.PhoneContact) if self.PhoneContact else 'None'
        error = str(self.Error) if self.Error else 'None'
        return (f"LVResponse: OverallCertainty={self.OverallCertainty}, OverallQuality={self.OverallQuality}, "
                f"LeadType={self.LeadType}, LeadCountry={self.LeadCountry}, NoteCodes={self.NoteCodes}, NoteDesc={self.NoteDesc}, "
                f"NameCertainty={self.NameCertainty}, NameQuality={self.NameQuality}, FirstName={self.FirstName}, LastName={self.LastName}, "
                f"FirstNameClean={self.FirstNameClean}, LastNameClean={self.LastNameClean}, NameNoteCodes={self.NameNoteCodes}, NameNoteDesc={self.NameNoteDesc}, "
                f"AddressCertainty={self.AddressCertainty}, AddressQuality={self.AddressQuality}, Address1={self.Address1}, Address2={self.Address2}, "
                f"Address3={self.Address3}, Address4={self.Address4}, Address5={self.Address5}, AddressLocality={self.AddressLocality}, "
                f"AddressAdminArea={self.AddressAdminArea}, AddressPostalCode={self.AddressPostalCode}, AddressCountry={self.AddressCountry}, "
                f"AddressNoteCodes={self.AddressNoteCodes}, AddressNoteDesc={self.AddressNoteDesc}, EmailCertainty={self.EmailCertainty}, "
                f"EmailQuality={self.EmailQuality}, EmailCorrected={self.EmailCorrected}, EmailNoteCodes={self.EmailNoteCodes}, EmailNoteDesc={self.EmailNoteDesc}, "
                f"IPAddressCertainty={self.IPAddressCertainty}, IPAddressQuality={self.IPAddressQuality}, IPCountry={self.IPCountry}, "
                f"IPLocality={self.IPLocality}, IPAdminArea={self.IPAdminArea}, IPNoteCodes={self.IPNoteCodes}, IPNoteDesc={self.IPNoteDesc}, "
                f"Phone1Certainty={self.Phone1Certainty}, Phone1Quality={self.Phone1Quality}, Phone1Locality={self.Phone1Locality}, "
                f"Phone1AdminArea={self.Phone1AdminArea}, Phone1Country={self.Phone1Country}, Phone1NoteCodes={self.Phone1NoteCodes}, Phone1NoteDesc={self.Phone1NoteDesc}, "
                f"Phone2Certainty={self.Phone2Certainty}, Phone2Quality={self.Phone2Quality}, Phone2Locality={self.Phone2Locality}, "
                f"Phone2AdminArea={self.Phone2AdminArea}, Phone2Country={self.Phone2Country}, Phone2NoteCodes={self.Phone2NoteCodes}, Phone2NoteDesc={self.Phone2NoteDesc}, "
                f"PhoneContact={phone_contact}, InformationComponents=[{info_components_string}], Error={error}")

Lead Validation NodeJS Rest Code Snippet

import axios from 'axios';
import querystring from 'querystring';
import { LVResponse } from './lv_response.js';

/**
 * @constant
 * @type {string}
 * @description The base URL for the live ServiceObjects Lead Validation (LV) API service.
 */
const LiveBaseUrl = 'https://sws.serviceobjects.com/lv/api.svc/json/';

/**
 * @constant
 * @type {string}
 * @description The base URL for the backup ServiceObjects Lead Validation (LV) API service.
 */
const BackupBaseUrl = 'https://swsbackup.serviceobjects.com/lv/api.svc/json/';

/**
 * @constant
 * @type {string}
 * @description The base URL for the trial ServiceObjects Lead Validation (LV) API service.
 */
const TrialBaseUrl = 'https://trial.serviceobjects.com/lv/api.svc/json/';

/**
 * <summary>
 * Checks if a response from the API is valid by verifying that it either has no Error object
 * or the Error.TypeCode is not equal to '3'.
 * </summary>
 * <param name="response" type="Object">The API response object to validate.</param>
 * <returns type="boolean">True if the response is valid, false otherwise.</returns>
 */
const isValid = (response) => !response?.Error || response.Error.TypeCode !== '3';

/**
 * <summary>
 * Constructs a full URL for the ValidateLead_V3 API endpoint by combining the base URL
 * with query parameters derived from the input parameters.
 * </summary>
 * <param name="params" type="Object">An object containing all the input parameters.</param>
 * <param name="baseUrl" type="string">The base URL for the API service (live, backup, or trial).</param>
 * <returns type="string">The constructed URL with query parameters.</returns>
 */
const buildUrl = (params, baseUrl) =>
    `${baseUrl}ValidateLead_V3?${querystring.stringify(params)}`;

/**
 * <summary>
 * Performs an HTTP GET request to the specified URL with a given timeout.
 * </summary>
 * <param name="url" type="string">The URL to send the GET request to.</param>
 * <param name="timeoutSeconds" type="number">The timeout duration in seconds for the request.</param>
 * <returns type="Promise<LVResponse>">A promise that resolves to an LVResponse object containing the API response data.</returns>
 * <exception cref="Error">Thrown if the HTTP request fails, with a message detailing the error.</exception>
 */
const httpGet = async (url, timeoutSeconds) => {
    try {
        const response = await axios.get(url, { timeout: timeoutSeconds * 1000 });
        return new LVResponse(response.data);
    } catch (error) {
        throw new Error(`HTTP request failed: ${error.message}`);
    }
};

/**
 * <summary>
 * Provides functionality to call the ServiceObjects Lead Validation (LV) API's ValidateLead_V3 endpoint,
 * retrieving lead validation information for a given US or Canada lead with fallback to a backup endpoint for reliability in live mode.
 * </summary>
 */
const ValidateLeadV3Client = {
    /**
     * <summary>
     * Asynchronously invokes the ValidateLead_V3 API endpoint, attempting the primary endpoint
     * first and falling back to the backup if the response is invalid (Error.TypeCode == '3') in live mode.
     * </summary>
     * @param {string} fullName - The contacts full name (e.g., "Jane Doe"). Optional.
     * @param {string} salutation - Salutation of the contact (e.g., "Dr", "Mr"). Optional.
     * @param {string} firstName - First name of the contact (e.g., "Jane"). Optional.
     * @param {string} lastName - Last name of the contact (e.g., "Doe"). Optional.
     * @param {string} businessName - The contacts company (e.g., "Service Objects"). Optional.
     * @param {string} businessDomain - Website domain associated with the business (e.g., "serviceobjects.com"). Optional.
     * @param {string} businessEIN - Company Tax Number for US leads. Optional.
     * @param {string} address1 - Address line 1 of the contact or business address. Optional.
     * @param {string} address2 - Address line 2 of the contact or business address. Optional.
     * @param {string} address3 - Address line 3 of the contact or business address. Optional.
     * @param {string} address4 - Address line 4 of the contact or business address. Optional.
     * @param {string} address5 - Address line 5 of the contact or business address. Optional.
     * @param {string} locality - The city of the contacts postal address. Optional.
     * @param {string} adminArea - The state or province of the contacts postal address. Optional.
     * @param {string} postalCode - The zip or postal code of the contacts postal address. Optional.
     * @param {string} country - The country of the contacts postal address (e.g., "United States", "US"). Optional.
     * @param {string} phone1 - The contacts primary phone number. Optional.
     * @param {string} phone2 - The contacts secondary phone number. Optional.
     * @param {string} email - The contacts email address. Optional.
     * @param {string} ipAddress - The contacts IP address in IPv4. Optional.
     * @param {string} gender - The contacts gender ("Male", "Female", "Neutral"). Optional.
     * @param {string} dateOfBirth - The contacts date of birth. Optional.
     * @param {string} utcCaptureTime - The time the lead was submitted. Optional.
     * @param {string} outputLanguage - Language for some output information. Optional.
     * @param {string} testType - The type of validation to perform. Required.
     * @param {string} licenseKey - Your license key to use the service.
     * @param {boolean} isLive - Value to determine whether to use the live or trial servers.
     * @param {number} timeoutSeconds - Timeout, in seconds, for the call to the service.
     * @returns {Promise<LVResponse>} - A promise that resolves to an LVResponse object.
     */
    async invokeAsync(fullName, salutation, firstName, lastName, businessName, businessDomain, businessEIN,
        address1, address2, address3, address4, address5, locality, adminArea, postalCode, country,
        phone1, phone2, email, ipAddress, gender, dateOfBirth, utcCaptureTime, outputLanguage, testType, licenseKey,
        isLive = true, timeoutSeconds = 15) {
        const params = {
            fullName, salutation, firstName, lastName, businessName, businessDomain, businessEIN,
            address1, address2, address3, address4, address5, locality, adminArea, postalCode, country,
            phone1, phone2, email, ipAddress, gender, dateOfBirth, utcCaptureTime, outputLanguage, testType, licenseKey
        };

        const url = buildUrl(params, isLive ? LiveBaseUrl : TrialBaseUrl);
        let response = await httpGet(url, timeoutSeconds);

        if (isLive && !isValid(response)) {
            const fallbackUrl = buildUrl(params, BackupBaseUrl);
            const fallbackResponse = await httpGet(fallbackUrl, timeoutSeconds);
            return fallbackResponse;
        }
        return response;
    },

    /**
     * <summary>
     * Synchronously invokes the ValidateLead_V3 API endpoint by wrapping the async call
     * and awaiting its result immediately.
     * </summary>
     * @param {string} FullName - The contacts full name. Optional.
     * @param {string} Salutation - Salutation of the contact. Optional.
     * @param {string} fullName - The contacts full name (e.g., "Jane Doe"). Optional.
     * @param {string} salutation - Salutation of the contact (e.g., "Dr", "Mr"). Optional.
     * @param {string} firstName - First name of the contact (e.g., "Jane"). Optional.
     * @param {string} lastName - Last name of the contact (e.g., "Doe"). Optional.
     * @param {string} businessName - The contacts company (e.g., "Service Objects"). Optional.
     * @param {string} businessDomain - Website domain associated with the business (e.g., "serviceobjects.com"). Optional.
     * @param {string} businessEIN - Company Tax Number for US leads. Optional.
     * @param {string} address1 - Address line 1 of the contact or business address. Optional.
     * @param {string} address2 - Address line 2 of the contact or business address. Optional.
     * @param {string} address3 - Address line 3 of the contact or business address. Optional.
     * @param {string} address4 - Address line 4 of the contact or business address. Optional.
     * @param {string} address5 - Address line 5 of the contact or business address. Optional.
     * @param {string} locality - The city of the contacts postal address. Optional.
     * @param {string} adminArea - The state or province of the contacts postal address. Optional.
     * @param {string} postalCode - The zip or postal code of the contacts postal address. Optional.
     * @param {string} country - The country of the contacts postal address (e.g., "United States", "US"). Optional.
     * @param {string} phone1 - The contacts primary phone number. Optional.
     * @param {string} phone2 - The contacts secondary phone number. Optional.
     * @param {string} email - The contacts email address. Optional.
     * @param {string} ipAddress - The contacts IP address in IPv4. Optional.
     * @param {string} gender - The contacts gender ("Male", "Female", "Neutral"). Optional.
     * @param {string} dateOfBirth - The contacts date of birth. Optional.
     * @param {string} utcCaptureTime - The time the lead was submitted. Optional.
     * @param {string} outputLanguage - Language for some output information. Optional.
     * @param {string} testType - The type of validation to perform. Required.
     * @param {string} licenseKey - Your license key to use the service.
     * @param {boolean} isLive - Value to determine whether to use the live or trial servers.
     * @param {number} timeoutSeconds - Timeout, in seconds, for the call to the service.
     * @returns {LVResponse} - An LVResponse object with lead validation details or an error.
     */
    invoke(fullName, salutation, firstName, lastName, businessName, businessDomain, businessEIN,
        address1, address2, address3, address4, address5, locality, adminArea, postalCode, country,
        phone1, phone2, email, ipAddress, gender, dateOfBirth, utcCaptureTime, outputLanguage, testType, licenseKey,
        isLive = true, timeoutSeconds = 15) {
        return (async () => await this.invokeAsync(
            fullName, salutation, firstName, lastName, businessName, businessDomain, businessEIN,
            address1, address2, address3, address4, address5, locality, adminArea, postalCode, country,
            phone1, phone2, email, ipAddress, gender, dateOfBirth, utcCaptureTime, outputLanguage, testType, licenseKey,
            isLive, timeoutSeconds
        ))();
    }
};

export { ValidateLeadV3Client, LVResponse };



/**
 * Information Component for API responses.
 */
export class InformationComponent {
    constructor(data = {}) {
        this.Name = data.Name;
        this.Value = data.Value;
    }

    toString() {
        return `Name = ${this.Name}, Value = ${this.Value}`;
    }
}

/**
 * Phone Contact for lead validation responses.
 */
export class PhoneContact {
    constructor(data = {}) {
        this.Name = data.Name;
        this.Address = data.Address;
        this.City = data.City;
        this.State = data.State;
        this.Zip = data.Zip;
        this.Type = data.Type;
    }

    toString() {
        return `PhoneContact: Name = ${this.Name}, Address = ${this.Address}, City = ${this.City}, State = ${this.State}, Zip = ${this.Zip}, Type = ${this.Type}`;
    }
}

/**
 * Error object for API responses.
 */
export class Error {
    constructor(data = {}) {
        this.Type = data.Type;
        this.TypeCode = data.TypeCode;
        this.Desc = data.Desc;
        this.DescCode = data.DescCode;
    }

    toString() {
        return `Error: Type = ${this.Type}, TypeCode = ${this.TypeCode}, Desc = ${this.Desc}, DescCode = ${this.DescCode}`;
    }
}

/**
 * Response from ValidateLead_V3 API, containing lead validation information.
 */
export class LVResponse {
    constructor(data = {}) {
        this.OverallCertainty = data.OverallCertainty;
        this.OverallQuality = data.OverallQuality;
        this.LeadType = data.LeadType;
        this.LeadCountry = data.LeadCountry;
        this.NoteCodes = data.NoteCodes;
        this.NoteDesc = data.NoteDesc;
        this.NameCertainty = data.NameCertainty;
        this.NameQuality = data.NameQuality;
        this.FirstName = data.FirstName;
        this.LastName = data.LastName;
        this.FirstNameClean = data.FirstNameClean;
        this.LastNameClean = data.LastNameClean;
        this.NameNoteCodes = data.NameNoteCodes;
        this.NameNoteDesc = data.NameNoteDesc;
        this.AddressCertainty = data.AddressCertainty;
        this.AddressQuality = data.AddressQuality;
        this.Address1 = data.Address1;
        this.Address2 = data.Address2;
        this.Address3 = data.Address3;
        this.Address4 = data.Address4;
        this.Address5 = data.Address5;
        this.AddressLocality = data.AddressLocality;
        this.AddressAdminArea = data.AddressAdminArea;
        this.AddressPostalCode = data.AddressPostalCode;
        this.AddressCountry = data.AddressCountry;
        this.AddressNoteCodes = data.AddressNoteCodes;
        this.AddressNoteDesc = data.AddressNoteDesc;
        this.EmailCertainty = data.EmailCertainty;
        this.EmailQuality = data.EmailQuality;
        this.EmailCorrected = data.EmailCorrected;
        this.EmailNoteCodes = data.EmailNoteCodes;
        this.EmailNoteDesc = data.EmailNoteDesc;
        this.IPAddressCertainty = data.IPAddressCertainty;
        this.IPAddressQuality = data.IPAddressQuality;
        this.IPCountry = data.IPCountry;
        this.IPLocality = data.IPLocality;
        this.IPAdminArea = data.IPAdminArea;
        this.IPNoteCodes = data.IPNoteCodes;
        this.IPNoteDesc = data.IPNoteDesc;
        this.Phone1Certainty = data.Phone1Certainty;
        this.Phone1Quality = data.Phone1Quality;
        this.Phone1Locality = data.Phone1Locality;
        this.Phone1AdminArea = data.Phone1AdminArea;
        this.Phone1Country = data.Phone1Country;
        this.Phone1NoteCodes = data.Phone1NoteCodes;
        this.Phone1NoteDesc = data.Phone1NoteDesc;
        this.Phone2Certainty = data.Phone2Certainty;
        this.Phone2Quality = data.Phone2Quality;
        this.Phone2Locality = data.Phone2Locality;
        this.Phone2AdminArea = data.Phone2AdminArea;
        this.Phone2Country = data.Phone2Country;
        this.Phone2NoteCodes = data.Phone2NoteCodes;
        this.Phone2NoteDesc = data.Phone2NoteDesc;
        this.PhoneContact = data.PhoneContact ? new PhoneContact(data.PhoneContact) : null;
        this.InformationComponents = (data.InformationComponents || []).map(component => new InformationComponent(component));
        this.Error = data.Error ? new Error(data.Error) : null;
    }

    toString() {
        const infoComponentsString = this.InformationComponents.length
            ? this.InformationComponents.map(component => component.toString()).join(', ')
            : 'null';
        return `LVResponse: OverallCertainty = ${this.OverallCertainty}, OverallQuality = ${this.OverallQuality}, ` +
            `LeadType = ${this.LeadType}, LeadCountry = ${this.LeadCountry}, NoteCodes = ${this.NoteCodes}, NoteDesc = ${this.NoteDesc}, ` +
            `NameCertainty = ${this.NameCertainty}, NameQuality = ${this.NameQuality}, FirstName = ${this.FirstName}, LastName = ${this.LastName}, ` +
            `FirstNameClean = ${this.FirstNameClean}, LastNameClean = ${this.LastNameClean}, NameNoteCodes = ${this.NameNoteCodes}, NameNoteDesc = ${this.NameNoteDesc}, ` +
            `AddressCertainty = ${this.AddressCertainty}, AddressQuality = ${this.AddressQuality}, Address1 = ${this.Address1}, Address2 = ${this.Address2}, ` +
            `Address3 = ${this.Address3}, Address4 = ${this.Address4}, Address5 = ${this.Address5}, AddressLocality = ${this.AddressLocality}, ` +
            `AddressAdminArea = ${this.AddressAdminArea}, AddressPostalCode = ${this.AddressPostalCode}, AddressCountry = ${this.AddressCountry}, ` +
            `AddressNoteCodes = ${this.AddressNoteCodes}, AddressNoteDesc = ${this.AddressNoteDesc}, EmailCertainty = ${this.EmailCertainty}, ` +
            `EmailQuality = ${this.EmailQuality}, EmailCorrected = ${this.EmailCorrected}, EmailNoteCodes = ${this.EmailNoteCodes}, EmailNoteDesc = ${this.EmailNoteDesc}, ` +
            `IPAddressCertainty = ${this.IPAddressCertainty}, IPAddressQuality = ${this.IPAddressQuality}, IPCountry = ${this.IPCountry}, ` +
            `IPLocality = ${this.IPLocality}, IPAdminArea = ${this.IPAdminArea}, IPNoteCodes = ${this.IPNoteCodes}, IPNoteDesc = ${this.IPNoteDesc}, ` +
            `Phone1Certainty = ${this.Phone1Certainty}, Phone1Quality = ${this.Phone1Quality}, Phone1Locality = ${this.Phone1Locality}, ` +
            `Phone1AdminArea = ${this.Phone1AdminArea}, Phone1Country = ${this.Phone1Country}, Phone1NoteCodes = ${this.Phone1NoteCodes}, Phone1NoteDesc = ${this.Phone1NoteDesc}, ` +
            `Phone2Certainty = ${this.Phone2Certainty}, Phone2Quality = ${this.Phone2Quality}, Phone2Locality = ${this.Phone2Locality}, ` +
            `Phone2AdminArea = ${this.Phone2AdminArea}, Phone2Country = ${this.Phone2Country}, Phone2NoteCodes = ${this.Phone2NoteCodes}, Phone2NoteDesc = ${this.Phone2NoteDesc}, ` +
            `PhoneContact = ${this.PhoneContact ? this.PhoneContact.toString() : 'null'}, InformationComponents = [${infoComponentsString}], ` +
            `Error = ${this.Error ? this.Error.toString() : 'null'}`;
    }
}

export default LVResponse;