WePay

Building an eCommerce Platform with WePay

Overview

WePay makes it easy to integrate payments into an eCommerce platform. In this section, you'll see how to:

  • Get a simple eCommerce platform integrated with just a few calls
  • Add support for more advanced eCommerce features like delayed capture
  • Take more control of the user experience while leaving PCI to WePay

Scenario & Key Requirements

You have a platform that allows your users to create websites for their businesses, organizations, etc. You are also adding the ability for these users to list products for sale and easily sell these products. Thus, you want to provide these users with a built-in payment system. You're also thinking about changing your platform's business model from charging monthly fees to a percentage of your user's sales.

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

Simple Approach

To get up and running quickly, you decide for your first version that you'll:

  • Leverage the WePay user experience as much as possible.
  • Assume your users are shipping on order, and so you'll capture funds immediately at checkout

Creating accounts for your merchants

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

Setting up a merchant account requires two steps:

  • Setup the user using OAuth2
  • Create a merchant account for that user

Set up a merchant using OAuth 2

The easiest approach is to redirect to WePay's OAuth2 authorization URI. Your merchants will see a popup where they can setup 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 platform has an access token, the first order of business is to create a merchant 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 platform's name, e.g. "ABC eCom Service". 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 platform just needs to handle simple checkout. A single call is all you need. Your platform will never touch sensitive info including the credit card, so your platform remains free of PCI requirements.
  • WePay will send emails to both your merchant and the customer. 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 (buyer) 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 platform is charging your merchants 5% of the total amount, and your merchants will pay this as a fee (not the payer/buyer).
  • 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=12345" \
    -d "amount=50.00" \
    -d "short_description=A brand new soccer ball" \
    -d "type=goods" \
    -d "currency=USD" \
    -d "hosted_checkout[require_shipping]=true" \
    -d "hosted_checkout[shipping_fee]=1.00" \
    -d "fee[app_fee]=2.50" \
    -d "fee[fee_payer]=payee", \
    -d "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", \
    -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", \
    -d "hosted_checkout[redirect_uri]=http://www.example.com/payment_success"
    
# 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 merchant 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 store.

Deferring capture until shipping

It's a best practice to delay actually charging credit cards until a merchant is ready to ship. However, you and your merchants want to know at the time customers checkout that a payment method is valid and to reserve the funds. The way to do this in WePay is to get a preapproval at the time of checkout, and follow it with a checkout call when the merchant ships.

Preapprovals work just like checkout objects, except they don't charge the card. They just validate that the card is good and hold the funds against the payer's credit limit. A preapproval is good for up to 14 days. If your merchants will not ship products within 14 days, then your platform needs to tokenize cards and delay authorizing them until shipping. We'll continue this example using preapprovals.

Change to checkout calls

To use preapprovals, simply change your /checkout/create calls to /preapproval/create. The user will see the same pop-up window to enter payment info, and your app will receive a preapproval_id that it must save.

New calls when your merchant ships

When your merchants indicate they have shipped a product, your platform calls /checkout/create, but this time, they pass in the preapproval_id obtained at checkout.

Just supply the preapproval_id.

Partial shipments

When payers buy multiple items in one checkout, sometimes merchants want to ship items at different times. Your platform can use a /checkout/create call multiple times against a single preapproval_id.

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 the payment_method_id and payment_method_type 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 "short_description=A brand new soccer ball" \
    -d "type=goods" \
    -d "currency=USD" \
    -d "payment_method[type]=credit_card" \
    -d "payment_method[credit_card][id]=1234"
# 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',
    :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
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',
    '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
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.

More Advanced Store Features

You can build a very sophisticated eCommerce platform with many payment options. Other techniques that might apply to your platform:

Saving payment info for returning users: The same tokenization method used to let your platform manage the checkout experience allows your platform to reference the tokenized credit card repeatedly. Since your platform has only stored a token, there is no further PCI risk in holding it for future checkouts. Be aware that credit cards do eventually expire.

Use the /credit_card API to return information about a saved credit card, such as its name and last 4 digits. You can show this safely to your payers to confirm this is the credit card they still want to use.

Subscriptions: You can use our subscription APIs to setup automatic, recurring charges. Read the subscription API documentation for more details.