Login | Register

WePay online payment system

WePay
http://www.wepay.com/

Updated on September 14, 2010
Views: 1189 | Clicks: 76


Website Screenshot



General Information

Since high school, Bill and Rich have been collecting and managing money for various activities, clubs and organizations. Bill was student body president and spent his afternoons slinging tickets to dances, lock-ins, fundraisers and trips. Rich was a traveling member of the debate team, and cofounder of a club dedicated to raising money to build a school in Nicaragua.

When Bill and Rich met at Boston College, they were both heavily involved in a wide range of groups that needed to collect and manage money. Bill was the treasurer of multiple on-campus clubs, and was "that guy" hounding his roommates to pay rent every month. Rich organized a 15-person service trip to Biloxi, Mississippi.

In all of these groups, more time was spent collecting, tracking and managing money than almost anything else.

About a year after graduating, Rich had to plan his brother’s bachelor party, while Bill was trying to collect money to rent a ski house. When Rich had to keep a spreadsheet and send out constant reminders, and Bill had to open a separate bank account just to hold the money, they had finally had enough. They decided to build WePay – the easiest way for groups to collect, manage, and spend money.

Currencies

USD

Countries of use

all

Users

personal and bisiness

Fees

WePay is free to signup, create groups, join groups, and make payments.

Groups incur a small fee for each payment they receive. All outgoing transactions are free.

Sending Bills

When sending a bill, groups can decide how recipients can pay.

With a bank account: 50¢
With a bank account or credit card: 3.5% (50¢ min)
Selling Tickets

When selling tickets, groups can decide how recipients can pay.

With a bank account: 50¢
With a bank account or credit card: 3.5% (50¢ min)
Accepting Donations
There is a 3.5% fee (50¢ min) on all donations.  
Deposits
With a bank account: 50¢
With a credit card: 3.5% (50¢ min)
WePay Prepaid Visa® Card
Shipping & Handling: $5.00
Domestic ATM Cash Withdrawal Fee: $1.50
International ATM Cash Withdrawal Fee: $1.50
Overdraft Fee: $10.00
Replacement Card Fee (for lost or stolen cards): $10.00
Expired Card Reissue Fee: $15.00
Expired Card Maintenance Fee: $5.00/month

Integration approaches

online

Information for developers

The WePay API is a simple OAuth-authenticated REST-based API with JSON responses.

You should first register your application to receive a consumer key and secret.

OAuth Dance

OAuth is a standard protocol that allows 3rd-party Web and Mobile applications to interact with WePay. You can read more about the protocol at http://oauth.net.

The main idea behind OAuth is that users are able to grant permission to a 3rd-party application to act on their behalf without giving their password to the 3rd-party. The application developer will follow the OAuth steps which results in the user being sent to a wepay.com page where she will enter her password and authorize the application. The application developer will store an access token and shared secret for each user that has granted the application access and will send the access token along in all API requests signed with the shared secret.

This might all sound a bit complicated, but there are libraries for all major languages out there that make it quite easy to implement. There is an extensive list at http://oauth.net/code/. The code examples here are written against PHP's pecl/oauth extension. You can find the documentation for that extension at http://php.net/oauth.

If you are already familiar with OAuth from interacting with other APIs, all you really need to know are the two oauth end points:

Request token URL
https://wepayapi.com/v1/oauth/request_token

Access token URL
https://wepayapi.com/v1/oauth/access_token

 

Note that the WePay OAuth implementation supports the ProblemReporting extension which should make it a little easier to debug issues when they come up.

 

Dance Step 1 - Obtaining a Request Token

Before you can start the dance, you need to register your application and get your consumer key and secret. Once you have those you can get what is known as an unauthorized request token. Using PHP's pecl/oauth extension, it would look like this:

<?php
define
('OAUTH_CONSUMER_KEY','<your consumer key goes here>');
define('OAUTH_CONSUMER_SECRET','<your shared secret goes here>');
$req_tok_url 'https://wepayapi.com/v1/oauth/request_token';
try {
    
$oauth = new OAuth(OAUTH_CONSUMER_KEYOAUTH_CONSUMER_SECRET);
    
$oauth->enableDebug();
    
$resp $oauth->getRequestToken($req_tok_url);
} catch(
OAuthException $E) {
    echo 
'Response: '$E->lastResponse "\n";
}
$url $resp['login_url'];
$token $resp['oauth_token'];
// Redirect user to authorization url
header("Location: $url");

You get 3 things back from this call.

oauth_token

,

oauth_token_secret

and

login_url

.

login_url

is where the user goes to authorize the request_token. You may optionally provide an

oauth_callback

parameter to the authorization URL which will be where the user is redirected to after they authorize your application. If you do not provide one, the callback you provided when you registered your application will be used. You will need to store the request token and secret for the next step.

 

Dance Step 2 - Authorizing the Request Token

The authorization url from Step 1 will look something like this:

 

https://www.wepay.com/session/authorize?oauth_token=93f8e7c12c7ca2&oauth_callback=http://example.com

 

Once the user authorizes the request token, your callback will be called with these GET parameters:

 

?oauth_token=a16c6abe8065tf018950&oauth_verifier=38ea814ya7cwca

 

This is known as an authorized request token. The script in Step 3 shows how to parse this response.

 

Dance Step 3 - Getting an Access Token
<?php
$secret 
'<oauth_token_secret from Step 1>';
try {
  
$oauth = new OAuth(OAUTH_CONSUMER_KEY,OAUTH_CONSUMER_SECRET,
                     
OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_FORM);
  
$oauth->enableDebug();
  
$oauth->setToken($_GET['oauth_token'], $secret);
  
$resp $oauth->getAccessToken("https://wepayapi.com/v1/oauth/access_token"
                                  
NULL$_GET['oauth_verifier']);
} catch(
OAuthException $E) {
        echo 
"Response: "$E->lastResponse "\n";
}
print_r($resp);

This will give you an

oauth_token

and an

oauth_token_secret

. This is the access token you need to store for the user who authorized it. You will send this access token with all API requests to be done on behalf of this user and it will work until the user manually revokes it on the WePay site.

 

Dance Step 4 - Making an Actual API Call
<?php
$access_token 
'<oauth_token from Step 3>';
$access_token_secret '<oauth_token_secret from Step 3>';
try {
  
$oauth = new OAuth(OAUTH_CONSUMER_KEY,OAUTH_CONSUMER_SECRET,
                     
OAUTH_SIG_METHOD_HMACSHA1,OAUTH_AUTH_TYPE_FORM);
  
$oauth->setToken($access_token$access_token_secret);
  
$resp $oauth->fetch("https://wepayapi.com/v1/group/list");
  
$json $oauth->getLastResponse();
} catch(
OAuthException $E) {
  echo 
"Response: "$E->lastResponse "\n";
}
print_r(json_decode($jsontrue));
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:

% gem install oauth json

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::CKself::CS
                                     
OAUTH_SIG_METHOD_HMACSHA1OAUTH_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,

WePay Comments:

Add your comment