UPS Tracking Service API

Introduction

This post covers the steps needed to use the Tracking Service Application Programming Interface (API) of United Parcel Service (UPS). We will cover the steps of registering with UPS first to get credentials/license key from UPS and then use the street address validation API in a C# console application. We will use Visual Studio 2015 as Integrated Development Environment (IDE) and build a Windows Communication Foundation (WCF) client to invoke the UPS API.

Assumptions:

  1. You are familiar with a .net programming language (preferably C#) and Visual Studio .Net.
  2. You understand the basics of Windows Communication Foundation and how to consume a web service with the help of a WSDL file.

If you perform an internet search on the keywords ‘UPS Developer API’, you will get the link to the web page that covers all the documentation you need. The link is:

https://www.ups.com/upsdeveloperkit

In order to access UPS API, you need a userid/password credential and an access key.

Step 1: Get Security Credentials

Get a userid and password by registering with My UPS if you don’t have one already. This is step 1 on UPS web page.

1

Step 2: Get Access Key

Login to the same page mentioned above by using the credentials obtained in step 1 and request access key (Step 5 on the page). The access key will be displayed on your browser window. You will also get an email with the same access key information.

2

Now we are ready to write code.

Step 3: Build Code

Step 3a: Download API Files

UPS exposes different APIs for different types of functionality. In this tutorial, we will use their ‘Tracking’ API. Please go ahead and download the API documentation.

 

The API will be downloaded as a zip file. Extract the zip file to a folder of your choice. Navigate to the folder that contains the WSDLs of the Address Validation Service. If you extracted the zip file to a folder called ‘C:\UPS\Tracking’, you will have to do the following:

Navigate to:

C:\UPS\Tracking\Tracking\TrackingPACKAGE\TRACKINGXMLTools\Schemas

Copy all the schema files (.xsd) files from this folder to:

C:\UPS\Tracking\TrackingPACKAGE\TRACKINGWebServices\SCHEMAS-WSDLs

The ‘SCHEMAS-WSDLs’ folder will look like this:

Please note that the WSDL file and all its dependencies (XML schemas) exist in the same folder.

Step 3b: Create Console Project with the name ‘UPSTrackingConsoleApplication’

Step 3c: Add Service Reference

Right click on the console project and add service reference to the UPS tracking service.

Now provide the full path of the WSDL file. Rename the proxy namespace to UPSTrackingProxy.

Also, please note how Visual Studio adds WCF client configuration to your app.config file. You don’t need to change this please note the address of the service and the types of binding and contract. The service endpoint URL is the URL of UPS test environment.

Step3d: Add code

Add the following code to the Program.cs project startup class. I have tried to document the code as much as possible so it becomes self-explanatory.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using UPSTrackingConsoleApplication.UPSTrackingProxy;</code>
 
namespace UPSTracking
{
class Program
{
static void Main(string[] args)
{
try
{
//create the client proxy
TrackPortTypeClient track = new TrackPortTypeClient();
 
//create username token
UPSSecurityUsernameToken upssUsrNameToken = new UPSSecurityUsernameToken();
//this is your my UPS userid
upssUsrNameToken.Username = "your userid";
//this is your my UPS password
upssUsrNameToken.Password = "your password";
 
UPSSecurityServiceAccessToken upssSvcAccessToken = 
new UPSSecurityServiceAccessToken();
//this is your my UPS access key
upssSvcAccessToken.AccessLicenseNumber = "your access token";
//create UPS security object
UPSSecurity upss = new UPSSecurity();
//set the user name token
upss.UsernameToken = upssUsrNameToken;
//set the service access token
upss.ServiceAccessToken = upssSvcAccessToken;
 
//create the request object
RequestType request = new RequestType();
//must be hard coded to 15
String[] requestOption = { "15" };
//set the request option
request.RequestOption = requestOption;
 
TrackRequest tr = new TrackRequest();
tr.Request = request;
//this is your UPS tracking id like 1Z123455....
tr.InquiryNumber = "1Zxxxxxxxxxx";
 
//added to handle the intermittent error with SSL/TLS connection
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | 
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | 
SecurityProtocolType.Tls12;
 
//open channel
track.Open();
 
//invoke the service
TrackResponse trackResponse = track.ProcessTrack(upss, tr);
 
//close channel
track.Close();
 
Console.WriteLine("The transaction was a " + 
trackResponse.Response.ResponseStatus.Description);
Console.WriteLine("Shipment Service " + 
trackResponse.Shipment[0].Service.Description);
 
//print tracking process result
foreach (ShipmentType shipment in trackResponse.Shipment)
{
foreach (PackageType package in shipment.Package)
{
 
foreach (ActivityType Act in package.Activity)
{
Console.WriteLine("City {0} {1}, Date {2}, Time {3}, Status {4}", 
Act.ActivityLocation.Address.City, 
Act.ActivityLocation.Address.StateProvinceCode, Act.Date, Act.Time, 
Act.Status.Description);
}
 
}
 
}
 
}
catch (Exception ex)
{
Console.WriteLine(String.Format("Error in processing tracking request: {0}", 
ex.Message));
}
 
Console.ReadKey();
 
}
}
}

Step 4: Test the code

Run the project and test with different values of address input. The output of the program will look similar to this.

The transaction was a Success
Shipment Service UPS GROUND
City XYZ CA, Date 20161129, Time 115600, Status Delivered
City XYZ CA, Date 20161129, Time 044000, Status Out For Delivery
City XYZ CA, Date 20161129, Time 042400, Status Out For Delivery
City XYZ CA, Date 20161129, Time 032500, Status Arrival Scan
City MNP CA, Date 20161129, Time 014600, Status Departure Scan
City MNP CA, Date 20161128, Time 082400, Status Arrival Scan
City EFG FL, Date 20161123, Time 103800, Status Departure Scan
City EFG FL, Date 20161123, Time 020400, Status Arrival Scan
City ABC FL, Date 20161122, Time 224300, Status Departure Scan
City ABC FL, Date 20161122, Time 173900, Status Origin Scan
City , Date 20161121, Time 193111, Status Order Processed: Ready for UPS

Please note:

  1. Make sure you pass value of “15” as RequestOption. Please see code comments for more details.
  2. I found UPS documentation to be dated and out of synch with their current code. But it is still a good idea to read their documentation to get some general ideas about their service.
  3. The code in this post works at the time of writing this post (December 1, 2016).
  4. No warranty is provided with the code or any documentation in this article.

This code could be refactored into multiple helper methods but I wanted to provide one block of code with no dependencies to keep things simple for this post.

Invoke UPS Address Validation API using C# and Visual Studio 2015

Introduction

This post covers the steps needed to use the Street Address Validation Application Programming Interface (API) of United Parcel Service (UPS). We will cover the steps of registering with UPS first to get credentials/license key from UPS and then use the street address validation API in a C# console application. We will use Visual Studio 2015 as Integrated Development Environment (IDE) and build a Windows Communication Foundation (WCF) client to invoke the UPS API.

Assumptions:

  1. You are familiar with a .net programming language (preferably C#) and Visual Studio .Net.
  2. You understand the basics of Windows Communication Foundation and how to consume a web service with the help of a WSDL file.

If you perform an internet search on the keywords ‘UPS Developer API’, you will get the link to the web page that covers all the documentation you need. The link is:

https://www.ups.com/upsdeveloperkit

In order to access UPS API, you need a userid/password credential and an access key.

Step 1: Get Security Credentials

Get a userid and password by registering with My UPS if you don’t have one already. This is step 1 on UPS web page.

1

Step 2: Get Access Key

Login to the same page mentioned above by using the credentials obtained in step 1 and request access key (Step 5 on the page). The access key will be displayed on your browser window. You will also get an email with the same access key information.

2

Now we are ready to write code.

Step 3: Build Code

Step 3a: Download API Files

UPS exposes different APIs for different types of functionality. In this tutorial, we will use their ‘Address Validation – Street Level’ API. Please go ahead and download the API documentation.

3

4

The API will be downloaded as a zip file. Extract the zip file to a folder of your choice. Navigate to the folder that contains the WSDLs of the Address Validation Service. If you extracted the zip file to a folder called ‘C:\UPS’, you will have to navigate to ‘C:\UPS\Street Level Address Validation for SHIPPING\XAVWebServices\SCHEMAS-WSDLs’

5

Please note that the WSDL file and all its dependencies (XML schemas) exist in the same folder.

Step 3b: Create Console Project

6

Step 3c: Add Service Reference

Right click on the console project and add service reference to the UPS service.

7

Now provide the full path of the WSDL file. Rename the proxy namespace to XAVServiceProxy.

8

Also, please note how Visual Studio adds WCF client configuration to your app.config file. You don’t need to change this please note the address of the service and the types of binding and contract. The service endpoint URL is the URL of UPS test environment.

9

Step3d: Add code

Add the following code to the Program.cs project startup class. I have tried to document the code as much as possible so it becomes self-explanatory.

using System;
 
using System.Collections.Generic;
 
using System.Linq;
 
using System.Net;
 
using System.Net.Security;
 
using System.Security.Cryptography.X509Certificates;
 
using System.Text;
 
using System.Threading.Tasks;
 
using UPSStreetAddressValidationConsoleApplication.XAVServiceProxy;
 
namespace UPSStreetAddressValidationConsoleApplication
 
{
 
class Program
 
{
 
static void Main(string[] args)
 
{
 
try
 
{
 
//this is the remote proxy object
 
XAVPortTypeClient Proxy = new XAVPortTypeClient();
 
//build the username token object
 
UPSSecurityUsernameToken UPSSecurityUsernameTokenObj = new UPSSecurityUsernameToken();
 
//use your userid when youn registered with my UPS
 
UPSSecurityUsernameTokenObj.Username = "your user id";
 
//use the password associated with your userid
 
UPSSecurityUsernameTokenObj.Password = "your password";
 
//build the security access token object
 
UPSSecurityServiceAccessToken UPSSecurityServiceAccessTokenObj = 
new UPSSecurityServiceAccessToken();
 
//your access key provided by UPS
 
UPSSecurityServiceAccessTokenObj.AccessLicenseNumber = "your access key";
 
//set the username and service access objects on the UPSSecurity input parm object
 
//this is the first parameter of the ProcessXAV method on UPS service
 
UPSSecurity UPSSecurityObj = new UPSSecurity();
 
UPSSecurityObj.UsernameToken = UPSSecurityUsernameTokenObj;
 
UPSSecurityObj.ServiceAccessToken = UPSSecurityServiceAccessTokenObj;
 
//build the transaction reference type
 
TransactionReferenceType TransactionReferenceTypeObj = new TransactionReferenceType();
//pass any value
TransactionReferenceTypeObj.CustomerContext = "Customer Data"; 
//pass any value
TransactionReferenceTypeObj.TransactionIdentifier = "12335"; 
 
//build the request type
 
RequestType RequestTypeObj = new RequestType();
//this value has to be 1
RequestTypeObj.RequestOption = new String[1] { "1"}; 
 
RequestTypeObj.TransactionReference = TransactionReferenceTypeObj;
 
//this is the class where we will pass the address data elements
 
//passing address of new York stock exchange for testing purpose
 
AddressKeyFormatType AddressKeyFormatTypeObj = new AddressKeyFormatType();
 
AddressKeyFormatTypeObj.AddressLine = new String[1] { "11 Wall Street" };
 
//political division 1 is required for get valid address validation code 
//otherwise you get an exception
 
AddressKeyFormatTypeObj.PoliticalDivision1 = "NY"; //state code
 
AddressKeyFormatTypeObj.PoliticalDivision2 = "New York"; //city
 
AddressKeyFormatTypeObj.CountryCode = "US"; //country must be US or PR
 
AddressKeyFormatTypeObj.PostcodePrimaryLow = ""; //passing a blank value
 
//now let’s build the second parameter
 
XAVRequest XAVRequestObj = new XAVRequest();
 
XAVRequestObj.AddressKeyFormat = AddressKeyFormatTypeObj;
 
XAVRequestObj.Request = RequestTypeObj;
 
//added to handle the intermittent error with SSL/TLS connection
 
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | 
SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | 
SecurityProtocolType.Tls12;
 
//open channel
 
Proxy.Open();
 
//call the service
 
XAVResponse Response = Proxy.ProcessXAV(UPSSecurityObj, XAVRequestObj);
 
//parse the result
 
ItemChoiceType Result = Response.ItemElementName;
//found multiple matches
if (Result == ItemChoiceType.AmbiguousAddressIndicator) 
{
 
Console.WriteLine(String.Format("Ambiguous Address.Found {0} matching candidate addresses",
Response.Candidate.Length.ToString()));
 
//print each candidate address that was returned as response
foreach (CandidateType candidateAddress in Response.Candidate)
{
Console.WriteLine(String.Format("Consignee Name: {0}", 
candidateAddress.AddressKeyFormat.ConsigneeName));
Console.WriteLine(String.Format("Street Line 1: {0}", 
candidateAddress.AddressKeyFormat.AddressLine[0]));
if (candidateAddress.AddressKeyFormat.AddressLine.Length > 1)
Console.WriteLine(String.Format("Street Line 2: {0}", 
candidateAddress.AddressKeyFormat.AddressLine[1]));
Console.WriteLine(String.Format("City: {0}", 
candidateAddress.AddressKeyFormat.PoliticalDivision2));
Console.WriteLine(String.Format("State: {0}", 
candidateAddress.AddressKeyFormat.PoliticalDivision1));
Console.WriteLine(String.Format("Zip: {0}-{1}",
candidateAddress.AddressKeyFormat.PostcodePrimaryLow,
Response.Candidate[0].AddressKeyFormat.PostcodeExtendedLow));
 
}
 
}
//invalid address no match found
else if (Result == ItemChoiceType.NoCandidatesIndicator) 
 
Console.WriteLine("Invalid Address");
//valid address exactly one candidate returned
else if (Result == ItemChoiceType.ValidAddressIndicator) 
 
{
 
Console.WriteLine("Valid Address");
 
Console.WriteLine(String.Format("Consignee Name: {0}", 
Response.Candidate[0].AddressKeyFormat.ConsigneeName));
 
Console.WriteLine(String.Format("Street Line 1: {0}", 
Response.Candidate[0].AddressKeyFormat.AddressLine[0]));
 
if (Response.Candidate[0].AddressKeyFormat.AddressLine.Length > 1)
 
Console.WriteLine(String.Format("Street Line 2: {0}", 
Response.Candidate[0].AddressKeyFormat.AddressLine[1]));
 
Console.WriteLine(String.Format("City: {0}", 
Response.Candidate[0].AddressKeyFormat.PoliticalDivision2));
 
Console.WriteLine(String.Format("State: {0}", 
Response.Candidate[0].AddressKeyFormat.PoliticalDivision1));
 
Console.WriteLine(String.Format("Zip: {0}-{1}",
Response.Candidate[0].AddressKeyFormat.PostcodePrimaryLow,
Response.Candidate[0].AddressKeyFormat.PostcodeExtendedLow));
 
}
 
//close communication channel
 
Proxy.Close();
 
}
 
catch (Exception ex)
 
{
 
//please add code to handle SOAP exceptions
 
Console.WriteLine(ex.Message);
 
}
 
//do not close the console window unless the user presses a key
 
Console.ReadKey();
 
}
 
}
 
}

 

Step 4: Test the code

Run the project and test with different values of address input. I have used the address of the New York Stock Exchange as a test address in my code example.

Please note:

  1. As per their website, the UPS Test URL works only for California and New York State addresses.
  2. Make sure you pass ‘US’ or ‘PR’ as country code. If you do not pass one of two values, you will get a SOAP Exception. The current UPS API supports US and Puerto Rico country codes.
  3. Make sure you pass value of “1” as RequestOption. Please see code comments for more details.
  4. Pass the two character state code in Political Division 1. If you don’t, you will get an exception.
  5. Pass the city name in the PoliticalDivision2 field.
  6. I found UPS documentation to be dated and out of synch with their current code. But it is still a good idea to read their documentation to get some general ideas about their service.
  7. The code in this post works at the time of writing this post (December 1, 2016).
  8. No warranty is provided with the code or any documentation in this article.

This code could be refactored into multiple helper methods but I wanted to provide one block of code with no dependencies to keep things simple for this post.

I will continue to test their APIs and try RESTful invocation if their API supports it. If you have any questions, feel free to post those in the comments area. Your feedback, as always, is appreciated.