This is the API for Basecamp Classic. Check out the API for the all new Basecamp at its new home on GitHub: https://github.com/37signals/bcx-api
The Basecamp Classic API is implemented as vanilla XML over HTTP using all four verbs (GET/POST/PUT/DELETE). Every resource, like Post, Comment, or TodoList, has their own URL and are manipulated in isolation. In other words, we've tried to make the API follow the REST principles as much as we can.
Authentication is managed using HTTP authentication (only "Basic" is supported right now). Every request must include the Authorization HTTP header. Use your API token as the username, and "X" (or some otherwise bogus text) as the password (only the API token is used for authenticating API requests). Example with Curl:
curl -H 'Accept: application/xml' -H 'Content-Type: application/xml' \
-u 653638dc733afce75130303fe6e6010f63768af0:X -d '<request>...</request>' https://url
Your API token can be found by logging into your Basecamp Classic account, clicking on the "My Info" link in the upper-right, and then clicking the "Show your tokens" at the bottom (under "Authentication tokens").
Be sure to set both the 'Content-Type' and 'Accept' headers to 'application/xml' to identify the request and response format. Example with Curl:
curl -H 'Accept: application/xml' -H 'Content-Type: application/xml' \
-u hoodlum:up2n0g00d \
-d '<todo-item><content>...</content></todo-item>' \
https://url/todo_lists/123/todo_items.xml
If a request succeeds, it will return a status code in the 200 range and often, an XML-formatted response. Note that, in general, if a request causes a new record to be created (like a new message, or to-do item, etc.), the response will use the "201 Created" status. Any other successful operation (like a successful query, delete, or update) will return a 200 status code. (You can look at the Ruby wrapper for more inspiration.)
If a request fails, a non-200 status code will be returned, possibly with error information in XML format as the response's content. For instance, if a requested record could not be found, the HTTP response might look something like:
HTTP/1.1 404 The record could not be found
Date: Thu, 16 Mar 2006 17:41:40 GMT
...
You can perform up to 500 requests per 10 second period from the same IP address for the same account. If you exceed this limit, you'll get a 503 response for subsequent requests. Check the Retry-After header to see how many seconds to wait before trying again.
A non-SSL request made against an account that has SSL enabled (and vice versa) will receive a "302 Found" response. The Location header will contain the correct URI.
If SSL is enabled for your account, ensure that you're using https. If it's not, ensure you're using http.
To make things easier to understand, the following notation is used:
#{text}:
Indicates text that should be replaced by your own data...:
Indicates content from the response has been elided for brevity in
documentation. See the list of data responses at the end of the page for
a full description of the format of that response type.Some operations, like creating messages or comments, or updating existing messages or comments, allow you to attach a file to the record. To do this via the API, you need to send a POST request to the "/upload" URI, with the HTTP Accept header set to 'application/xml'. The body of the request should be the content of the file you want to attach:
POST /upload HTTP/1.0
Accept: application/xml
Content-Type: application/octet-stream
Content-Length: 23123
... (file contents go here)
If the upload succeeds, you'll get an XML response back, telling you the ID of your upload. (Your upload is not yet associated with any record, and if you do not do anything with it, it will be deleted sometime within the next 30 minutes.)
HTTP/1.0 201 OK
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<upload><id>441b2cec.eve.21267</id></upload>
Armed with the ID, your next step is to attach the file to a record. Using the "create message" action, for instance, you pass an array of attachment data in. Assuming you had two files you wanted to attach (which you had previously uploaded, as described), your attachment data would look something like this (formatted as XML):
<attachments>
<name>A pretty sunset</name>
<file>
<file>441b2cec.eve.21267</file>
<content-type>image/jpg</content-type>
<original-filename>sunset.jpg</original-filename>
</file>
</attachments>
<attachments>
<name>The ocean</name>
<file>
<file>441b2fff.log.21285</file>
<content-type>image/png</content-type>
<original-filename>ocean.png</original-filename>
</file>
</attachments>
The Ruby wrapper implements this conversion for you--you can look at that implementation for inspiration, if you'd like.