NAV
json javascript

Welcome to our DOCS site

Here at BEX we frequently develop and publish new API’s to assist our customers who wish to gain deeper control and visibility into their courier processes.

These API’s allow for direct integration into our courier platform, allowing data to be read and created using requests in JSON format. Couple this with our token based Authentication methods and standard HTTP verbs (which are understood by most HTTP clients) you have the capability to orchestrate and manage a number of processes within the courier environment.

We hope that you will build something great and benefit from integrating with our courier API’s.

We want your courier journey to be pain-free - If you run into any difficulties, or perhaps you have some suggestions for us, please do not hesitate to reach out and we will gladly work with you.

Requirements

To make use of our API integration we require the following:

  1. A valid shipping account with BEX.
  2. The creation of an integration user identity under which you will transact over the API’s
  3. For security sensitive data requests, a valid token.

Note: If you have multiple shipping accounts you are not required to transact under multiple integration identities (“tokens”). Our platform supports the assignment of multiple shipping accounts to a single token, making integration across multiple business units easier.

Request/Response Format

Our API endpoints will respond with JSON content accompanied by a 200 OK HTTP status. This includes any possible processing errors. Please see the Errors section.

Errors

You can find the errors specific to each API endpoint under its dedicated API topic.

API errors are communicated through the ex (short for exception) property inside the response body. Please inspect this property for any possible errors that may have occurred.

A possible problematic response could look as follows:

200 OK with error ex: Above: Note the 200 OK status whilst receiving an error "ex": response

In instances where there is a technical breakdown in the processing of the API request, such as querying the wrong endpoint address, you will receive the appropriate http status code such as a 404.

Parameters

All parameters as required by the relevant API endpoint may be provided in either query string format (e.g. POST /getcustomquicktracking_v3?ref=test123) OR as part of the body in JSON format.

The parameters the relevant API endpoint requires are discussed in its relevant section.

Tools

You are free to use any IDE or tool that satisfies your needs. We do recommend the use of POSTMAN to test your requests to our server.

Run In Postman

Other tools you could also look at are:

Authentication

Authentication against the BEX API ecosystem is a two-part process and is required to prevent access to confidential client data. The process involves the generation of your API security token which is described in the next section. This token is then included in the HTTP headers of your API calls and serves to identify and authenticate you on our platform.

API's that serve non-sensitive client data such as our quick waybill tracking do not require your token to be present in the API call and can be called anonymously.

Login

Overview

The login service serves as the starting point from which a valid session token will be generated. You call this endpoint to authenticate yourself using your BEX credentials.

The BEX platform will validate your request and if successful, generate and return in the response object a token contained in the value attribute.

Endpoint

The authentication endpoint is located at https://api.bex.co.za/api/service/login.

Ensure special characters are URL encoded.

{
  "username": "your_bex_username", 
  "password": "your_bex_password"
}
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>BEX API Login Example</title>
<script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
    var user = encodeURIComponent('username'); //encode the username
    var pass = encodeURIComponent('password'); //encode the password
    jQuery.support.cors = true; //this will enable cross domain access for all services

    //call the service using jQuery ajax and passing the parameters
    $.ajax({
      url: 'https://api.bex.co.za/api/service/login?userName=' + user + '&password=' + pass, 
      type: 'POST', 
      async: false, //No need for async
      success: function (d) {
        if (d.ex) {
          alert('An error has occurred. ' + d.ex);
          return;
        }

        alert('Your token is ' + d.value);
      }
    });
</script>
</body>
</html>

Parameters

Parameter FieldType Required Description
username String Yes Your integration account username.
password String Yes Your integration account password (case sensitive).
preferAlternateToken Boolean No Set to true if so required by the documentation.

Response

Sample json response.

{
    "id": 19696,
 // Here's the token -------------------------------------------------------
    "value": "dOdw98ycsih298749bd6MbZre8o7tt3r3nhfowo8dnBDpEJvkzcQG1vb44sy",
 // ------------------------------------------------------------------------
    "isStrongPassword": "True",
    "isEmailVerified": "True",
    "email": "your.email@company.com",
    "signalREnabled": "False",
    "allowApiLogin": "False"
}

The response body is structured as follows:

Attribute Type Description
id Int An internal BEX ID used to identify your user.
value String Your unique and private token.
isStrongPassword String Confirms whether your password meets our complexity requirements.
isEmailVerified String Your email address is used to recover forgotten passwords or lost tokens and needs to be verified before transactions are possible.
email String The recovery email address against which this token is registered.
signalRenabled Boolean For internal use only.
allowApiLogin Boolean For internal use only.

With your token now generated you can proceed to call our security restricted API's.

Tracking

Overview

You can query our courier platform for up-to-the-minute tracking information pertaining to your shipments. We have exposed a lightweight tracking service that returns non-sensitive tracking events for the shipments queried. To cater for customers wishing to display this tracking information on their own websites we include a schema definition in the tracking response that can be used to bind the fields to a client grid implemented on your website.

The service allows for the submission of up to ten (10) waybills and/or customer reference numbers per API call.

You may submit a combination of waybill and/or reference numbers in a single call.

Endpoint

The tracking API is located at https://api.bex.co.za/api/service/waybillquicktrackingv3customtreeview.

You can complete the request by using query parameters, for example /api/service/waybillquicktrackingv3customtreeview?searchItems=Item_1,Item_2,Item_3 or by submitting a JSON request.

Sample json request

{
  "searchItems": "ACP1055352,MDH42240,MA210214"
}

Parameters

Parameter Type Required Description
searchItems String Yes A comma separated list of items to be searched. Can be either a waybill, reference number, or a combination of both.

Response

Sample json tracking response

{
    "id": 0,
    "items": [
    // first object is our data-definition object, identified by the groupingIndex == -1.
        {
            "id": 0,
            "dataTypeId": 4,
            "groupingIndex": -1,
            "headerName": "Tracking",
            "col1": "Date",
            "col2": "Waybill",
            "col3": "Senders Ref",
            "col4": "Tracking Description",
            "col5": "User",
            "internalRef": "Internal Ref"
        },
    // subsequent objects are the tracking events themselves, identified by the groupingIndex == 0
        {
            "id": 13751791,
            "dataTypeId": 2,
            "headerName": "Tracking",
            "col1": "06-09-2021 08:03",
            "col2": "ACP1055352",
            "col3": "740493",
            "col4": "Delivered to PRTER ME.A at 08:26 on 03 Sep 2021",
            "col5": "SAMMY GROBLER",
            "internalRef": "13751791",
            "groupingIndex": 0
        },
        {
            "id": 13751791,
            "dataTypeId": 2,
            "headerName": "Tracking",
            "col1": "03-09-2021 08:26",
            "col2": "",
            "col3": "740493",
            "col4": "Driver confirmed successful delivery",
            "col5": "JACKIE MATHOLE",
            "internalRef": "13751791",
            "groupingIndex": 0
        },
        {
            "id": 13751791,
            "dataTypeId": 2,
            "headerName": "Tracking",
            "col1": "03-09-2021 07:06",
            "col2": "",
            "col3": "740493",
            "col4": "Loaded onto vehicle for delivery",
            "col5": "MORAKA RAMOKGOPA",
            "internalRef": "13751791",
            "groupingIndex": 0
        },
        {
            "id": 13751791,
            "dataTypeId": 2,
            "headerName": "Tracking",
            "col1": "03-09-2021 06:37",
            "col2": "",
            "col3": "740493",
            "col4": "Arrived into PRY depot",
            "col5": "MORAKA RAMOKGOPA",
            "internalRef": "13751791",
            "groupingIndex": 0
        },
        {
            "id": 13751791,
            "dataTypeId": 2,
            "headerName": "Tracking",
            "col1": "02-09-2021 21:35",
            "col2": "",
            "col3": "740493",
            "col4": "Departed JNB depot for PRY branch",
            "col5": "GEOFREY SEANEGO",
            "internalRef": "13751791",
            "groupingIndex": 0
        },
        {
            "id": 13751791,
            "dataTypeId": 2,
            "headerName": "Tracking",
            "col1": "02-09-2021 17:49",
            "col2": "",
            "col3": "740493",
            "col4": "Shipment integrated to courier system",
            "col5": "JONATHAN DAVIS",
            "internalRef": "13751791",
            "groupingIndex": 0
        }
    ]
}

The response object contains an items array. The first object in this array is our data definition object. It’s purpose is to communicate the bindings of the column names to their column numbers in the subsequent objects. The purpose of this first object is to allow you to use this information for the binding up of the data to a client grid on your website if you wish.

Attribute Type Description
id int Our internal ID which has no relevance to you.
items array An array containing the tracking event objects.

The objects contained in the items array are comprised as follows:

Attribute Type Description
id int Our internal ID which has no relevance to you.
dataTypeId int Internal to BEX and of no use to you.
groupingIndex int A tree hierarchy index used to identify parent objects from children.
headerName string The name of the entity being returned, in this case “Tracking”.
col1 string Column1, typically the DateTime the event occurred.
col2 string Column2, typically the Waybill Number of the shipment.
col3 string Column3, typically the Customer reference supplied for the shipment.
col4 string Column4, typically the description of the Tracking event.
col5 string Column5, the BEX member of staff who recorded the event.
internalRef string Our internal ID which has no relevance to you.

Quoting

Overview

The BEX quoting service allows you to view dynamic shipping pricing across our range of delivery services. By providing us with your shipment addressing information we can return a pricing spread as well as delivery estimations which you can use to make a more informed shipping choice.

Endpoint

The quoting API endpoint is located at https://api.bex.co.za/api/service/getquoteservicedeliverypricingv2.

Sample json quoting message body

{
    "dispatchDate": "2021-09-03",
    "totalWeight": "10",
    "dimMass": "25000",
    "accountNumber": "316085",
    "originSuburb": "Ballito",
    "originPostCode": "4319",
    // If you provide coordinates as well as location names we will favour the coordinates
    "originLatCoord": -29.1234,
    "originLongCoord": "18.5099",
    "destinationLatCoord": "-26.1327",
    "destinationLongCoord": "28.1957"
}

Parameters

To offer an accurate price we require the following parameters from you.

Parameter Type Description
dispatchDate Date The intended date of shipping.
totalWeight Decimal The total actual weight in kilograms (as placed on a scale) of all of the goods to be shipped
dimMass Decimal The sum of the total cubic centimetres of all of the goods to be shipped. (length x breadth x height) + (length x breadth x height)
accountNumber String Your shipping account number with BEX.
originSuburb String The suburb from where we will collect your shipment
originPostCode String The postcode of the suburb from where we will collect your shipment.
destinationSuburb String The suburb where we will deliver your shipment
destinationPostCode String The postcode of the suburb where we will deliver your shipment.
originLatCoord Decimal The GPS latitude (north-south position) of your collection location, expressed in decimal notation.
originLonCoord Decimal The GPS longitude (east-west position) of your collection location, expressed in decimal notation.
destinationLatCoord Decimal The GPS latitude (north-south position) of your delivery location, expressed in decimal notation.
destinationLonCoord Decimal The GPS longitude (east-west position) of your delivery location, expressed in decimal notation.

We are flexible as to how you supply the addressing.

// Snippet 1: Just coordinates
{
    "originLatCoord":"-26.2462726",
    "originLonCoord":"28.0969053",
    "destinationLatCoord":"-26.5372133",
    "destinationLonCoord":"29.1284535",
    "totalWeight":"43",
    "dimMass":"224000"
}

// Snippet 2: Just location names
{
    "originSuburb":"Steeledale",
    "originPostCode":"2197",
    "destinationSuburb":"Secunda",
    "destinationPostCode":"2302",
    "totalWeight":"43",
    "dimMass":"224000"
}

// Snippet 3: A combination of both
{
    "originLatCoord":"-26.2462726",
    "originLonCoord":"28.0969053",
    "destinationSuburb":"Secunda",
    "destinationPostCode":"2302",
    "totalWeight":"43",
    "dimMass":"224000"
}

Calculation of the delivery charges

In courier we use the greater of the actual weight or the volume of the goods to be shipped. Basically, we charge by weight OR by the physical size of the goods, whichever is greater (aircraft get expensive when flying empty boxes around).

These 2 parameters are:

  1. totalWeight The total weight in kilograms of all the goods on this order
  2. dimMass The sum of the total cubic centimetres of all the goods on this order

Example: A customer order is going from Sandton to Secunda. The order is made up of 2 boxes as follows:

  1. A stock 1 box (40cm x 40cm x 20cm) and weighing 18kgs
  2. A stock 4 box (80cm x 80cm x 30cm) and weighing 25kgs.

Looking at the code snippets on the right, you can see that the quotation request is to be structured as follows:

For the addressing, first prize we would like the co-ordinates of the collection and delivery locations (json snippet 1), otherwise you can pass us the suburb and postcode of the collection and delivery locations (snippet 2 or 3).

Response

json quoting response.

{
    "id": 0,
    "items": [
        {
            "id": 0,
            "customerName": "BOEING AIRCRAFT COMPANY",
            "serviceId": 449,
            "serviceCodeStr": "ONC",
            "serviceNameStr": "OVERNIGHT COURIER",
            "originSuburb": "AGGENEYS",
            "originCity": "AGGENEYS",
            "originRateCategory": "REMOTE",
            "originBranchStr": "CAPE TOWN",
            "originHub": "CPT",
            "originLocationCode": "",
            "destinationSuburb": "CROYDON",
            "destinationCity": "KEMPTON PARK",
            "destinationRateCategory": "MAJOR",
            "destinationBranchStr": "JOHANNESBURG",
            "destinationHub": "JNB",
            "destinationLocationCode": "",
            "estimatedTransitDays": 4,
            "scheduledTransitDays": 4,
            "estimatedHolidays": 0,
            "scheduledHolidays": 0,
            "scheduleBy": "2021-10-05 16:00:00",
            "estimatedCollectionDateAndTime": "2021-10-05 18:00:00",
            "latestCollectionDateAndTime": "2021-10-05 18:00:00",
            "estimatedDeliveryDateAndTime": "2021-10-09 10:00:00",
            "scheduledDeliveryDateAndTime": "2021-10-09 14:00:00",
            "isDeliveryGuaranteed": "True",
            "surchargeAddons": "SURSAT",
            "customerChargeableWeight": 10,
            "baseRateTotal": 0.00,
            "fuel": 0.00,
            "insuranceRequired": 0.00,
            "otherSurcharges": 0.00,
            "surchargeTotal": 0.00,
            "subTotal": 0.00,
            "vat": 0.00,
            "totalCharges": 0.00
        },
        {
            "id": 0,
            "customerName": "BOEING AIRCRAFT COMPANY",
            "serviceId": 449,
            "serviceCodeStr": "ONC",
            "serviceNameStr": "OVERNIGHT COURIER",
            "originSuburb": "AGGENEYS",
            "originCity": "AGGENEYS",
            "originRateCategory": "REMOTE",
            "originBranchStr": "CAPE TOWN",
            "originHub": "CPT",
            "originLocationCode": "",
            "destinationSuburb": "CROYDON",
            "destinationCity": "KEMPTON PARK",
            "destinationRateCategory": "MAJOR",
            "destinationBranchStr": "JOHANNESBURG",
            "destinationHub": "JNB",
            "destinationLocationCode": "",
            "estimatedTransitDays": 4,
            "scheduledTransitDays": 4,
            "estimatedHolidays": 1,
            "scheduledHolidays": 1,
            "scheduleBy": "2021-10-03 16:00:00",
            "estimatedCollectionDateAndTime": "2021-10-03 18:00:00",
            "latestCollectionDateAndTime": "2021-10-03 18:00:00",
            "estimatedDeliveryDateAndTime": "2021-10-08 10:30:00",
            "scheduledDeliveryDateAndTime": "2021-10-08 11:00:00",
            "isDeliveryGuaranteed": "True",
            "surchargeAddons": "",
            "customerChargeableWeight": 10,
            "baseRateTotal": 0.00,
            "fuel": 0.00,
            "insuranceRequired": 0.00,
            "otherSurcharges": 0.00,
            "surchargeTotal": 0.00,
            "subTotal": 0.00,
            "vat": 0.00,
            "totalCharges": 0.00
        }
    ]
}

In the response object you will find an items array of objects containing the different service and pricing options available for the shipment routing you have requested.

The objects in the items array are comprised as follows:

Attribute Type Description
Id Int An internal BEX field.
customerName String Your account name with BEX.
serviced Int An internal id used to identify the shipping service in question.
serviceCodeStr String The shipping service code.
serviceNameStr String The full name of the shipping service.
originSuburb String The suburb we calculated from where your shipment will be sent.
originCity String The city from where your shipment will be sent.
originRateCategory String The billing category of the location from where your shipment will be sent.
originBranchStr String The name of the BEX branch who will handle the collection of your shipment.
originHub String The 3 letter code of the BEX branch that will collect your shipment.
originLocationCode String The 3 letter town code of the location from where your shipment will be sent.
destinationSuburb String The suburb where your delivery will take place.
destinationCity String The city where your delivery will take place.
destinationRateCategory String The billing category of the location where your shipment will be delivered.
destinationBranchStr String The name of the BEX branch that will handle the delivery of your shipment.
destinationHub String The 3 letter code of the BEX branch that will deliver your shipment.
destinationLocationCode String The 3 letter town code of the location where your shipment will be delivered.
estimatedTransitDays Int The number of business days we believe it will take to complete delivery of your shipment.
scheduledTransitDays Int The number of business days we may take to complete the delivery of your shipment, based on the service level of the shipping service.
estimatedHolidays Int The number of non-working days falling within the period of our delivery lead-time estimation.
scheduledHolidays Int The number of non-working days falling within the period of our service sla lead-time.
scheduleBy Datetime The cut-off time by which you need to capture your shipping request into our system to ensure the delivery lead times are achievable.
estimatedCollectionDateAndTime Datetime The estimated date and time we can collect your shipment at its origin location to commence the shipping process.
latestCollectionDateAndTime DateTime Our operational cut-off time after which we are unable to collect your shipment.
estimatedDeliveryDateAndTime DateTime Our estimated date and time of delivery of your shipment.
scheduledDeliveryDateAndTime DateTime The scheduled date and time of delivery of your shipment.
isDeliveryGuaranteed String Some delivery schedules are guaranteed, depending on the shipping service selected.
surchargeAddons String An optional service-addon which if selected, will provide additional options such as a Saturday or After hours delivery.

Waybill

Overview

This service is used to create a waybill shipping entry into the BEX courier database. This allows BEX customers to directly interface their shipping requests and helps to eliminate errors as a result of manual data capture or misinterpretation of written content on shipping documentation. The service allows for the communication of a number of shipping options, such as:

Endpoint

The waybill API endpoint is located at https://api.bex.co.za/api/service/submitwaybillv4.

The parameter requirements for this API call have been broken down into five sub-sections, namely:

Sample json message body.

{
    "waybillNumber": "", //Leave empty to auto generate OR enter a custom waybill number.
    "autoGenerateWaybillNumber": true, //Set this to _false_ if you are providing a custom waybill number.
    "waybillDate": "YYYY-MM-DD",
    "accountNumber": "your_bex_account_number",
    "serviceCode": "ONC", //or whichever service you may require
    "sendersRef": "a reference for the sender", //(optional)
    "instructions": "special instructions for the courier", //(optional)
    "insuranceRequired": false, //Set to _true_ if you require insurance
    "insuranceValue": 0, //(optional) Specify a value only if _insuranceRequired_ is set to _true_.
    "senderCompany": "Doe Digital Works", //(optional)
    "senderFloorBuilding": "17 Cheltham House, Floor 3", //(optional)
    "senderStreet": "123 John Doe Avenue",
    "senderSuburb": "Ross Kent South",
    "senderCity": "Odendaalsrus", 
    "senderPostCode": "9800", 
    "senderProvince": "Free State", //(optional)
    "senderContactName": "John Doe", //(optional)
    "senderMobile": "1234567890", //(optional)
    "senderEmail": "john@domain.com", //(optional) 
    "senderTel": "1234567890", //(optional)
    "senderTelHome": "1234567890", //(optional) 
    "senderLat": sender_latitude, //(optional) Although, we encourage the use of coordinates!
    "senderLon": sender_longitude, //(optional) Although, we encourage the use of coordinates!
    "receiverCompany": "Jane Flower Works", //(optional) 
    "receiverFloorBuilding": "Floor B-4", //(optional) 
    "receiverStreet": "166 Wringham Drive", 
    "receiverSuburb": "Table View", 
    "receiverCity": "Cape Town", 
    "receiverPostCode": "7441",
    "receiverProvince": "Western Cape", //(optional) 
    "receiverContactName": "Jane Doe", //(optional) 
    "receiverMobile": "1234567890", //(optional) If a number is provided, delivery notifications will be sent to this number.
    "receiverEmail": "jane@domain.com", //(optional) If an email is provided, delivery notifications will be sent to this address. 
    "receiverTel": "1234567890", //(optional) 
    "receiverTelHome": "1234567890", //(optional) 
    "receiverLat": receiver_latitude, //(optional) Although, we encourage the use of coordinates!
    "receiverLon": receiver_longitude, //(optional) Although, we encourage the use of coordinates!
    "returnParcelPrintingText": false, //(optional) Returns EPL thermal label data as part of the response for you to send to the thermal printer.
    "printParcels": false, //(optional) If _true_, parcels are printed to the thermal label printer after submission using the URL specified.
    "printUrl": "", //(optional) Specify the thermal label printer URL to print to IF _printParcels=true_.
    "printParcelsPrintNode": false, //(optional) Specify _true_ to use PrintNode to print the labels if _printParcels=true_.
    "dimensions": [{
        "dimension1": length_cm, 
        "dimension2": breadth_cm, 
        "dimension3": height_cm, 
        "weight": parcel_weight_kg, 
        "reference": "" //(optional) A parcel description
    }],
    "additionalReferences": [{
        "value": "reference_1"
    }, {
        "value": "reference_2"
    }]
}

jQuery Waybill Submission Example.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>BEX waybill API example</title>
<script src="http://code.jquery.com/jquerylatest.min.js" type="text/javascript"></script>
</head>
<body>
<script type="text/javascript">
//********** Login Service Call ********************
var tokenStr = '';
var user = encodeURIComponent('someusername'); //encode the username
var pass = encodeURIComponent('somepassword'); //encode the password
var host = 'https://api.bex.co.za';
//********** Submit Waybill Service Call ***********
var postData = {};

//BASIC
postData.waybillNumber = 'IT2701152404'; //or leave empty and set [autoGenerateWaybillNumber=true]
postData.autoGenerateWaybillNumber = false; //set to [false] if you're supplying a waybill number.
postData.waybillDate = '20150127';
postData.accountNumber = '111983';
postData.serviceCode = 'NCA';
postData.sendersRef = 'WE HAVE A REFERENCE';
postData.instructions = 'DO NOT INVERT COMPONENT';

//INSURANCE OPTIONS
postData.insuranceRequired = false; //Set to true if you need insurance.
postData.insuranceValue = 0; //Set the waybill value here if [insuranceRequired=true].

//SENDER DETAILS
//--Address
postData.senderCompany = 'THE BOEING COMPANY';
postData.senderFloorBuilding = 'UNIT 6 ASSEMBLY BUILDING';
postData.senderStreet = '21 AIRCRAFT LANE';
postData.senderSuburb = 'MARLBORO';
postData.senderCity = 'SANDTON';
postData.senderPostCode = '2050';
postData.senderProvince = 'GAUTENG'; //optional
postData.senderLat = null; //optional BUT WE ENCOURAGE the use of COORDINATES. Enter the LATITUDE here, e.g. -26.123496410189606
postData.senderLon = null; //optional BUT WE ENCOURAGE the use of COORDINATES. Enter the LONGITUDE here, e.g. 28.205670867327754

//--Contact
postData.senderContactName = 'JONATHAN'; //optional
postData.senderMobile = '0821234321'; //optional
postData.senderEmail = 'JONATHAN@BOEING.COM'; //optional
postData.senderTel = '0119299700'; //optional
postData.senderTelHome = '0119299700'; //optional

//RECEIVER DETAILS
//--Address
postData.receiverCompany = 'THE AIRLINER CO';
postData.receiverFloorBuilding = '1ST FLOOR HEAD OFFICE';
postData.receiverStreet = '21 TULP STREET';
postData.receiverSuburb = 'MILNERTON';
postData.receiverCity = 'CAPE TOWN';
postData.receiverPostCode = '7401';
postData.receiverProvince = 'WESTERN CAPE'; //optional
postData.receiverLat = null; //optional BUT WE ENCOURAGE the use of COORDINATES. Enter the LATITUDE here, e.g. -26.123496410189606
postData.receiverLon = null; //optional BUT WE ENCOURAGE the use of COORDINATES. Enter the LONGITUDE here, e.g. 28.205670867327754

//--Contact
postData.receiverContactName = 'DEREK';
postData.receiverMobile = '0833211234';
postData.receiverEmail = 'DEREK@THEAIRLINER.COM';
postData.receiverTel = '0218641202';
postData.receiverTelHome = '0218641202';

//PARCELS AND DIMENSIONS
var dimensions = [];
var parcel1 = {};
parcel1.dimension1 = 40; //Length (cm)
parcel1.dimension2 = 30; //Breadth (cm) 
parcel1.dimension3 = 1; //Height (cm)
parcel1.weight = 6; //Parcel Weight (nearest whole kg)
parcel1.reference = 'AIRFRAME COMPONENT'; //(optional)A reference for this parcel.
dims.push(parcel1);

//-->...continue adding the rest of the parcels

postData.dims = dims;

//ADDITIONAL REFERENCES []
var additionalRefs = [];
var ref1 = {};
ref1.value = "ORDER 22341";
additionalRefs.push(ref1);

//-->...continue adding the rest of your references.

postData.additionalReferences = additionalRefs;

//THERMAL LABEL PRINTING
postData.returnParcelPrintingText = false; //(optional) Returns EPL thermal label data as part of the response for you to send to the thermal printer.
postData.printParcels = false; //(Optional) When set to [true], parcels are printed to the thermal label printer after submission using the [printUrl] specified.
postData.printUrl = ''; //(optional) Specify the thermal label printer URL to print to IF [printParcels=true]
postData.printParcelsPrintNode = false; //(optional) Specify [true] to use PrintNode to print the labels if [printParcels=true].

//----- SUBMIT TO BEX -----//
//NOTE: If your call fails, it will still be communicated as 200 OK. Inspect the [ex] property in the response for error information.
jQuery.support.cors = true; //Enables cross-domain access to our services using jQuery ajax.

//--Step 1: Get your token.
$.ajax({
  url: host + '/api/service/login?userName=' + user + '&password=' + pass, 
  type: 'POST', 
  async: false, //No need for async here.
  success: function (d) {
    if (d.ex) {
      alert('We couldnt complete the request. ' + d.ex);
      return;
    }

    tokenStr = data.value;
  }
});

//--Step 2: Submit your waybill request.
$.ajax({
  url: host + '/api/service/submitwaybillv4', 
  type: 'POST', 
  data: JSON.stringify(postData), 
  dataType: 'json', 
  contentType: 'application/json; charset=UTF8', 
  beforeSend: function (xhr) {
    //Add your token to the header
    xhr.setRequestHeader('token', tokenStr);
  }, 
  success: function (d) {
    if (d.ex) {
        document.write('We failed to submit your waybill. ' + d.ex);
        return;
    }

    document.write('Your waybill was created successfully.');
  }
});
</script>
</body>
</html>

Basic Details

Parameter FieldType Case Required Note
waybillNumber String No* No A unique waybill number. This field will be required if AutoGenerateWaybillNumber is set to false.
autoGenerateWaybillNumber Boolean N/A No* If set to true, the BEX system will automatically generate a waybill number on your behalf.
waybillDate Date No No Date of collection by BEX. Format yyyy-mm-dd
accountNumber String No Yes
sendersRef String No No For tracking, reporting and invoice requests
instructions String No No Communicate additional info

*waybillNumber is auto-generated by BEX and communicated in the service response when making use of alternative shipping stationery options such as thermal labels or A4 waybills

Parameter FieldType Case Required Note
serviceCode String No Yes The service delivery priority code

Service delivery code values are:

Sender Address

Parameter FieldType Case Required Note
senderCompany String No No Company from which to collect
senderFloorBuilding String No Yes Floor, building, office park
senderStreet String No Yes Street for shipment collection
senderSuburb String No Yes Sender suburb
senderCity String No Yes Sender town or city
senderPostCode String No Yes Sender postcode
senderProvince String No No Sender province.
senderLat Double N/A No Sender coordinate latitude value (we encourage the use of these)
senderLon Double N/A No Sender coordintae longitude value (we encourage the use of these)
senderContactName String No No Contact person for collection/dispatch
senderMobile String No No Contact person mobile number
senderTel String No No Contact person telephone number
senderTelHome String No No Contact person telephone number (home or alternate)
senderEmail String No No Contact person email address

Receiver Address

Parameter FieldType Case Required Note
receiverCompany String No No Receiver individual/company name
receiverFloorBuilding String No No Floor and building address.
receiverStreet String No Yes Receiver street number and name
receiverSuburb String No Yes Receiver suburb.
receiverCity String No Yes Receiver city or town.
receiverPostCode String Yes No Receiver postcode
receiverProvince String No No Receiver province.
receiverLat Double N/A No Receiver coordinate latitude value (we encourage the use of these)
receiverLon Double N/A No Receiver coordinate longitude value (we encourage the use of these)
receiverContactName String No No Receiver name.
receiverMobile String No No Useful for status updates
receiverEmail String No No Useful for status updates
receiverTel String No No Receiver telephone number
receiverTelHome String No No Receiver telephone number (home or alternate).

If you would like to add insurance cover on your waybill, complete these two fields:

Parameter FieldType Case Required Note
insuranceRequired Boolean No No true if insurance is required for this shipment.
insuranceValue Float/Double No Yes Insured value, in ZAR. Omit this field if you do not require insurance.

Dimensioning

For communication of parcel specific information for each package that comprises this waybill shipping request.

Parameter FieldType Case Required
dimensions Array No Yes

The dimensions array comprises:

FieldName FieldType Req Description
dimension1 Int Yes Length of the package, rounded up to the nearest whole centimeter
dimension2 Int Yes Width of the package, rounded up to the nearest whole centimeter
dimension3 Int Yes Height of the package, rounded up to the nearest whole centimeter
weight Float Yes Actual weight of package in kilograms
reference String No Tag this package with parcel specific information.

Additional References

You can include additional references to the waybill for ease of reference and search.

Parameter FieldType Case Required
additionalReferences Array No No

The additionalReferences array comprises:

FieldName FieldType Req Description
value String Yes The reference number you want to add.

Printing Options

These options should only be used if so advised by your sales representative or a BEX staff member. You may need additional information and/or setup before you may use these features.

Parameter FieldType Req Required
returnParcelPrintingText Boolean No Optional. If true, returns EPL thermal label data as part of the response for you to send to the thermal printer.
printParcels Boolean No Optional. If true, parcels are printed to the thermal label printer after submission using the printUrl specified.
printUrl String No Optional. Specify the thermal printer URL to print to IF printParcels=true.
printParcelsPrintNode Boolean No Optional. Specify true to use PrintNode to print the labels.

Response

The base object will contain a property called items which consists of an array holding a single object with the following properties:

Property Description
waybillNumber String value reflecting the unique BEX waybill number for this successful shipping request.
baseRateTotal Price of the rate card billing component for shipment.
surchargesTotal Price of the surcharges for additional service add-ons
subTotal The subtotal, excluding VAT, for the shipment routing requested.
vat The VAT portion of the pricing for the delivery.
totalCharges The grand total price for the waybill.
volRatio The volumetric ratio used during the volumetric weight calculation in the billing engine. This ratio is directly dependent on the service delivery priority requested.

Submission Failures

Should your request fail, please inspect the ex property as mentioned earlier in this document.

Waybill Downloads

Overview

As part of our service offering we allow you to download an e-waybill and any parcel labels associated with the waybill. The e-waybill is in A4 format and can be printed using any printer at your disposal.

Authentication

The stationery download service requires a different token than the one you have been using to access the other endpoints.

You will need to re-complete the authentication procedure but you are required to set the preferAlternateToken to true. This will result in a completely different token being issued for your request. You must use this new token for the stationery download service only.

eWaybill Download

You can download the e-waybill from https://api.bex.co.za/api/service/downloadewaybill.

Supply only 1 waybill number per call.

{
  "token": "`alternate_token`", 
  "waybillNumber": "waybill_number"
}

Parameters

Parameter FieldType Required Description
token String Yes The alternate_token received through the login service.
waybillNumber String Yes A single waybill number to lookup and produce a PDF for.

Response

A successful response will be the resulting PDF document. If you are accessing it through a browser, the download will happen automatically.

If you decide to integrate using your own system or code, you will need to process the response accordingly.

Labels Downloads

You can download "thermal" labels from https://api.bex.co.za/api/service/downloadparcellabels.

Example JSON body.

{
  "token": "`alternate_token`", 
  "waybillNumbers": "waybill_number_1,waybill_number_2,waybill_number_3,..."
}

Parameters

Parameter FieldType Required Description
token String Yes The alternate_token received through the login service.
waybillNumbers String Yes A comma-seperated list of waybill numbers or parcel numbers to generate PDF labels for.

Response

A successful response will be the resulting PDF document. If you are accessing it through a browser, the download will happen automatically.

If you decide to integrate using your own system or code, you will need to process the response accordingly.

Label Size

The downloadable label is sized at 10.08cm x 14.98cm and may be printed on any printer you have at your disposal.

Webhooks Guide

Getting Started

In order to use our WebHooks, you need to ensure that you have a valid and actively trading customer account registered with BEX. Once you have your account number, you will need to request a WebHook API key from our IT department. We will communicate this to you but it is your responsibility to ensure the secrecy of it.

Before we get started, please ensure that you understand and have implemented the necessary methods required to work with WebHooks.

WebHook Registration

The registration is a two-part process that requires two individual requests.

In the header of your request, you should add a new key pair that represents your WebHook API key:

{ 
    “X-InsightWebHooks-Auth”: “Your API Key” 
}

The request body is made up of:

{
    WebHookUri: “your endpoint where the webhook will post”, 
    Secret: “A secret key that you generate”, 
    Description: “A description for your webhook”, 
    Filters: [ “filterA”, “filterB” ]
}

Providing the request body with the following values:

{
    webHookKey: “your API key”
}

A Word on Filters

We provide several different types of WebHook events and you can subscribe to one or all of them. If you want to subscribe to ALL events, then you should ensure that your code can differentiate between these types of events. In this case, you should provide an empty value for the Filters parameter i.e., Filters: []

If you would like to subscribe to certain events only, then you need to provide each event type you want to subscribe to, e.g. Filters: [ “event 1”, “event 2”, … ]

We provide the following filters/event types:

Unsubscribing

To unsubscribe from our WebHook, send a POST request to: https://webhook.bex.co.za/api/UnsubscribeWebHook

The request body should consist of:

{ 
    webHookKey: “your API key”
}

Filters/Event Types

Basic Payload Structure

The basic payload structure for our WebHook would look like this:

{ 
    “Id”: “a unique id for this message”, 
    “Attempt”: 1, 
    “Properties”: { }, 
    “Notifications”: [{
        “Action”: “tracking_type”, 
        
    }]
}

As part of the request to your WebHook endpoint, we also include a special header:

Notifications Property

The notifications property will contain the type of notification you are receiving (“Action”) followed by the list of properties relating to that specific event type. These properties are listed below for your convenience.

Verifying WebHook Signature

Since we are only sending you a request with a payload and that we have no knowledge of your infrastructure, the message will be sent “anonymously” and won’t provide any mechanism to allow authentication to a closed system. It is your responsibility to ensure that the endpoint you specify accepts anonymous users and that you perform message validation as an alternative to authentication.

Every WebHook request that we send will have the special ms-signature header key containing the hash of the body we’ve sent. You should calculate the signature using the supplied secret (during registration) based on the body of the message you’ve received from us.

A C# example of calculating the signature would be:

var secret = Encoding.UTF8.GetBytes(secretYouProvidedDuringRegistration);
using (var hasher = new HMACSHA256(secret)) 
{
    var serializedBody = body.ToString();
    request.Content = new StringContent(serializedBody, Encoding.UTF8, application/json);

    var data = Encoding.UTF8.GetBytes(serializedBody);
    var sha256 = hasher.ComputeHash(data);
    var headerValue = EncodingUtilities.ToHex(sha256);
}

Event Types/Payloads

Each event will be sent using the basic payload structure and contain different properties for each type of event.

Tracking Events

{
    “Action”: “tracking_event”, 
    “WaybillNumber”: 12345, 
    “TrackingDate”: 2021-07-12 11:59:25, 
    “TrackingUser”: “John Doe”, 
    “TrackingDescription”: “tracking description”, 
    “TrackingReference”: “some reference”, 
    “TrackingTypeId”: -1
}

POD

{
    “Action”: “tracking_event”, 
    “WaybillNumber”: 12345, 
    “TrackingDate”: 2021-07-12 11:59:25, 
    “TrackingUser”: “John Doe”, 
    “TrackingDescription”: “tracking description”, 
    “TrackingReference”: “some reference”, 
    “TrackingTypeId”: -1
}   {
    “Action”: “pod”, 
    “WaybillNumber”: 12345, 
    “PODDate”: 2021-07-12, 
    “PODTime”: 11:34:25, 
    “Signee”: “Jane Doe”, 
    “PODPieces”: 1
}

Attempted Delivery

{
    “Action”: “attempted_delivery”, 
    “WaybillNumber”: 12345, 
    “AttemptedDate”: 2021-07-12, 
    “AttemptedTime”: 11:12:16, 
    “NonDeliveryReason”: “Wrong route”, 
    “DriverComment”: “driver”
}

Waybill Note

{
    “Action”: “waybill_note”, 
    “PostedBy”: “John Doe”, 
    “NoteDate”: 2021-07-12 12:08:16, 
    “NoteText”: “Customer will phone when home”
}

Waybill Update

{
    “Action”: “waybill_update”, 
    “WaybillNumber”: 12345, 
    “Service”: “ONC”, 
    “InsuranceRequired”: false, 
    “InsuranceValue”: 0, 
    “ActualWeight”: 1.0, 
    “VolumetricWeight”: 1.0, 
    “ChargeableWeight”: 1.0, 
    “BaseRateTotal”: 25, 
    “SurchargesTotal”: 17.50, 
    “SubTotal”: 42.50, 
    “Vat”: 6.38,
    “TotalCharges”: 48.88, 
    “Parcels”: [
    { 
          “ParcelBarcodeNumber”: “P1, 
          “Dimension1”: 40, 
          “Dimension2”: 30, 
          “Dimension3”: 1, 
          “Weight”: 1.0, 
          “ParcelDescription”: “”
    }, 
    ]
}   



Tracking Event ID Descriptions:

Tracking Type ID Description
1 Shipment handed to courier.
4 Shipment departed XYZ branch/depot.
5 Shipment arrived at XYZ branch/depot.
7 Shipment loaded onto vehicle for delivery.
9 Delivery attempt failed because (reason variable)
13 Shipment integrated into our system.