API Conventions

APIs are about standards. We've worked hard to establish some sensible conventions in forming our API; some are industry standards, many are inspired by our favorite APIs.

Understand these common conventions in the Kiva API and making sense of the rest should be a breeze.

RESTful

First and foremost, the Kiva API is a web-service API. It works like the web (e.g., HTTP) and works well with the tools of the web (e.g., browsers). More specifically, the Kiva API is a RESTful web-service API. To us, “REST” means that our API is resource-oriented where the method calls are actually URLs that point to data you fetch or modify. The “ful” part of this means we not that picky about a formal definition of REST and actually quite happy to use our intuition about things as we go along.

At Kiva, our resources are generally the nouns you think of when visit our site – Loans, Lenders, Field Partners, and Lending Teams. Thus, in true RESTful fashion, if you wanted to fetch data about a loan at Kiva, you'd make an HTTP GET request accompanied by the proper URI for the loan about which you want information. To create a loan, you might send a POST request to a similar URI. Since the Kiva API currently only supports fetching data, you only need to concern yourself with GET requests for now.

Generally, the RESTful nature of an API is wrapped up on the manner in which that API lets users modify, remove, or fetch data. However, it has some healthy implications for how other very important parts of the API work too.

Response Formats

If you make a Kiva API call, you're guaranteed some kind of response. If you make a successful call you'll get an HTTP response with a status 200 OK and the content of that response will usually be data, serialized in some meaningful way.

You can request response data from any Kiva API call in one of two formats, JSON or XML. (Some calls are available in feed-based formats, which we talk about later.) The format depends on which extension you append to the end of your URL request. This call returns the newest loans at Kiva as JSON:

http://api.kivaws.org/v1/loans/newest.json

This call returns the same data as XML:

http://api.kivaws.org/v1/loans/newest.xml

Simple. The format you choose probably depends on what you're most familiar with and what tools you have available to you. If you can't decide, we suggest JSON because it's concise, predictable, and all-around awesome. Some would say it is beautiful. We won't hide the fact that it is our favorite of the two. In fact, most of our data responses are designed for JSON first, then translated to XML systematically.

Because XML is by definition, extensible, it also means that saying we support XML responses doesn't provide much detail how the data might be structured. Really useful XML documents often conform to a more specific standard tied to the data they represent. In choosing our convention for XML, our first goal was to make it intuitive, and the second was to make it easily de-serializable. That is, we wanted to make the data easy to organize into an in-memory data structure such as a PHP array or a hash in Ruby. The JSON format already has this property so we created a few rules to help translate hierarchical data into XML reliably.

  • Data responses are made up of ordered arrays, associative arrays (hashes), and strings.
  • The root of the data response is always an associative array.
  • Associative arrays are composed of keys and values. Keys translate to XML elements where the name of the key is the name of the element. The value of the element can be a string or another element depending on value type.
  • Associative arrays themselves are elements with keys as child elements. The array takes its name from the respective key from the parent array. The root array always takes the name response.
  • Ordered arrays also translate to named elements, but their child elements are different. The children take their name from the singular version of the parent (eg, “loans” becomes “loan”). Also, the parent element representing the array has an attribute type with the value of “list.”

As an example, here's a simplified API response in JSON:

{ "people": [ {"name":"Jeremy","id":2}, {"name":"Roma","id":38}, {"name":"Zvi","id":21} ] }

And here's how this same data translates to XML:

<response> <people type="list"> <person><name>Jeremy</name><id>2</id></person> <person><name>Roma</name><id>38</id></person> <person><name>Zvi</name><id>21</id></person> </people> </response>

Test Responses

We haven't told the full story yet. Actually, we've baked in a very special response format to every API call that we think will be really helpful for testing the Kiva API or debugging programs built on the API. Since our API is RESTful, it is trivial to call from a web browser, but JSON and XML are designed for computers to read, not humans. We thought it would be handy to provide an HTML response format that makes it easy for humans to play around with the API using any common browser. To try this out, click on this link:

http://api.kivaws.org/v1/loans/newest.html

Viola! We simply subbed out our old response extension for an HTML extension. In fact, this also works if you don't provide an extension at all. Compare this to what happens in your browser if try to request a JSON response instead.

Responses as Feeds

Some API calls can also return responses formatted as a syndicated feed, such as RSS. These are really useful with many consumer tools which have powerful built-in capabilities for tracking, presenting, and mashing up feeds. Since working with feeds can be very different than working with standard API responses, feeds have their own section. Just note that if you request a feed format for an API method which doesn't support it, you'll get an error.

JSONP

JSONP is an unofficial protocol that allows scripts to work around the "same origin policy", permitting client-side scripts to easily access JSON data originating on a different server. There are some risks, and generally we encourage developers to retrieve and verify JSON on the server side. However, due to significant demand, we've decided to add JSONP support as well. If you add a "jsonp= ... " parameter to any .json request, the JSON will come back wrapped in a function call to the callback you've specified.

As an example, the simplified API response above, if requested with a "jsonp=my_js_function" GET parameter, would come back as follows:

my_js_function({ "people": [ {"name":"Jeremy","id":2}, {"name":"Roma","id":38}, {"name":"Zvi","id":21} ] })

As this is now javascript rather than pure JSON, the "Content-type" header of the API response will be "text/javascript" rather than "application/json".

Errors

Like any good RESTful service, your first clue to how your API request went is the HTTP status code. If it's something other than 200 OK, something went awry. While some such responses might be informational (300s), most will be errors, either yours (400s) or ours (500s).

Here are some common HTTP error codes you might see in your responses:

400 Bad Request
Something was wrong with your request. More than likely, you passed in a bad parameter value.
401 Unauthorized
The request you made requires authorization yet no credentials were provided. Likely, you forgot an Authorization header for a resource that requires it.
403 Forbidden
Your request was understood by the server and rejected it. This is common when you request sensitive resources insecurely (eg, not using HTTPS to access user-sensitive data), or if your authorization credentials don’t match up with data your are trying to access - for example you supply Lender credentials to access private data for a Partner.
404 Not Found
We couldn't find the resource you requested. In other words, your URI was probably incorrect. It may be the case of a non-existent resource name or a bad ID parameter.
405 Method Not Allowed
The resource you requested is valid, but it doesn't support the HTTP method you used to access it. For example, you may have sent a POST request for a resource only available by a GET request.
500 Internal Server Error
This one's our fault. Kindly post to the forum if you see this so we can look into it.
503 Service Unavailable
The Kiva servers are overloaded or down for maintenance. In the latter case, we'll typically add a Retry-After header that lets you know when things might be back up.

HTTP status codes are good for web tools, but fancy software programs and humans deserve more. That's why every error response will also have a simple content body with more detail on your error. We provide a computer-friendly code and a human-friendly message both serialized in the response format you specified. If you made a GET request for this URI:

http://api.kivaws.org/v1/gobbledygook.json

here's what you'd get:

{ "code":"org.kiva.InvalidResource" "message":"We could’t find the resource you were trying to access. Check your URL to confirm it’s a valid API endpoint. Check your HTTP request method (GET, POST, etc.) to make sure it is supported by the corresponding endpoint." }

XML responses look similar with a root element of error. Test responses in HTML will also show you the HTTP status code in the HTML response. Errors for a feed format (RSS, ATOM, etc.) will default to HTML output.

The message value in errors is our attempt to help you resolve the problem with your call. For instance, if you pass in a bad parameter, we'll tell you which parameter didn't make the cut. The code value is a unique string in reverse-domain notation that your application can test against to get finer granularity on what happened outside of the HTTP status. You may choose to use this code to pass on a localized error message to your users in certain conditions. Here's a list of some of the more common codes:

org.kiva.InvalidResource
The URI in your request was malformed so we don't know what resources you're looking for. Perhaps the API endpoint you want to call doesn't exist or you might have a poorly formed parameter in the URI that is causing problems.
org.kiva.MalformedParameter
You passed in a value that was outside the bounds of what we allow for a particular parameter.
org.kiva.InvalidIdentifier
You passed in an value for a identifier parameter that does not correspond to anything we know about. For example, '111' is not a valid ID for a loan.
org.kiva.HttpsRequired
You are trying to use HTTP to access a resource that is only available via HTTPS.
org.kiva.ServerMaintenance
We're upgrading our servers to make Kiva better and the Kiva API is not available at this time. Try again later.

Parameters

In a RESTful API, parameters are a bit of a misnomer since the focus is usually on the unique URI you send with your HTTP request. Still, most developers think in terms of functional API calls so we think it helps to talk a bit about what parameters look like in our system.

The most important distinction is between required and optional parameters. You can't make an API request without a required parameter, and there is no such thing as a default value for something that's required. Because they are so essential and distinctive, required parameters always tend to pop up in the middle of our API URIs rather than somewhere at the end (i.e., the query string). For example, check out this call for detail about a loan:

http://api.kivaws.org/v1/loan/76950.xml

This request looks like a simple URL, but we call this API method loan/<id> because the value 76950 is actually a required parameter. If you changed the value to 76961 it is intuitive that you'd get data back for a different loan, which is part of the beauty of the API being RESTful.

Optional parameters usually come in the query string of the HTTP request. Sometimes they have default values too. Check out these API calls:

http://api.kivaws.org/v1/search.json http://api.kivaws.org/v1/search.json?page=1

These two calls return the same data because page is an optional parameter that has a default value of 1. Since it is passed in the query string and not a part of the main URI, it's also pretty intuitive that you don't need it for a call.

All parameters to Kiva API calls are validated. We do this mainly to protect you from making mistakes. We'd hate it if you felt responsible for accidentally screwing things up here at Kiva, but more importantly we want to give you the right feedback so you know how to fix your request. When you pass bad parameter values to an API call, we'll let you know with an error response.

Any parameter might have a unique set of restrictions, but there are some common types we refer to in our documentation:

boolean
an integer value, 0 or 1
integer
an signed integer value, 0 or 1
number
any number, including signed floats
string
almost everything else
array
a comma-delimited list of any of the above

The most significant of these basic types is the array since it's able to include values of other types. Arrays are powerful in that they let you easily make requests for lots of different data, or different types of data at once. Whitespace is respected both before and after the comma delimiter when parsing values in an array. It's okay to have an array parameter with only one value (i.e., no commas), but arrays cannot contain other arrays. Here's an example of an API call that accepts an array value:

http://api.kivaws.org/v1/loans/76950,277,37541.xml

This is call is just like one of our earlier examples except that instead of fetching the data for just one loan, we can fetch the data for three.

app_id

Every method call can accommodate app_id as a parameter. This is a value that uniquely identifies your application apart from others calling the API. It is only used for tracking purposes. You're free to send any valid value you wish.

If sent, an App ID must be a string in reverse-DNS notation at least 8 characters in length. Only alphanumeric characters, dashes, and dots are allowed. (A-Z a-z 0-9 '.' '-') Unicode and high-ASCII characters are not recommended as they are not reliably supported in URIs. If you send an invalid App ID in your API request, you may receive an error response.

We suggest you use a reversed-DNS prefix you own (like org.kiva) to ensure uniqueness of your ID. Using someone else's App ID is pointless, other than inflating someone else's statistics. We don't use App IDs for rate-limiting or security. Examples of App IDs in the suggested format include:

org.kiva.build com.foo.myGreatApplication

In addition to including app_id in API calls, you can use them in referral links to the Kiva website. This helps us track which applications are sending traffic to Kiva and driving other actions, like lending or joining teams. Check out some examples here

Paging

If not for paging, most responses from the Kiva API would be unreasonably large for sending to thousands of requesters every hour. For example, there are over 80,000 loans at Kiva and nearly half a million lenders — each of these data sets are easily several megabytes large. Moreover, most applications can only use or represent a fraction of the data at a time anyway. Paging the data responses helps keep data exchange sane both for Kiva and applications.

We chose a simple model for data paging where page sizes are fixed for any one particular type of data. For example, loan listings currently come 20 to a page; lender listings are offered 50 to a page. Applications should not expect the page size for anyone type of data to stay constant forever, but we also don't plan to change a page size unless we come across a really good reason to do so. Since page sizes are fixed, you only have to supply a page number to pick a cross-section out of a large data response. The default page number for any applicable API method is always 1. For example if you request the list of newest loans suppling no parameters, you'll get paging information in your response that looks something like this (sans comments):

"paging": { "page": 1 // the current page represented "total": 105 // the total number of loan listings for this call "page_size": 20 // the number of listings returned per page "pages": 6 // the total number of pages available }

To get the full list of fundraising loans in this case, you'd need to call the same API method 5 more times with each of the page numbers 2 through 6. Currently, calling the method with page number 7 would return no results.

Kiva