A quick note here on how to connect to the DHL API and check on a package given a tracking number.
Why?
In our megafunction to generate a customer, a product/item, a sales order, an invoice, a package slip/delivery note, a shipment order; as well as record any payments, inventory adjustments, status changes; all from an eBay Order coming into the system via a webhook... I would like to mark a shipment as delivered only if the courier, in this case DHL, confirms the tracked order was delivered.
How?
So first I'll give some brief instructions on how to get an API key from DHL as a developer and then I'll include the code to query the shipment status based on a tracking number.
Becoming a DHL Developer
- Browse to https://developer.dhl.com/user/register to Signup
- Complete the form with your details > Confirm via Email
- Create an app as described under Get Access section
- Click My Apps on the portal website
- Click on the App you created
- Note the API Key by clicking on "Show Key"
The deluge function
So this function will return the word "delivered" or whatever other statuses there are for a package:
/* Function: String fn_DHL_CheckShipmentStatus(string p_TrackingNumber) Purpose: Queries DHL for tracking information about a shipment and returns the status code (eg. "delivered") Date Created: 2023-03-21 (Joel Lipman) - Initial release Date Modified: 2023-03-21 (Joel Lipman) - ??? More Info: - DHL Developer Portal: https://developer.dhl.com/ - DHL Developer Portal Signup: https://developer.dhl.com/user/register - DHL Developer API Documentaiton: https://developer.dhl.com/api-reference/shipment-tracking#reference-docs-section */ // // initialize v_ShipmentStatus = "error"; v_TrackingNumber = ifnull(p_TrackingNumber,0); // // specify your DHL API Key (no need for the secret or base64 encoding) v_DHL_API_Key = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // // build up header m_Header = Map(); m_Header.put("DHL-API-Key",v_DHL_API_Key); // // build up request v_Endpoint = "https://api-eu.dhl.com/track/shipments?trackingNumber=" + v_TrackingNumber; // // send request r_ShipmentDetails = invokeurl [ url: v_Endpoint type: GET headers: m_Header detailed: true ]; // // parse response if(r_ShipmentDetails.get("responseCode")==200) { l_Shipments = r_ShipmentDetails.get("responseText").get("shipments"); for each r_Shipment in l_Shipments { if(!isnull(r_Shipment.get("status"))) { v_ShipmentStatus = r_Shipment.get("status").get("statusCode"); info v_ShipmentStatus; } } } // // return response return v_ShipmentStatus;
- /*
- Function: string fn_DHL_CheckShipmentStatus(string p_TrackingNumber)
- Purpose: Queries DHL for tracking information about a shipment and returns the status code (eg. "delivered")
- Date Created: 2023-03-21 (Joel Lipman)
- - Initial release
- Date Modified: 2023-03-21 (Joel Lipman)
- - ???
- More Info:
- - DHL Developer Portal: https://developer.dhl.com/
- - DHL Developer Portal Signup: https://developer.dhl.com/user/register
- - DHL Developer API Documentaiton: https://developer.dhl.com/api-reference/shipment-tracking#reference-docs-section
- */
- //
- // initialize
- v_ShipmentStatus = "error";
- v_TrackingNumber = ifnull(p_TrackingNumber,0);
- //
- // specify your DHL API Key (no need for the secret or base64 encoding)
- v_DHL_API_Key = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- //
- // build up header
- m_Header = Map();
- m_Header.put("DHL-API-Key",v_DHL_API_Key);
- //
- // build up request
- v_Endpoint = "https://api-eu.dhl.com/track/shipments?trackingNumber=" + v_TrackingNumber;
- //
- // send request
- r_ShipmentDetails = invokeUrl
- [
- url: v_Endpoint
- type: GET
- headers: m_Header
- detailed: true
- ];
- //
- // parse response
- if(r_ShipmentDetails.get("responseCode")==200)
- {
- l_Shipments = r_ShipmentDetails.get("responseText").get("shipments");
- for each r_Shipment in l_Shipments
- {
- if(!isnull(r_Shipment.get("status")))
- {
- v_ShipmentStatus = r_Shipment.get("status").get("statusCode");
- info v_ShipmentStatus;
- }
- }
- }
- //
- // return response
- return v_ShipmentStatus;
Alternative get request:
r_ShipmentDetails = getUrl(v_Endpoint, m_Header, false);
- r_ShipmentDetails = getUrl(v_Endpoint, m_Header, false);
Not done yet!
Of course, it would help if when something was delivered, that was conveyed back to the system that asked, in this case Zoho Inventory. So for this, I've set up a nightly schedule which checks on all the shipments from a certain date and updates the shipment status for items that have been delivered:
Login to ZohoInventory > Setup (Cog Icon) > Automation > Schedules > New Schedule > I'm calling mine Nightly Schedule To Update Shipment Status
// // init v_DaysAgo = 2; v_BooksOrgID = organization.get("organization_id"); // // specify DHL API Key (no need for the secret) v_DHL_API_Key = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ"; // // build up header m_Header = Map(); m_Header.put("DHL-API-Key",v_DHL_API_Key); // // generate a list based on the number of days ago (list of dates to check) l_GeneratedList = leftpad(" ",v_DaysAgo).replaceAll(" ",",").toList(); // // loop through for each index v_Index in l_GeneratedList { // output to developer for debug purposes v_Date = zoho.currentdate.subDay(v_Index).toString("yyyy-MM-dd"); info v_Date; // // set criteria of what shipment orders to retrieve m_Criteria = Map(); m_Criteria.put("date",v_Date); // // retrieve all shipment orders for that day from ZohoInventory r_YesterdaysShipments = zoho.inventory.getRecords("shipmentorders",v_BooksOrgID,m_Criteria,"ab_inventory"); if(!isnull(r_YesterdaysShipments.get("shipmentorders"))) { l_YesterdaysShipments = r_YesterdaysShipments.get("shipmentorders"); for each r_ZohoShipment in l_YesterdaysShipments { if(!isnull(r_ZohoShipment.get("tracking_number"))) { // // build up request v_Endpoint = "https://api-eu.dhl.com/track/shipments?trackingNumber=" + r_ZohoShipment.get("tracking_number"); info "SO-Ref: " + r_ZohoShipment.get("salesorder_number"); info "Tracking #: " + r_ZohoShipment.get("tracking_number"); // // send request r_DhlShipmentDetails = invokeurl [ url :v_Endpoint type :GET headers:m_Header detailed:true ]; // // parse response if(r_DhlShipmentDetails.get("responseCode") == 200) { l_DhlShipments = r_DhlShipmentDetails.get("responseText").get("shipments"); for each r_DhlShipment in l_DhlShipments { if(!isnull(r_DhlShipment.get("status"))) { v_ShipmentStatus = r_DhlShipment.get("status").get("statusCode"); if(v_ShipmentStatus == "delivered") { v_EndpointUpdate = "https://inventory.zoho.eu/api/v1/shipmentorders/" + r_ZohoShipment.get("shipment_id") + "/status/delivered?organization_id=" + v_BooksOrgID; r_ZohoShipmentUpdate = invokeurl [ url :v_EndpointUpdate type :POST connection:"ab_inventory" ]; info "Message: " + r_ZohoShipmentUpdate.get("message"); } } } } } } } }
- //
- // init
- v_DaysAgo = 2;
- v_BooksOrgID = organization.get("organization_id");
- //
- // specify DHL API Key (no need for the secret)
- v_DHL_API_Key = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ";
- //
- // build up header
- m_Header = Map();
- m_Header.put("DHL-API-Key",v_DHL_API_Key);
- //
- // generate a list based on the number of days ago (list of dates to check)
- l_GeneratedList = leftpad(" ",v_DaysAgo).replaceAll(" ",",").toList();
- //
- // loop through
- for each index v_Index in l_GeneratedList
- {
- // output to developer for debug purposes
- v_Date = zoho.currentdate.subDay(v_Index).toString("yyyy-MM-dd");
- info v_Date;
- //
- // set criteria of what shipment orders to retrieve
- m_Criteria = Map();
- m_Criteria.put("date",v_Date);
- //
- // retrieve all shipment orders for that day from ZohoInventory
- r_YesterdaysShipments = zoho.inventory.getRecords("shipmentorders",v_BooksOrgID,m_Criteria,"ab_inventory");
- if(!isnull(r_YesterdaysShipments.get("shipmentorders")))
- {
- l_YesterdaysShipments = r_YesterdaysShipments.get("shipmentorders");
- for each r_ZohoShipment in l_YesterdaysShipments
- {
- if(!isnull(r_ZohoShipment.get("tracking_number")))
- {
- //
- // build up request
- v_Endpoint = "https://api-eu.dhl.com/track/shipments?trackingNumber=" + r_ZohoShipment.get("tracking_number");
- info "SO-Ref: " + r_ZohoShipment.get("salesorder_number");
- info "Tracking #: " + r_ZohoShipment.get("tracking_number");
- //
- // send request
- r_DhlShipmentDetails = invokeUrl
- [
- url :v_Endpoint
- type :GET
- headers:m_Header
- detailed:true
- ];
- //
- // parse response
- if(r_DhlShipmentDetails.get("responseCode") == 200)
- {
- l_DhlShipments = r_DhlShipmentDetails.get("responseText").get("shipments");
- for each r_DhlShipment in l_DhlShipments
- {
- if(!isnull(r_DhlShipment.get("status")))
- {
- v_ShipmentStatus = r_DhlShipment.get("status").get("statusCode");
- if(v_ShipmentStatus == "delivered")
- {
- v_EndpointUpdate = "https://inventory.zoho.eu/api/v1/shipmentorders/" + r_ZohoShipment.get("shipment_id") + "/status/delivered?organization_id=" + v_BooksOrgID;
- r_ZohoShipmentUpdate = invokeUrl
- [
- url :v_EndpointUpdate
- type :POST
- connection:"ab_inventory"
- ];
- info "message: " + r_ZohoShipmentUpdate.get("message");
- }
- }
- }
- }
- }
- }
- }
- }
Caveat(s):
- Limited to 250 requests per day (can be upgraded at a cost)
Source(s):
- DHL API Developer Portal
- DHL API Developer Portal - API Reference - Shipment Tracking - Unified v1.4.1