88 Miles  - Simple time tracking

Developers area

Did you know that 88 Miles has a completely open REST webservice API? Well it does. So if you are interesting in extending 88 Miles or creating some sort of time tracking mash-up, you are in the right place.

What's a webservice?

A webservice is kind of like a web page, but it is designed to be used by other computers rather than people. This means you can access the features of 88 Miles from your own CMS, website or desktop application. This makes 88 Miles even MORE flexible

What types of web services do you offer?

88 Miles currently supports REST.

I‘m not a developer? What can I do?

MadPilot Productions is available to help you integrate your current systems into 88 Miles. Please contact them if you would like to discuss your requirements.

Webservice authentication

Looking for the page to register your 3rd Party application for OAuth? Then step this way!

The 88 Miles REST interface supports both OAuth and basic authentication. OAuth, whilst being a little bit harder to configure, it doesn't require you to ask for a users password, and is the preferred method of connecting to 88 Miles. There are already a number of libraries for supporting OAuth in many different languages, check out if your favourite one is already supported. If you are a developer and you wish to register your application as a 88 Miles OAuth consumer, you can do so here.

Currently, the 88 Miles OAuth implementation only supports the get http method and the query scheme.

If you are unable to use OAuth, you can still fall back to basic authentication, where you need to send your username and password with each query. If you are worried about revealing you password on each query, feel free to use the secure version of the webservices at https://www.88miles.net/

Please note, for simplicity, the examples below use basic authentication, as curl doesn't support OAuth (easily).

Documentation

Using REST makes accessing the webservices easy. As long as your language of choice can handle making remote HTTP calls and can generate and parse XML, you will fine.

The 88 Miles REST interface is accessed by appending .xml as demostrated below

REST uses verbs to perform actions on a specific URL. Below is a table of how this works for the companies resource.

ResourceVerbActionDescription
/companies.xmlGETlistList all companies
/companies/1.xmlGETshowGet the company with id of 1
/companiesPOSTcreateCreate a new company
/companies/1.xmlPUTupdateUpdate the company with the id of 1
/companies/1.xmlDELETEdestroyDelete the company with the id of 1

88 Miles uses nested resources which makes accessing projects and shifts easy! The following example shows you how to perform actions on projects belonging to a certain Company.

ResourceVerbActionDescription
/companies/1/projects.xmlGETlistList all projects belonging to company with an id of 1
/projects/10.xmlGETshowGet the project with id of 10
/companies/1.xmlPOSTcreateCreate a new project belonging to the company with id of 1
/projects/10.xmlPUTupdateUpdate the project with the id of 10
/projects/10.xmlDELETEdestroyDelete the project with the id of 10

The complete API

Staff | Companies | Projects | Shifts | Timezones | Errors

Staff

Get a list of all your staff (including you)

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/staff.xml

XML to send: None

Returns:

<users>
  <user>
    <id>1001</id>
    <username>wayne.wilks</username>
    <first_name>Wayne</first_name>
    <last_name>Wilks</last_name>
    <email_address>wayne@symag.com</email_address>
    <active>true</active>
  </user>
  <user>
    <id>1004</id>
    <username>marilynn.gaskins</username>
    <first_name>Marilynn</first_name>
    <last_name>Gaskins</last_name>
    <email_address>marilynn@symag.com</email_address>
    <active>true</active>
  </user>
</users>
Get a staff member with a supplied id

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/staff/1004.xml

XML to send: None

Returns:

 <user>
   <id>1004</id>
   <username>marilynn.gaskins</username>
   <first_name>Marilynn</first_name>
   <last_name>Gaskins</last_name>
   <email_address>marilynn@symag.com</email_address>
   <active>true</active>
 </user>
Create a new staff member

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/staff.xml -X post -d [See below]

XML to send:

 <user>
   <username>esmeralda.hahn</username>
   <first_name>Esmeralda</first_name>
   <last_name>Hahn</last_name>
   <email_address>esmeralda@symag.com</email_address>
   <time_zone>Australia/Perth</time_zone>
   <password>Mittens</password>
 </user>

Returns: 201 - Created

Update a staff member

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/staff/1004.xml -X put -d [See below]

XML to send:

 <user>
   <id>1006</id>
   <username>esmeralda.wible</username>
   <first_name>Esmeralda</first_name>
   <last_name>Wible</last_name>
   <email_address>esmeralda@symag.com</email_address>
 </user>

Returns: 200 - Success

Delete a staff member

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/staff/1004.xml -X delete

XML to send: None

Returns: 200 - Success

Companies

Get a list of all your companies

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/companies.xml

XML to send: None

Returns:

<companies>
  <company>
    <id>560</id>
    <name>Atection Consulting</name>
    <visibility>public</visibility>
  </company>
  <company>
    <id>569</id>
    <name>Trenthan Systems</name>
    <visibility>custom</visibility>
    <user_ids type="array">
      <user type="integer">243</user>
      <user type="integer">258</user>
    </user_ids>
  </company>
  <company>
    <id>578</name>
    <name>Proup Devices</name>
    <visibility>private</visibility>
    <website>http://www.proup-devices.com.au/</website>
    <main_phone>+61.8.9332.1349</main_phone>
    <main_address>45/2 James St</main_address>
    <main_city>Northbridge</main_city>
    <main_state>Western Australia</main_state>
    <main_postcode>6001</main_postcode>
    <main_country>Australia</main_country>
    <contact_salutation>Mr</contact_salutation>
    <contact_first_name>Mike</contact_first_name>
    <contact_last_name>Wentworth</contact_last_name>
    <contact_email_address>m.wentworth@proup-devices.com</contact_email_address>
    <notes></notes>
  </company>
</companies>
Get a company with a supplied id

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/company/578.xml

XML to send: None

Returns:

<company>
  <id>578</id>
  <name>Proup Devices</name>
   <website>http://www.proup-devices.com.au/</website>
   <main_phone>+61.8.9332.1349</main_phone>
   <main_address>45/2 James St</main_address>
   <main_city>Northbridge</main_city>
   <main_state>Western Australia</main_state>
   <main_postcode>6001</main_postcode>
   <main_country>Australia</main_country>
   <contact_salutation>Mr</contact_salutation>
   <contact_first_name>Mike</contact_first_name>
   <contact_last_name>Wentworth</contact_last_name>
   <contact_email_address>m.wentworth@proup-devices.com</contact_email_address>
   <notes></notes>
  <visibility>private</visibility>
</company>
Create a new company

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/companies.xml -X post -d [See below]

XML to send:

 <company>
   <name>Gabtune</name>
   <visibility>public</visibility>
 </company>
Create a new company for selected users

You will get an Company::UserNotAllowed error if one of the users isn't in your staff list.

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/companies.xml -X post -d [See below]

XML to send:

 <company>
   <name>Gabtune</name>
   <visibility>custom</visibility>
   <user_ids type="array">
     <user type="integer">243</user>
     <user type="integer">258</user>
   </user_ids>
 </company>

Returns: 201 - Created

Update a company

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/company/590.xml -X put -d [See below]

XML to send:

 <company>
   <name>Gabtune</name>
   <visibility>private</visibility>
   <website>http://www.gabtune.com/</website>
   <main_phone>+61.8.9467.1254</main_phone>
   <fax_phone>+61.8.9467.1255</fax_phone>
   <main_address>416 Beaufort St</main_address>
   <main_city>Inglewood</main_city>
   <main_state>Western Australia</main_state>
   <main_postcode>6051</main_postcode>
   <main_country>Australia</main_country>
   <contact_salutation>Ms</contact_salutation>
   <contact_first_name>Mary</contact_first_name>
   <contact_last_name>Trentson</contact_last_name>
   <contact_email_address>mary@gabtune.com</contact_email_address>
   <contact_home_phone>+61.8.9307.6243</contact_home_phone>
   <contact_mobile_phone>+61.409.153.534</contact_mobile_phone>
   <notes>Is a podcast post-production house</notes>
 </company>

Returns: 200 - Success

Delete a company

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/company/590.xml -X delete

XML to send: None

Returns: 200 - Success

Projects

Get a list of all your projects

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/projects.xml

XML to send: None

Returns:

<projects>
  <project>
    <id>2856</id>
    <name>Website</name>
    <visibility>public</visibility>
    <active>true</active>
    <time_limit_string>4 hours</time_limit_string>
    <default_tags>design development</default_tags>
    <notes></notes>
    <company_id>578</company_id>
    <taglist></taglist>
  </project>
  <project>
    <id>2856</id>
    <name>Maintenance plan</name>
    <visibility>custom</visibility>
    <user_ids type="array">
      <user type="integer">345</user>
      <user type="integer">546</user>
    </user_ids>
    <active>true</active>
    <time_limit_string>20 hours</time_limit_string>
    <default_tags></default_tags>
    <notes></notes>
    <company_id>538</company_id>
    <taglist></taglist>
  </project>
  <project>
    <id>2887</id>
    <name>SEO</name>
    <visibility>private</visibility>
    <active>true</active>
    <time_limit_string>>30 minutes</time_limit_string>
    <default_tags></default_tags>
    <notes>Part two of four part contract</notes>
    <company_id>560</company_id>
    <taglist>work, contract</taglist>
  </project>
</projects>
Get a list of all projects belonging to a specific company

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/company/578/projects.xml

XML to send: None

Returns:

<projects>
  <project>
    <id>2856</id>
    <name>Website</name>
    <visibility>public</visibility>
    <active>true</active>
    <time_limit_string>4 hours</time_limit_string>
    <default_tags></default_tags>
    <notes></notes>
    <taglist>new_tag, old_tag</taglist>
  </project>
</projects>
Get a project with a supplied id

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/project/2887.xml

XML to send: None

Returns:

<project>
  <id>2887</id>
  <name>SEO</name>
  <visibility>private</visibility>
  <active>true</active>
  <time_limit_string>30 minutes</time_limit_string>
  <default_tags></default_tags>
  <notes></notes>
  <company_id>560</company_id>
  <taglist></taglist>
</project>
Create a new project

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/company/560/projects.xml -X post -d [See below]

XML to send:

<project>
  <name>Email newsletter</name>
  <visibility>public</visibility>
  <time_limit_string>30 minutes</time_limit_string>
  <default_tags></default_tags>
  <notes>Check with Michael about body copy</notes>
  <taglist></taglist>
</project>
Create a new project for a selected users

You will get an Project::UserNotAllowed error if one of the users isn't in your staff list.

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/company/560/projects.xml -X post -d [See below]

XML to send:

<project>
  <name>Email newsletter</name>
  <visibility>custom</visibility>
   <user_ids type="array">
     <user type="integer">243</user>
     <user type="integer">258</user>
   </user_ids>
  <time_limit_string>30 minutes</time_limit_string>
  <default_tags></default_tags>
  <notes>Check with Michael about body copy</notes>
  <taglist></taglist>
</project>

Returns: 201 - Created

Update a project

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/project/3054.xml -X put -d [See below]

XML to send:

<project>
  <name>Email newsletter</name>
  <visibility>private</visibility>
  <time_limit_string>30 minutes</time_limit_string>
  <default_tags>email design</default_tags>
  <notes></notes>
  <taglist></taglist>
</project>

Returns: 200 - Success

Delete a project

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/project/3054.xml -X delete

XML to send: None

Returns: 200 - Success

Punch in to a project

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' 'https://www.88miles.net/project/3054/punch_in.xml' -X post

XML to send: None

Returns: 200 - Success

Punch out of a project

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' 'https://www.88miles.net/project/3054/punch_out.xml' -X post

XML to send: None

Returns: 200 - Success

Shifts

Get a list of all your shifts

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/shifts.xml

XML to send: None

Returns:

<shifts>
  <shift>
    <id>16253</id>
    <user_id>543</user>
    <staff_member>Esmeralda Wible</staff_member>
    <start>Wed, 13 Dec 2006 23:32:25 GMT</start>
    <stop> 14 Dec 2006 01:06:40 GMT</stop>
    <time_zone>Australia/Perth</time_zone>
    <notes>Initial Design Meeting</notes>
    <project_id>2854</project_id>
    <taglist></taglist>
  </shift>
  <shift>
    <id>16253</id>
    <user_id>543</user>
    <staff_member>Esmeralda Wible</staff_member>
    <start>Thu, 14 Dec 2006 01:12:39 GMT</start>
    <stop>Thu, 14 Dec 2006 01:20:12 GMT</stop>
    <time_zone>Australia/Perth</time_zone>
    <notes>Setting up Domain</notes>
    <project_id>2854</project_id>
    <taglist></taglist>
  </shift>
</shifts>
Get a list of all shifts belonging to a specific project

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/project/2854/shifts.xml

XML to send: None

Returns:

<shifts>
  <shift>
    <id>16253</id>
    <user_id>543</user>
    <staff_member>Esmeralda Wible</staff_member>
    <start>Wed, 13 Dec 2006 23:32:25 GMT</start>
    <stop> 14 Dec 2006 01:06:40 GMT</stop>
    <time_zone>Australia/Perth</time_zone>
    <notes>Initial Design Meeting</notes>
    <taglist></taglist>
  </shift>
  <shift>
    <id>16253</id>
    <user_id>543</user>
    <staff_member>Esmeralda Wible</staff_member>
    <start>Thu, 14 Dec 2006 01:12:39 GMT</start>
    <stop>Thu, 14 Dec 2006 01:20:12 GMT</stop>
    <time_zone>Australia/Perth</time_zone>
    <notes>Setting up Domain</notes>
    <taglist></taglist>
  </shift>
</shifts>
Get a project with a supplied id

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/shift/16253.xml

XML to send: None

Returns:

<shift>
  <id>16253</id>
  <user_id>543</user>
  <staff_member>Esmeralda Wible</staff_member>
  <start>Thu, 14 Dec 2006 01:12:39 GMT</start>
  <stop>Thu, 14 Dec 2006 01:20:12 GMT</stop>
  <time_zone>Australia/Perth</time_zone>
  <notes>Setting up Domain</notes>
  <project_id>2854</project_id>
  <taglist></taglist>
</shift>
Create a new shift

Note: For consistency, you can send the staff_member parameter in your data, but it will be ignored

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/project/2887/shifts.xml -X post -d [See below]

XML to send:

<shift>
  <start>Thu, 07 Mar 2007 13:07:23</start>
  <stop>Thu, 07 Mar 2007 13:53:12</stop>
  <time_zone>Australia/Perth</time_zone>
  <notes>Worked on new website design</notes>
</shift>

Returns: 201 - Created

Update a shift

Note: For consistency, you can send the staff_member parameter in your data, but it will be ignored

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/shift/89092.xml -X put -d [See below]

XML to send:

<shift>
  <start>Thu, 08 Mar 2007 13:07:23</start>
  <stop>Thu, 08 Mar 2007 13:53:12</stop>
  <time_zone>Australia/Perth</time_zone>
  <notes>Worked on new website design</notes>
</shift>

Returns: 200 - Success

Delete a shift

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/shift/89092.xml -X delete

XML to send: None

Returns: 200 - Success

Timezones

Get a list of all the timezones

curl -u 'username:password' -H 'Accept: application/xml' -H 'Content-type: application/xml' https://www.88miles.net/time_zones.xml -X get

XML to send: None

Returns: 200 - Success

<time_zones>
  <time_zone>
    <zone>Vatican</zone>
    <longitude>12.45</longitude>
    <latitude>41.9</latitude>
    <offset>1</offset>
    <dst>false</dst>
  </time_zone>
  <!-- Rest of them cut because there are lots of time_zones -->
</time_zones>

Dealing with Errors

When dealing with XML, any potential errors are handled by a psuedo-exceptions. The structure of the XML is below:

<errors>
  <error type="Project::ReadDenied">Sorry, you aren't allow to view that project</error>
</errors>

Here is a list of some of the Exception types:

Staff
NameDescription
User::ErrorGeneral errors
User::MaxTimeYou aren't able to enter any more time — you have already used entered the maximum time allowed on your account
User::MaxStaffYou aren't able to enter any more staff members — you have used created the maximum amount of staff allowed on you account
User::StaffNotAllowedThe account you have doesn't allow staff members
User::ReadDeniedYou aren't allowed to read the details of that staff member
User::UpdateDeniedYou aren't allowed to update the details of that staff member
User::DeleteDeniedYou aren't allowed to delete that staff member
Companies
NameDescription
Company::ErrorGeneral errors
Company::ParamMissingThe haven't supplied enough parameters in your query
Company::ReadDeniedYou aren't allowed to read the details of that company
Company::UpdateDeniedYou aren't allowed to update the details of that company
Company::DeleteDeniedYou aren't allowed to delete that company
Company::UserNotAllowedYou have tried to add a user to your company that isn't part of your user list
Projects
NameDescription
Project::ErrorGeneral errors
Project::ParamMissingThe haven't supplied enough parameters in your query
Project::ReadDeniedYou aren't allowed to read the details of that project
Project::UpdateDeniedYou aren't allowed to update the details of that project
Project::DeleteDeniedYou aren't allowed to delete that project
Project::ProjectInactiveThe project you are trying to punch in to is inactive
Project::PunchedInThe project you are trying to punch in to has already been punched in to
Project::PunchedOutThe project you are trying to punch out of has not been punched in to
Project::UserNotAllowedYou have tried to add a user to your project that isn't part of your user list
Shifts
NameDescription
Shift::ErrorGeneral errors
Shift::ParamMissingThe haven't supplied enough parameters in your query
Shift::ReadDeniedYou aren't allowed to read the details of that project
Shift::UpdateDeniedYou aren't allowed to update the details of that project
Shift::DeleteDeniedYou aren't allowed to delete that project