OAuth Dancing with Python
This Python example uses python-oauth2. To install python-oauth2, do this:
% git clone http://github.com/simplegeo/python-oauth2.git
% make
% python setup.py install
Here is a full standalone command line example. It uses an OAuth helper site at http://progphp.com/oauth to take the place of your own callback. When you integrate this in your own code you would replace the progphp.com callback url with your own, of course. Using progphp.com in the example here makes it work from the command-line.
import urllib
import simplejson
import sys
import oauth2 as oauth
class WePay:
CONSUMER_KEY = "<Your Consumer Key>"
SHARED_SECRET = "<Your Consumer Secret>"
API_URL = "https://wepayapi.com/v1"
def __init__(self): self.consumer = oauth.Consumer(key = WePay.CONSUMER_KEY,
secret = WePay.SHARED_SECRET)
self.client = oauth.Client(self.consumer)
self.request_token = self.get_request_token("http://progphp.com/oauth")
login_url = self.request_token["login_url"]
self.redirect(login_url)
verifier = self.request_token_verifier()
access_results = self.request_access_token(verifier)
self.access_with(access_results)
def request_token_url(self) : return self.API_URL + "/oauth/request_token"
def access_token_url(self) : return self.API_URL + "/oauth/access_token"
def request_token_verifier(self) : tokenurl = "http://progphp.com/oauth/" + self.request_token["oauth_token"]
verifier_result = simplejson.load(urllib.urlopen(tokenurl))
return verifier_result["verifier"]
def redirect(self, login_url): # Now the user has to go to the login url. The resulting token will be
# cached at the progphp.com callback.
print "Point your browser towards " + login_url
print "Hit enter once you've made it to progphp.com"
sys.stdin.readline()
def get_request_token(self, callback) : # Specify the callback url
params = {}
params["oauth_callback"] = callback
# With the oauth2 library, body data only works using POST
resp, request_token_content = self.client.request(self.request_token_url(),
"POST", body=urllib.urlencode(params))
# Make a dictionary out of the token content so we can retrieve pieces.
return dict(urlparse.parse_qsl(request_token_content))
def request_access_token(self, verifier) : verified_token = oauth.Token(self.request_token['oauth_token'],
self.request_token['oauth_token_secret'])
verified_token.set_verifier(verifier)
self.client = oauth.Client(self.consumer, verified_token)
resp, content = self.client.request(self.access_token_url(), "POST")
return dict(urlparse.parse_qsl(content))
def access_with(self, access_results): access_token = oauth.Token(access_results['oauth_token'],
access_results['oauth_token_secret'])
self.client = oauth.Client(self.consumer, access_token)
def get(self, path) : resp, content = self.client.request(WePay.API_URL + path)
return simplejson.loads(content)
wepay = WePay()
print wepay.get("/user")
OAuth Dancing with Ruby
Getting at the WePay API from Ruby is not very difficult, but the Ruby OAuth gem can be a bit temperamental, so we have included some hints here. The first thing you are going to need is to install the oauth and json gems:
and write a Ruby class that looks like this:
require 'rubygems'
require 'oauth'
require 'json'
class WePay
CONSUMER_KEY = "<Your Consumer Key>"
SHARED_SECRET = "<Your Consumer Secret>"
APIURL = "https://wepayapi.com"
def initialize( _access_token )
@access = _access_token
end
def get path
if !/^\/v1\//.match(path)
path = "\/v1" + path
end
JSON.parse(@access.get(path).body)
end
end
The path mangling there is to get around having to specify "/v1" on every request. Now to get a request token you would do this:
begin
# Configure the OAuth session o = OAuth::Consumer.new( WePay::CONSUMER_KEY, WePay::SHARED_SECRET, {
:site => WePay::APIURL,
:http_method => :post,
:authorize_path => "/v1/oauth/authorize",
:access_token_path => "/v1/oauth/access_token",
:request_token_path => "/v1/oauth/request_token"})
# Get a request token request_token = o.get_request_token({
:oauth_callback => "http://example.com/your_callback",
:scheme => :query_string })
# Now you should have the login_url to redirect the user to puts "Redirect user to " + request_token.params[:login_url]
Next, once your callback is hit with the oauth_token and verifier, you need to turn it into an access token like this:
access_token = request_token.get_access_token({:oauth_verifier => verifier})
And now you should be ready to make an actual API request:
user = wp.get("/user")
puts "Hello, #{user["result"]["firstName"]} #{user["result"]["lastName"]}"
API Reference
HTTP Methods
- GET
- Fetch resource(s) from WePay
- POST
- Create a new resource
- PUT
- Modify a resource
- DELETE
- Delete a resource
Resources are things like groups, bills, invitations, events and alerts. Note that the format of the body of a PUT request is outside of the scope of the OAuth spec and there are no real conventions around it. The WePay API accepts "application/json" and POST-like "application/x-www-form-urlencoded" PUT bodies. A valid json PUT body would look like this:
{"name":"My Group","description":"Rasmus' Group"}
The same thing url encoded would be:
name=My%20Group&description=Rasmus%27%20Group
Make sure your OAuth request includes the correct Content-Type header to indicate which format your PUT body is in. If no Content-Type is provided we assume form-urlencoded. This is only for PUT. POST requests should of course be using the standard form-urlencoded format.
HTTP Status Codes
The following HTTP status codes will be returned from API requests:
- 200
- GET/PUT/DELETE request succeeded
- 201
- POST request succeeded (resource created)
- 400
- Parameter missing
- 403
- Forbidden
- 404
- Unknown API Call
- 405
- Method not allowed
- 500
- Internal Error - contact api@wepay.com
JSON Response Syntax
This is a typical response you will see from a call to https://wepayapi.com/v1/group/12345.
{ "result": { "id":12345, "name":"Soccer Team", "description":"This is the group for my soccer team", "founder_name":"Rasmus Lerdorf", "image":"https:\/\/www.wepay.com\/img\/nopic\/group_160.jpg", "pending_balance":0, "balance":0, "public_url":"https:\/\/www.wepay.com\/public\/view\/12345", "member_url":"https:\/\/www.wepay.com\/group\/view\/12345", "member_count":1, "members":[ { "user_id":11254, "firstName":"Rasmus", "lastName":"Lerdorf", "email":"api@wepay.com", "picture":"https://www.wepay.com/img/nopic/user_80.jpg", "registered":1, "status":"active" } ] } }
It won't have the new-lines that are shown here, and it really isn't meant to be human readable. You will want to parse it with a json parser. With PHP you might do something like this:
<?php
$group = json_decode($json);
echo $group->result->name;
echo " - ";
echo $group->result->members[0]->firstName;
This would output: Soccer Team - Rasmus
Making POST/PUT/DELETE Method Calls
The WePay Api is what is known as a Representational State Transfer (REST) API. It uses GET requests for reading resources, POST requests for creating new resources, PUT requests for modifying existing resources and DELETE requests for deleting resources. In most OAuth libraries, it is quite easy to send the right type of request. For example, to create a new WePay group using PHP's OAuth extension the code would look like this:
<?php
try {
$oauth = new OAuth(OAUTH_CONSUMER_KEY,OAUTH_CONSUMER_SECRET,
OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_FORM);
$oauth->setToken($access_token, $shared_secret);
$group = array('name' => 'Group Create Test',
'description' => 'Group Created with the WePay API');
$resp = $oauth->fetch("https://wepayapi.com/v1/group/create",
$group,
OAUTH_HTTP_METHOD_POST);
$json = $oauth->getLastResponse();
} catch(OAuthException $E) {
echo "Response: ". $E->lastResponse . "\n";
}
$group = json_decode($json);
echo "Your new group id is {$group->id}";
We recognize that there are OAuth implementations out there that do not send PUT and DELETE requests correctly. You can emulate it by adding ?method=PUT or ?method=DELETE to the URL you are hitting and using a GET request instead.
Callbacks
The WePay API supports push notifications of events. You simply call /group/callback/12345 to register a callback for group 12345. A callback is just a URL that you specify to which the WePay servers will make a POST request to when an event occurs on group 12345.
The POST request will have event, group_id, application_id and transaction_id fields. The event field is a string containing a human-readable event description. The current set of events are, "Sent Money", "Received Money", "Bill Sent", "Bill Received", "User Add", "User Remove", "Status Change", "Transaction Pending", and "Transaction Denied".
The details in this POST request are vague on purpose. We do not require you to provide an HTTPS (SSL) URL here, so we avoid sending any sensitive information in this request. You would typically make an API request over SSL to /transaction/<transaction_id> to get the full details.
SDK?
People occasionally ask if we have an SDK. Since this is just OAuth and REST requests, it doesn't seem necessary. But here is a simple PHP one.
<?php
class WePay {
const CK = '<your consumer key goes here>';
const CS = '<your consumer secret goes here>';
private $oauth;
private $apiurl = 'https://wepayapi.com/v1';
private $methods = array(
'get' => OAUTH_HTTP_METHOD_GET,
'post' => OAUTH_HTTP_METHOD_POST,
'put' => OAUTH_HTTP_METHOD_PUT,
'delete' => OAUTH_HTTP_METHOD_DELETE);
public function __construct($access_token,$access_secret) {
try {
$this->oauth = new OAuth(self::CK, self::CS,
OAUTH_SIG_METHOD_HMACSHA1, OAUTH_AUTH_TYPE_FORM);
$this->oauth->setToken($access_token, $access_secret);
$this->oauth->enableDebug(); // Remove for production
} catch(OAuthException $E) {
error_log($E->getMessage());
}
}
public function __call($method, $args) {
if(!isset($args[0])) { echo "Error - no API command provided"; return false; }
$method = strtolower($method);
$cmd = $args[0];
if(!isset($args[1])) $send_data = null;
else $send_data = $args[1];
try {
$this->oauth->fetch($this->apiurl.$cmd, $send_data, $this->methods[$method]);
return json_decode($this->oauth->getLastResponse())->result;
} catch(OAuthException $E) {
error_log($E->lastResponse);
return false;
}
}
}
To use it, once you have gone through the OAuth Dance you instantiate the WePay class with your authorized access_token and associated access_secret. Then you just call the various methods documented here. Like this:
<?php
// Fetch $access_token and $access_secret from your backend datastore
// Then instantiate the WePay class
$W = new WePay($access_token, $access_secret);
// Get the feed of events for group 1711
$feed = $W->get('/group/feed/1711/100');
print_r($feed);
// Register a new user
$user = array('name'=>'John Smith','email'=>'jsmith@example.com');
$resp = $W->post('/user/register', $user);
print_r($resp);
User API
All calls are prefixed with: https://wepayapi.com/v1
[...] indicates an optional argument
GET
/user
Get the current user's info.
- Arguments:
- none
- Returns:
- user_id, firstname, lastname, email, picture, registered
POST
/user/invite_accept/321
Accept invitation 321. This results in the accepting user being added to a group.
- Arguments:
- none
- Returns:
- true/false
GET
/user/invites_received
Get a list of the group invites received by the current user.
- Arguments:
- none
- Returns:
- array of invites (id, group_id, sender_id, recipient_id, message, sent, status)
GET
/user/invites_sent
Get a list of the group invites sent by the current user.
- Arguments:
- none
- Returns:
- array of invites (id, group_id, sender_id, recipient_id, message, sent, status)
GET
/user/lookup
Returns a user record or false if it doesn't exist
- Arguments:
- email
- Returns:
- user_id, firstName, lastName, email, picture, registered
POST
/user/register
Register a user. If the user is already registered, their user data is returned and the registered return flag is set to true. Otherwise the user is created and the new user data is returned.
You can have the user go to https://www.wepay.com/session/verify_account/<user_id> to set their password and verify their email address. You may pre-fill the email address if you like by passing a GET-method em parameter. eg. https://www.wepay.com/session/verify_account/<user_id>?em=user@example.com
If provided, image_url will be fetched and used as this user's profile image. It will be cropped square, so providing a mostly square image of less than 3M in size will give the best results.
- Arguments:
- email, [name], [image_url]
- Returns:
- user_id, firstName, lastName, email, picture, registered
Group API
GET
/group/list
List all the user's groups.
- Arguments:
- none
- Returns:
- array of (id, name, description,founder_name,founder_id, image, public_url, member_url)
GET
/group/12345
Get the group info, including the member list, for group id 12345. The first user listed in the returned members array is the group founder. The
status field can have 3 values:
- active
- Member has joined the group by accepting an invitation or had her request to join accepted.
- invited
- Member has been invited but has not accepted yet.
- requested
- Member has requested to join the group but has not been accepted yet.
It is important to note that you can still send bills to
invited and
requested members.
You should also remember that group permissions may prevent you from seeing the member list and/or the contact info for each member.
- Arguments:
- none
- Returns:
- id, net, fee, direction, bill_id, status, description, text, from_id, from, email, to_id, to,