The API is a JSON-based API, in which parameters are sent to the server via traditional URL-based encoding, and responses are sent back to the client in Json format.
Log-in to OkCupid via the login service, detailed below. That returns a standard HTTP-cookie (name is session
), which should then be sent back to the server with each subsequent request in the session. We recommend using TLS/HTTPS to encrypt the whole session. But we support either HTTP or HTTPs.
To invoke the API, rather than the regular site, either provide the URL parameter okc_api=1
or the HTTP header parameter:
X-OkCupid-Api-Version: 1
We leave this parameter out in the documentation below, assuming it in all cases.
Output types in our API are in JSON. This section presents our way of describing what form this JSON should take.
In our JSON, we use 5 primitive types:
“44991023949129394123”
) so that the client doesn't have a chance to perform that incorrect conversion.
Compound structures are combinations of these primitive types. For instance, here is a dictionary that has one field, named userid
, that is of type q
:
{ userid:q }
Here is an array of 0 or more ints:
[ i* ]
And here is an array of 0 or more dictionaries, each containing the field userid
:
[ { userid:q }* }
We of course can combine these to make more complicated structures, as seen below:
{ ints : [ i* ], events : [ { type:s, from:s }* ], people : [ { screenname:s, gender:s, is_online:b, userid:q }* ] }
That is to say, the top-level object is a JSON dictionary, with three fields, events
, ints
,
and people.
events
and people
are both arrays of dictionaries, whereas ints
is an array of integers.
Value | Description |
---|---|
0 | OK |
1 | OK_DUPLICATE |
2 | OK_NAG |
100 | FAIL |
101 | FAIL_SELF |
102 | FAIL_OFFLINE |
103 | FAIL_NO_IM |
104 | FAIL_BAD_PW |
105 | FAIL_DELETED |
106 | FAIL_NO_USER |
107 | FAIL_BLACKLISTED |
108 | FAIL_DISABLED |
109 | FAIL_NEED_LOGIN |
Error sequences 0 through 99 are various flavors of `OK'. 100-plus are various flavors of failure.
These should probably be presented in this same order to maintain consistency with the website
Code | Description |
---|---|
34 | Girls (who like guys) |
17 | Guys (who like girls) |
40 | Girls (who like girls) |
20 | Guys (who like guys) |
54 | Both (who like bi guys) |
57 | Both (who like bi girls) |
2 | Straight Girls Only |
1 | Straight Guys Only |
8 | Gay Girls Only |
4 | Gay Guys Only |
32 | Bi Girls Only |
16 | Bi Guys Only |
42 | Girls |
21 | Guys |
63 | ALL |
Code | Description |
---|---|
0 | Anywhere |
25 | 25 Units |
50 | 50 Units |
100 | 100 Units |
250 | 250 Units |
500 | 500 Units |
“Units” is either “Miles” or “Kilometers”, depending on the logged-in user's settings
Code (Seconds) | Description |
---|---|
3600 | Online in the last hour |
86400 | Online in the last day |
604800 | Online in the last week |
2678400 | Online in the last month |
31536000 | Online in the last year |
315360000 | Online in the last ten years |
Code | Description |
---|---|
1 | Mandatory |
2 | Very Important |
3 | Somewhat Important |
4 | A Little Important |
5 | Irrelevant |
Code | Description |
---|---|
0 | FLAG_USERPIC |
1 | FLAG_PROFILE |
2 | FLAG_IM |
4 | FLAG_JOURNAL |
5 | FLAG_COMMENT |
6 | FLAG_JOURNAL_COMMENT |
8 | FLAG_TESTPIC |
9 | FLAG_FORUM_COMMENT |
10 | FLAG_FORUM_TOPIC |
11 | FLAG_QUIZZY |
12 | FLAG_MESSAGE |
13 | FLAG_ALBUM_PIC |
14 | FLAG_REVIEW |
Set Bit | Description |
---|---|
0 | LOOKING_NULL |
1 | LOOKING_FRIEND |
2 | LOOKING_LONGTERMDATING |
3 | LOOKING_SHORTTERMDATING |
4 | LOOKING_ACTIVITYPARTNERS |
5 | LOOKING_PENPALS |
6 | LOOKING_SEXPARTNERS |
7 | LOOKING_POLY *(not currently used) |
A Looking for value of 72 decodes to : (2^3 + 2^6) : LOOKING_SORTTERMDATING + LOOKING_SEXPARTNERS
fake |
underage |
scammer |
other |
(Some text here about what the API Key ought to be, and also X-OkCupid header fields like software version, device ID, etc).
Most API methods below output the following parameters:
status
:e — the status of the last operationstatus_str
:s — a string representation of the status (optional)num_quiver
:i — the number of quivers left after the last operation (mail sends and quiver rejections might change this)num_unread
:i – the number of unread mails after the the previous operationauthcode
:s — an authentication code that some POSTs ought to send back to the server. Such a code is set to expire and only valid for the current user, so it's used as XSS-prevention.Here is a method-by-method listing of the OkCupid API.
Get the events most relevant to this user (as deemed by the server)
None
{ events : [ { username:s, time:t, type:s, online:b, image:s, contents:s, class:s }* ], image:s, numunread:i, numquiver:i, location:s, locid:i, image:s, announce : { url:s, height:i, width:i} viewer: { userid: q, username: s, gender: i, age: i, orientation: i, relationship_status: i, ethnicity: [ i* ], children: i, drinking: i, smoking: i, drugs: i, education_level: i, education_status: i, jobtype: i, money: i, cats: i, dogs: i, religion: i, religion_serious: i, country: s }, }
events
— an array of pertinent eventsusername
— the main user involvedtime
— when the event happenedtype
— the type of the event (all-caps enumerated)online
— if the user is online or notimage
— image of the usercontent
— the content of the event to be displayed in the feedclass
— ?announce
— An announcement iFrame to make a free-form announcement. The server-side can specify a height and width so that the client can correctly size the iframe. Eventually the client might specify the size of its display to help the server out in this regard.Instantevents is the service that handles the chat client, buddy lists, and any sort of event-based notifications. We might enable some of these later on. There are two modes: poll and send. Poll is discussed here, and send is discussed below.
Call this method as:
''http://www.okcupid.com/instantevents?''//args//
either via HTTP POST or GET. Input arguments are detailed below, and passed via URL-encoding, chained together with &
characters. Use instantevents in polling mode to figure out which server-side events ought to be shown on the client (such as incoming IMs), who the user's buddies are, or both in one call.
Treating these two cases separately, the call:
http://www.okcupid.com/instantevents?server_seqid=0&server_gmt=0
Will poll the server for events relevant to this user. If there is no event ready to show, it can wait up to a minute before replying. Once the server replies, it will return a server_gmt
and a server_seqid.
The client should turn around and send these back to the server on the subsequent call.
Another use is to immediately return the user's buddy list:
http://www.okcupid.com/instantevents?buddylist=1&load_thumbnails=1&default_thumbnails=1&show_offline=1
Which will not return any events, just a list of people.
These two calls can be combined by supplying the additional parameter do_event_poll=1
,:
http://www.okcupid.com/instantevents?buddylist=1&do_event_poll=1&server_seqid=0&server_gmt=0
Which will poll the server for events. When an event is ready, it will return with the relevant events, and with a fully populated buddy list.
buddylist=1
— return a full buddy listload_thumbnails=1
— load thumbnails for all buddies returnedshow_offline=1
— show offline as well as online users.default_thumbnails=1
— specify default thumbnails for users who don't have them.do_event_poll=1
— don't return right away, poll for the next interesting event.server_seqid=
seqid — 0 on the first request, or the sequence ID returned by the server if known.server_gmt=
server_gmt — the GMT time last output by the server.do_post_read=1
— post a read event which means that the user will get credit for having read the IM. Without this, the user might get messages in his inbox saying that he missed an IM.Json Format:
{ events : [ { type:s, from:s, to:s, contents:s, server_gmt:t, server_seqid:i }* ], people : [ { screenname:s, gender:s, orientation:s, location:s, thumb:s, match:i, friend:i, enemy:i, is_ok:b, open_connection:b, userid:q }* ], num_unread:i, num_quivers:i, status:b, status_str:s }
status
is either OK or FAIL_NEED_LOGIN to denote needing a login.buddylist=1
show_offline=
bload_thumbnails=
b[ { userid:q, screenname:s, is_online:b, im_ok:b, thumbnail }* ]
The same instant events service, with different parameters, can also be used to send messages to other users via IM. The simple request:
http://www.okcupid.com/instantevents?send=1&recipient=chris&body=yoyoyo+boo&rid=44455
Will send an IM to the user chris
with the text yoyoyo boo.
send=1
— turn this mode to 1 to enable 'sending'recipient=
user — specify the user that the IM is going tobody=
text — specify the text to send in the IMrid=
random — specify a new random token with each IM sent{ status:e, status_str:s, server_gmt:t }
Most important, specify the status of the operation. Can be one of:
Code | Description |
---|---|
OK | All worked. |
OK_DUPLICATE | It worked, but it was a duplicate message, so it will be swallowed. |
OK_NAG | It worked, but the user has sent a lot of IMs, therefore, should be nagged to upgrade to Pro. |
FAIL | Generic failure |
FAIL_SELF | Cannot send to self. |
FAIL_OFFLINE | Cannot send; user DNE or is offline. |
FAIL_NO_IM | Cannot send; user is offline. |
Call /login
to establish a session with OkCupid. For a user with username max and a password pluto, you can post the following HTTP request to login:
http://www.okcupid.com/login?username=max&password=pluto
If it's the correct username and password, a session will be established on the server-side. The server will send back cookies:
username=mnk77; expires=Thu, 26 Jan 2012 17:07:42 GMT; path=/; domain=.okcupid.com guestid=; expires=Wed, 02 May 2007 17:07:42 GMT; path=/; domain=.okcupid.com session=590435105645882864%1234512345; expires=Tue, 02 Feb 2010 17:07:42 GMT; path=/;domain=.okcupid.com
The client should then back the values for session and username with each subsequent request to continue acting in the session.
username=
username — the username to log-in aspassword=
password — the password to use when logging in{ screenname:s, userid:q, status:e, status_str:s }
Here are the relevant error codes:
Code | Description |
---|---|
OK | Login Ok! Expect a session cookie |
FAIL_BAD_PW | Login failed due to a bad PW |
FAIL_UNDERAGE | Login failed because the user is underage (not used) |
FAIL_DELETED | Login failed because the user has been deleted |
FAIL_NO_USER | Login failed because there was no such user |
FAIL_BLACKLISTED | Login failed because the user was blacklisted; set blacklist cookie. |
username=
usernamestaff_override=1
ajax=1
{ screenname:s, userid:q, status:e, status_str:s }
This API method offers both folder-level views of all of the threads in a given mailbox folder, and also message-level views of all of the messages in a given thread. We describe the folder view here, and the thread view below.
There are two relevant folders: inbox, sent and smiles. To access the first, issue:
http://www.okcupid.com/mailbox?folderid=1&low=1
The output gives the active threads in that mailbox
folderid
— 1 for inbox, 2 for sent-mail and 3 for smileslow
– the low thread to display. by default the low is 1 and there are 30 threads per page.{ numunread:i, numthreads:i, max_message:i, status:e, status_str:s, messages : [ { thread_id:q, subject:s, person:s, snippet:s, msg_class:s, is_new:b, timestamp:i, thumbnail_path:s }* ] }
This “snippet” field shows the first 50 characters or so of the message. Each entry of the messages array is a dictionary, containing the description of a message thread.
One you have a valid thread ID, you can request the corresponding messages that comprise the thread:
http://www.okcupid.com/mailbox?readmsg=1&threadid=5555541338581775397
Assuming it's a valid thread, you'll get back all messages in the given thread.
/mailbox
in folder view){ is_quiver_msg:b, messages : [ { age_gen:s, timestamp:t, body:s, receiver_name:s, sender_name:s, senderid:q, image:s, from_user:b, from_me:b, msgid:q, is_anchor:b }* ], thread_start:t, threadid:q, subject:s, num_msg:i, authcode:s, showmatch:b, screenname:s, buddy_name:s, status:e, status_str:s }
Send a message in an existing thread by specifying a thread ID, or send in a new thread if no thread ID is specified.
{ num_unread:i, status_str:s, status:e, num_quivers:i, msgid:q }
For all of these features, the output is of the form:
{ status:e, status_str:s }
Block the given thread ID's sender. As also, thread IDs are 64-bit unsigned IDs.
blockuser=1
threadid
=idDelete the given thread from the server
deletethread=1
threadid
=idChange a thread from unstarred to starred, or vice-versa.
starmsg=
b — provide 1 or 0threadid=
idsearchprefs.display
=1{ gentation: i, age_min: i, age_max: i, only_single: i, only_photos: i, lookingfor: i }
Return a random user that the current user hasn't voted on yet. Pass votes themselves through /vote_handler, reloading /getlucky for each
cgi_prefs
=1
— This tells the service to override stored preferences with CGIlocid=
id — Location, as retrieved from /locqueryage_from=
i — Youngest acceptable aged user to returnage_to=
i — Oldest acceptable aged user to returngentation=
g — Combined gender/orientation code to returnshown_uid=
uid — User ID of the last person shown. Use this if you want the server to return match/profile data for the previous person as well as the current person{ userid : q, username : i, pics : [ { thumb : s, pic : s, pic2 : s, caption : s }* ], essays : [ { title : s, body : s}* ], gender : i, prev : { uid: q, username : s, age : i, thumb : s, gender : i, gender_letter : s, pronoun : s, orientation : i, orient_name : s, status : i, status_name : s, location : s, }, adjectives : [ s* ], percentage : i, fpercentage : i, epercentage : i, is_male : b, has_persona : b, persona : s }
Vote 1 to 5 stars on a user or object, or add a note for a user
score
– the score, an integer between 1 and 5type
— provide vote
target_userid=
useridtarget_objectid=
objectid — 0
for users, otherwise pass id of object (quiz)vote_type
— provide personality
for people or quiz
for quizzestype
— provide note
target_userid=
useridnote=
string — note contents{ status:e }
http://okcupid.com/profile/username1/compare/username2
target_user_only=
b – Will return an array of traits for username1common_traits_only=
b – Will return traits that username1 and username2 both shareTrait data:
range : [min,max] axis_high : description axis_low : description
Example (http://okcupid.com/profile/frostedwheat/compare/staffrobot?okc_api=1):
{ "status" : 0, "staffrobot": [ { "range": [ "12", "34" ], "axis_high": "more adventurous", "axis_low": "less adventurous" }, ... ], "frostedwheat": [ { "range": [ "58", "98" ], "axis_high": "more adventurous", "axis_low": "less adventurous" }, ... ] }
Example (http://okcupid.com/profile/frostedwheat/compare/staffrobot?okc_api=1&target_user_only=1):
{ "status" : 0, "frostedwheat": [ { "range": [ "58", "98" ], "axis_high": "more adventurous", "axis_low": "less adventurous" }, ... ] }
This service manages a user's uploaded photos. It is also necessary to register a photo with this service's “Add Photo” function after submitting the photo data through /ajaxuploader.
{ pics : [{ url:s, picid:q, caption:s, ordinal:i, primary:b }*] }
{ pics : [{ url:s, picid:q, caption:s, ordinal:i, primary:b }*] }
{ picid:q, error:s, type:s, status:i }
will be null if there was an error.
{ picid:q, error:s, type:s, status:i }
{ picid:q, error:s, type:s, status:i }
{ picid:q, error:s, type:s, status:i }
{ id:q, url:s, thumb_url:s, from:s, width:i, height:i, type:s, original_source_url:s, original_source_file:s }
Visit /profile/username
{ userid:q, username:s, thumbnail:s, thumbnail_100:s, thumbnail_60:s, adjectives:[ s* ], status:i, status_str:s, gender:i, gender_str:s, orientation:i, orientation_str:s age:i, location:s, distance:i, units:s, join_date:i, last_login:i, is_buddy:b, is_blocked:b, matchpercentage:i, friendpercentage:i, enemypercentage:i, curr_score:i, is_online:b, distance:i, skinny: { ethnicities: [ s* ], lookingfor: [ s* ], languages: [ s* ], last_online: i, join_date: i, smoker: s height: i, bodytype: s, drinker: s, drugs: s, religion: s, religionserious: s, sign: s, sign_status: s, education: s, education_status: s, job: s, income: s, children: s, dogs: s, cats: s, dogsandcats: s }, essays : [ { essay : [ { essay_editors : [ s* ], lang : s, text : s }* ], title }* ], photos : [ { caption: s, image_url: s }* ] }
u=
swoo=
1ajax=
1{ status : e }
u=
sajax=
1addbuddy=
1sendmessage=
b{ status : e }
u=
sajax=
1removebuddy=
1{ status : e }
{ ideal_answers: [ { text: s }* ], qtext: s, answers : [ { CHECKED: i, text: s }* ], question_num: i, max_match: s, num_answered_str: s, qid: q, no_skip: i }
{ ideal_answers: [ { text: s }* ], qtext: s, answers : [ { CHECKED: i, text: s }* ], question_num: i, max_match: s, num_answered_str: s, qid: q, no_skip: i }
{ no_skip: i, errors: [ s* ], num_answered_str: s, answers: [ { CHECKED: i, text: s, }* ], qtext: s, qid: i, max_match: s, question_num: i, ideal_answers: [ { text: s }* ] }
Visit /visitors
stalkers = [ { count : i, event_acct_level : i, event_gets_badge : b, event_SHOW_IM : b, event_time : i, event_userid : s, event_username : s, event_age : i, event_gender : s, event_user_location : s, event_user_orientation : s, event_user_status : s, event_user_thumbnail : s, match_percentage : i, friend_percentage : i, enemy_percentage : i, image : s }* ]
JSON=
1doFlag=
1name=
stype=
ireason=
scomment=
comment stringowner_id=
uidobject_id=
tid
Note: The “name” field should be the username of the offender
{ status : e }
Visit /quiver
quiver = [ { userid : s, username : s, age : i, gender : s, orientation : s, thumbnail_filepath : s, location : s, uber_description : s, note : s, reject : b }* ]
quiver = [ { userid : s, username : s, age : i, gender : s, orientation : s, thumbnail_filepath : s, location : s, uber_description : s, note : s, reject : b }* ]
func=query
(use the exact string “query”)query=
query string (such as “Seattle”)cbust=
random{ status: e, query: s, locid: i, results: [ { locid: i, text: s }* ] }
NOTE: The low
parameter is how you control pagination. Basically a 1-indexed number indicating which item to start with.
IMPORTANT: Only pass this in when N != 1
Filter | Type Code | Param1 | Param2 |
---|---|---|---|
Gentation | 0 | Gentation Code | – |
Photos | 1 | needs_photos: b | – |
Age | 2 | min_age: i | max_age: i |
Distance | 3 | Distance Code | – |
Last online | 5 | Last Online Code | – |
Single | 7 | must_be_single: b | – |
So for example, if you want single straight females with pictures, you'd pass:
?filter1=0,17&filter2=1,1&filter3=7,1
Sort | Type Code |
---|---|
Match | 0 |
Enemy | 1 |
Friend | 3 |
Last Online | 4 |
Who's New | 6 |
The parameter of a sort is the weight to be put on sorting on that dimension. You should just pass in “100” for a sort on a single dimension. Some examples are:
Parameters | Description |
---|---|
?sort1=0,100 | Match |
?sort1=3,100 | Friend |
?sort1=1,100 | Enemy |
?sort1=6,100 | Who's New |
?sort1=4,100 | Last Online |
?sort1=0,50&sort2=6,50 | Match & New |
?sort1=0,50&sort2=4,50 | Match & Last Online |
?sort1=0,50&sort2=7,50 | Match & Distance |
?sort1=2,20&sort2=0,50&matchSortRelative=1 | “Special Blend” |
{ username: s, foundany: i, maxmatch: i, lquery: s, numanswered: i, filters: { gentation: i, locid_str: s, gentation_str: s, locid: i, photos_only: s, radius: i, lquery: s, age_min: i, age_max: i, single_only: s, desc: s } amateur_results: [ { personality_orientation: i, r_ncontacts_in_28_no_im: s, s_looks_perc_adj_1: s, r_account_age: s, uber_description: s, match_perc: s, s_gender: s, note: s, message_votes: i, contacts_this_week: i, uncontacted_index: i, last_contact: i, personality_gender: i, s_avg_msg_vote_10_1: s, online_now: i, VIEWEE_PRO_STATUS: i, personality_code: s, age: i, last_login: i, location: s, friend_percentage: i, thumbnail_filepath: s, recent_contacts: i, personality: s, status: s, contacts_today: i, HAS_CR: i, age_delta: s, personality_score: i, s_profile_len: s, enemy_percentage: i, r_ncontacts_in_28: s, reply_perc: i, which_essay: i, match_percentage: i, uncontacted: i, reciprocol_percentage: i, message_points: i, r_reply_ratio_28_4_no_im: s, s_ncontacts_in_28_no_im: s, orientation_code: i, SHOW_IM: i, userid: s, first_contact_time: i, username: s, join_date: i, MEMBERS_ONLY: i, gender: s, recent_replies: i, contact_rating: i }* ], alist_results: [ { // Same structure as amateur results }* ] }
lat_long_loc=1
lat=
latitudelong=
longitude{ locid: i, location: s }