Skip to main content

FedEx integration example

This tutorial shows how to integrate FedEx.

1. Preparation​

1.1. Create a FedEx account

Create an account on the developer portal.

1.2. Create projects and get tokens

In My projects, create two projects and save the client ID and client secret.

The first project is for managing shipments:

The second project is for tracking shipments:

1.3. Create delivery statuses

On the statuses tab of the order storage, create statuses (opens in a new tab):

  • order_delivery
  • order_delivery_started
  • ready_for_pickup

1.4. Create an event to track statuses

In the Events (opens in a new tab) module, create an event that tracks when an order changes to the order_delivery status.

The order delivery event with the marker order_delivery: module orders, storage test_order_storage, status order_delivery, "Integrations" selected.

1.5. Create a delivery collection

In the Integration Collections (opens in a new tab) module, create a delivery collection with these attributes:

  • name (string)
  • address (string)
  • phone_number (string)
  • city (string)
  • state_code (string)
  • postal_code (string)
  • country_code (string)
  • tracking_number (string)
  • transaction_id (string)
  • ship_datestamp (string)
  • delivery_datestamp (string)

The "Integration collections" section: the list shows the new delivery collection with the marker delivery.

1.6. Create a test order

Create an order and a collection record for it.

POST request to /api/content/orders-storage/marker/order_storage/orders with a JSON body for a test order: form order_form, payment paypal, product 1 × 2.

POST request to /api/content/integration-collections/marker/delivery/rows: a record for order 1 with form delivery_form and recipient data.

2. Creating a shipment​

2.1. Track the delivery event

  • Drag the events (opens in a new tab) node onto the workspace.
  • Enter a name for the node.
  • Change the value of the "Set" field to "orderEvent". The event is saved to the "msg.orderEvent" object, and other nodes can use it.
  • Select the "order delivery" event you created and click "submit".

The order delivery event node: "Set" is msg.orderEvent, and order delivery is selected in "Events".


2.2. Get a token

  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.
  • Replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with your own values.

The auth body node: the code in the "Function" field sets msg.payload with client_credentials, YOUR_CLIENT_ID, and YOUR_CLIENT_SECRET, and a Content-Type header.

msg.payload = {
'grant_type': 'client_credentials',
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET'
}
msg.headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}

return msg;

For details on the parameters, see the FedEx documentation.


  • Drag the http request (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • In the Method field, select "POST".
  • In the Data field, select "Send as request body".
  • In the Link field, enter https://apis-sandbox.fedex.com/oauth/token.
  • In the Return field, select "Object JSON".

The auth request node: "Method" is POST, "Data" is Send as request body, "Link" is https://apis-sandbox.fedex.com/oauth/token, "Return" is Object JSON.


  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The set access token node: the code in the "Function" field copies access_token from msg.payload to msg.access_token.

msg.access_token = msg.payload.access_token;

return msg;

2.3. Create the shipment

  • Drag the admin-api (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Select the "Receiving all records belonging to the collection" method and paste the code below into the "Data" field.
{
"entityType": "orders",
"entityId": "{{orderEvent.order.id}}",
"langCode": "en_US",
"offset": 0,
"limit": 1,
"marker": "delivery"
}

The find collection rows node: "Type" is Receiving all records belonging to the collection; "Query parameters" contains JSON with marker delivery, entityType orders, and entityId orderEvent.order.id.


  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The shipment data node: the code in the "Function" field builds headers with a Bearer token and recipient data from the collection record.

// get the previously saved token
const token = msg.access_token;

// set the headers
msg.headers = {
'Content-Type': 'application/json',
'authorization': `Bearer ${token}`
};

// get the collection from the previous step
const collection = msg.payload.items[0];
// convert the array to an object
const formData = collection.formData.reduce((acc, item) => {
acc[item.marker] = item.value;
return acc;
}, {});
// set the recipient parameters from the form
const recipient = {
"address": {
"streetLines": [
formData.address
],
"city": formData.city,
"stateOrProvinceCode": formData.state_code,
"postalCode": formData.postal_code,
"countryCode": formData.country_code
},
"contact": {
"personName": formData.name,
"phoneNumber": formData.phone_number
}
}
// store the collection data in msg for later use
msg.collection = collection;
// set the request parameters for FedEx
msg.payload = {
"labelResponseOptions": "URL_ONLY",
"accountNumber": {
"value": "510087020"
},
"requestedShipment": {
"shipper": {
"contact": {
"personName": "SENDER NAME",
"phoneNumber": "9018328595"
},
"address": {
"streetLines": [
"SENDER ADDRESS 1"
],
"city": "MEMPHIS",
"stateOrProvinceCode": "TN",
"postalCode": "38116",
"countryCode": "US"
}
},
"recipients": [
recipient
],
"serviceType": "STANDARD_OVERNIGHT",
"packagingType": "YOUR_PACKAGING",
"pickupType": "DROPOFF_AT_FEDEX_LOCATION",
"shippingChargesPayment": {
"paymentType": "SENDER",
"payor": {
"responsibleParty": {
"accountNumber": {
"value": "510087020",
"key": ""
}
},
"address": {
"streetLines": [
"SENDER ADDRESS 1"
],
"city": "MEMPHIS",
"stateOrProvinceCode": "TN",
"postalCode": "38116",
"countryCode": "US"
}
}
},
"labelSpecification": {},
"requestedPackageLineItems": [
{
"customerReferences": [
{
"customerReferenceType": "CUSTOMER_REFERENCE",
"value": `Collection${collection.id}`
}
],
"weight": {
"units": "LB",
"value": "20"
}
}
]
}
};

return msg;

For details on the parameters, see the FedEx documentation.


  • Drag the http request (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • In the Method field, select "POST".
  • In the Data field, select "Send as request body".
  • In the Link field, enter https://apis-sandbox.fedex.com/ship/v1/shipments.
  • In the Return field, select "Object JSON".

The shipment request node: "Method" is POST, "Data" is Send as request body, "Link" is https://apis-sandbox.fedex.com/ship/v1/shipments, "Return" is Object JSON.


The debug node debug fedex shipment: "Output" is msg.payload.


  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The update row data node: the code in the "Function" field builds new formData for the collection record with the transaction_id and ship_datestamp fields from the FedEx response.

// get the shipment data
const shipment = msg.payload.output.transactionShipments[0];
// get the previously saved collection data
const collection = msg.collection;

// write the shipment data to the form attributes
const newFormData = [
...collection.formData
.filter(item => !['transaction_id', 'ship_datestamp', 'delivery_datestamp', 'tracking_number'].includes(item.marker)),
{
marker: 'transaction_id',
value: msg.payload.transactionId,
type: 'string'
},
{
marker: 'ship_datestamp',
value: shipment.shipDatestamp,
type: 'string'
},
{
marker: 'delivery_datestamp',
value: shipment.pieceResponses[0].deliveryDatestamp,
type: 'string'
},
{
marker: 'tracking_number',
value: shipment.masterTrackingNumber,
type: 'string'
}
]

// set the parameters for updating the collection
msg.params = {
langCode: 'en_US',
id: collection.id,
marker: 'delivery'
}

msg.data = {
formIdentifier: 'delivery_form',
formData: {
en_US: newFormData
},
entityId: collection.entityId,
entityType: collection.entityType
}

// store the collection data for later use
msg.collection = collection;

return msg;

  • Drag the admin-api (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Select the "Changing a record in the collection" method.

The update collection row node: "Changing a record in the collection" is selected in "Type"; "Query parameters" is empty.


2.4. Update the order status

  • Drag the admin-api (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Select the "Updating the status of an order belonging to the order storage object" method.
  • Paste the code below into the "Query parameters" field.
{
"id": 1,
"orderId": "{{collection.entityId}}"
}
  • Paste the code below into the "Request body" field.
{
"statusIdentifier": "order_delivery_started"
}

The order delivery started node: the type updates the status of an order in the order storage; the parameters are id and orderId, and the body contains statusIdentifier.


The debug node debug status update 1: "Output" is msg.payload.


3. Tracking the shipment status​

3.1. Get the orders to track

  • Drag the interval (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Enter the interval in minutes.

The set interval node: the "interval" field is set to 60.


  • Drag the admin-api (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Select the "Receiving all orders belonging to the order storage object" method.
  • Paste the code below into the "Query parameters" field.
{
"statusIdentifier": "order_delivery_started",
"langCode": "en_US",
"offset": 0,
"limit": 100,
"id": 1
}

The find orders by status node: "Type" is Receiving all orders belonging to the order storage object; "Query parameters" contains JSON with statusIdentifier order_delivery_started, limit 100, and id 1.


  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The set orders node: the code in the "Function" field writes msg.payload.items to msg.payload.

msg.payload = msg.payload.items;

return msg;

  • Drag the split (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Enter the length.

The split node: "Property" is payload, "Length" is 1.


  • Drag the admin-api (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Select the "Receiving all records belonging to the collection" method.
  • Paste the code below into the "Query parameters" field.
{
"marker": "delivery",
"entityId": "{{payload.id}}",
"entityType": "orders",
"langCode": "en_US",
"limit": 1,
"offset": 0
}

The find collection rows node: "Type" is Receiving all records belonging to the collection; "Query parameters" contains JSON with marker delivery, entityId payload.id, and entityType orders.


  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The "Node Information" window of the "set row" function node: the code in the "Function" field writes the first element of msg.payload.items to msg.payload

msg.payload = msg.payload.items[0]

return msg;

  • Drag the switch (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Add a check rule and select the "not empty" condition.

The "Node Information" window of the "switch" node: property "payload", mode "check all rules", and the "not empty" condition selected in the rule


  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The "Node Information" window of the "set trackingNummber" function node: the code in the "Function" field takes the value of the field with the tracking_number marker from formData and writes it to msg.trackingNumber

msg.trackingNumber = msg.payload
.formData
.find(item => item.marker === 'tracking_number')
.value;

msg.collection = msg.payload;

return msg;

3.2. Get a token

  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.
  • Replace YOUR_CLIENT_ID and YOUR_CLIENT_SECRET with your own values.

The "Node Information" window of the "auth body" function node: the code in the "Function" field builds the token request body with grant_type, client_id, and client_secret, using the YOUR_CLIENT_ID and YOUR_CLIENT_SECRET placeholders

msg.payload = {
'grant_type': 'client_credentials',
'client_id': 'YOUR_CLIENT_ID',
'client_secret': 'YOUR_CLIENT_SECRET'
}
msg.headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}

return msg;

For details on the parameters, see the FedEx documentation.


  • Drag the http request (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • In the Method field, select "POST".
  • In the Data field, select "Send as request body".
  • In the Link field, enter https://apis-sandbox.fedex.com/oauth/token.
  • In the Return field, select "Object JSON".

The "Node Information" window of the "auth request" http request node: method "POST", "Send as request body", URL apis-sandbox.fedex.com/oauth/token, "Return" set to "Object JSON"


3.3. Get the shipment status

  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The "Node Information" window of the "tracking data" function node: the code in the "Function" field sets a Bearer authorization header with the token and a request body with trackingNumber

const token = msg.payload.access_token;

msg.headers = {
'content-type': 'application/json',
'authorization': `Bearer ${token}`
};

msg.payload = {
"trackingInfo": [
{
"trackingNumberInfo": {
"trackingNumber": msg.trackingNumber
}
}
],
"includeDetailedScans": true
}

return msg;

For details on the parameters, see the FedEx documentation.


  • Drag the http request (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • In the Method field, select "POST".
  • In the Data field, select "Send as request body".
  • In the Link field, enter https://apis-sandbox.fedex.com/track/v1/trackingnumbers.
  • In the Return field, select "Object JSON".

The "Node Information" window of the "tracking request" http request node: method "POST", "Send as request body", URL apis-sandbox.fedex.com/track/v1/trackingnumbers, "Return" set to "Object JSON"


  • Drag the function (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Paste the example code into the "Function" field.

The "Node Information" window of the "set tracking result" function node: the code in the "Function" field writes the tracking result from msg.payload.output to msg.payload

msg.payload = msg.payload.output.completeTrackResults[0].trackResults[0].latestStatusDetail.statusByLocale;

return msg;

3.4. Update the order status

  • Drag the switch (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Add a check rule, select the "==" condition, and enter "Ready for pickup" as the value.

The "Node Information" window of the "check ship status" switch node: property "payload", condition "==", value "Ready for pickup"


  • Drag the admin-api (opens in a new tab) node onto the workspace and connect it to the node from the previous step.
  • Select the "Updating the status of an order belonging to the order storage object" method.
  • Paste the code below into the "Query parameters" field.
{
"id": 1,
"orderId": "{{collection.entityId}}"
}
  • Paste the code below into the "Request body" field.
{
"statusIdentifier": "ready_for_pickup"
}

The "Node Information" window of the "update status" node: the type updates the order status; "Query parameters" contains id and orderId, and "Request body" contains statusIdentifier ready_for_pickup


The "Node Information" window of the "debug status update 2" debug node: "Output" set to msg.payload