Create a FedEx Express Shipping Label Using Coldfusion

In my previous post, I talked about FedEx Address verification. In this post, I present a function that will create a FedEx Express shipping label. It will pass along your shipment information and then save the shipping label as a PDF file (or PNG, DPL, etc..) on your hard drive.

Before running this code and creating your own FedEx shipping labels, you need to register with FedEx and get an API access key. Once you have that, you are ready to access the FedEx test server.

As you can see, this function contains a substantial number of arguments. I think most of the arguments are self-explanatory. The first set of arguments, grouped as [To Address], are the shipping address.

The second set of arguments, grouped as [Package Details], concerns your package’s weight, length, etc. FedEx has several different types of boxes to choose from, and I list all available options under the argument PackagingType, attribute “Hint.” Whenver an option is available, I have listed it under the “Hint” attribute in other arguments too. You are supposed to choose one of them as the value when more than one option is available.  

Argument [orderid], is any number you wish to use to identify your order. I used this same ID number to name the PDF file that saves the shipping label. For example, if your Order ID is 1234, you will have a file named1234.pdf. I also used this number to create log file names. FedEx prints this number on the shipping label so you can track packages using your FedEx account. The arguments [Department] and [ponumber] also appear on the FedEx label, and FedEx uses them as additional reference values.  

Under the argument [SpecialServices], if you choose “HOLD_AT_LOCATION,” then you have to include the location address in the [“Hold At" Location Address] section. If you chose ‘DRY_ICE,’ then you have to include a weight in the [DryIceWeight] section.

The arguments [returnLog] and [fedexcallLog] are the folder path to log request and response. If you don’t need to keep a log, these arguments can remain empty.

The [fedex Access Settings] section provides the API access details, such as your access key, password, meter number etc. I keep these values in the application scoop, and they are entered as default values.

Argument [FedexPDF] defines the full path of the folder where you want to save the label PDF file. The default value is FedexPDF, which is a folder named FedexPDF saved in the same location as your ColdFusion file. If this default folder does not exist, the PDF file for the shipping label will not get saved.

After saving the label file and the log files, the FedEx tracking number will be returned as a string.

There are lot more options you can add into this function, especially in the special services area. For now, though, this function covers all the basics––actually, a bit more than the basics!

   1: <cffunction name="shipping" access="remote" returntype="string" output="No">
   2: <!--- To Address --->
   3:  <cfargument name="Company"    type="string" required="Yes" >
   4:  <cfargument name="Name"    type="string" required="Yes" >
   5:  <cfargument name="Address1"    type="string" required="Yes" >
   6:  <cfargument name="Address2"    type="string" required="No" default="">
   7:  <cfargument name="City"    type="string" required="Yes" >
   8:  <cfargument name="State"    type="string" required="Yes" >
   9:  <cfargument name="ZIP"     type="string" required="Yes" >
  10:  <cfargument name="Phone"    type="string" required="Yes" >
  11:  <cfargument name="IsResident"    type="string" required="No" default="false" >
  12: <!--- package Details --->
  13:  <cfargument name="weight"    type="string" required="Yes" >
  14:  <cfargument name="Length"    type="string" required="Yes" >
  15:  <cfargument name="Width"    type="string" required="Yes" >
  16:  <cfargument name="Height"    type="string" required="Yes" >
  17:  <cfargument name="PackagingType" type="string" required="Yes" hint="Available Options : FEDEX_10KG_BOX, FEDEX_25KG_BOX, FEDEX_BOX, FEDEX_ENVELOPE, FEDEX_PAK, FEDEX_TUBE, YOUR_PACKAGING">
  18: <!--- shipping details ---->
  19:  <cfargument name="orderid"    type="string" required="No" default="#CreateUUID()#">
  20:  <cfargument name="ShippingMethod" type="string" required="No" default="STANDARD_OVERNIGHT" hint="Available Options : EUROPE_FIRST_INTERNATIONAL_PRIORITY, FEDEX_1_DAY_FREIGHT, FEDEX_2_DAY, FEDEX_2_DAY_FREIGHT, FEDEX_3_DAY_FREIGHT, FEDEX_EXPRESS_SAVER, FEDEX_GROUND, FIRST_OVERNIGHT, GROUND_HOME_DELIVERY, INTERNATIONAL_ECONOMY, INTERNATIONAL_ECONOMY_FREIGHT, INTERNATIONAL_FIRST, INTERNATIONAL_PRIORITY, INTERNATIONAL_PRIORITY_FREIGHT, PRIORITY_OVERNIGHT, SMART_POST, STANDARD_OVERNIGHT">
  21:  <cfargument name="ShipDate"    type="string" required="No" default="#now()#">
  22:  <cfargument name="department"    type="string" required="No" default="">
  23:  <cfargument name="ponumber"    type="string" required="No" default="">
  24:  <cfargument name="DropoffType"    type="string" required="No" default="REGULAR_PICKUP" hint="Available Options : REGULAR_PICKUP, REQUEST_COURIER, DROP_BOX, BUSINESS_SERVICE_CENTER, STATION">
  25:  <cfargument name="SpecialServices" type="string" required="No" default="" hint="Available Options : DANGEROUS_GOODS, BROKER_SELECT_OPTION, COD, DRY_ICE, ELECTRONIC_TRADE_DOCUMENTS, EMAIL_NOTIFICATION, FUTURE_DAY_SHIPMENT, HOLD_AT_LOCATION, HOME_DELIVERY_PREMIUM, INSIDE_DELIVERY, INSIDE_PICKUP, PENDING_SHIPMENT, RETURN_SHIPMENT, SATURDAY_DELIVERY, SATURDAY_PICKUP">
  26:  <cfargument name="DryIceWeight" type="string" required="No" default="" hint="Dry Ice Weight">
  27: <!--- "Hold At" Location Address ---->
  28:  <cfargument name="HoldAtAddress1" type="string" required="No" default="">
  29:  <cfargument name="HoldAtAddress2" type="string" required="No" default="">
  30:  <cfargument name="HoldAtCity"    type="string" required="No" default="">
  31:  <cfargument name="HoldAtState"    type="string" required="No" default="">
  32:  <cfargument name="HoldAtZIP"    type="string" required="No" default="">
  33:  <cfargument name="HoldAtPhone"    type="string" required="No" default="">
  34:  <cfargument name="HoldAtIsResident" type="string" required="No" default="false" >
  35: <!--- log settings --->
  36:  <cfargument name="returnLog"    type="string" required="No" default="#ExpandPath('log/return/')#">
  37:  <cfargument name="fedexcallLog" type="string" required="No" default="#ExpandPath('log/fedexcall/')#">
  38: <!--- fedex Access Settings --->
  39:  <cfargument name="key"     type="string" required="No" default="#application.FedExkey#">
  40:  <cfargument name="password"    type="string" required="No" default="#application.FedExpassword#">
  41:  <cfargument name="account"    type="string" required="No" default="#application.FedExaccount#">
  42:  <cfargument name="meter"    type="string" required="No" default="#application.FedExmeter#">
  43:  <cfargument name="serverurl"    type="string" required="No" default="#application.FedExserver#" hint="SandBox : https://gatewaybeta.fedex.com/xml , Production: https://gateway.fedex.com/xml">
  44:  <cfargument name="billingAct"    type="string" required="No" default="#application.FedExbillingAct#">
  45:  <cfargument name="PaymentType"    type="string" required="No" default="THIRD_PARTY" hint="Available Options : COLLECT, RECIPIENT, SENDER, THIRD_PARTY">
  46:  <cfargument name="LabelType"    type="string" required="No" default="PAPER_4X6" hint="Available Options : PAPER_4X6, PAPER_4X8, PAPER_4X9, PAPER_7X4.75, PAPER_8.5X11_BOTTOM_HALF_LABEL, PAPER_8.5X11_TOP_HALF_LABEL, STOCK_4X6, STOCK_4X6.75_LEADING_DOC_TAB, STOCK_4X6.75_TRAILING_DOC_TAB, STOCK_4X8, STOCK_4X9_LEADING_DOC_TAB, STOCK_4X9_TRAILING_DOC_TAB">
  47: <!--- shipping label settings --->
  48:  <cfargument name="FedexPDF"    type="string" required="No" default="#ExpandPath('FedexPDF/')#">
  49:  <cfargument name="labelFile"    type="string" required="No" default="pdf" hint="Available Options : DPL, EPL2, PDF, PNG, ZPLII">
  50: <!--- From Address --->
  51:  <cfargument name="FromCompany"    type="string" required="No" default="My Company" >
  52:  <cfargument name="FromName"    type="string" required="No" default="John Doe" >
  53:  <cfargument name="FromAddress1" type="string" required="No" default="16 Court Street" >
  54:  <cfargument name="FromAddress2" type="string" required="No" default="">
  55:  <cfargument name="FromCity"    type="string" required="No" default="New York">
  56:  <cfargument name="FromState"    type="string" required="No" default="NY">
  57:  <cfargument name="FromZIP"    type="string" required="No" default="10211">
  58:  <cfargument name="FromPhone"    type="string" required="No" default="2015282777" >
  59:  <cfargument name="FromIsResident" type="string" required="No" default="false" >
  60: 
  61:  <!---- ************************************************************** --->
  62:  <!---- create fedex xml                                                --->
  63:  <!---- ************************************************************** --->
  64:  <cfsavecontent variable="XMLPacket"><cfoutput>
  65:  <ns:ProcessShipmentRequest
  66:  xsi:schemaLocation ="http://www.fedex.com/templates/components/apps/wpor/secure/downloads/xml/Aug09/Advanced/ShipService_v7.xsd"
  67:  xmlns:ns    ="http://fedex.com/ws/ship/v7"
  68:  xmlns:xsi    ="http://www.w3.org/2001/XMLSchema-instance">
  69: 
  70:  <ns:WebAuthenticationDetail>
  71:     <ns:UserCredential>
  72:     <ns:Key>#arguments.key#</ns:Key>
  73:     <ns:Password>#arguments.password#</ns:Password>
  74:     </ns:UserCredential>
  75:  </ns:WebAuthenticationDetail>
  76: 
  77:  <ns:ClientDetail>
  78:     <ns:AccountNumber>#arguments.account#</ns:AccountNumber>
  79:     <ns:MeterNumber>#arguments.meter#</ns:MeterNumber>
  80:  </ns:ClientDetail>
  81: 
  82:  <ns:TransactionDetail>
  83:     <ns:CustomerTransactionId>#arguments.orderid#</ns:CustomerTransactionId>
  84:  </ns:TransactionDetail>
  85: 
  86:  <ns:Version>
  87:     <ns:ServiceId>ship</ns:ServiceId>
  88:     <ns:Major>7</ns:Major>
  89:     <ns:Intermediate>0</ns:Intermediate>
  90:     <ns:Minor>0</ns:Minor>
  91:  </ns:Version>
  92:  <ns:RequestedShipment>
  93:     <ns:ShipTimestamp>#dateformat(arguments.ShipDate,"yyyy-mm-dd")#T#TimeFormat(arguments.ShipDate, "HH:mm:ss")#</ns:ShipTimestamp>
  94:     <ns:DropoffType>#arguments.DropoffType#</ns:DropoffType>
  95:     <ns:ServiceType>#trim(arguments.ShippingMethod)#</ns:ServiceType>
  96:     <ns:PackagingType>#trim(arguments.PackagingType)#</ns:PackagingType>
  97:     <ns:Shipper>
  98:     <ns:Contact>
  99:      <ns:PersonName>#arguments.FromName#</ns:PersonName>
 100:      <ns:CompanyName>#arguments.FromCompany#</ns:CompanyName>
 101:      <ns:PhoneNumber>#arguments.FromPhone#</ns:PhoneNumber>
 102:     </ns:Contact>
 103:     <ns:Address>
 104:      <ns:StreetLines>#arguments.FromAddress1#</ns:StreetLines>
 105:      <cfif len(trim(arguments.FromAddress2))><ns:StreetLines>#XMLFormat(arguments.FromAddress2)#</ns:StreetLines></cfif>
 106:      <ns:City>#arguments.FromCity#</ns:City>
 107:      <ns:StateOrProvinceCode>#arguments.FromState#</ns:StateOrProvinceCode>
 108:      <ns:PostalCode>#arguments.FromZIP#</ns:PostalCode>
 109:      <ns:CountryCode>US</ns:CountryCode>
 110:      <ns:Residential>#arguments.FromIsResident#</ns:Residential>
 111:     </ns:Address>
 112:     </ns:Shipper>
 113:     <ns:Recipient>
 114:     <ns:Contact>
 115:      <ns:PersonName>#XMLFormat(arguments.Name)#</ns:PersonName>
 116:      <cfif len(trim(arguments.Company))>
 117:      <ns:CompanyName>#XMLFormat(arguments.Company)#</ns:CompanyName>
 118:      </cfif>
 119:      <ns:PhoneNumber>#XMLFormat(arguments.Phone)#</ns:PhoneNumber>
 120:     </ns:Contact>
 121:     <ns:Address>
 122:      <ns:StreetLines>#XMLFormat(arguments.Address1)#</ns:StreetLines>
 123:      <cfif len(trim(arguments.Address2))><ns:StreetLines>#XMLFormat(arguments.Address2)#</ns:StreetLines></cfif>
 124:      <ns:City>#XMLFormat(arguments.City)#</ns:City>
 125:      <ns:StateOrProvinceCode>#XMLFormat(arguments.State)#</ns:StateOrProvinceCode>
 126:      <ns:PostalCode>#XMLFormat(arguments.ZIP)#</ns:PostalCode>
 127:      <ns:CountryCode>US</ns:CountryCode>
 128:      <ns:Residential>#arguments.IsResident#</ns:Residential>
 129:     </ns:Address>
 130:     </ns:Recipient>
 131: 
 132:     <ns:ShippingChargesPayment>
 133:     <ns:PaymentType>#arguments.PaymentType#</ns:PaymentType>
 134:     <ns:Payor>
 135:      <ns:AccountNumber>#arguments.billingAct#</ns:AccountNumber>
 136:      <ns:CountryCode>US</ns:CountryCode>
 137:     </ns:Payor>
 138:     </ns:ShippingChargesPayment>
 139:     <cfif len(arguments.SpecialServices) and listfind("SATURDAY_DELIVERY,SATURDAY_PICKUP,HOLD_AT_LOCATION",arguments.SpecialServices)>
 140:     <ns:SpecialServicesRequested>
 141:     <ns:SpecialServiceTypes>#arguments.SpecialServices#</ns:SpecialServiceTypes>    
 142:      <cfswitch expression="#arguments.SpecialServices#">
 143:      <cfcase value="HOLD_AT_LOCATION">
 144:         <ns:HoldAtLocationDetail>
 145:         <ns:PhoneNumber>#XMLFormat(arguments.HoldAtPhone)#</ns:PhoneNumber>
 146:         <ns:Address>
 147:         <ns:StreetLines>#XMLFormat(arguments.HoldAtAddress1)#</ns:StreetLines>
 148:         <cfif len(trim(arguments.HoldAtAddress2))><ns:StreetLines>#XMLFormat(arguments.HoldAtAddress2)#</ns:StreetLines></cfif>
 149:         <ns:City>#XMLFormat(arguments.HoldAtCity)#</ns:City>
 150:         <ns:StateOrProvinceCode>#XMLFormat(arguments.HoldAtState)#</ns:StateOrProvinceCode>
 151:         <ns:PostalCode>#XMLFormat(arguments.HoldAtZIP)#</ns:PostalCode>
 152:         <ns:CountryCode>US</ns:CountryCode>
 153:         <ns:Residential>#arguments.HoldAtIsResident#</ns:Residential>
 154:         </ns:Address>
 155:         </ns:HoldAtLocationDetail>
 156:      </cfcase>
 157:      </cfswitch>
 158:     </ns:SpecialServicesRequested>
 159:     </cfif>
 160:     
 161:     <ns:LabelSpecification>
 162:     <ns:LabelFormatType>COMMON2D</ns:LabelFormatType>
 163:     <ns:ImageType>#ucase(arguments.labelFile)#</ns:ImageType>
 164:     <ns:LabelStockType>#arguments.LabelType#</ns:LabelStockType>
 165:     </ns:LabelSpecification>
 166:     
 167:     <ns:RateRequestTypes>ACCOUNT</ns:RateRequestTypes>
 168:     
 169:     <ns:PackageCount>1</ns:PackageCount>
 170:     <ns:PackageDetail>INDIVIDUAL_PACKAGES</ns:PackageDetail>
 171:     <ns:RequestedPackageLineItems>
 172:     <ns:SequenceNumber>1</ns:SequenceNumber>
 173:     <ns:Weight>
 174:      <ns:Units>LB</ns:Units>
 175:      <ns:Value>#trim(arguments.weight)#</ns:Value>
 176:     </ns:Weight>
 177:     <ns:Dimensions>
 178:      <ns:Length>#trim(arguments.Length)#</ns:Length>
 179:      <ns:Width>#trim(arguments.Width)#</ns:Width>
 180:      <ns:Height>#trim(arguments.Height)#</ns:Height>
 181:      <ns:Units>IN</ns:Units>
 182:     </ns:Dimensions>
 183:     <ns:PhysicalPackaging>BOX</ns:PhysicalPackaging>
 184: 
 185:     <ns:CustomerReferences>
 186:     <ns:CustomerReferenceType>INVOICE_NUMBER</ns:CustomerReferenceType>
 187:     <ns:Value>#arguments.orderid#</ns:Value>
 188:     </ns:CustomerReferences>
 189:     <cfif len(arguments.department)>
 190:     <ns:CustomerReferences>
 191:     <ns:CustomerReferenceType>DEPARTMENT_NUMBER</ns:CustomerReferenceType>
 192:     <ns:Value>#arguments.department#</ns:Value>
 193:     </ns:CustomerReferences>
 194:     </cfif>
 195:     <cfif len(arguments.ponumber)>
 196:     <ns:CustomerReferences>
 197:     <ns:CustomerReferenceType>P_O_NUMBER</ns:CustomerReferenceType>
 198:     <ns:Value>#arguments.ponumber#</ns:Value>
 199:     </ns:CustomerReferences>
 200:     </cfif>
 201:     <cfif len(arguments.SpecialServices) and listfind("DRY_ICE,DANGEROUS_GOODS",arguments.SpecialServices)>
 202:     <ns:SpecialServicesRequested>
 203:     <ns:SpecialServiceTypes>#arguments.SpecialServices#</ns:SpecialServiceTypes>    
 204:     <cfswitch expression="#arguments.SpecialServices#">
 205:      <cfcase value="DRY_ICE">
 206:      <ns:DryIceWeight>
 207:         <ns:Units>KG</ns:Units>
 208:         <ns:Value>#arguments.DryIceWeight#</ns:Value>
 209:      </ns:DryIceWeight>
 210:      </cfcase>
 211: <!--- More special services discussions needed to be added here ---->    
 212:     </cfswitch>
 213:     </ns:SpecialServicesRequested>
 214:     </cfif>
 215:     
 216:     </ns:RequestedPackageLineItems>
 217:  </ns:RequestedShipment>
 218:  </ns:ProcessShipmentRequest>
 219:  </cfoutput></cfsavecontent>
 220: 
 221: 
 222:  <!---- ************************************************************** --->
 223:  <!---- log the outgoing fedex request                                 --->
 224:  <!---- ************************************************************** --->
 225:  <cfif len(arguments.fedexcallLog) and DirectoryExists(arguments.fedexcallLog)>
 226:  <cfif FileExists("#arguments.fedexcallLog##arguments.orderid#.xml")>
 227:     <cffile
 228:     action = "delete"
 229:     file = "#arguments.fedexcallLog##arguments.orderid#.xml">
 230:  </cfif>
 231:  <cffile
 232:     action = "write"
 233:     charset ="utf-8"
 234:     file = "#arguments.fedexcallLog##arguments.orderid#.xml"
 235:     output = "#XMLPacket#">
 236:  </cfif>
 237:  <!---- ************************************************************** --->
 238:  <!---- call fedex                                                     --->
 239:  <!---- ************************************************************** --->
 240:  <cftry>
 241:  <cfhttp url="#arguments.serverurl#" port="443" method ="POST" throwonerror="yes">
 242:     <cfhttpparam name="name" type="XML" value="#XMLPacket#">
 243:  </cfhttp>
 244:  <cfset local.output = XmlParse(CFHTTP.FileContent)>
 245:  <cfcatch>
 246:     <cfset TrackingNumber = "">
 247:     <cfset local.output = cfcatch>
 248:  </cfcatch>
 249:  </cftry>
 250: 
 251:  <!---- ************************************************************** --->
 252:  <!---- log fedex return                                                --->
 253:  <!---- ************************************************************** --->
 254:  <cfif len(arguments.returnLog) and DirectoryExists(arguments.returnLog)>
 255:  <cfif FileExists("#arguments.returnLog##arguments.orderid#.xml")>
 256:     <cffile
 257:     action = "delete"
 258:     file = "#arguments.returnLog##arguments.orderid#.xml">
 259:  </cfif>
 260:  <cffile
 261:     action = "write"
 262:     file = "#arguments.returnLog##arguments.orderid#.xml"
 263:     output = "#local.output#"
 264:     charset = "utf-8">
 265:  </cfif>
 266: 
 267:  <!---- ************************************************************** --->
 268:  <!---- save Label / Get Tracking Number                                --->
 269:  <!---- ************************************************************** --->
 270:  <cfif IsDefined("local.output.ProcessShipmentReply.CompletedShipmentDetail.CompletedPackageDetails.TrackingIds.TrackingNumber")>
 271:  <cfset TrackingNumber = local.output.ProcessShipmentReply.CompletedShipmentDetail.CompletedPackageDetails.TrackingIds.TrackingNumber.XmlText>
 272: 
 273:  <cfif len(arguments.FedexPDF) and DirectoryExists(arguments.FedexPDF)>
 274:     <cfset local.img    = local.output.ProcessShipmentReply.CompletedShipmentDetail.CompletedPackageDetails.Label.Parts.Image.XmlText>
 275:     <cfset local.img = ToBinary(local.output.ProcessShipmentReply.CompletedShipmentDetail.CompletedPackageDetails.Label.Parts.Image.XmlText)>
 276:     
 277:     <cfif FileExists("#arguments.FedexPDF##arguments.orderid#.#arguments.labelFile#")>
 278:     <cffile
 279:      action = "delete"
 280:      file = "#arguments.FedexPDF##arguments.orderid#.#arguments.labelFile#">
 281:     </cfif>
 282:     <cffile action ="write"
 283:     charset ="utf-8"
 284:     file ="#arguments.FedexPDF##arguments.orderid#.#arguments.labelFile#"
 285:     output ="#local.img#">
 286:  </cfif>
 287:  <cfelse>
 288:  <cfset TrackingNumber = "">
 289:  </cfif>
 290:  <cfreturn TrackingNumber>
 291: </cffunction>
Show/Hide Line Numbers . Full Screen . Plain

Here is the FedEx ShipAPI Certification Test Scenario Cheat Sheet using this function.

9 Comments :
Westfork
Thursday 25 October 2012 06:40 PM
This tag looks great, but I'm not getting any output.
Is there a method to dump FedEx error codes?
Thursday 25 October 2012 07:00 PM
This logs all the requests and response. You can look at the log folder
Amit Pandey
Monday 25 June 2012 07:33 AM
Thanx a lot really helpful article.
Raf
Friday 08 July 2011 09:45 PM
Is there a way to a add price or rate to it?
Monday 18 April 2011 10:20 AM
This was a huge help. Can you post Close and Cancel routines?
Evan
Tuesday 22 March 2011 10:12 PM

SHIPPER_ACCOUNT_NUMBER


Can you help?
Wednesday 23 March 2011 12:18 AM
Where that part came from? Any more info?
Tuesday 22 February 2011 03:18 PM
I just wanted to thank you for posting this tag. It saved me a lot of time reading through the docs and almost purchasing that same program from above. I'm going to spend some time handling the XML error responses and then put it into production.
Steve F.
Thursday 07 October 2010 11:55 AM
If only I had found this site before I paid $150 for a Custom Tag that does the same thing. Awesome, awesome, awesome.