Fedex Address Validation API with Using Coldfusion

The FedEx shipping API is beautiful––soundly documented and trouble-free to work with. Before you use the FedEx API in your own application, you must register with FedEx to get an API Key, password, account number, and meter number. It is not difficult to do. Click here, and follow the instructions. Afterward, you can test the following code using your own API access key.

In the function below, I used the following values in the application scoop:
Key = application.AVkey
Password = application.AVpassword
Account Number =  application.AVaccount
Meter Number = application.AVmeter
application.AVserver = https://gateway.fedex.com/xml

You may want to set these same values in your Application file.

The first six arguments below (CompanyName, StreetLine1, etc.) are self-explanatory. The final argument, (FatalList), is the odd one. It lists the states from which messages may return from FedEx. If an address is returned, the function has decided that the address is incorrect and needs to be reentered FedEx will also suggest a correct address. If an empty string is returned, then your address passed with flying colors.

If your address is correct, this function will return an empty string. If not, this will send you an message with suggested address, if one available.

   1: <cffunction name="AddressValidation" access="remote" returntype="string">
   2:  <cfargument name="CompanyName" type="string" required="no" default="">
   3:  <cfargument name="StreetLine1" type="string" required="yes">
   4:  <cfargument name="StreetLine2" type="string" required="no" default="">
   5:  <cfargument name="City"    type="string" required="yes">
   6:  <cfargument name="State"    type="string" required="yes">
   7:  <cfargument name="PostalCode" type="string" required="yes">
   8:  <cfargument name="FatalList" type="string" required="No" default="BOX_NUMBER_REQUIRED,RR_OR_HC_BOX_NUMBER_NEEDED,UNABLE_TO_APPEND_NON_ADDRESS_DATA,INSUFFICIENT_DATA,HOUSE_OR_BOX_NUMBER_NOT_FOUND,POSTAL_CODE_NOT_FOUND,SERVICE_UNAVAILABLE_FOR_ADDRESS">
   9: <cftry>
  10: <cfsavecontent variable="local.XMLPacket"><cfoutput>
  11: <ns:AddressValidationRequest
  12:  xsi:schemaLocation="http://www.fedex.com/templates/components/apps/wpor/secure/downloads/xml/Aug09/Advanced/AddressValidationService_v2.xsd"
  13:  xmlns:ns ="http://fedex.com/ws/addressvalidation/v2"
  14:  xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance">
  15:  <ns:WebAuthenticationDetail>
  16:  <ns:UserCredential>
  17:     <ns:Key>#application.AVkey#</ns:Key>
  18:     <ns:Password>#application.AVpassword#</ns:Password>
  19:  </ns:UserCredential>
  20:  </ns:WebAuthenticationDetail>
  21:  <ns:ClientDetail>
  22:  <ns:AccountNumber>#application.AVaccount#</ns:AccountNumber>
  23:  <ns:MeterNumber>#application.AVmeter#</ns:MeterNumber>
  24:  </ns:ClientDetail>
  25:  <ns:Version>
  26:  <ns:ServiceId>aval</ns:ServiceId>
  27:  <ns:Major>2</ns:Major>
  28:  <ns:Intermediate>0</ns:Intermediate>
  29:  <ns:Minor>0</ns:Minor>
  30:  </ns:Version>
  31:  <ns:RequestTimestamp>#dateformat(now(),"yyyy-mm-dd")#T#TimeFormat(now(),"HH:mm:ss")#</ns:RequestTimestamp>
  32:  <ns:Options>
  33:  <ns:CheckResidentialStatus>1</ns:CheckResidentialStatus>
  34:  <ns:MaximumNumberOfMatches>5</ns:MaximumNumberOfMatches>
  35:  <ns:StreetAccuracy>MEDIUM</ns:StreetAccuracy>
  36:  <ns:DirectionalAccuracy>MEDIUM</ns:DirectionalAccuracy>
  37:  <ns:CompanyNameAccuracy>MEDIUM</ns:CompanyNameAccuracy>
  38:  <ns:ConvertToUpperCase>1</ns:ConvertToUpperCase>
  39:  <ns:RecognizeAlternateCityNames>1</ns:RecognizeAlternateCityNames>
  40:  <ns:ReturnParsedElements>1</ns:ReturnParsedElements>
  41:  </ns:Options>
  42:  <ns:AddressesToValidate>
  43:  <ns:AddressId>1</ns:AddressId>
  44:  <cfif len(arguments.CompanyName)><ns:CompanyName>#arguments.CompanyName#</ns:CompanyName></cfif>
  45:  <ns:Address>
  46:     <ns:StreetLines>#trim(arguments.StreetLine1)#</ns:StreetLines>
  47:     <cfif len(arguments.StreetLine2)><ns:StreetLines>#trim(arguments.StreetLine2)#</ns:StreetLines></cfif>
  48:     <ns:City>#arguments.City#</ns:City>
  49:     <ns:StateOrProvinceCode>#arguments.State#</ns:StateOrProvinceCode>
  50:     <ns:PostalCode>#arguments.PostalCode#</ns:PostalCode>
  51:     <ns:CountryCode>US</ns:CountryCode>
  52:  </ns:Address>
  53:  </ns:AddressesToValidate>
  54: </ns:AddressValidationRequest>
  55: </cfoutput></cfsavecontent>
  56:  <cfhttp url="#application.AVserver#" port="443" method ="POST" throwonerror="yes">
  57:     <cfhttpparam name="name" type="XML" value="#local.XMLPacket#">
  58:  </cfhttp>
  59: 
  60:  <cfset vari    = XMLParse(CFHTTP.FileContent)>
  61: 
  62:  <cfset local.msg    = "">
  63:  <cfset local.changed    = "">
  64:  <cfset vari = vari.AddressValidationReply.AddressResults.ProposedAddressDetails>
  65:  <!--- ************************************************************************** --->
  66:  <!--- check fatal error                                                         --->
  67:  <!--- ************************************************************************** --->
  68:  <cfloop from="1" to="#ArrayLen(vari.XmlChildren)#" index="i">
  69:     <cfif listlast(vari.XmlChildren[i].XmlName,':') eq 'Changes'>
  70:     <cfif listfind(arguments.FatalList,vari.XmlChildren[i].XmlText)>
  71:      <cfset local.msg = 'False'>
  72:     </cfif>
  73:     </cfif>
  74:  </cfloop>
  75: 
  76:  <!--- ************************************************************************** --->
  77:  <!--- Post box address                                                            --->
  78:  <!--- ************************************************************************** --->
  79:  <cfif IsDefined('vari.ParsedAddress.ParsedStreetLine.Elements.Name.XmlText') and vari.ParsedAddress.ParsedStreetLine.Elements.Name.XmlText eq 'postOfficeBoxNumber'>
  80:     <cfif not len(local.msg)>
  81:     <cfset local.msg = "FedEx cannot deliver to P.O. boxes">
  82:     </cfif>
  83:  </cfif>
  84:  <!--- ************************************************************************** --->
  85:  <!--- check if address changed                                                    --->
  86:  <!--- ************************************************************************** --->
  87:  <cfif not len(local.msg)>
  88:     <cfloop from="1" to="#ArrayLen(vari.ParsedAddress.ParsedStreetLine.XmlChildren)#" index="i">
  89:     <cfif vari.ParsedAddress.ParsedStreetLine.Elements[i].Changes.XmlText neq 'NO_CHANGES'>
  90:      <cfset local.changed = "1">
  91:     </cfif>
  92:     </cfloop>
  93:     <cfif vari.ParsedAddress.ParsedCity.Elements.Changes.XmlText neq 'NO_CHANGES'>
  94:     <cfset local.changed = "1">
  95:     </cfif>
  96:     <cfif vari.ParsedAddress.ParsedStateOrProvinceCode.Elements.Changes.XmlText neq 'NO_CHANGES'>
  97:     <cfset local.changed = "1">
  98:     </cfif>
  99:     <cfif vari.ParsedAddress.ParsedStateOrProvinceCode.Elements.Changes.XmlText neq 'NO_CHANGES'>
 100:     <cfset local.changed = "1">
 101:     </cfif>
 102:     <cfif vari.ParsedAddress.ParsedPostalCode.Elements.Changes.XmlText neq 'NO_CHANGES'>
 103:     <cfset local.changed = "1">
 104:     </cfif>
 105:  </cfif>
 106:  <!--- ************************************************************************** --->
 107:  <!--- Fedex Retrun Same Address . a Workaround                                 --->
 108:  <!--- ************************************************************************** --->
 109:  <cfset local.match = 0>
 110:  <cfset local.StreetLines = trim(replace('#arguments.StreetLine1# #arguments.StreetLine2#',' ',' ','all'))>
 111:  <cfif local.StreetLines eq vari.Address.StreetLines.XmlText>
 112:     <cfset local.match = local.match+1>
 113:  </cfif>
 114:  <cfif trim(arguments.City) eq vari.Address.City.XmlText>
 115:     <cfset local.match = local.match+1>
 116:  </cfif>
 117:  <cfif trim(arguments.State) eq vari.Address.StateOrProvinceCode.XmlText>
 118:     <cfset local.match = local.match+1>
 119:  </cfif>
 120:  <cfif trim(listfirst(arguments.PostalCode,'-')) eq listfirst(vari.Address.PostalCode.XmlText,'-')>
 121:     <cfset local.match = local.match+1>
 122:  </cfif>
 123: 
 124:  <!--- ************************************************************************** --->
 125:  <!--- get the new address                                                        --->
 126:  <!--- ************************************************************************** --->
 127:  <cfif val(local.changed) and local.match neq 4>
 128:     <cfset ProposedAddress = ArrayNew(1)>
 129:     <cfloop from="1" to="#ArrayLen(vari.Address.XmlChildren)#" index="i">
 130:     <cfset ArrayAppend(ProposedAddress,vari.Address.XmlChildren[i].XmlText)>
 131:     </cfloop>
 132:     <cfset local.ProposedAddress = ArrayToList(ProposedAddress,'<br />')>
 133:  <cfelse>
 134:     <cfset local.ProposedAddress = "">
 135:  </cfif>
 136: 
 137:  <cfset local.out = "#local.msg##local.ProposedAddress#">
 138:  <cfcatch>
 139:  <cfset local.out = "FedEx cannot verify Your address at this time. Please try again.">
 140:  </cfcatch>
 141: </cftry>
 142:  <cfreturn trim(local.out)>
 143:  </cffunction>
Show/Hide Line Numbers . Full Screen . Plain


12 Comments :
Mike
Wednesday 08 May 2013 12:17 PM
This is very useful. Thanks for sharing.

Also note that id you need to determine the RESIDENTIAL/BUSINESS status of an address you can find it in:

vari.ResidentialStatus.XmlText

This will have 3 possible values: RESIDENTIAL, BUSINESS or UNDETERMINED

The first two are quite obvious but there are a few "rules" you can use to communicate with your end user. For instance, if it comes back UNDETERMINED there is a problem with the address. Perhaps a missing Suite or Apartment number.

If it returns RESIDENTIAL or BUSINESS but no address suggestion, then everything was fine. If it returns RESIDENTIAL or BUSINESS and has an address suggestion, everything was technically fine but it did make formatting corrections to the address.
Jake
Friday 05 October 2012 04:56 PM
This code was exactly what I was looking for but I had the same "Authentication Failed" error as everyone else. I just got done on the phone with FedEx Integration department and they did in fact need to do something additional to unlock this on my FedEx account. I was told I'll need certification but that's really just a request they have to submit to someone else who will approve it in a couple days. I was also told the URL here is correct (https://gateway.fedex.com/xml) and there is NOT a dev server version of this API as it relies on production server data. Hence you'll need a real FedEx account number and meter number to get this setup.

The # I had to call was:
1.877.339.2774 (When prompted, please say "Web Services"). Whoever I got connected to at first couldn't help me though and transfered me to "integration".

Hopefully this helps someone in a similar situation save a lot of time!
Jon
Friday 07 October 2011 04:04 PM
Thanks for the code. This looks like exactly what I need. I've setup the account as instructed and have entered my meeter #, account #, etc., in the code, but it doesn't seem to be authinticating. When I dump the CFHTTP.FileContent var from the call to https://gateway.fedex.com/xml, I get "Authentication Failed" for AddressValidationReply.Notifications.message. I have also tried using https://gatewaybeta.fedex.com.

Is there a different URL to post to? Or something I'm missing? Thanks!
Friday 07 October 2011 05:36 PM
https://gateway.fedex.com/xml is correct. That still in my production server and it works. You get the authentication error because your code works correctly. I?m not sure do you have to add 'Address Validation' API accesses to your account, inside Fedex Member area or does Fedex take time to actually activate your account. (I have a vague memory I had to go through something like that).
Andy
Tuesday 10 January 2012 12:14 PM
No. Still "Authentication Failed."

Tuesday 10 January 2012 10:14 AM
Hi Andy, is your issue solved?

Andy
Monday 02 January 2012 04:49 PM
I'm having the same "Authentication Failed" issue as Jon. Can anyone confirm this might be due to a Settings issue within the FedEx member account itself?

Tuesday 14 June 2011 04:09 PM
Sam - got this working (i think). Issue was that the URL I was posting too wasn't correct.

Changed it to post to the XML expectant URL on the Fedex side and this seems to be working now. Appreciate your help.
Tuesday 14 June 2011 09:17 AM
Ok, thanks. I'll figure out what's what then. FWIW, this is the error msg I keep getting back from the fedex server:

<?xml version="1.0" encoding="UTF-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Body><soapenv:Fault><faultcode>soapenv:Client</faultcode><faultstring>The message must be an instance of: {http://schemas.xmlsoap.org/soap/envelope/}Envelope</faultstring><detail><con:fault xmlns:con="http://www.bea.com/wli/sb/context"><con:errorCode>9999</con:errorCode><con:reason>The message must be an instance of: {http://schemas.xmlsoap.org/soap/envelope/}Envelope</con:reason><con:details><err:InvalidEnvelope xmlns:err="http://www.bea.com/wli/sb/errors"><err:localpart>AddressValidationRequest</err:localpart><err:namespace>http://fedex.com/ws/addressvalidation/v2</err:namespace></err:InvalidEnvelope></con:details></con:fault></detail></soapenv:Fault></soapenv:Body></soapenv:Envelope>
Tuesday 14 June 2011 01:39 PM
It’s possible the address string breaking the xml. XmlFormat() it or try out with a plain string like, 800, 42 street, NY, 10004 …
Brian
Monday 13 June 2011 03:23 PM
Saman - does this function still work for you? We're testing out something similar with Fedex and I came across this code. It looks perfect for what we need.

When i dropped it into our environment with our Fedex API keys etc, I'm getting an error using this function. So I figured I'd reach out and see if this was still working for you or if something had changed and this function wasn't working anymore with Fedex.

Thanks,
Brian
Monday 13 June 2011 05:26 PM
I just tested this code with my fedex keys, and it still works.