WePay

Building an Online Marketplace with WePay

Overview

WePay makes it easy to integrate payments into a marketplace. In this section, you'll see how to:

  • Get a simple marketplace integrated with just a few calls.
  • Take more control of the user experience while leaving PCI to WePay.

Scenario & Key Requirements

Your site is focused on buying and selling baseball cards. Sellers register with your site and list items for sale. Buyers search and browse, and buy individual items for sale. Your site makes money by charging a transaction fee. You are considering offering premium services for a fixed monthly fee.

At WePay, your sellers are the merchants, and the buyers are the payers, and we'll use those terms in this guide.

Simple Approach

To get up and running quickly, you decide that for your first version you'll leverage the WePay user interface as much as possible.

Creating accounts for your merchants

Each of your merchants will get their own WePay payment account. This keeps all the money management with WePay. Your site will facilitate creating this account, and will receive an access token that your site saves. This access token allows your site to handle checkout, get status, etc.

Creating a payment account involves 2 steps:

  • Setup the merchant using OAuth2.
  • Create a payment account for that merchant.

Setup a merchant using OAuth2

The easiest approach is to redirect to WePay's OAuth2 authorization URI. Your merchant will see a popup where they can set up their login.

https://www.wepay.com/v2/oauth2/authorize
?client_id=[your client id]
&redirect_uri=[your redirect uri ex. 'http://example.com/wepay']
&scope=[the permissions you want ex. manage_accounts,collect_payments]

When merchants complete this, follow up with the /oauth2/token call to receive an access token for this merchant:

  • PHP
  • cURL
  • Ruby
  • Python
<?php
    // WePay PHP SDK - http://git.io/mY7iQQ
    require 'wepay.php';

    // oauth2 parameters
    $code = $_GET['code']; // the code parameter from step 2
    $redirect_uri = "http://www.example.com/oauth2_redirect_uri"; // this is the redirect_uri you used in step 1

    // application settings
    $client_id = 123456789;
    $client_secret = "1a3b5c7d9";

    // change to useProduction for live environments
    Wepay::useStaging($client_id, $client_secret);

    $wepay = new WePay(NULL); // we don't have an access_token yet so we can pass NULL here

    // create an account for a user
    $response = WePay::getToken($code, $redirect_uri);

    // display the response
    print_r($response);
?>
curl https://stage.wepayapi.com/v2/oauth2/token \
	-d "client_id=123456789" \
	-d "client_secret=1a3b5c7d9" \
	-d "code=52sdga231sddd213jj9a" \
	-d "redirect_uri=http://www.example.com/oauth2_redirect_uri"
				
# WePay Ruby SDK - http://git.io/a_c2uQ
require 'WePay_API_v2_Ruby_SDK.rb'

# oauth2 parameters
code = params[:code]; # the code parameter from step 2
redirect_uri = "http://www.example.com/oauth2_redirect_uri"; # this is the redirect_uri you used in step 1

# application settings
client_id = 123456789
client_secret = '1a3b5c7d9'

# set _use_stage to false for live environments
wepay = WePay.new(client_id, client_secret, _use_stage = true)

# create an account for a user
response = wepay.oauth2_token(code, redirect_uri)

# display the response
p response
# WePay Python SDK - http://git.io/v7Y1jA
from wepay import WePay

# oauth2 parameters
code = '52sdga231sddd213jj9a'; # the code parameter from step 2
redirect_uri = "http://www.example.com/oauth2_redirect_uri"; # this is the redirect_uri you used in step 1

# application settings
client_id = 123456789
client_secret = '1a3b5c7d9'
production = False

# set production to True for live environments
wepay = WePay(production, None)

# create an account for a user
response = wepay.get_token(redirect_uri, client_id, client_secret, code)

# display the response
print response

Create a payment account

Now that your site has an access token, the first order of business is to create a payment account. Although there are many optional arguments, all you need to provide for US merchants are the name of the account and a description. The name is typically based on your site's name, e.g. "ABC Baseball Card Trading". The description is variable and up to you.

  • PHP
  • cURL
  • Ruby
  • Python
<?php
    // WePay PHP SDK - http://git.io/mY7iQQ
    require 'wepay.php';

    // application settings
    $client_id = 123456789;
    $client_secret = "1a3b5c7d9";
    $access_token = "STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20";

    // change to useProduction for live environments
    Wepay::useStaging($client_id, $client_secret);

    $wepay = new WePay($access_token);

    // create an account for a user
    $response = $wepay->request('account/create/', array(
        'name'          => 'Account Name',
        'description'   => 'A description for your account.'
    ));

    // display the response
    print_r($response);
?>
curl https://stage.wepayapi.com/v2/account/create \
	-H "Authorization: Bearer STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20" \
	-d "name=Account name" \
	-d "description=A description for your account."
				
# WePay Ruby SDK - http://git.io/a_c2uQ
require 'WePay_API_v2_Ruby_SDK.rb'

# application settings
client_id = 123456789
client_secret = '1a3b5c7d9'
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20'

# set _use_stage to false for live environments
wepay = WePay.new(client_id, client_secret, _use_stage = true)

# create an account for a user
response = wepay.call('/account/create', access_token, {
    :name          => 'Account Name',
    :description   => 'A description for your account.'
})

# display the response
p response
# WePay Python SDK - http://git.io/v7Y1jA
from wepay import WePay

# application settings
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20'
production = False

# set production to True for live environments
wepay = WePay(production, access_token)

# create an account for a user
response = wepay.call('/account/create', {
    'name': 'Account Name',
    'description': 'A description for your account.'
})

# display the response
print response

Processing payments

Let's assume the following:

  • For the first version your site just needs to handle simple checkout. A single call is all you need. Your site will never touch sensitive info including the credit card, so your site remains free of PCI requirements.
  • WePay will send emails to both your merchant and the payer. You can inject a message including embedded HTML. A good use for this is to summarize the purchase. Letting WePay send the email means you'll only get an email if the payer successfully checks out.
  • Your merchant has decided on a flat $1.00 shipping charge per order. Your platform will instruct WePay to ask for shipping info as part of the checkout process.
  • Your site is charging your merchants 5% of the total amount, and your merchants will pay this as a fee (not the payer).
  • Finally, set the redirect URI to your platform's "Congratulations" page. As a side effect, catching this URI will let your platform know that the checkout completed successfully.

Call /checkout/create with these arguments:

  • PHP
  • cURL
  • Ruby
  • Python
<?php
    // WePay PHP SDK - http://git.io/mY7iQQ
    require 'wepay.php';

    // application settings
    $account_id = 123456789; // your app's account_id
    $client_id = 123456789;
    $client_secret = "1a3b5c7d9";
    $access_token = "STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20"; // your app's access_token

    // change to useProduction for live environments
    Wepay::useStaging($client_id, $client_secret);

    $wepay = new WePay($access_token);

    // create the checkout
    $response = $wepay->request('checkout/create', array(
        'account_id'            => $account_id,
        'amount'                => '50.00',
        'currency'              => 'USD',
        'short_description'     => 'Purchase from John Smith\'s Website',
        'type'                  => 'goods',
        'hosted_checkout'       =>  array(
            'require_shipping'  =>  true,
            'shipping_fee'      =>  '1.00',
            'redirect_uri'      =>  'http://www.example.com/payment_success'
        ),
        'fee'                  =>  array(
            'app_fee'          => '2.50',
            'fee_payer'        => 'payee'
        ),
        'email_message'        => array(
            'to_payer'         => 'Items<BR>Ron Santo 1969 - $20.00<BR>Ernie Banks 1970 - $30.00<br>Tax - $2.50<br>Total: $50.00',
            'to_payee'         => 'Items<BR>Ron Santo 1969 - $20.00<BR>Ernie Banks 1970 - $30.00<br>Tax - $2.50<br>Total: $50.00'
        )
    ));

    // display the response
    print_r($response);
?>
$ curl https://stage.wepayapi.com/v2/checkout/create \
    -H "Authorization: Bearer STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20" \
    -d "account_id=233" \
    -d "amount=50.00" \
    -d "short_description=A brand new soccer ball" \
    -d "type=goods" \
    -d "currency=USD" \
    -d "fee[app_fee]=2.50" \
    -d "fee[fee_payer]=payee" \
    -d "hosted_checkout[require_shipping]=true" \
    -d "hosted_checkout[shipping_fee]=1.00" \
    -d "hosted_checkout[redirect_uri]=http://www.example.com/payment_success" \
    -d "email_message[to_payer]=Items<BR>Ron Santo 1969 - $20.0<BR>Ernie Banks 1970 - $30.00<BR>Tax - $2.50<BR>Total: $50.00" \
    -d "email_message[to_payee]=Items<BR>Ron Santo 1969 - $20.00<BR>Ernie Banks 1970 - $30.00<BR>Tax - $2.50<BR>Total: $50.00"
				
# WePay Ruby SDK - http://git.io/a_c2uQ
require 'WePay_API_v2_Ruby_SDK.rb'

# application settings
account_id = 123456789  # your app's account_id
client_id = 123456789
client_secret = '1a3b5c7d9'
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20' # your app's access_token

# set _use_stage to false for live environments
wepay = WePay.new(client_id, client_secret, _use_stage = true)

# create the checkout
response = wepay.call('/checkout/create', access_token, {
    :account_id          => account_id,
    :amount              => '50.00',
    :currency            => 'USD',
    :short_description   => 'A brand new soccer ball',
    :type                => 'goods',
    :hosted_checkout     => {
            :require_shipping    => true,
            :shipping_fee        => '1.00',
            :redirect_uri        => 'http://www.example.com/payment_success'
    },
    :fee                => {
            :app_fee       =>   2.50,
            :fee_payer     =>   'payee',
    },
    :email_message      =>  {
            :to_payer   =>   'Items<BR>Ron Santo 1969 - $20.00<BR>Ernie Banks 1970 - $30.00<br>Tax - $2.50<br>Total: $50.00',
            :to_payee   =>  'Items<BR>Ron Santo 1969 - $20.00<BR>Ernie Banks 1970 - $30.00<br>Tax - $2.50<br>Total: $50.00',
    }
})

# display the response
p response
# WePay Python SDK - http://git.io/v7Y1jA
from wepay import WePay

# application settings
account_id = 123456789 # your app's account_id
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20' # your app's access_token
production = False

# set production to True for live environments
wepay = WePay(production, access_token)

# create the checkout
response = wepay.call('/checkout/create', {
    'account_id': account_id,
    'amount': '24.95',
    'short_description': 'A brand new soccer ball',
    'type': 'goods',
    'currency': 'USD',
    'hosted_checkout': {
            'require_shipping': True,
            'shipping_fee': '1.00',
            'redirect_uri': 'http://www.example.com/payment_success'
    },
    'fee':  {
            'app_fee': '0.15',
            'fee_payer': 'payee'
    },
    'email_message':  {
            'to_payer': 'Items<BR>Ron Santo 1969 - $20.00<BR>Ernie Banks 1970 - $30.00<br>Tax - $2.50<br>Total: $50.00',
            'to_payee': 'Items<BR>Ron Santo 1969 - $20.00<BR>Ernie Banks 1970 - $30.00<br>Tax - $2.50<br>Total: $50.00'
    }
})

# display the response
print response

The /checkout/create call will return a checkout_id and a URI for the payment page.

Post-checkout processing

The easiest way to know when the payer completes checkout is by waiting for the callback_uri. Before showing the congrats page, get the shipping address from the checkout object:

  • PHP
  • cURL
  • Ruby
  • Python
<?php
    // WePay PHP SDK - http://git.io/mY7iQQ
    require 'wepay.php';

    // application settings
    $account_id = 123456789; // your app's account_id
    $client_id = 123456789;
    $client_secret = "1a3b5c7d9";
    $access_token = "STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20"; // your app's access_token
    $checkout_id = 7734724523235;

    // change to useProduction for live environments
    Wepay::useStaging($client_id, $client_secret);

    $wepay = new WePay($access_token);

    // create the checkout
    $response = $wepay->request('checkout', array(
        'checkout_id'       => $checkout_id
    ));

    // display the response
    print_r($response);
?>
$ curl https://stage.wepayapi.com/v2/checkout \
    -H "Authorization: Bearer STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20" \
    -d "checkout_id=7734724523235"
# WePay Ruby SDK - http://git.io/a_c2uQ
require 'WePay_API_v2_Ruby_SDK.rb'

# application settings
account_id = 123456789  # your app's account_id
client_id = 123456789
client_secret = '1a3b5c7d9'
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20' # your app's access_token
checout_id = 7734724523235

# set _use_stage to false for live environments
wepay = WePay.new(client_id, client_secret, _use_stage = true)

# create the checkout
response = wepay.call('/checkout', access_token, {
    :checkout_id        => checkout_id
})

# display the response
p response
# WePay Python SDK - http://git.io/v7Y1jA
from wepay import WePay

# application settings
account_id = 123456789 # your app's account_id
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20' # your app's access_token
production = False
checkout_id = 7734724523235

# set production to True for live environments
wepay = WePay(production, access_token)

# create the checkout
response = wepay.call('/checkout', {
    'checkout_id': 7734724523235
})

# display the response
print response

This will return a great deal of information, including the shipping_address structure.

That's it - your platform is doing everything it needs to do for a simple marketplace.

Customizing the checkout experience

  • Reminder on risks and responsibilities
  • Using /credit_card/create
  • Turning off WePay emails and sending your own

The first part of the user experience partners want to customize is usually the payment experience. Instead of using WePay's embedded iframe or pop-up window, as we did in the above example, partners can completely own the checkout experience.

Before you jump in - a note on security

A big part of what WePay provides is minimizing the scope of security requirements for your platform. Using the approach in this section raises your platform's responsibility compared with the approach in the previous section. Please read our security page for more information.

Securely obtaining credit card info

You can design your credit card acceptance form any way you wish, but you need to use WePay's JavaScript library to securely send the credit card info directly to WePay's servers. Do not accept credit card information onto your own server and then call WePay's APIs.

WePay's JavaScript library uses the /credit_card/create API call to store the payer's credit card info securely on WePay's servers, and returns your platform a token. This token can then be used in a /checkout/create call to complete a transaction without any further user interaction.

A minimal credit card form looks like this:

Name:
Email:
Credit Card Number: (Example Card Numbers)
Expiration Month:
Expiration Year:
CVV:
Zipcode:

And the HTML source is here:

<script type="text/javascript" src="https://static.wepay.com/min/js/tokenization.v2.js">
</script>
<script type="text/javascript">
    WePay.set_endpoint("stage"); // change to "production" when live

function chargeCard(){
        var response = WePay.credit_card.create( {
            "client_id":118711,
            "user_name":document.getElementById('name').value,
            "email":document.getElementById('email').value,
            "cc_number":document.getElementById('cc-number').value,
            "cvv":document.getElementById('cc-cvv').value,
            "expiration_month":document.getElementById('cc-month').value,
            "expiration_year":document.getElementById('cc-year').value,
            "address":
                {
                    "zip":document.getElementById('zip').value
                }
        }, function(data) {
            if (data.error) {
                console.log(data);
                // handle error response
            } else {
                // call your own app's API to save the token inside the data;
                // show a success page
            }
        } );
    }
</script>
<table>
    <tr><td>Name: </td><td><input id="name" type="text"></input></td></tr>
    <tr><td>Email: </td><td><input id="email" type="text"></input></td></tr>
    <tr><td>Credit Card Number: </td><td><input id="cc-number" type="text"></input></td></tr>
    <tr><td>Expiration Month: </td><td><input id="cc-month" type="text"></input></td></tr>
    <tr><td>Expiration Year: </td><td><input id="cc-year" type="text"></input></td></tr>
    <tr><td>CVV: </td><td><input id="cc-cvv" type="text"></input></td></tr>
    <tr><td>Zipcode: </td><td><input id="zip" type="text"></input></td></tr>
    <tr><td></td><td><input type="submit" name="Submit" value="Submit" onclick="chargeCard()"/></td></tr>
</table>

The function chargeCard() is invoked when the user submits the checkout form. chargeCard extracts the credit card fields and maps them to WePay's JavaScript call WePay.credit_card_create. In this way, the sensitive information is passed directly to WePay's servers, and your platform receives a token for later use.

Your chargeCard function can take the data response and call your own server's APIs to store the token.

Completing checkout using a token

When it's time to charge the credit card, follow the /checkout/create example shown before, but this time add these parameters:

  • PHP
  • cURL
  • Ruby
  • Python
<?php
// WePay PHP SDK - http://git.io/mY7iQQ
require 'wepay.php';

// application settings
$account_id = 123456789;
$client_id = 123456789;
$client_secret = "1a3b5c7d9";
$access_token = "STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20";

// credit card id to charge
$credit_card_id = 123456789;

// change to useProduction for live environments
Wepay::useStaging($client_id, $client_secret);

$wepay = new WePay($access_token);

// charge the credit card
$response = $wepay->request('checkout/create', array(
    'account_id'        => $account_id,
    'amount'        => '25.50',
    'currency'      =>  'USD',
    'short_description'    => 'A brand new soccer ball',
    'type'            => 'goods',
    'payment_method'   =>  array(
        'type'        => 'credit_card',
        'credit_card'   =>   array(
            'id'    => $credit_card_id
        )
    )
));

// display the response
print_r($response);
?>
$ curl https://stage.wepayapi.com/v2/checkout/create \
    -H "Authorization: Bearer STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20" \
    -d "account_id=123456789" \
    -d "amount=25.50" \
    -d "currency=USD" \
    -d "short_description=A brand new soccer ball" \
    -d "type=goods" \
    -d "payment_method[type]=credit_card" \
    -d "payment_method[credit_card][id]=123"
# WePay Ruby SDK - http://git.io/a_c2uQ
require 'WePay_API_v2_Ruby_SDK.rb'

# application settings
account_id = 123456789
client_id = 123456789
client_secret = '1a3b5c7d9'
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20'

# credit card to charge
credit_card_id = 123456789

# set _use_stage to false for live environments
wepay = WePay.new(client_id, client_secret, _use_stage = true)

# charge the credit card
response = wepay.call('/checkout/create', access_token, {
    :account_id                => account_id,
    :amount                    => '25.50',
    :currency               => 'USD',
    :short_description        => 'A brand new soccer ball',
    :type                   => 'goods',
    :payment_method         =>  {
        :type   => 'credit_card',
        :credit_card => {
           :id       => credit_card_id
        }
    }
})

# display the response
p response
# WePay Python SDK - http://git.io/v7Y1jA
from wepay import WePay

# application settings
account_id = 123456789
access_token = 'STAGE_8a19aff55b85a436dad5cd1386db1999437facb5914b494f4da5f206a56a5d20'
production = False

# credit card id to charge
credit_card_id = 123456789

# set production to True for live environments
wepay = WePay(production, access_token)

# charge the credit card
response = wepay.call('/checkout/create', {
    'account_id': account_id,
    'amount': '25.50',
    'short_description': 'A brand new soccer ball',
    'type': 'goods',
    'currency': 'USD',
    'payment_method':  {
        'type': 'credit_card',
        'credit_card': {
            'id': credit_card_id
        }
    }
})

# display the response
print response

Because your platform already has the card info, this usage of /checkout/create will immediately charge the card with no user interaction.

Sending your own emails to merchants and payers

Another way your platform can take more control of the user experience is to generate your own emails to merchants and payers during checkout. Your WePay account manager can assist you in turning off specific emails.

Advanced Features

WePay supports a number of advanced payment options that your marketplace may want to take advantage of.

  • Subscriptions: Besides (or instead of) taking a transaction fee, your platform can charge your merchants a monthly fee. See the subscription section of our API for details.

  • Splitting payments: Sometimes platforms want to send a portion of each transaction to a 3rd party. Your platform can do this with WePay, provided:

    • The third party becomes a merchant and your platform obtains its access token (your platform can have a special signup you use for these 3rd parties so they don't look like regular sellers on your platform.)
    • Your payers will see the 3rd party split as a separate transaction on their credit card, to the 3rd party.

    The process is based on the tokenization of credit cards shown earlier. Your platform simply makes two or more charges, one to each "merchant". As long as you make the total clear to the payer and also advise they will see multiple charges and to whom, this is OK.

  • For more info, see our tutorial on splitting payments.