Process Recurring Payments
In order to provide recurring billing for your users, your platform must first build a recurring billing engine (or use a third party billing engine) and a recurring billing UI. The recurring billing engine will calculate recurrence and programmatically initiate POST /payments
calls. The recurring billing UIs will enable your payers and merchants to create and manage recurring payments.
This guide describes recurring billing chronologically, but you can find recommendations for the recurring billing engine starting in the Store Details section.
Be sure to read about and review NACHA rules and regulations regarding payments outlined in the Card Network Rules article.
Build UIs
You must provide a method for payers to interact with recurring payments. Recurring payment UIs must encompass:
- Method for payer to acknowledge that payment details will be kept on file for future payments
- Method for payer to manage recurring payments (cancel, modify, etc.)
- Disclosure to the payer of an upcoming payment (at least 10 days in advance, with the amount, and explicit mention of any amount above the initial authorization)
Find out more about these requirements here.
The UI for your payers could look something like this:
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('select');
var instances = M.FormSelect.init(elems);
});
<body>
<nav>
<div class="nav-wrapper">
<ul id="nav-mobile" class="left">
<li class="active"><a href="">Manage Subscriptions</a></li>
<li><a href="#">Past Orders</a></li>
<li><a href="#">Manage Cards</a></li>
<li><a href="#"><i class="material-icons">account_circle</i></a></li>
</ul>
</div>
</nav>
<div class="row"></div>
<div class="row">
<div id="dropdown-container">
<div class="">
<div class="card blue-grey darken-1">
<div class="card-content white-text">
<span class="card-title">Mop Heads</span>
<div class="container">
<div class="row">
<p>You're subscribed to get one mop head delivered to you monthly.<br><br>Update your subscription...
</p>
<div class='input-field col s8'>
<select>
<option value="" disabled selected>Choose one</option>
<option value="1">Two monthly</option>
<option value="2">Three monthly</option>
<option value="3">Four monthly</option>
<option value="4">Five monthly</option>
<option value="5">Six monthly</option>
</select>
</div>
</div>
<div class="row">
<button class="col s5 btn waves-effect waves-light" type="submit" name="action">Submit
<i class="material-icons right">send</i>
</button>
</div>
<div class="row">
<button class="col s9 btn red darken-2 waves-effect waves-light" type="submit" name="action">Cancel
subscription
<i class="material-icons right">cancel</i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div id="dropdown-container">
<div class="">
<div class="card blue-grey darken-1">
<div class="card-content white-text">
<span class="card-title">Floor Cleaner</span>
<div class="container">
<div class="row">
<p>You're subscribed to get one 16 oz. bottle of floor cleaner delivered to you monthly.<br><br>Update
your subscription...</p>
<div class='input-field col s8'>
<select>
<option value="" disabled selected>Choose one</option>
<option value="1">Two monthly</option>
<option value="2">Three monthly</option>
<option value="3">Four monthly</option>
<option value="4">Five monthly</option>
<option value="5">Six monthly</option>
</select>
</div>
</div>
<div class="row">
<button class="col s5 btn waves-effect waves-light" type="submit" name="action">Submit
<i class="material-icons right">send</i>
</button>
</div>
<div class="row">
<button class="col s9 btn red darken-2 waves-effect waves-light" type="submit" name="action">Cancel
subscription
<i class="material-icons right">cancel</i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script src="https://cdn.wepay.com/wepay.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0/js/materialize.min.js"></script>
</body>
Additional recurring payment UI components may include features like:
- Scheduling tools for merchants who are generating invoices
A sample recurring payment UI for payers setting up a subscription and leveraging the credit card iFrame could look like the following:
<!DOCTYPE html>
<html>
<head>
<title>Credit Card iFrame</title>
</head>
<body>
<div class="dropdown">
<button onclick="myFunction()" class="dropbtn">Select your subscription plan:</button>
<div id="myDropdown" class="dropdown-content">
<a onclick="myFunction2()" id="select" value="daily">Daily</a>
<a onclick="myFunction3()" id="select" value="weekly">Weekly</a>
<a onclick="myFunction4()" id="select" value="monthly">Monthly</a>
</div>
<p></p>
<div id="credit-card-iframe"></div>
<button id="submit-credit-card-button">Submit</button>
<p></p>
<p>By signing up for a subscription, you're agreeing to store this payment method with Mops Galore, and to be automatically charged for your subscription.</p>
<script>
function myFunction() {
document.getElementById("myDropdown").classList.toggle("show");
};
function myFunction2() {
console.log('daily');
document.getElementById("myDropdown").classList.toggle("show");
};
function myFunction3() {
console.log('weekly');
document.getElementById("myDropdown").classList.toggle("show");
};
function myFunction4() {
console.log('monthly');
document.getElementById("myDropdown").classList.toggle("show");
};
</script>
<script src="https://cdn.wepay.com/wepay.min.js"></script>
<script>
var myAppId = "153047";
var apiVersion = "3.0";
var error = WePay.configure("stage", myAppId, apiVersion);
if (error) {
console.log(error);
}
var iframe_container_id = "credit-card-iframe";
var custom_style = "";
var creditCard = WePay.createCreditCardIframe(iframe_container_id, custom_style);
if (creditCard.error_code){
}
document.getElementById('submit-credit-card-button').addEventListener('click', function (event) {
creditCard.tokenize()
.then(function (response) {
console.log('response', JSON.stringify(response));
var node = document.createElement('div');
node.innerHTML = JSON.stringify(response);
})
.catch(function (error) {
console.log('error', error);
var node = document.createElement('div');
node.innerHTML = JSON.stringify(error);
document.getElementById('token').appendChild(node);
});
});
</script>
</body>
</html>
Create a Recurring Payment
To create a recurring payment, the payer will submit their payment details and select/agree to a payment schedule. This can be accomplished with the credit card iFrame.
In all the above cases, thecard_on_file
and recurring
parameters should be added to the payment method and set to true
. When tokenizing cards or using the credit card iFrame, send a POST /payment_methods/id
request to add those parameters after the token has been converted into a payment method. This process will look like the following:1. Convert a token into a payment method:
curl -X POST \
--url 'https://stage-api.wepay.com/payment_methods' \
-H 'Accept: application/json'\
-H 'App-Id: {YOUR_APP_ID}'\
-H 'App-Token: {stage_YOUR_APP_TOKEN}'\
-H 'Api-Version: 3.0'\
-H 'Content-Type: application/json' \
--data-raw '{
"type": "credit_card",
"token": {
"id": "payment_methods-3731efd4-bd36-477a-a413-50548f759a11"
}
}'
00000000-6363-0000-0000-000060380996
.2. Update the payment method with card_on_file
and recurring
parameters:
curl -X POST \
--url 'https://stage-api.wepay.com/payment_methods/00000000-6363-0000-0000-000060380996' \
-H 'Accept: application/json'\
-H 'App-Id: 12121'\
-H 'App-Token: stage_BGDS9205HGGQ4LWIzOWYtNGU0Yy1iMTU4LTM4Zjg0YmYxODQzOA'\
-H 'Api-Version: 3.0'\
-H 'Content-Type: application/json' \
--data-raw '{
"type": "payment_bank_us",
"credit_card": {
"card_on_file": true,
"recurring": true
}
}'
credit_card
structure on the POST /payment_methods
request:curl -X POST \
--url 'https://stage-api.wepay.com/payment_methods' \
-H 'Accept: application/json'\
-H 'App-Id: {YOUR_APP_ID}'\
-H 'App-Token: stage_{YOUR_APP_TOKEN}'\
-H 'Api-Version: 3.0'\
-H 'Content-Type: application/json' \
--data-raw '{
"credit_card": {
"auto_update": false,
"card_holder": {
"address": {
"country": "US",
"postal_code": "94025",
"city": "San Francisco",
"line1": "123 Fake St",
"region": "CA"
},
"email": "example@wepay.com",
"holder_name": "John Snow",
"phone": {
"country_code": "+1",
"phone_number": "5555555555",
"type": "mobile"
}
},
"card_number": "4111111111111111",
"cvv": "123",
"expiration_month": 4,
"expiration_year": 2020,
"trigger_verification": true,
"virtual_terminal_mode": "web",
"card_on_file": true,
"recurring": true
},
"type": "credit_card"
}'
Depending on the circumstance, an initial payment may be executed upon recurring payment method setup, or the initial payment may be scheduled during setup. See our section on how to Execute Recurring Payments for details on this step.
Be sure to:
payment_methods.updated
notification topic to be notified of expired credit card payment methods.Enable Auto Card Updates
BETA
This feature is currently in a closed BETA, and is not available for public use.
The Account Updater feature provides merchants with current cardholder information when participating issuing banks make changes to card data. The most common updates include identifying new account numbers, expiration dates, closed accounts, and brand changes or “card flips”. Account Updater is an automated, dedicated, and secure service that allows your platform to make timely, efficient, and cost-effective change to cardholder account information.
Create a payment method by sending aPOST/ payment_methods
request, card_on_file
and auto_update
must be set to true
.POST/ payment_methods
curl -X POST \
--url 'https://stage-api.wepay.com/payment_methods' \
-H 'Accept: application/json'\
-H 'App-Id: {YOUR_APP_ID}'\
-H 'App-Token: stage_{YOUR_APP_TOKEN}'\
-H 'Api-Version: 3.0'\
-H 'Content-Type: application/json' \
--data-raw '{
"credit_card": {
"auto_update": true,
"card_holder": {
...
},
"card_on_file": true,
...
payment_methods.updated
notification topic to receive updates when this happens. Real-time updates allows for card information to be updated during authorization in which we store the updated information right away.Update Type | WePay Action | ISV/ merchant Action |
---|---|---|
New card/ account number | Updates card on file | No action required |
New expiration date | Updates card on file | No action required |
Card closed | Updates card on file and notifies Partner | Contact card holder to get updated payment method |
Contact cardholder | Updates card on file and notifies Partner | Contact card holder to get updated payment method |
Store Details
The recurring billing engine that you build will run based on billing schedules and recurring payment profiles which your platform creates and stores when a payer first creates a recurring payment. A billing schedule needs to define a start date, end date, cadence (i.e. weekly, monthly, etc.), and number of expected payments. A recurring payment profile needs to identify the billing schedule, recurring payment amount, payment currency, payment method ID, and merchant account ID.
First, create a table in your database for billing schedules with the following data point columns:
- ID (Assign unique identifiers to each billing schedule as it is created.)
- Start date (This can be assigned automatically as the date on which the payer submitted payment details.)
- End date (Disclose the length of recurring payment to the payer, or allow them to customize in your UI.)
- Schedule
- Next payment date (To be calculated and updated by your engine, described in Execute Recurring Payments below.)
- Number of expected payments (Calculate the number of expected payments based on start date, end date, and cadence.)
Second, create a table in your database for payment profiles with the following data point columns:
- ID (Assign unique identifiers to each billing schedule as it is created.)
- Amount
- Currency
- Billing schedule ID
- Payment method ID
- Merchant account ID
- Optional: Payer user ID (If your platform assigns user IDs to payers, include this data point.)
When the payer is submitting their payment details to initiate recurring payments, collect the amount, currency, billing schedule ID, payment method ID, and merchant account ID being generated/used in the initial payment for continued use.
Execute Recurring Payments
To execute recurring payments, you'll need an engine to:
- Calculate the
next_payment_date
for all billing schedules in your data base and update that field. - Run a job to get payment profile IDs which have a billing schedule ID where
next_payment_date
matches the current date. - Run a job to construct and send
POST /payments
requests for each payment profile from step 2.
POST /payments
requests will be constructed based on the data available in the payment profile. For example, you have a payment profile with the following data:
Database Column | Data |
---|---|
id | ABC123 |
amount | 3000 |
currency | USD |
billing_schedule_id | B-890xyz |
payment_method_id | 00000000-6363-0000-0000-0000cd225fe1 |
merchant_account_id | d3f61e56-5d99-4895-af2d-a07ab48476e9 |
payer_user_id | P-nbjd8573 |
Given the above, the resulting POST /payments
request would be constructed like so:
curl -X POST \
--url 'https://stage-api.wepay.com/payments' \
-H 'Accept: application/json'\
-H 'App-Id: {YOUR_APP_ID}'\
-H 'App-Token: stage_{YOUR_APP_TOKEN}'\
-H 'Api-Version: 3.0'\
-H 'Content-Type: application/json'\
-H 'Unique-Key: Unique-Key0' \
--data-raw '{
"account_id": "d3f61e56-5d99-4895-af2d-a07ab48476e9",
"amount": 3000,
"auto_capture": true,
"currency": "USD",
"payment_method": {
"type": "payment_method_id",
"payment_method_id": "00000000-6363-0000-0000-0000cd225fe1"
},
"initiated_by": "customer"
}'
initiated_by
parameter should be included on all recurring payments. This parameter indicates that the customer initiated the first payment, and has agreed to periodical recurring payments in the future.It is also recommended to implement the custom_data
and reference_id
parameters. In the case of recurring payments, the custom_data
parameter could look like the following:{
"custom_data": {
"billing_schedule_id": "B-890xyz",
"payer_user_id": "P-nbjd8573"
}
}