Tempo API Reference

We have exposed an API so that anyone who is so inclined can create alternative interfaces to Tempo or integrate Tempo with an external service. This document describes how to connect to the API and what resources and methods are available.

Requirements

Here’s an example of such a request, using curl:
curl -X GET -H 'Accept: application/xml' -H 'Content-Type: application/xml' \
  --user mylogin:mypassword https://app.keeptempo.com/entries

Since all Tempo accounts support SSL, it would be prudent of you to connect using https when accessing the API to protect your password from prying eyes.

RESTful Resources

All end-points in our API are REST-style resources, supporting the usual set of GET, PUT, POST and DELETE operations at RESTful URLs. Currently there are only two resources available, Entries and Projects, described below.

Resource: Entries

This is what a time entry looks like when rendered in XML by the API:

<entry>
  <command nil="true"></command>
  <created-at type="datetime">2008-03-31T15:06:46-04:00</created-at>
  <creator-id type="integer">2048</creator-id>
  <hours type="decimal">5.0</hours>
  <id type="integer">8192</id>
  <is-locked type="boolean">true</is-locked>
  <is-timing type="boolean" nil="true"></is-timing>
  <notes>client meeting in NYC to discuss project requirements</notes>
  <occurred-on type="datetime">2008-03-31T00:00:00-04:00</occurred-on>
  <project-id type="integer">4096</project-id>
  <source>twitter</source>
  <start-at type="datetime" nil="true"></start-at>
  <stop-at type="datetime" nil="true"></stop-at>
  <updated-at type="datetime">2008-06-09T13:31:06-04:00</updated-at>
  <user-id type="integer">2048</user-id>
  <tag-s>meetings discovery</tag-s>
</entry>

Not all fields may be updated directly; these are: :created_at, :creator_id, :id, :is_locked, :is_timing, :source, :start_at, :stop_at, :updated_at

Thus, when you want to create a new entry, you might supply a piece of XML like this:

<entry>
  <hours type="decimal">5.0</hours>
  <notes>client meeting in NYC to discuss project requirements</notes>
  <project-id type="integer">4096</project-id>
  <tag-s>meetings discovery</tag-s>
</entry>

Here’s how we’d post it using curl, and the response we get:

$ curl -X POST -T entry-sample.xml -H 'Accept: application/xml' \
  -H 'Content-Type: application/xml' --user billy:sekrit https://app.keeptempo.com/entries

The API will return the new entry to you as XML, or you’ll get an error response if a field was missing or incorrect:

<?xml version="1.0" encoding="UTF-8"?>
<errors>
  <error>Project can't be blank</error>
</errors>

Available URIs and methods

Special Fields / Tricks

Hours:

If you don’t supply the hours with an entry, you create a new entry that has zero hours to start with, and a timer running. Sending an otherwise blank entry with stop or starting another timer entry will stop the previous timer.

Start & Stop:

The start and stop methods affect whether or not an entry is timing. So a request to /entries/5/start would cause that entry to start timing, and sending a request to /entries/5/stop would halt the timer. Note that only one timer can be running at any time, so starting a timer on one entry stops any currently running timer on another entry. Timers can be re-started, and when stopped the time is added to any time already on the entry. Read more about timers here.

Entries & Search:

When the /entries method is called via GET, a list of entries is returned for the default ‘context’ of a new session in Tempo. The basic gist here is that the entries you’ll get back from calling GET on /entries will just be for the last week, and just for the current user. As a user normally interacts with Tempo, she clicks on projects, users and tags she is interested in reporting on, and often changes the date range, too. For a full discussion of how to search entries and change the context using the API, please see the search section below.

Resource: Projects

This is what a basic Tempo project looks like when requested from the API and rendered in XML:

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <basecamp-id nil="true"></basecamp-id>
  <created-at type="datetime">2008-03-31T10:03:32-04:00</created-at>
  <creator-id type="integer">1</creator-id>
  <estimated-hours type="decimal" nil="true"></estimated-hours>
  <id type="integer">1</id>
  <is-active type="boolean">true</is-active>
  <name>Personal</name>
  <updated-at type="datetime">2008-03-31T10:03:32-04:00</updated-at>
  <users type="array">
    <user>
      <email>billy@tankcrash.com</email>
      <id type="integer">1</id>
      <login>billy</login>
      <name>Billy Gray</name>
    </user>
  </users>
</project>

Not all fields may be updated directly; these are: :basecamp_id, :created_at, :creator_id, :id, :updated_at

The only required field when creating a project is :name. The project’s users are included for your convenience, as we have not exposed a users resource in the API just yet.

Thus, to create a new project, you could use an XML document like this:

<?xml version="1.0" encoding="UTF-8"?>
<project>
  <name>New Project</name>
</project>

Available URIs and methods

Note: The management of user assignments to projects and managerial delegation is not available through the API at this time.

Searching Entries via Context

POST https://app.keeptempo.com/entries/search

When requesting a set of entries from Tempo via search, you must provide a Context XML document. This is basically a set of parameters telling Tempo which entries you want. It allows you to specify which users to look at, projects, tags, and the date range. Here’s a full sample of the options:

<?xml version="1.0" encoding="UTF-8"?>
<context>
  <start-date>2008-01-01</start-date>
  <end-date>2008-06-01</end-date>
  <project-ids type="array">
    <project-id type="integer">1024</project-id>
    <project-id type="integer">2048</project-id>
    <project-id type="integer">8192</project-id>
  </project-ids>
  <user-ids type="array">
    <user-id type="integer">1024</user-id>
    <user-id type="integer">2048</user-id>
  </user-ids>
  <tags type="array">
    <tag>tempo</tag>
    <tag>support</tag>
  </tags>
</context>

Here’s an example of how you’d execute the search using curl, assuming you saved your XML in a file called ‘context.xml’:

curl -k -X POST -T context.xml -H 'Content-Type:application/xml' \
  -H 'Accept:application/xml' --user login:password \
  https://app.keeptempo.com/entries/search