API Example
The following is a simple introduction to the PostRank APIs and the interactions between the various APIs. Once finished, you should have a clear understanding of how the PostRank APIs fit together and be able to create your own applications utilizing those APIs.
Overview
There are two broad categories of APIs. Those requiring authentication and those that do not. The APIs requiring authentication center around subscription management and retrieving user channel information. We're going to start by looking at the authentication process and the APIs requiring authentication. Once that's done we'll start in on the un-authenticated APIs.
At any point you can refer to the API Documentation for more information on a specific API or greater explanation of the API parameters.
Authenticated APIs
If you want your application to use the authenticated APIs you'll need to register on the PostRank site to obtain a token and secret key. These are only needed to access the authenticated portion of the site.
Login to PostRank.com with your username and password. Once logged in you can access the developers portion of the site by clicking on the settings link presented at the top of the page. Select the Developer tab and you'll be presented with the Developer Resources section. Enter the name and main URL of your application and hit the Register button. You'll be presented with a Consumer Key and a Consumer Secret. Record these values somewhere as you'll need them later.

PostRank authentication uses OAuth. We use the standard OAuth endpoints: /oauth/request_token, /oauth/authorize and /oauth/access_token, so if your language of choice has an OAuth library you can use PostRank.com as the base URI and everything should work.
There are two cases you'll need to handle when dealing with authorization. If the user has never used your application before, PostRank needs them to authorize the application. If the user has previously used your application, it should have saved their secret and token.
Using the Ruby OAuth gem we can authorize a user as follows:
require 'rubygems'
gem 'oauth'
require 'oauth/consumer'
consumer = OAuth::Consumer.new('I2rJydezODTaWiaxdQ3nqA', # Consumer Key
'xpHNFxkAv7rngRqPFhB7FhytSi1CYg3gwTfakDQmXVg', # Consumer Secret
{:site => 'http://www.postrank.com'})
request_token = consumer.get_request_token
puts request_token.authorize_url # => http://www.postrank.com/oauth/authorize?oauth_token=rVFPYUBvYIXy1Wby1g5JAA
access_token = request_token.get_access_token
user_token = access_token.token #=> "7CMuH2TZziofq3ZAraEpqA"
user_secret = access_token.secret # => "ugaScelGJoBKir3qlJOJA5moiefKi3r85IG3eVz2Gc"
Before you can use the get_access_token method the user must go to the URL provided in the authorize_url call and allow the application access to their account information.
Once you've retrieved the access token you'll want to store the user_token and user_secret so the user doesn't have to re-authorize the application each time they try to use it.

For a user which has previously authorized the application you'd do the following:
require 'rubygems'
gem 'oauth'
require 'oauth/consumer'
consumer = OAuth::Consumer.new('I2rJydezODTaWiaxdQ3nqA', # Consumer Key
'xpHNFxkAv7rngRqPFhB7FhytSi1CYg3gwTfakDQmXVg', # Consumer Secret
{:site => 'http://www.postrank.com'})
access_token = OAuth::AccessToken.new(consumer, '7CMuH2TZziofq3ZAraEpqA', # User Token
'ugaScelGJoBKir3qlJOJA5moiefKi3r85IG3eVz2Gc') # User Secret
All of your requests to the server will be done through the access_token using the get, post, put and delete methods.
If your language of choice doesn't have a convenient OAuth library you can still authenticate with PostRank. You can refer to the OAuth specification to determine the correct commands to send to the server.
From this point onwards I'm going to assume you're using a library to access the authenticated APIs. All the examples will make the assumption that access_token has previously been created.
User Information
Before we look at the /v2/channel API we need the unique identifier for the current user. We can grab the users identifier and various other bits of information by using the /user/info API.
>> puts access_token.get('/user/info')
{"user": {"user_hash": "c6eb5f55517477ec6216d8c22c933e1fce3472f5", "email": "dj2@everburning.com"}}
We can retrieve the user information in JSON or XML format. The default is to return JSON. To request XML all you need to do is call /user/info.xml.
>> puts access_token.get('/user/info.xml')
<?xml version="1.0" encoding="UTF-8"?>
<user>
<email>dj2@everburning.com</email>
<user-hash>c6eb5f55517477ec6216d8c22c933e1fce3472f5</user-hash>
</user>
Subscription Information
The real juicy piece of authenticated information is the users subscriptions. These are the feeds that the user has subscribed to along with any PostRank filters, keyword filters and tags assigned to the subscription.
We can use the API to create, retrieve, update and delete the users subscriptions.
Retrieving Subscriptions
We can retrieve either all the users subscriptions or individual subscriptions. To retrieve all subscriptions we get /myfeeds/subscriptions. To retrieve a specific subscription we get /myfeeds/subscriptions/{id}. The subscriptions API will respond with JSON, XML or HTML depending on how it's queried.
>> puts access_token.get("/myfeeds/subscriptions.js")
[{"subscription": {"updated_at": "2008-10-15T03:30:42Z", "keyword_filter": "", "postrank_filter": 1.0,
"id": 17, "tag_list": "cocoa ruby ewl", "user_id": 5,
"feed_hash": "cb3e81ac96fb0ada1212dfce4f329474", "created_at": "2008-10-13T02:55:34Z"}},
{"subscription": {"updated_at": "2008-10-15T03:30:44Z", "keyword_filter": "", "postrank_filter": 1.0,
"id": 21, "tag_list": "foo ewl", "user_id": 5,
"feed_hash": "cb3e81ac96fb0ada1212dfce4f329474", "created_at": "2008-10-15T03:30:44Z"}},
{"subscription": {"updated_at": "2008-10-15T03:22:26Z", "keyword_filter": "", "postrank_filter": 1.0,
"id": 20, "tag_list": "cocoa ewl", "user_id": 5,
"feed_hash": "139400fb2b8206267ae7d7db523d30aa", "created_at": "2008-10-15T03:22:26Z"}}]
>> puts access_token.get("/myfeeds/subscriptions/17.js")
{"subscription": {"updated_at": "2008-10-15T03:30:42Z", "keyword_filter": "", "postrank_filter": 1.0,
"id": 17, "tag_list": "cocoa ruby ewl", "user_id": 5,
"feed_hash": "cb3e81ac96fb0ada1212dfce4f329474", "created_at": "2008-10-13T02:55:34Z"}}
We're using a HTTP GET request to retrieve the subscriptions and the .js syntax to request JSON output. You could also use .xml to retrieve XML output. Specifying no extension will return the information in HTML format.
The primary fields of interest are keyword_filter, tag_list, postrank_filter and feed_hash. We'll discuss how to retrieve and translate the feed hash value when we get to the /v2/feed/info API.
Updating Subscriptions
Updating a subscription is done by sending an HTTP PUT request with the new subscription values.
>> s = JSON.parse(access_token.get('/myfeeds/subscriptions/17.js').body)
=> {"subscription"=>{"updated_at"=>"2008-10-15T03:30:42Z", "keyword_filter"=>"",
"postrank_filter"=>1.0, "tag_list"=>"cocoa ruby ewl", "id"=>17,
"feed_hash"=>"cb3e81ac96fb0ada1212dfce4f329474", "user_id"=>5,
"created_at"=>"2008-10-13T02:55:34Z"}}
>> s['subscription']['postrank_filter'] = 7.2
>> puts access_token.put('/myfeeds/subscriptions/17.js', s.to_json,
{'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => 'Orderly'})
This example updates the postrank filter for subscription 17 to a value of 7.2. Note, if you're sending the information through JSON format, at least with the Ruby OAuth library, you need to specify the Accept and Content-Type headers for things to work correctly.
Creating New Subscriptions
Similar to updating a subscription we can create a new subscription. The main difference being we'll be sending an HTTP POST request to /myfeeds/subscriptions instead of a HTTP PUT request.
>> t
=> {"subscription"=>{"keyword_filter"=>"legendary", "postrank_filter"=>9.9,
"tag_list"=>"awesome excellent", "feed_hash"=>"cb3e81ac96fb0ada1212dfce4f329474"}}
>> access_token.post('/myfeeds/subscriptions.js', t.to_json,
{'Accept' => 'application/json',
'Content-Type' => 'application/json',
'User-Agent' => 'Orderly'})
Again, note that you need to specify the Accept and Content-Type headers if you're using the Ruby OAuth gem. Other OAuth libraries may not require these headers to be sent manually.
Deleting Subscriptions
The final piece of subscription management is deletion. We use the HTTP DELETE method with the /myfeeds/subscriptions/{id} endpoint.
>> puts access_token.delete('/myfeeds/subscriptions/21')
Open APIs
That's it for the authenticated APIs. The rest of these APIs don't require you to authenticate through OAuth before accessing them.
Feeds
Feeds are the building blocks of the system. Many of the other APIs require feed identifiers in order to do their work (you'll remember I mentioned the feed identifier required for the subscription API). There are two APIs centered around feeds: /v2/feed/info and /v2/feed. We're going to look at /v2/feed/info first and, using the information it returns, grab the full feed listing from the /v2/feed API.
Feed/Info
When we want to start working with a feed we need to convert the feed URL into an feed identifier. This is done by using the /v2/feed/info API. You provide the /v2/feed/info API with a feed identifier or URL and it will return information pertaining to that feed such as the description, ID, title and link for the given URL.
[root@rei-lab ~]# curl "http://api.postrank.com/v2/feed/info?appkey=postrank.com/example&id=everburning.com"
{ "ttl": 60, "xml": "http:\/\/everburning.com\/feed\/", "title": "everburning",
"id": "cb3e81ac96fb0ada1212dfce4f329474", "feed_id": 204053, "link": "http:\/\/everburning.com\/",
"description": "the taste of nonsense and chaos",
"image": { "title": "PostRank - Read what matters",
"url": "http:\/\/www.postrank.com\/images\/postrank_logo.gif",
"link": "http:\/\/www.postrank.com" } }
[root@rei-lab ~]# curl "http://api.postrank.com/v2/feed/cb3e81ac96fb0ada1212dfce4f329474/info?appkey=postrank.com/example"
{ "ttl": 60, "xml": "http:\/\/everburning.com\/feed\/", "title": "everburning",
"id": "cb3e81ac96fb0ada1212dfce4f329474", "feed_id": 204053, "link": "http:\/\/everburning.com\/",
"description": "the taste of nonsense and chaos",
"image": { "title": "PostRank",
"url": "http:\/\/www.postrank.com\/graphics\/postrank_logo.png",
"link": "http:\/\/www.postrank.com" } }
Feed
Once we've got the feed identifier we can query the /v2/feed API to retrieve the feed posts. We can specify the number of items we want returned using the num parameter. Using the start parameter we can iterate through all of the available posts.
[root@rei-lab ~]# curl "http://api.postrank.com/v2/feed/cb3e81ac96fb0ada1212dfce4f329474?appkey=postrank.com/example&num=1"
{ "items": [ { "pubdate": 1213645560, "title": "The Incredible Hulk", "feed_title": "everburning",
"feed_url": "http:\/\/everburning.com\/feed\/", "postrank": 1.0,
"id": "b2df2457449accac4b97c54f5af1b1a2",
"original_link": "http:\/\/everburning.com\/news\/the-incredible-hulk\/",
"link": "http:\/\/api.postrank.com\/log?url=http%3A%2F%2Feverburning.com%2Fnews%2Fthe-incredible-hulk%2F",
"content": "<p>I convinced <a href=\"http:\/\/perplexity.org\" onclick=\"javascript:pageTracker._trackPageview ('\/outbound\/perplexity.org');\">Stacy<\/a> to see <em>another superhero flick<\/em> on the weekend. I think the fact that Edward Norton is the star helped with that a bit.<\/p>\\\n<p>Anyway, while her opinion will differ, and I think it’s biased by her views going in, this movie was really well done. The animation is fantastic and it didn’t feel over the top. The hulk has visible and understandable facial emotions which I thought was pretty cool.<\/p>\\\n<p>I’d recommend this to anyone that wants to see a good action flick.<\/p>\\\n<p>The one thing I wasn’t able to sort out, does this movie ignore the first one or continue on? Stacy thinks it’s a continuation, I think it’s a ignore the first and start again.<\/p>\\\n<p>Either way, this movie felt like the hulk.<\/p>\\\n", "postrank_color": "#ffe08e", "description": "I convinced Stacy to see another superhero flick on the weekend. I think the fact that Edward Norton is the star helped with that a bit. Anyway, while her opinion will differ, and I think it' s biased by her views going in, this movie was really well done. The animation is fantastic and it didn' t feel over the top. The hulk has visible and understandable facial emotions which I thought was pretty cool. I' d recommend this to ..."
} ],
"meta": { "opensearch:itemsPerPage": 1,
"title": "everburning - AideRSS (PostRank: All)",
"opensearch:startIndex": 0,
"opensearch:totalResults": 43,
"postrank:searchPostrank": 1.0,
"image": { "title": "PostRank",
"url": "http:\/\/www.postrank.com\/graphics\/postrank_logo.png",
"link": "http:\/\/www.postrank.com" } } }
You can see in this example we're querying for one post from the feed with identifier cb3e81ac96fb0ada1212dfce4f329474. The information returned contains two main elements, items and meta. We can use items to iterate over all of the returned stories. Each story will contain a description, original link, link, content (trimmed), title, publication date and feed title. The meta section returns some extra meta data on the query. This data includes the number of items we attempted to retrieve (opensearch:itemsPerPage), the feed title (title), the start index we requested opensearch:startIndex, the total results available for the given feed (opensearch:totalResults) and the PostRank value used in the given request (postrank:searchPostrank).
Along with the start index and number of posts to return we could have provided a level parameter to specify that we're only interested in posts with a PostRank greater then the given value. The value is a float between 1.0 and 10.0 inclusive. The q parameter allows us to enter keyword filters. Only posts matching the provided filter will be returned. The filters accept boolean logic, doing OR by default.
PostRanks
The /v1/postrank API allows us to retrieve the feed based or thematic PostRank for a set of posts. The thematic PostRank gives you the PostRank for each provided post relative to the other provided posts. The feed based PostRank will return the PostRank of the given post in the given feed.
We interact with the /v1/postrank API by sending the URLs and feeds of interest in a POST request.
[root@rei-lab ~]# curl "http://api.postrank.com/postrank?appkey=postrank.com/example" -d "url[]=http://everburning.com/news/a-peek-at-ruby-internals/&url[]=http://everburning.com/news/forked-by-rspec/&url[]=http://everburning.com/news/introducing-ruby-postrank-05-beta/"
{ "http:\/\/everburning.com\/news\/introducing-ruby-postrank-05-beta\/": { "postrank": 5.0,
"postrank_color": "#ffaf61" },
"http:\/\/everburning.com\/news\/forked-by-rspec\/": { "postrank": 1.0,
"postrank_color": "#ffe08e" },
"http:\/\/everburning.com\/news\/a-peek-at-ruby-internals\/": { "postrank": 1.0,
"postrank_color": "#ffe08e" } }
The above is a thematic PostRank query. We provide the URLs to query by passing url[] key/value pairs to the API. The PostRank API will return a hash mapping the provided URL to the PostRank value and PostRank colour.
[root@rei-lab ~]# curl "http://api.postrank.com/postrank?appkey=postrank.com/example" -d "url[]=http://everburning.com/news/a-peek-at-ruby-internals/&url[]=http://everburning.com/news/forked-by-rspec/&url[]=http://everburning.com/news/introducing-ruby-postrank-05-beta/&feed_id[]=204053"
{ "http:\/\/everburning.com\/news\/introducing-ruby-postrank-05-beta\/": { "postrank": 9.6,
"postrank_color": "#ff752c" },
"http:\/\/everburning.com\/news\/forked-by-rspec\/": { "postrank": 1.0,
"postrank_color": "#ffe08e" },
"http:\/\/everburning.com\/news\/a-peek-at-ruby-internals\/": { "postrank": 1.0,
"postrank_color": "#ffe08e" } }
Similarly, we can get the feed based PostRank values for the same URLs. We do this by adding in the feed_id[] parameters. If you URLs were from several feeds you'd need to set a feed_id[] parameter for each URL. Since all my URLs are from a single feed the API is designed that it will reuse the last provided feed_id[] option to all the URLs missing a feed_id[] parameter.
You may have noticed a slight inconsistency with the /postrank API. Namely, the feed_id[] parameters aren't the same as the feed identifiers pass to the /v2/feed API. The PostRank API is still working off of the old feed identifiers which can be retrieved from /v2/feed/info as the feed_id value.
Channels
The final API we're going to look at is /v2/channel. If you remember back when we were looking at the /myfeeds/subscriptions endpoint each subscription had some optional tags associated with it. These tags can be passed to the channel API to retrieve a feed that contains the posts from the subscriptions containing the given tag. The posts returned will have the PostRank filters and keyword filters applied that are specified in the subscriptions.
[root@rei-lab ~]# curl "http://api.postrank.com/v2/channel/aabe36179cd12314620eb78776e652bd475e1580/cloud?appkey=postrank.com/example&num=1"
{ "items": [ { "pubdate": 1223063820, "title": "Forked by rSpec", "feed_title": "everburning",
"feed_url": "http:\/\/everburning.com\/feed\/", "postrank": 1.0,
"id": "a020c1c3a5b2aef1ab4a7307cf3d2cb6",
"original_link": "http:\/\/everburning.com\/news\/forked-by-rspec\/",
"link": "http:\/\/api.postrank.com\/log?url=http%3A%2F%2Feverburning.com%2Fnews%2Fforked-by-rspec%2F",
"postrank_color": "#ffe08e",
"content": "<p>So, I’ve been working at integrating some more of our test code into our automated build system at work and have spent a day trying to figure out why everything was failing with the tests. They ran fine in my lab, they’d run fine individually but when I used rake to run them everything would bomb.<\/p>\n<p>Eventually, I found out that all the rspec tests were being run twice. The first set of tests all passed the second set all failed. After a while I also realized the second set of tests were being run in the background. Odd, very odd.<\/p>\n<p>Fast forward another hour, a lot of digging in the rspec code and I realized it’s because we fork inside the spec files. We fork and execute the server we want to test. rSpec sets up an <em>at_exit<\/em> handler to run the specs at exit if they haven’t been run. That at_exit handler would run number of forks + 1 times for each spec file.<\/p>\n<p>I finally found <a href=\"http:\/\/blog.hiremaga.com\/2008\/01\/31\/dont-get-forked-by-rspec\/\" onclick=\"javascript:pageTracker._trackPageview ('\/outbound\/blog.hiremaga.com');\">Don\u2019t get forked by rSpec<\/a>, setup the <code>at_exit { exit! }<\/code> code in my spec files and everything is happy again.<\/p>\n<p>Wheeee…<\/p>\n",
"description": "So, I' ve been working at integrating some more of our test code into our automated build system at work and have spent a day trying to figure out why everything was failing with the tests. They ran fine in my lab, they' d run fine individually but when I used rake to run them everything would bomb. Eventually, I found out that all the rspec tests were being run twice. The first set of tests all passed the second ..." } ],
"meta": { "opensearch:itemsPerPage": 1, "ttl": 60, "pubDate": "Fri, 17 Oct 2008 21:21:51 GMT",
"title": "Cloud Channel - (aabe36179cd12314620eb78776e652bd475e1580) AideRSS",
"opensearch:startIndex": 0, "description": "Merged and filtered feed.",
"link": "http:\/\/www.aiders.com",
"image": { "title": "PostRank",
"url": "http:\/\/www.postrank.com\/graphics\/postrank_logo.png",
"link": "http:\/\/www.postrank.com" },
"lastBuildDate": "Fri, 17 Oct 2008 21:21:51 GMT" } }
The returned results are similar to those seen in the feed API with the inclusion of PostRank information for each post. The one big difference with this API compared to the feed API is that we return the full post contents in the content field.
Conclusions
So, that was the whirlwind introduction to the APIs that we're providing. Hopefully with that, and the API Documentation you should be able to get your application up and using PostRank without too much trouble. If you've got any questions please let us know.