Data & Delivery Format
Introduction
This document describes the data format that contains all necessary information, so that an external system can use Bettermile as a route optimization system. Drivers using Bettermile App will get an optimized route sequence, routing support (turn by turn navigation), consignee addresses, timeframes and other helpful information. Furthermore, it is a prerequisite for route optimization analysis and monitoring within the Bettermile Backoffice. The top level object in the data format is job, which is an abstraction of a single task a delivery driver has to perform. Currently there are three different types of jobs:
- delivery - job type for which the consignee-contact will be considered for tour calculation.
- pickup - pickup of a specific parcel with an already known parcel id. Shipper-contact will be considered for tour-calculation.
- collection - collecting an unknown number of parcels at the shipper-contact location (e.g. parcel shop, drop box).
Although all required information could technically be combined in one single job object, the different aspects typically become available at different points in time in the lifecycle of a parcel. Bettermile considers three phases of data transmission:
- master data - job properties that do not change (id, type, depot) or that are unlikely to change (shipper & consignee information) until the job is done. This information can be transmitted to Bettermile as soon as it is available in the tenants IT system. The actual date of delivery does not need to be final at this time.
-
assignment data
- contains assignment information for one
job
to a specific driver (or route, vehicle, etc) on a specific
date.
This is required for all jobs designated for a specific driver/route before Better Route is able to calculate optimized sequences and navigation routes for the driver.
The ultimate goal is that assignments reflect 100% of the parcels physically present in a driver's vehicle when he/she leaves the depot in the morning and logs into Bettermile App.
Please note that it is quite common that there will be multiple assignments for one job:- Drivers trade/swap parcels after the initial assignment was transmitted: in that case the tenant's connector should send a new assignment for the same job id with the new assignment value and a later scan date.
- A parcel was not delivered today and it will be assigned to the same (or another) driver/route tomorrow: in this case the connector needs to transmit a new assignment for the next day, so that Better Route can include it on a new delivery sequence for the next day.
- status updates - are typically sent after the driver left the depot and a parcel gets a new status (e.g. “delivered”) in the tenants IT systems. Main purpose is to know which jobs need to be considered for tour (re-)calculation and which can be ignored because they are done.
General remarks on the format
Bettermile expects that all the data that is required for a certain date is exported daily before any driver activity takes place. The standard delivery mechanism is a periodic upload to an AWS S3 bucket.
The data is sent in JSON format as a top level array of elements (preferred) or as concatenated JSON.
Array example:
[
{
"id": "dc5a6618-66ac-4128-b198-fabcfca45423",
"date": "2020-01-02",
"...": "..."
},
{
"id": "f30f3f1c-2115-4f36-8be3-c0fda62a78aa",
"date": "2020-01-02",
"...": "..."
}
]
Concatenated JSON (Wikipedia):
{
"id": "dc5a6618-66ac-4128-b198-fabcfca45423",
"date": "2020-01-02",
"...": "..."
}
{
"id": "f30f3f1c-2115-4f36-8be3-c0fda62a78aa",
"date": "2020-01-02",
"...": "..."
}
The encoding of the data must be in UTF-8.
Additionally, the data has to be compliant with the JSON schema (see https://json-schema.org/). The D&D schema can be found under the following URLs:
- https://api.dgw.secondscreen.delivery/api/v1/dad-schema-array.json or
- https://api.dgw.secondscreen.delivery/api/v1/dad-schema.json (single job element)
Any particular payload should be validated against the schema by using a JSON schema validator (eg. JSON Schema Validator). Invalid job objects will not be processed by Bettermile Data Gateway.
Example
This is an example of import file, representing a Job object.
{
"id" : "54365964-xyz",
"date" : "2021-12-07",
"created" : "2021-12-06T17:25:51.443-08:00",
"source" : "manifest",
"depot" : "ORC",
"type" : "delivery",
"shipper" : {
"names" : [
"Thalia Bücher GMBH"
]
},
"consignee" : {
"type": "private",
"names" : [
"Firstname Lastname"
],
"address" : {
"street" : "4400 MacArthur BLVD",
"postalCode" : "92660",
"locality" : "NEWPORT BEACH",
"province" : "CA",
"country" : "US"
},
"email" : "user@foo.com",
"phone" : "+4916012345678",
"timeFrames" : [
{
"type" : "required",
"earliest" : "09:00:00",
"latest" : "14:00:00",
"timezone" : "Europe/Brussels"
}
]
},
"assignment" : {
"scantime" : "2021-12-06T17:25:51.443-08:00",
"properties" : {
"route" : "4711"
}
},
"services" : [
{
"acronym" : "PRI",
"description" : "Priority Delivery"
},
{
"acronym" : "SIG",
"description" : "Adult Signature Required"
}
],
"physicalProperties" : [
{
"property" : "quantity",
"value" : 1
},
{
"property" : "weight",
"value" : 12.0
}
]
}
Types
Job
A job contains everything that is necessary for a driver to perform a task. Most of the time, it is about delivering a parcel to a particular address.
Name | Mandatory | Description |
---|---|---|
id | yes | Identifier for this job. It must be unique for at least 30 days in the tenants systems. Typically this is a parcel id. There is no restriction on the format (e.g. a UUID or a number) but provided as STRING in the JSON. |
date | yes | Expected delivery, pickup or collection date. Date in YYYY-MM-DD format. For master data this does not need to be the final delivery date. But when transmitting assignments for a job, this needs to be the date the parcel will be physically present in the last mile vehicle. |
created | no (but recommended!) | When was the data created (e.g. when did some automatic process create this data set). RFC 3339 section 5.6 timestamp, for example: 2022-05-12T08:00:13.623Z or 2022-05-12T10:00:13.623+02:00 Used for a last one wins approach if conflicting data is sent to Bettermile. |
source | yes | A predefined constant that describes in which process this job description was generated. Possible values: "master", "manifest", "assignment", "scan". |
depot | yes | Tenant specific identifier that assigns the data to a particular depot. |
type | no | delivery, pickup, collection. Classification of this job. |
realtimeTracking | no (yes for Real-time Tracking usage) | See RealtimeTracking. It contains information that controls Real-time Tracking behavior for this job. |
shipperReference | no | Shipper’s reference. Example: “Amazon Order #12345678”. Might be shown to the consignee within Real-time Tracking. |
shipper | no (yes for pickup/collection) | See Contact. This is the delivery sender or pickup/collection contact. |
consignee | no (yes for delivery) | See Contact. This is the object representing the recipient and it contains the delivery address. |
redirectContact | no | See Contact. If a redirectContact is provided, its address will be used instead of shipper or consignee by Better Route to determine the waypoint coordinates for this job. Typical use case is a planned redirect to a parcel shop. |
services | no | A list of service and products. See Services. Examples are “Euro Business Small Parcel”, “G24”, “Flex Delivery“. This can mean that the product adheres to size and weight conventions (small business parcel) or has a special service to perform “ident“ or “cash on delivery“. The driver knows what it means, so this is worth displaying. |
physicalProperties | no | Physical properties like weight, height, length, volume, etc. |
statusChanges | no | A list of state changes that reflect what happened (or just happened) in the delivery process. See StatusChange. |
assignment | no | See Assignment. The assignment assigns a job to a particular driver, route or vehicle. This is a crucial piece of information, so that the correct jobs, which are relevant for a particular driver, can be retrieved for example in the Bettermile App." |
unassignment | no | An optional Unssignment of a job to rollback a previous assignment. |
Assignment
Note - Currently, an assignment has no specific source and date referred to it directly. This information is specified in the containing job object.
Name | Mandatory | Description |
---|---|---|
properties | yes | Object with property “vehicle”, “route” or “driver”, … Choose an assignment property that is established in the tenants IT systems and that is also known by the driver/user of Bettermile App. The string value provided with the chosen property will be the identifier a driver needs to select his/her route in the Bettermile App. |
scantime | no | Time when a job was scanned by the driver or the prepicker. RFC 3339 section 5.6 timestamp for example 2022-05-12T08:00:13.623Z or 2022-05-12T10:00:13.623+02:00 |
priorityGroup | no | An integer number. A priority group number is used to prestructure the Better Route optimized sequence. First all jobs assigned with the lowest group number will be considered for the Better Route sequence, then all jobs with the next higher group number. Jobs with different priorityGroup will not be combined in one waypoint. If the job also has timeFrames, they can be in conflict with the priorityGroup and might be ignored. |
assignmentTags | no | Object with key-value pairs for optional information on the current assignment properties. These tags are intended solely for informational purposes and do not define or affect the mandatory assignment properties object. |
Assignment Tags
Assignment tags allow Bettermile to receive custom tenant-specific fields to enrich the required assignment property values. Assignment tags are enabled on a tenant-by-tenant basis and serve complimentary details to various Bettermile platform components such as Route, RTT, and Backoffice on tenant-specific operational contexts surrounding the submitted assignment values.
Assignment tags have the same lifespan as the parent assignment object: they expire when a new assignment for the Job is received or at midnight local time.
Name | Mandatory | Description |
---|---|---|
driverName | no | A string field with the driver's name. If enabled for a tenant, this information will be presented in the Bettermile Backoffice alongside the assignment properties for Cloudtracking tours. |
tourGroup | no | A string field designating the tour number. If enabled for a tenant, this information will be presented in the Bettermile Backoffice alongside the actual assignment properties (e.g."driver"). |
loadingZone | no | A string field designating the loading zone for a specific job. If enabled for a tenant, this information will be presented to the drivers on the Bettermile app loading screen. |
subcontractorName | no | A string field with the subcontractor name. If enabled for a tenant, this information will be presented in the Bettermile Backoffice alongside the assignment properties for Cloudtracking tours. |
Example
{
"id": "624717089",
"date": "2021-09-01",
"created": "2021-09-01T14:03:08.190+02:00",
"depot": "687",
"source": "assignment",
"assignment": {
"scantime": "2021-09-01T02:34:00Z",
"priorityGroup": 1,
"properties": {
"vehicle": "2003"
},
"assignmentTags": {
"driverName": "Jane Doe",
"loadingZone": "Zone 2",
"tourGroup": "5001",
"subcontractorName": "John Doe"
}
}
}
Unassignment
Note - Currently, an unassignment has no specific source and date referred to it directly. This information is specified in the containing job object.
Name | Mandatory | Description |
---|---|---|
unassignment | yes | Specifies which assignment to remove from the job ID (see Assignment). |
Example
{
"id": "5743897964",
"date": "2022-05-12",
"created": "2022-05-12T13:11:23.264+02:00",
"depot": "CT",
"source": "assignment",
"unassignment": {
"assignment": {
"properties": {
"vehicle": "2003"
}
}
}
}
Contact
Name | Mandatory | Description |
---|---|---|
address | no | The postal address. |
no | Email address. | |
phone | no | A telephone number. E.164 format (https://en.wikipedia.org/wiki/E.164) |
names | no | List of identifying names for the contact, e.g. "Microsoft", "Sales department", "c/o Jane Doe" or simply just one element like "John Doe". |
hints | no | A list of helpful driver hints (for display only): “2nd backyard”, “Laderampe 5”, “deliver at back entrance only“, “pickups from ramp only“, … |
timeFrames | no | A list of Timeframe objects. A timeframe is a temporal constraint for the job that will be considered in sequence calculation. |
type | no | business, private, parcel_locker, parcel_shop. |
id | no | A unique contact ID. This may be used to group jobs into contact specific groups or may be required for shipper contacts for Real-time Tracking. For a shipper contact this may be for example “72645-Adidas” |
language | no | Preferred language of contact when contacted digitally for example within Real-time Tracking. Consists of language identifier and optional country code. For example: es, en, en_IE, en_US etc. (ISO 639-1 language codes and ISO-3166-1 alpha 2 country codes). If not provided, the language defaults to the depot/tenant language. |
Address
Name | Mandatory | Description |
---|---|---|
street | yes | The street address including house numbers (if available) in country specific formats: “10 Downing Street”, “Harzer Str. 39”, “Via Garibaldi 374”. Do not include information that is irrelevant for geocoding. Additional delivery instructions to the driver should be send as “hints” property instead. |
postalCode | yes | Postal code. |
locality | no | E.g. the city. |
province | no | Optional hint in which province, county, district or region an address is located. |
country | yes | Alpha 2 country code: https://en.wikipedia.org/wiki/ISO_3166-1. |
geoCoordinates | no | List of WGS84 lat/lngs. It is optional, since Bettermile performs the geocoding of the supplied address, but may be set as a fallback. |
GeoCoordinates
Geo coordinates can be sent in one of the following data structures:
Name | Mandatory | Description |
---|---|---|
type | no | E.g. “rooftop”, “parking stop”, “street coordinates”, “handover”. |
latitude | yes | WGS 84 latitude. At least 5 digits precision after the comma, like 52.53526 (1.1m accuracy) |
longitude | yes | WGS 84 longitude. At least 5 digits precision after the comma, like 13.24351 (1.1m accuracy) |
Name | Mandatory | Description |
---|---|---|
type | no | E.g. “rooftop”, “parking stop”, “street coordinates”, “handover”. |
w3w | yes | A what3word address as a string. It must be three words separated with dots or a japanese middle dot character (・) |
Timeframe
Name | Mandatory | Description |
---|---|---|
type | yes | Can only be “required”. |
earliest | yes | Earliest time for delivery or collection. Format is HH:MM:SS. (24h) It is meant to refer to the tenant’s default timezone or the one that is specified here in attribute timezone . It refers to the date of the job. |
latest | yes | Latest time for delivery or collection. Must be later than earliest time. Format is HH:MM:SS. (24h) It is meant to refer to the tenant’s timezone or the one that is specified here in attributetimezone . It refers to the date of the job. |
timezone | no | The timezone the timeframe is in. If not specified, the default timezone of the tenant is assumed. It must be one of https://en.wikipedia.org/wiki/List_of_tz_database_time_zones (e.g. Europe/Brussels). For countries with more than one timezone this property is mandatory. The timezone explicity defined here should be the timezone where the contact is located. |
Services
Name | Mandatory | Description |
---|---|---|
acronym | yes | Acronym of a service (for instance: "ESBP"). |
description | yes | Complete name or description of the service (for instance: “European Small Business Parcel”). |
Physical Property
Name | Mandatory | Description |
---|---|---|
property | yes | weight, height, length, width, volume, quantity. Units are predefined:
|
value | yes | Decimal value, provided as JSON number (not string!) For example, 20.6 . |
RealtimeTracking
The realtimeTracking (RTT) object contains additional configuration data required specifically for Better Tracking services.
Name | Mandatory | Description |
---|---|---|
enabled | no | true/false: enables/disables RTT for the specific job. If a tenant is using RTT, the default is true, otherwise RTT will not be enabled anyway. |
notification | no | Notification details for this job. See Notification below. |
redirect | no | Real-time Tracking parcel redirect options for example depending on service type. Contains the attributes neighbor , deposit and parcelShop to set permissions for this job, wether the delivery may ad-hoc be redirected to a neighbor or be deposited at a consignee location or be handed over to a parcel shop.Example: "redirect" : { Defaults: false for all fields. |
Notification
Describes how and when to contact the consignee via Real-Time Tracking.
Name | Mandatory | Description |
---|---|---|
invite | no | How to send the “Invite” to the consignee. Contains the attributes email and sms (true/false) to define whether or not to send invite messages via these channels.Example:
|
reminder | no | How to send the reminder to the consignee. Contains the attributes email and sms (true/false) to define whether or not to send reminder messages via these channels.Example:
|
Full example
{
"enabled": true,
"notification": {
"invite": {
"email": true,
"sms": false
},
"reminder": {
"email": true,
"sms": false
}
},
"redirect": {
"neighbor": true,
"deposit": false,
"parcelShop": true
}
}
StatusChange
Name | Mandatory | Description |
---|---|---|
state | yes |
|
timestamp | yes | Date and time of status change most likely determined on the driver's scanning device. RFC 3339 section 5.6 timestamp, for example 2022-05-12T08:00:13.623Z or 2022-05-12T10:00:13.623+02:00 |
outcome | no | “success”, “unsuccessful” (parcel was delivered or not, pickup was collected or not). Should be set for “processed” events so a problem view in the Bettermile App will contain unsuccessful delivery attempts. Also the driver may reopen a waypoint containing a job with an unsuccessful delivery attempt. |
outcomeDetails | no | See OutcomeDetails below. Further details about redirects or delivery failures |
onLocation | no | true, false: whether the driver was at the waypoint or not. Currently unused. |
description | no | A textual description of the event to be displayed in the BetterRoute conflict view. |
geoCoordinates | no | WGS84 lat/lngs of the location where the handscanner event took place. See GeoCoordinates. |
Example
{
"id": "9200313150",
"date": "2022-05-23",
"source": "scan",
"created": "2022-05-23T09:21:58.123+02:00",
"statusChanges": [
{
"state": "processed",
"timestamp": "2022-05-23T09:17:12.876+02:00",
"outcome": "success",
"outcomeDetails": {
"type": "neighbor",
"names": [
"Beauty Hair Berlin",
"c/o Jane Doe" ]
},
"description": "to neighbour",
"geoCoordinates": {
"latitude": 37.72525,
"longitude": 15.19114 }
}
]
}
StatusChange - OutcomeDetails
The information here is largely used for Bettermile Real-time Tracking
Name | Mandatory | Description |
---|---|---|
type | yes | A categorisation of different outcomes. Used primarily in Better Tracking.
|
hint | no | Free text to further enhance the outcome type. It is shown on Better Tracking website. This may contain information like where the parcel was finally deposited (“deposited in garage”, “deposited on terrace”, etc.) |
names | no | List of identifying names, e.g. "Beauty Hair Berlin", "c/o Jane Doe" or simply just one element like "John Doe". |
address | no | See Address. The exact address, for example of the parcel shop. |
Outcome Details - Parcel shop example
"outcomeDetails": {
"type": "parcel_shop",
"names": [
"Kiosk & Bakery"
],
"address": {
"street": "Gubener Str. 23",
"postalCode": "10243",
"locality": "Berlin",
"province": "BE",
"country": "DE"
}
}
Outcome Details - Neighbor example
"outcomeDetails": {
"type": "neighbor",
"names": [
"Beauty Hair Berlin",
"c/o Jane Doe"
]
}
Outcome Details - Deposit example
"outcomeDetails": {
"type": "deposit",
"hint": "on the terrace"
}
Outcome Details - Unsuccessful outcome because parcel was refused
"outcomeDetails": {
"type": "not_accepted"
}
Notes for the types
- Mandatory means that it must be present and not empty.
- Date and times must follow the RFC 3339 section 5.6 standard . Timestamps must be UTC or include a timezone to be unambiguous.