Index

Contents



2. Authentication

Return to Top

Almost all requests to the API require proper authentication. There are a number of ways in which a client can authenticate, depending on the details and level of access available to it.

To summarise, a client can authenticate using any of the following methods

  •   Site API Key (and secret)
  •   User API Key (and secret)
  •   Session Token

In order to generate a Session token, a single call must be made with a valid Site or User credential. Session tokens are IP locked, and can be locked to an arbitrary IP (i.e. a Server can create on behalf of a client).

 

Site API Key

A Site API Key must be requested and cannot automatically be generated. Once enabled a site can create users, and users can authorise the site to authenticate on their behalf (they must do this through their 'home' site).

Any user created by a site will have that site set as their 'home', therefore sites creating users must implement a mechanism to allow users to authorise other site keys

to act on their behalf (A site may be a website, a smartphone app or anything similar).

When authenticating using a site key, three headers must be sent (unless creating a user, in which case the user key will not yet be known)

  •    X-VEHMAN-SITE
  •    X-VEHMAN-KEY
  •    X-VEHMAN-USER

The key used should be that of the site (not the user). If the Site is authorised to act on the users behalf, all transactions will be enacted as if that user had authenticated directly.

See the section 'Secret Keys' for information on how the key should be encoded.

 

User API Key

A user can authenticate directly against the API using their API key and Secret key, to do so the following HTTP headers should be included

  •    X-VEHMAN-USER
  •    X-VEHMAN-KEY

See the section 'Secret Keys' for information on how the key should be encoded.

 

Session Token

In order to allow the use of the API by client-side libraries (such as Javascript) without divulging API keys, a session token can be generated. The host system should place a call to /authentication/session using either their Site API key or the User API key.

The request should include the key "IP" with a value matching that of the client IP which will be making calls, as with all API calls this should be JSON encapsulated and submitted via POST within a variable 'data'.

In response, the API will create a unique, signed session token, locked to the specified IP. This session data can then be used to authenticate against the API for up to 15 minutes.

The Session token can be submitted in one of two ways

  •   HTTP Header X-VEHMAN-SESSION
  •   Request variable SESS (via POST or GET)

 

Secret Keys

Although it is expected that all API calls will take place over HTTPS, it's not mandated. As a result, authentication tokens are most at risk of compromise when in transit on-the-wire - they are encrypted within the API and MUST be encrypted when stored by client devices/sites.

To lessen the risk of compromise, Secret Keys should be used to sign requests in the form of an SHA1 hash. In order to ensure that a generated hash is not re-usable, the following method should be used

  1.   Generate the JSON request string and pass it through SHA1.
  2.   Prefix the secret key with the resulting string and pass through SHA1 once more
  3.   Submit the generated hash as the secret key.

To ensure that otherwise identical requests receive different hashes, it's strongly recommended that you include a random, arbitrary token within the JSON request string. Anything assigned to the key 'randtoken' will be ignored by the API except as part of validating the submitted hash.

 

Example Code

<?php
  $mykey='1234';
  $request = new stdClass();
  $request->redirect = true;
  $request->randtoken = mt_rand(0,1000000);
  $submission = json_encode($request);
  $api-secret = sha1(sha1($submission).$mykey);
  // Submit $api-secret as header X-VEHMAN-KEY

?>

 

API Responses

If authentication is successful, the requested action will be completed.

If authentication headers were not provided, or those that were provided were invalid, the API will return a HTTP 403. In most cases a JSON encapsulated response will also be provided detailing the issue encountered.

Return to Top

3. Sessions

Return to Top

The Session module allows you to mint and destroy session tokens.

The idea being that rather than needing to send explicit authentication details with every request, you can send them once to mint the token and then simply provide the token with each subsequent request.

An additional benefit of this is that it allows you to pass a users browser a sessionKey so that they can place requests themselves (perhaps via AJAX, or at a basic level, to simply load a chart).

 

Creating a Session Token

To create a session token, place a request to

/session/create

Within the JSON request, you must specify the following

  • ClientIP: The IP address that subsequent requests will originate from. This _must_ be correct, otherwise access will be denied

The token will be generated for whichever user is currently authenticated, so if you're using a site key to authenticate on behalf of a user, ensure your authentication headers include the user's key (See the Authentication documentation for more detail).

 

Response

The JSON response will be an array containing the minted token in key 0 and the expiry time in key 1;

{
"timestamp":1382057808,
"response":[
"eJw9jMsOgjAQRb+GLslMI3S66EJ0485o+IAKAxINwRYT+HtREjZnce7jyUvfeBQxDI13BFp0PHhUJMFYAhLTMrK\/cUqC5ykGn9kyk\/J8WZGpw0rCHJXO0chc\/6Q8ruR57COnrbS9kQXawiu\/P5wmbsplf6lw31aJ4+7\/2p5EeHU+PQKK1Hde17YlBdYwILaG0dUuqDvIYArtQNtQ8Bq6L577OhI=",
1382058708
],
"errors":null,
"error":0
}

Be aware that session tokens are only valid for 15 minutes once they've been minted

 

Destroying a Session

To destroy a session, place an authenticated request to

/session/destroy

Within the JSON request you must specify the Session token as DestToken. As an additional security measure (to prevent users from destroying other's sessions), you must also be authenticated (whether directly, or as a site on behalf) as the user the token was created for.

 

Response

{
"timestamp":1382057808,
"response":1,
"errors":null,
"error":0
}

Note: If you fail to authenticate as the user the session relates to, no error will be returned, the session will simply remain valid.

 

Errors

The following errors may be returned

  • Authentication Failed: The system was unable to authenticate your request, check you've sent valid auth headers with your create/destroy request
  • IP Not Specified: You didn't specify a ClientIP in your request. The token is locked to a specific IP for security reasons, so a token could not be minted.
  • Token Not Specified: You placed a destroy request, but didn't specify the session token.
Return to Top



6. Service and Maintenance

Return to Top

Service and maintenance module etc.

Return to Top

7. Journeys

Return to Top

The Journey module is used to record journey details, of most direct use within the API are the speed records.

The usual authentication requirements apply to all areas of this module.

 

 

GPX File Import

The API supports import of GPS eXchange (GPX) files. In order to provide a file for import, a request must be made using POST to

/journey/import/{vehicle identifier}

All journeys must be recorded against a specific vehicle.

Note: Due to the intensive nature of this function, The GPX file will not be imported at the time of the request, but an import task will be queued.

The response will therefore confirm whether or not the task was successfully queued and provide the JobID. See the Queue submodule documentation for information on checking the status of a Queued task.

The GPX file should be submitted as a HTML form field, the field in question should be 'subfile'.

The request should therefore be of the type 'multipart/form-data'.

Data Filtering and Manipulation

By default, the system will use 'SmartTrack'. If a trackpoint occurs more than 1 hour (3600 seconds) after the previous trackpoint, a new GPS track will automatically be started.

To disable this, the JSON request should include the key/value

smartTrack: false

The smartTrack threshold can also be adjusted, the value should be passed in seconds, so to set to 2 hours, we'd send

smartTrackThreshold: 7200

It is also possible to suppress certain information. For example, if the user does not want their GPS position to be recorded within the system, it can be suppressed. To suppress any of the following, an array called suppress should be submitted as part of the request

Valid values are;

  • speed
  • location
  • elevation

Although GPXIngest supports suppression of dates, the Database schema doesn't allow for this, therefore any attempts to suppress date will lead to the import being rejected.

Example Call

# curl -F "subfile=@importfile.gpx;type=text/xml" \
-H "X-VEHMAN-KEY: Test: `echo {mykey} | sha1sum | awk -F\ '{print $1}'`" \
-H "X-VEHMAN-USER: {myuserkey}" \
{apiurl}/journey/import/{vehicleidentifier}



Example Response

{
"timestamp":1378824115,
"response":{
"status":"Queued",
"JobNumber":4
},
"errors":null,
"error":0
}

 

 

JSON File Import

When the API receives a GPS eXchange (GPX) file, it processes it and creates a GPXIngest Object (See https://github.com/bentasker/PHP-GPX-Ingest/).

If preferred, (for example because you intend to suppress location data and don't want to send that data across the network at all) a JSON encapsulate GPXIngest object can be submitted instead. The necessary JSON can be extracted from GPXIngest with the method getJSON().

The JSON string should be written to a file, inclusion in the request is NOT supported.
In order to provide a file for import, a request must be made using POST to

/journey/importjson/{vehicle identifier}

All journeys must be recorded against a specific vehicle.

Note: Due to the intensive nature of this function, The JSON file will not be imported at the time of the request, but an import task will be queued.

The response will therefore confirm whether or not the task was successfully queued and provide the JobID. See the Queue submodule documentation for information on checking the status of a Queued task.

The JSON file should be submitted as a HTML form field, the field in question should be 'subfile'.

The request should therefore be of the type 'multipart/form-data'.

Example Call

# curl -F "subfile=@importfile.json;type=text/json" \
-H "X-VEHMAN-KEY: {mykey}" \
-H "X-VEHMAN-USER: {myuserkey}" \
{apiurl}/journey/importjson/{vehicleidentifier}

 

Example Response

{
"timestamp":1378824216,
"response":{
"status":"Queued",
"JobNumber":5
},
"errors":null,
"error":0
}

 

 

List Journeys

To retrieve of all journeys recorded for a specific vehicle, place a call to

/journey/listjourneys/{vehicle identifier}

A record will be returned for every track recorded (as 'journeys' may include more than one track).

Example Response

Note: The list of stats returned may vary from those shown below - new statistics are being implemented

{
"timestamp":1378830060,
"response":{
"row0":{
"journeyID":"1",
"trackID":"2",
"journeyDuration":"5190",
"start":"1377581448",
"end":"1377586638",
"avgSpeed":"55.83",
"maxSpeed":"70",
"minSpeed":"0",
"modalSpeed":"68",
"map":"http:\/\/example.com\/chart\/journeymap\/1\/1\/2"
}
},
"errors":null,
"error":0
}

 

Journey Path Details

Use this section of the module to retrieve full details for a specific journey. Depending on the parameters used when the source GPX file was ingested, this will include all or some of the following

  • latitude
  • longitude
  • Speed
  • Elevation
  • Time
  • Journey Track ID

In order to place a request to this function, you must provide both the correct vehicle identifier and a valid Journey ID

/journey/journeytrack/{vehicle identifier}/{journey id}/{track id} - Optional

So both of the following would be valid requests to retreive the track points for a full journey

/journey/journeytrack/1/1
/journey/journeytrack/A123%20DAL/1


Whilst the following would be valid requests to retrieve track points for a Track with an ID of 6 within journey 1.

/journey/journeytrack/1/1/6 /journey/journeytrack/A123%20DAL/1/6

Note: Track ID's are completely independant of Journey ID's, so no two journeys will contain a segment with the same ID.

 

Example Response

{
"timestamp":1378830787,
"response":{
"row0":{
"TrackPtID":"1",
"segmentID":"1",
"JourneyID":"1",
"VehicleID":"1",
"lat":"52.129725",
"lon":"1.415779",
"time":"1377581448",
"speed":"0 mph",
"speedint":"0",
"elevation":"62"
},
"row1":{
"TrackPtID":"2",
"segmentID":"1",
"JourneyID":"1",
"VehicleID":"1",
"lat":"52.129744",
"lon":"1.415823",
"time":"1377581457",
"speed":"0 mph",
"speedint":"0",
"elevation":"68"
},
},
"errors":null,
"error":0
}
Return to Top

8. Charts

Return to Top

The Charts module is used to view charts and graphs containing data from the other core modules. Each supported type is prefixed by it's parent module below, and will honour any filters passed that are supported by the parent.

Charts can be made public for embedding into websites (as seen on the example charts page), or can be kept private to the user.

 

Request Specifics

As with any other module, any variables relevant to the request should be POST'd as JSON within a variable called data.

Currently supported are

  • smoothing - Boolean - Should values be normalised against a running average?
  • deviation - INT - What percentage deviation is permitted before the value is normalised (to the top of the range)
  • redirect - Boolean - If set to true, the API will not return JSON and will simply 302 to the generated chart
  • makePublic - Boolean - Make the chart public (default false)
  • chart->showLegend - Boolean - Show chart legend?
  • chart->showValues - Boolean - Include the exact values within the linechart
  • chart->useCurve - Boolean - Use a cubic curve to link the points
  • chart->showMarkers - Boolean - Include a marker for each datapoint
  • chart->Height - Height in pixels for the resulting chart
  • chart->Width - Width in pixels for the resulting charts
  • chart->XScale - How often should a value on the X axis be marked?
  • chart->Title - String - Title to use for the chart. Send with an empty value to disable the title.

Note: If specified, width and height must be specified together. If only one is specified they will be ignored. Redirect can also be appended as part of the request URI

Example

  {
"smoothing":false,
"deviation":60,
"redirect":true,
"makePublic": true,
"chart":{
"showLegend":true,
"showValues":true,
"useCurve": false,
"showMarkers": true,
"Height":460,
"Width": 800,
"XScale": 3
 }
}

The example above disables value normalisation and redirects the browser to the chart. Every 3rd value is marked on the X Axis.

 

Response

The API responses are in line with the rest of the API, unless you elect otherwise in your request you will receive JSON.

Within response will be ChartURL - this contains the full URL to use to view the chart.

Example

  {
"timestamp":1378240663,
"response":{
"cacheStatus":"MISS",
"ChartURL":"http:\/\/vehiclefueltracker.co.uk\/chartCache\/F-A123-DAL-ad2a34d12119fee25e49bee5d476c3c52a29c81b.png"
},
"errors":null,
"error":0
}

 

Charting Engines

The Charts module supports two main engines - pChart and Google Charts. The former generates a PNG image containing the requested chart, whilst the latter generates an interactive chart embedded into a webpage.

pChart

pChart is the default engine as it suits a wider range of applications, Google charts do not work well on some mobiles and are not well suited for any application that may lack an internet connection (i.e.) they can't easily be cached locally.
Therefore, to use pChart, you simply need to place requests exactly as described in this documentation

Google Charts

The Google Charts API can generate some attractive looking charts, which are well suited to being embedded within a webpage. In order to use the GoogleChart engine, place requests exactly as specified in this document, but add an additional segment to the end of the request URL - google.

So to request an economy chart we might use

/chart/economy/1/google

 

Fuel - Vehicle Economy

To generate a linegraph containing a single vehicle's average monthly economy

/chart/economy/{Vehicle Identifier}

The vehicle ID is preferred, but the registration can be used.

 

Fuel - Vehicle Average Price per Litre

To generate a chart containing the average price per litre throughout the recorded lifetime of a vehicle

/chart/fuelprice/{Vehicle Identifier}

 

Fuel - Historic Average Price per Litre

To generate a chart containing the average price per litre throughout the recorded history of a driver (based on all vehicles assigned to them)

/chart/allfuelprices

The driver used will be the one associated with the API Key used to authenticate against the system.

 

Fuel - Monthly Fuel Cost

To generate a chart showing a vehicles Monthly fuel cost,

/chart/fuelcost/{Vehicle Identifier}

 

Fuel - Monthly Fuel Cost Per Mile

To generate a chart showing the monthly fuel cost per mile

/chart/monthlyfuelcpm/{Vehicle Identifier}

 

Fuel - Monthly Mileage

To generate a chart showing a vehicles monthly mileage (based on fuel records)

/chart/monthlymileage/{Vehicle Identifier}

 

Servicing - Monthly Maintenance Cost

To generate a chart displaying the total monthly maintenance cost /chart/monthlyservicecost/{Vehicle Identifier}

 

Servicing - Monthly Maintenance Costs

To generate a chart displaying a breakdown of Monthly maintenance costs between fault and non-fault repair /chart/monthlyservicebreakdown/{Vehicle Identifier}

 

Journeys - Journey Route

The charting API can also generate a Google Maps call with a specific journey's route pre-plotted. To generate, use

/chart/journeyroute/{Vehicle Identifier}/{Journey Identifier}/{Segment Identifier (optional)}

 

Journeys - Journey Speed Profie

Generates a chart mapping the speed travelled during the specified journey.

/chart/journeyspeed/{Vehicle Identifier}/{Journey Identifier}/{Segment Identifier (optional)}

Return to Top

9. Processing Queue

Return to Top

The Queue module is used to view and manage a users queued tasks. These will primarily be processing tasks (such as GPX/JSON imports) but may also include other intensive tasks.

All requests must be properly authorised, and only items queued by (or on behalf of) the current user can be viewed.

Job Classes

Each API submodule has its own JobClass, and any queued jobs will be assigned to this class.

  • GPX - Journey, specifically GPX or JSON Import
  • VEH - Vehicle SubModule, usually deletion

 

Job Statuses

Wherever individual Jobs are returned, the relevant Job status will also be returned. There are 6 possible statuses;

  • Awaiting Processing
  • Locked - Currently being processed
  • Completed
  • Failed
  • Cancelled By User
  • Unknown

If the API returns a job status of unknown it's representative of an internal error.

 

Show Queue

To View the current Queue (including some historic items) request

/queue/queue

Example Response


{
"timestamp":1379864224,
"response":{
"jobs":{
"J0":{
"jobID": 1,
"JobClass":"GPX",
"Task":"Import",
"started":"1378825905",
"ended":null,
"status":"Locked"
},
"J1":{
"jobID": 15,
"JobClass":"GPX",
"Task":"Import",
"started":"1379115601",
"ended":null,
"status":"Failed",
"failurereason":"Journey creation failed"
},
"J2":{
"jobID": 43,
"JobClass":"GPX",
"Task":"ImportJSON",
"started":"1379849777",
"ended":"1379849779",
"status":"Completed"
},
"J3":{
"jobID": 116,
"JobClass":"GPX",
"Task":"ImportJSON",
"started":null",
"ended":"1378826723",
"status":"Cancelled By User"
}
},
"errors":null,
"error":0
}

 

Job Status

To retrieve the status of a single Job, place a request to

/queue/jobstatus/{job id}

e.g. to retrieve the third job in the example above, we'd place a request to

/queue/jobstatus/43

Example Response

{
"timestamp":1379871871,
"response":{
"jobID": 43,
"JobClass":"GPX",
"Task":"ImportJSON",
"started":"1379849777",
"ended":"1379849779",
"status":"Completed"
},
"errors":null,
"error":0
}

 

Historic Items

Jobs are not automatically purged from the database on completion, but the queue is pruned periodically by a cron script. Expect completed queue items to persist for no more than 7 days, although the actual retention period may vary from time to time.

Failed items are retained for a slightly longer period.

 

Submodule specific failure reasons

Journey / GPX

There are a number of failure reasons which may be returned by Jobs in the GPX class, most of which should be self-explanatory. If an error arises, the source GPX/JSON file will need to be checked and resubmitted for processing.

Should a warning occur, the main journey record will have been created, so if the intention is to resubmit for processing this record will need to be removed. See the Journey submodule documentation for information on removing Journey records.

Fatal Errors

  • Source file does not exist - A file was queued for import, but doesn't appear to exist on the server
  • Invalid GPX File - A GPX Import job was queued, but the XML could not be parsed.
  • Invalid JSON File - A JSON Import job was queued, but the JSON could not be parsed.
  • Date is suppressed - Will only occur when a JSON file has been submitted for import. Whilst GPXIngest will allow you to suppress dates, the API does not support import of Journeys without date information.
  • Journey creation failed - The journey could not be created in the database. Either there's an issue with the Journey data, or more commonly, that Journey has previously been imported.

Warnings

  • Track x: creation failed - A specific track id could not be created, any child Segments and trackpoints will have been skipped
  • Segment x / y: creation failed - A specific segment could not be created in the database. x signifies the relevant trackID. Any child trackpoints will have been skipped
  • Trackpoint x / y / z: creation failed - A specific trackpoint could not be created in the database. x signifies the relevant trackID, y the segment ID and z the trackpoint ID.
Return to Top

10. Request Filters

Return to Top

Request filters allow you to filter the data that the API returns, for example limiting a fuel-log listing to entries between specific dates.

All filters should be within the main JSON encapsulated request, under variable 'filter'.

Key/value pairs within the filters object should specify what to filter on, the full range of supported keys varies by submodule, but the global filters are detailed below

Date

Date can be passed as a value (i.e. match exactly) or as an array - start and end.

filters{
"Date":[ '2013-10-14','2013-10-15' ]
}

Date should always be passed in MySQL format

 

Fuel Filters

Valid filters are;

  • Date
  • Garage
  • Mileage
  • MileageLess
  • MileageMore
  • Cost
  • CostLess
  • CostMore

 

Service Filters

Valid filters are;

  • Date
  • Garage
  • Mileage
  • MileageLess
  • MileageMore
  • Cost
  • CostLess
  • CostMore
  • Work
  • Fault

Journey Filters

  • Order (ASC/DESC) - Currently only supported on ListJourneys
Return to Top