Skip to content


Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
A thin client for the Pivotal Tracker API
branch: master

Revamped the way version is handled.

This allows us to bring back the Pivotal object import inside __init__
for a nicer API.
latest commit 279571a878
@robhudson authored orcasrob committed
Failed to load latest commit information.



Pivotal-Py is a very thin wrapper built on top of httplib2 to make requests against the Pivotal Tracker API.


Install from PyPI with easy_install or pip:

pip install pivotal-py


Pivotal-Py requires httplib2 0.6.0 or later.


This Pivotal Tracker API client uses the token to authenticate with Pivotal Tracker. You can get a token by going to your user profile and creating an API token.

Once you have an API token making requests against the APIs follows a simple pattern of chainable methods, for example:

import pivotal

pv = pivotal.Pivotal('TOKEN')

# Assuming a base URL of ''

# Perform a GET at /projects and processes content via ElementTree.
etree = pv.projects().get_etree()

# Perform the same GET at /projects but return the response and
# content direct from httplib2.
response, content = pv.projects().get()

Note: As seen above, there are two ways to get the content of a request:

  1. Call get_etree() to return the content as ElementTree object.
  2. Call get() to return the tuple containing both the response and content direct from httplib2.

Any positional arguments get pushed onto the URL:

# Perform a GET at /projects/[id]/stories where [id] is a project ID.
etree = pv.projects(id).stories().get_etree()

Any keyword arguments get mapped to the URL query string and appended at the end of the URL:

# Perform a GET at /projects/[id]/stories and filter stories by those that
# are not started.
etree = pv.projects(id).stories(filter='state:unstarted').get_etree()
# Results in a URL of: /projects/[id]/stories?filter=state%3Aunstarted

Note: POSTs are currently not implemented, but the plan is to implement a post method that takes a body argument which is the body of the POST:

# TODO: POST to /projects to create a new project
etree = pv.projects().post(xml_body)
Something went wrong with that request. Please try again.