Plurk API provides a standard way of accessing and implementing applications on top of the Plurk platform. The API is a simple HTTP API that can be accessed from any language that supports creation of HTTP requests.
You can contact us if you have any problems or wish to report bugs.
The API returns JSON encoded data. You should use a JSON library to decode the data returned. Some good JSON libraries are simplejson (Python), JSON.simple (Java) or json (Ruby).
The current limit is 50.000 calls pr. day. If you need more than this contact us with a description of what you are making.
Tools:
Implementations:
You need an API key to use the Plurk API. Getting one is easy thought, simply use this form an we'll email you an API key:
Example of using Plurk API from Python (using only Python standard library). In this example we login and plurk a hello world message :)
NOTE: In your real code you should do HTTPS requests to /API/Users/login, /API/Users/register and /API/Users/update.
#--- Setup ----------------------------------------------
import urllib, urllib2, cookielib opener = urllib2.build_opener(urllib2.HTTPCookieProcessor()) api_key = 'dKkIdUCoHo7vUDPjd3zE0bRvdm5a9sQi' get_api_url = lambda x: 'http://www.plurk.com/API%s' % x encode = urllib.urlencode #--- Requests ---------------------------------------------- fp = opener.open(get_api_url('/Users/login'), encode({'username': 'user_x', 'password': 'user_x_pw', 'api_key': api_key})) print fp.read() fp = opener.open(get_api_url('/Timeline/plurkAdd'), encode({'content': 'hello world', 'qualifier': 'says', 'lang': 'en', 'api_key': api_key})) print fp.read()
Here's how to login and plurk a message using Java and Apache's HttpClient library (which we recommend, since it offers a higher abstractions than Java's standard library).
NOTE: In your real code you should do HTTPS requests to /API/Users/login, /API/Users/register and /API/Users/update.
import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; public class TestClass { private static String API_KEY = "dKkIdUCoHo7vUDPjd3zE0bRvdm5a9sQi"; public static String getApiUri(String uri) { return "http://www.plurk.com/API" + uri; } public final static void main(String[] args) throws Exception { HttpClient httpclient = new DefaultHttpClient(); HttpGet httpget = new HttpGet(getApiUri("/Users/login?"+ "api_key=" + API_KEY + "&" + "username=" + "user_x" + "&" + "password=" + "user_x_pw" )); ResponseHandler responseHandler = new BasicResponseHandler(); System.out.println(httpclient.execute(httpget, responseHandler)); httpget = new HttpGet(getApiUri("/Timeline/plurkAdd?"+ "api_key=" + API_KEY + "&" + "content=" + "Hello+nasty" + "&" + "qualifier=" + "says" + "&" + "lang=en" )); responseHandler = new BasicResponseHandler(); System.out.println(httpclient.execute(httpget, responseHandler)); httpclient.getConnectionManager().shutdown(); } }
{"responses_seen": 0, "qualifier": "thinks", "plurk_id": 90812, "response_count": 0, "limited_to": null, "no_comments": 0, "is_unread": 1, "lang": "en", "content_raw": "test me out", "user_id": 1, "plurk_type": 0, "content": "test me out", "qualifier_translated": "thinks", "posted": "Fri, 05 Jun 2009 23:07:13 GMT", "owner_id": 1}
{"lang": "en", "posted": "Fri, 05 Jun 2009 23:07:13 GMT", "qualifier": "thinks", "plurk_id": 90812, "owner_id": 1, "content": "test me out", "user_id": 1, "is_unread": 1, "no_comments": 0, "plurk_type": 0}
null. If the Plurk is posted to a user's friends then limited_to is [0]. If limited_to is [1,2,6,3] then it's posted only to these user ids.
{"display_name": "amix3", "gender": 0, "nick_name": "amix", "has_profile_image": 1, "id": 1, "avatar": null}
For other type of requests, such as viewing a friend list or a profile, the data returned will be larger:
{"display_name": "Alexey", "is_channel": 0, "nick_name": "Scoundrel", "has_profile_image": 1, "location": "Canada", "date_of_birth": "Sat, 19 Mar 1983 00:00:00 GMT", "relationship": "not_saying", "avatar": 3, "full_name": "Alexey Kovyrin", "gender": 1, "page_title": "", "recruited": 6, "id": 5, "karma": 33.5}
amix.Amir S. Only set if it's non empty.Aarhus Denmark.Amir Salihefendic.not_saying, single,
married, divorced,
engaged, in_relationship,
complicated, widowed,
open_relationship user_id specifies user's id while avatar specifies the profile image version.
If has_profile_image == 1 and avatar == null then the avatar is:
http://avatars.plurk.com/{user_id}-small.gif
http://avatars.plurk.com/{user_id}-medium.gif
http://avatars.plurk.com/{user_id}-big.jpg
http://avatars.plurk.com/{user_id}-small{avatar}.gif
http://avatars.plurk.com/{user_id}-medium{avatar}.gif
http://avatars.plurk.com/{user_id}-big{avatar}.jpg
http://www.plurk.com/static/default_small.gif
http://www.plurk.com/static/default_medium.gif
http://www.plurk.com/static/default_big.gif
male or female.YYYY-MM-DD, example 1985-05-13.{"id": 42, "nick_name": "frodo_b", ...}{"error_text": "Email invalid"} as body{"error_text": "User already found"} as body{"error_text": "Email already found"} as body{"error_text": "Password too small"} as body{"error_text": "Nick name must be at least 3 characters long"} as body{"error_text": "Nick name can only contain letters, numbers and _"} as body{"error_text": "Internal service error. Please, try later"} as body/API/Profile/getOwnProfile. Should be HTTPS. "1" then the common data is not returned.
Use this if you only want to login the user and don't plan to use the data that's supplied by /API/Profile/getOwnProfile./API/Profile/getOwnProfile if no_data isn't set.
no_data is set to "1" then {"success_text": "ok"} is returned.
{"error_text": "Invalid login"} as body{"error_text": "Too many logins"} as body{"success_text": "ok"} if the user is logged out.world (whole world can view the profile), only_friends (only friends can view the profile) or only_me (only the user can view own plurks).YYYY-MM-DD, example 1985-05-13.{"id": 42, "nick_name": "frodo_b", ...}{"error_text": "Invalid current password"} as body{"error_text": "Email invalid"} as body{"error_text": "Email already found"} as body{"error_text": "Password too small"} as body{"error_text": "Display name too long, should be less than 15 characters long"} as body{"error_text": "Internal service error. Please, try later"} as body/API/Users/updatePicture.
The picture will be scaled down to 3 versions: big, medium and small. The optimal size of profile_image should be 195x195 pixels.
{"id": 42, "nick_name": "frodo_b", ...}{"error_text": "Requires login"} as body{"error_text": "Not supported image format or image too big"} as body{"error_text": "Requires login"} as bodyuser_id of the public profile. Can be integer (like 34) or nick name (like amix).{"error_text": "Invalid user_id"} as body{"error_text": "User not found"} as bodyGet instant notifications when there are new plurks and responses on a user's timeline. This is much more efficient and faster than polling so please use it!
This API works like this:
/API/Realtime/getUserChannel and in it you get an unique channel to currnetly logged in user's timeline
{"comet_server": "http://comet03.plurk.com/comet/1235515351741/?channel=generic-4-f733d8522327edf87b4d1651e6395a6cca0807a0",
"channel_name": "generic-4-f733d8522327edf87b4d1651e6395a6cca0807a0"}
You'll get an URL from /API/Realtime/getUserChannel and you do GET requests to this URL to get new data.
Your request will sleep for about 50 seconds before returning a response if there is no new data added to your channel.
You won't get notifications on responses that the logged in user adds, but you will get notifications for new plurks.
/API/Realtime/getUserChannel channel_name parameter.
new_offset.
{"new_offset": -1} {"new_offset": 3} {"new_offset": 21, "data": [{"plurk_id": 241392217, "response_count": 12, "type": "new_response", "response": {"lang":"en", "content_raw":"@Zap: (cozy)", ...},"user": {"5737406": {"display_name":"","uid":5737406, ...}}, "_cid": 21}]} {"new_offset": 27, "data": [{"lang":"en", "content":"test another", "content_raw":"test another", "user_id":1, "plurk_type":1, "plurk_id":241403675, "type":"new_plurk", "response_count":0, "favorite":false, "qualifier":"says", "id":241403675, "is_unread":0, "responses_seen":0, "posted":"Tue, 02 Mar 2010 16:21:29 GMT", "limited_to":"|1||1|", "no_comments":0, "favorite_count":0, "owner_id":1, "_cid":27}]} {"new_offset": -3}
You should use this call to find out if there any new plurks posted to the user's timeline.
It's much more efficient than doing it with /API/Timeline/getPlurks, so please use it :)
2009-6-20T21:55:34.
{"plurks": [{"plurk_id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", "lang": "en" ...}, ...], "plurk_users": {"3": {"id": 3, "nick_name": "alvin", ...}} {"error_text": "Requires login"} as bodyUse this call to find out if there are unread plurks on a user's timeline.
{"all": 2, "my": 1, "private": 1, "responded": 0} {"error_text": "Requires login"} as body{"plurks": {"plurk_id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", "lang": "en" ...}, ...], "user": {"id": 3, "nick_name": "alvin", ...}} {"error_text": "Plurk owner not found"} as body{"error_text": "Plurk not found"} as body{"error_text": "No permissions"} as body2009-6-20T21:55:34.
20.
{"plurks": [{"plurk_id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", "lang": "en" ...}, ...], "plurk_users": {"3": {"id": 3, "nick_name": "alvin", ...}} {"error_text": "Requires login"} as body2009-6-20T21:55:34.
{"plurks": [{"plurk_id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", "lang": "en" ...}, ...], "plurk_users": {"3": {"id": 3, "nick_name": "alvin", ...}} {"error_text": "Requires login"} as bodylimited_to should be a JSON list of friend ids, e.g. limited_to of [3,4,66,34] will only be plurked to these user ids.
If limited_to is [0] then the Plurk is privatley posted to the poster's friends.
{"plurk_id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", "lang": "en" ...} {"error_text": "Requires login"} as body{"error_text": "Invalid data"} as body{"error_text": "Must be friends"} as body{"error_text": "Content is empty"} as body{"error_text": "anti-flood-same-content"} as body{"error_text": "anti-flood-too-many-new"} as body{"success_text": "ok"} if the plurk is deleted{"error_text": "Requires login"} as body{"error_text": "Plurk not found"} as body{"error_text": "No permissions"} as body{"plurk_id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", "lang": "en" ...}{"error_text": "Requires login"} as body{"error_text": "Plurk not found"} as body{"error_text": "No permissions"} as body[342,23242,2323] {"success_text": "ok"} if the plurks are muted{"error_text": "Requires login"} as body[342,23242,2323] {"success_text": "ok"} if the plurks are unmuted{"error_text": "Requires login"} as body[342,23242,2323] true responses_seen of the plurks will be updated as well (to match response_count).
{"success_text": "ok"} if the plurks are marked as read{"error_text": "Requires login"} as body
To upload a picture to Plurk, you should do a multipart/form-data POST request to /API/Timeline/uploadPicture. This will add the picture to Plurk's CDN network and return a image link that you can add to /API/Timeline/plurkAdd
Plurk will automatically scale down the image and create a thumbnail.
{"full": "http://images.plurk.com/3466076_9b41abf90c623ba18f6ada5c1d37156f.jpg", "thumbnail": "http://images.plurk.com/tn_3466076_9b41abf90c623ba18f6ada5c1d37156f.gif"}.
{"error_text": "Requires login"} as body{"error_text": "Invalid file"} as bodyplurk_id and some basic info about the users.
{"friends": {"3": ...}, "responses_seen": 2, "responses": [{"lang": "en", "content_raw": "Reforms...}} {"error_text": "Requires login"} as body{"error_text": "Invalid data"} as body{"error_text": "Plurk not found"} as body{"error_text": "No permissions"} as bodyplurk_id. Language is inherited from the plurk.
{"id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", ...} {"error_text": "Requires login"} as body{"error_text": "Invalid data"} as body{"error_text": "Content is empty"} as body{"error_text": "Plurk not found"} as body{"error_text": "No permissions"} as body{"error_text": "anti-flood-same-content"} as body{"error_text": "anti-flood-too-many-new"} as body{"success_text": "ok"} if the response has been deleted.{"error_text": "Requires login"} as body{"error_text": "Invalid data"} as body{"error_text": "No permissions"} as bodyuser_id's friend list in chucks of 10 friends at a time.
[{"id": 3, "nick_name": "alvin", ...}, ...]user_id's fans list in chucks of 10 fans at a time.
[{"id": 3, "nick_name": "alvin", ...}, ...]users that the current logged in user follows as fan - in chucks of 10 fans at a time.
[{"id": 3, "nick_name": "alvin", ...}, ...]friend_id. User with friend_id has to accept a friendship.
{"success_text": "ok"} if a friend request has been made.{"error_text": "User can't be befriended"} as body{"error_text": "User already befriended"} as bodyfriend_id. friend_id won't be notified.
{"success_text": "ok"} if friend_id has been removed as friend.fan_id. To stop being a fan of someone, user /API/FriendsFans/setFollowing?fan_id=FAN_ID&follow=false.
{"success_text": "ok"} if the current logged in user is a fan of fan_id.user_id. A user can befriend someone, but can unfollow them. This request is also used to stop following someone as a fan.
true if the user should be followed, and false if the user should be unfollowed.
{"success_text": "ok"} if following information is updated.{"error_text": "User must be befriended before you can follow them"} as body{"2": {"nick_name": "kan", "full_name": "Kan Kan"}, "4": {"nick_name": "mitsuhiko", ...}, ...} Friendship request:
{"type": "friendship_request", "from_user": {"nick_name": ...}, "posted": ...}
Friendship pending:
{"type": "friendship_pending", "to_user": {"nick_name": ...}, "posted": ...}
New fan notification: (does not require actions from the user)
{"type": "new_fan", "new_fan": {"nick_name": ...}, "posted": ...}
Friendship accepted notification: (does not require actions from the user)
{"type": "friendship_accepted", "friend_info": {"nick_name": ...}, "posted": ...}
New friend notification: (does not require actions from the user)
{"type": "new_friend", "new_friend": {"nick_name": ...}, "posted": ...}
[{"id": 42, "nick_name": "frodo_b", ...}, ...] JSON object of all the active alerts{"error_text": "Requires login"} as body[{"nick_name": "frodo_b", ...}, ...] JSON object of all the history alerts{"error_text": "Requires login"} as bodyuser_id as fan.
{"success_text": "ok"}{"error_text": "Requires login"} as body{"success_text": "ok"}{"error_text": "Requires login"} as body{"success_text": "ok"}{"error_text": "Requires login"} as bodyuser_id as friend.
{"success_text": "ok"}{"error_text": "Requires login"} as bodyuser_id.
{"success_text": "ok"}{"error_text": "Requires login"} as bodyuser_id.
{"success_text": "ok"}{"error_text": "Requires login"} as bodyplurk_id of the oldest Plurk in the last search result.
[{"id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", ...}, ...]query, users are sorted by karma.
[{"id": 3, "content": "Test", "qualifier_translated": "says", "qualifier": "says", ...}, ...]
{"karma": {"0": [[":-))", "http:\/\/statics.plurk.com\/XXX.gif"], ...], ...},
"recuited": {"10": [["(bigeyes)", "http:\/\/statics.plurk.com\/XXX.gif"], ...], ...}
}
emoticons["karma"][25] denotes that the user has to have karma over 25 to use these emoticons. emoticons["recuited"][10] means that the user has to have user.recuited >= 10 to use these emoticons. It's important to check for these things on the client as well, since the emoticon levels are checked in the models.
{"total": 12, "users": {"display_name": "amix3", "gender": 0, "nick_name": "amix", "has_profile_image": 1, "id": 1, "avatar": null}, ...]}{"success_text": "ok"}{"success_text": "ok"}["Homies", "Coders", ...] [{"display_name": "amix3", "gender": 0, "nick_name": "amix", "has_profile_image": 1, "id": 1, "avatar": null}, ...] {"success_text": "ok"} {"success_text": "ok"} {"success_text": "ok"} {"error_text": "Clique not created"} as body{"success_text": "ok"} {"error_text": "Clique not created"} as body