UPS Address Verification with ColdFusion

UPS API documentation sucks! I just have to say that out loud before I start this post.

This ColdFusion function will connect with the UPS Address Verification API. To use it, you must first have a UPS license number, a username, and a password for UPS shipping API. You can get that by registering in here. This is a simple Function that performs a simple task. Just fill in the address, city, state, zip, and country, and the function will tell you whether the address is correct. If it’s not, the function may suggest a correct address. UPS API login details are shown in my application file as application.UPSLicense, application.UPSUserId and application.UPSPassword.

Here is the function first:

   1: <cffunction name="AddressVerification" access="remote" returntype="struct" output="true">
   2:  <cfargument name="address"    type="string" required="yes">
   3:  <cfargument name="city"    type="string" required="yes">
   4:  <cfargument name="state"    type="string" required="yes">
   5:  <cfargument name="zip"    type="string" required="yes">
   6:  <cfargument name="country"    type="string" required="No" default="US">
   7:  <cfargument name="License"    type="string" required="No" default="#application.UPSLicense#">
   8:  <cfargument name="UserId"    type="string" required="No" default="#application.UPSUserId#">
   9:  <cfargument name="Password" type="string" required="No" default="#application.UPSPassword#">
  10:  <cfargument name="Request"    type="string" required="No" default="3">
  11: 
  12:  <cfset var local = StructNew()>
  13: 
  14:  <cfsavecontent variable="local.reqxml"><cfoutput>
  15:  <?xml version="1.0"?>
  16:  <AccessRequest xml:lang="en-US">
  17:     <AccessLicenseNumber>#arguments.License#</AccessLicenseNumber>
  18:     <UserId>#arguments.UserId#</UserId>
  19:     <Password>#arguments.Password#</Password>
  20:  </AccessRequest>
  21:  <?xml version="1.0"?>
  22:  <AddressValidationRequest xml:lang="en-US">
  23:     <Request>
  24:     <TransactionReference>
  25:      <CustomerContext>Address Varification</CustomerContext>
  26:      <XpciVersion>1.0</XpciVersion>
  27:     </TransactionReference>
  28:     <RequestAction>XAV</RequestAction>
  29:     <RequestOption>#arguments.Request#</RequestOption>
  30:     </Request>
  31:     <AddressKeyFormat>
  32:     <AddressLine>#arguments.address#</AddressLine>
  33:     <PoliticalDivision2>#arguments.city#</PoliticalDivision2>
  34:     <PoliticalDivision1>#arguments.state#</PoliticalDivision1>
  35:     <PostcodePrimaryLow>#arguments.zip#</PostcodePrimaryLow>
  36:     <CountryCode>#arguments.country#</CountryCode>
  37:     </AddressKeyFormat>
  38:  </AddressValidationRequest>
  39:  </cfoutput></cfsavecontent>
  40:  <cfset local.out    = StructNew()>
  41:  <cfset local.out.validation = "">
  42:  <cfset local.out.address = "">
  43:  <cfset local.out.city    = "">
  44:  <cfset local.out.state    = "">
  45:  <cfset local.out.zip    = "">
  46:  <cfset local.out.country = "">
  47: 
  48:  <cftry>
  49:  <cfhttp url="https://wwwcie.ups.com/ups.app/xml/XAV" method="post" result="result">
  50:  <cfhttpparam type="xml" name="data" value="#local.reqxml#">
  51:  </cfhttp>
  52:  <cfset local.results = XMLParse(result.Filecontent)>
  53:  <cfcatch>
  54:     <cfset local.out.validation    = "False">
  55:     <cfset local.out.type    = "Failure">
  56:     <cfset local.out.ErrorDescription = "Connection Failure">
  57:  </cfcatch>
  58:  </cftry>
  59: 
  60:  <cfif IsDefined('local.results.AddressValidationResponse.AddressClassification.Description.XmlText')>
  61:  <cfset local.out.type = local.results.AddressValidationResponse.AddressClassification.Description.XmlText>
  62:  <cfif not IsDefined('local.results.AddressValidationResponse.AddressKeyFormat')>
  63:     <cfset local.out.validation = "False">
  64:  <cfelse>
  65:     <cfset local.out.validation = "True">
  66:     <cfif not local.results.AddressValidationResponse.AddressKeyFormat.AddressLine.XmlText eq trim(arguments.address) or
  67:     not local.results.AddressValidationResponse.AddressKeyFormat.PoliticalDivision2.XmlText eq trim(arguments.city) or
  68:     not local.results.AddressValidationResponse.AddressKeyFormat.PoliticalDivision1.XmlText eq trim(arguments.state) or
  69:     not local.results.AddressValidationResponse.AddressKeyFormat.PostcodePrimaryLow.XmlText eq trim(listfirst(arguments.zip,'-'))
>
  70:     <cfif IsDefined('local.results.AddressValidationResponse.AddressKeyFormat.AddressLine.XmlText')>
  71:      <cfset local.out.address = local.results.AddressValidationResponse.AddressKeyFormat.AddressLine.XmlText>
  72:     </cfif>
  73:     <cfif IsDefined('local.results.AddressValidationResponse.AddressKeyFormat.PoliticalDivision2.XmlText')>
  74:      <cfset local.out.city = local.results.AddressValidationResponse.AddressKeyFormat.PoliticalDivision2.XmlText>
  75:     </cfif>
  76:     <cfif IsDefined('local.results.AddressValidationResponse.AddressKeyFormat.PoliticalDivision1.XmlText')>
  77:      <cfset local.out.state = local.results.AddressValidationResponse.AddressKeyFormat.PoliticalDivision1.XmlText>
  78:     </cfif>
  79:     <cfif IsDefined('local.results.AddressValidationResponse.AddressKeyFormat.PostcodePrimaryLow.XmlText')>
  80:      <cfset local.out.zip = local.results.AddressValidationResponse.AddressKeyFormat.PostcodePrimaryLow.XmlText>
  81:     </cfif>
  82:     <cfif IsDefined('local.results.AddressValidationResponse.AddressKeyFormat.PostcodePrimaryLow.XmlText')>
  83:      <cfset local.out.zip = local.results.AddressValidationResponse.AddressKeyFormat.PostcodePrimaryLow.XmlText>
  84:      <cfif IsDefined('local.results.AddressValidationResponse.AddressKeyFormat.PostcodeExtendedLow.XmlText')>
  85:      <cfset local.out.zip = '#local.results.AddressValidationResponse.AddressKeyFormat.PostcodePrimaryLow.XmlText#-#local.results.AddressValidationResponse.AddressKeyFormat.PostcodeExtendedLow.XmlText#'>
  86:      </cfif>
  87:     </cfif>
  88:     <cfif IsDefined('local.results.AddressValidationResponse.AddressKeyFormat.AddressLine.XmlText')>
  89:      <cfset local.out.country = local.results.AddressValidationResponse.AddressKeyFormat.CountryCode.XmlText>
  90:     </cfif>
  91:     </cfif>
  92:  </cfif>
  93:  <cfelse>
  94:  <cfset local.out.validation    = "False">
  95:  <cfset local.out.type    = "Failure">
  96:  <cfif IsDefined('local.results.AddressValidationResponse.Response.Error.ErrorDescription.XmlText')>
  97:     <cfset local.out.ErrorDescription = local.results.AddressValidationResponse.Response.Error.ErrorDescription.XmlText>
  98:  <cfelse>
  99:     <cfset local.out.ErrorDescription = "">
 100:  </cfif>
 101:  </cfif>
 102: 
 103:  <cfreturn local.out>
 104: </cffunction>
Show/Hide Line Numbers . Full Screen . Plain

Here is a bit more information about the result structure.

This is what you get if the address you provided is correct, i.e. it was verified successfully. Here is my correct example:
AddressVerification('118A FULTON ST','NEW YORK', 'NY', '10038'),
It returns the TYPE of address (Commercial or Resident), VALIDATION = TRUE, and the other fields remain empty.



If the address is wrong, as with my mistyped and ZIP Code missing address here:
AddressVerification('118A FaLTON ST','NEW YORK', 'NY', ')
UPS may return a suggested address.



If the address is wrong and UPS does not suggested an address, as with this fake address:
AddressVerification('118A Fake ST','NEW YORK', 'NY', '10038'),
then Validation = False.



If the address verification fails completely, as happened when I tried to verify the UPS head office address here:
AddressVerification('55 Glenlake Parkway NE','Atlanta', 'GA', '30328'),
it will return Type = Failure and an Error Description message.


9 Comments :
Friday 14 November 2014 05:19 AM
Excellent post.
Doug
Friday 15 November 2013 03:07 PM
Sounds like getting the UPS API up and running is about as bad as the USPS API . What a headache it is with getting permissions after every step, especially when the testing servers don't work. Conflicting documentation doesn't help either.
Chris
Monday 11 June 2012 11:52 AM
So I actually figured this out - you must request a Production Key form UPS - only CA / NY work in the test Env...
Chris
Monday 11 June 2012 11:36 AM
Ok, so I am able to validate a CA and NY addresses but a Colorado address yields the "The state is not supported in the Customer Integration Environment. " error - do you know what this error means?
Joe
Thursday 21 July 2011 03:50 PM
I tried using this to verify a canadian address (passing country 'CA'), but I keep getting the below ERRORDESCRIPTION even though I know my canadian address is valid.

ERRORDESCRIPTION: The state is not supported in the Customer Integration Environment.

Is 'CA' the correct country value to pass into the country argument of this function?
Saturday 23 July 2011 11:47 PM
Hi Joe, I’m not really sure since I have not tried CA. you have to make sure the State is correct too. http://www.ups.com/worldshiphelp/WS12/ENU/AppHelp/Codes/State_Province_Codes.htm
jack roack
Saturday 23 April 2011 08:15 PM
Very nice--thanks!
Thursday 13 January 2011 08:40 PM
Do you know if this will work when there is a second line to the address like an apartment number?
Friday 14 January 2011 03:05 PM
If you mean something like “30 ColdFusion St, Apt 2” sort of a situation, that may not fail, just because Apt 2 is not wrong.