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:

jshtml
Copy
Copied
  document.addEventListener('DOMContentLoaded', function() {
    var elems = document.querySelectorAll('select');
    var instances = M.FormSelect.init(elems);
  });
Copy
Copied
<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:

Copy
Copied
<!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, the card_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:

Copy
Copied
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"
  }
}'
The API response here will include a payment method ID for use in the next step. For the purposes of this example, the returned payment method ID used is 00000000-6363-0000-0000-000060380996.

2. Update the payment method with card_on_file and recurring parameters:

Copy
Copied
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
  }
}'
Alternatively, when using server-to-server processing, include those parameters in the credit_card structure on the POST /payment_methods request:
Copy
Copied
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:
Subscribe to the 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 a POST/ payment_methods request, card_on_file and auto_update must be set to true.POST/ payment_methods
Copy
Copied
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,
    ...
Updates are available in batches (for Visa and MasterCard) or real-time (Visa). Batch updates enables scheduled, large-scale updates including portfolio conversions between payment brands. Every 30 days, we will submit a batch of cards on file to our updating service. Subscribe to the 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 TypeWePay ActionISV/ merchant Action
New card/ account numberUpdates card on fileNo action required
New expiration dateUpdates card on fileNo action required
Card closedUpdates card on file and notifies PartnerContact card holder to get updated payment method
Contact cardholderUpdates card on file and notifies PartnerContact 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:

  1. Calculate the next_payment_date for all billing schedules in your data base and update that field.
  2. Run a job to get payment profile IDs which have a billing schedule ID where next_payment_date matches the current date.
  3. 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 ColumnData
idABC123
amount3000
currencyUSD
billing_schedule_idB-890xyz
payment_method_id00000000-6363-0000-0000-0000cd225fe1
merchant_account_idd3f61e56-5d99-4895-af2d-a07ab48476e9
payer_user_idP-nbjd8573

Given the above, the resulting POST /payments request would be constructed like so:

Copy
Copied
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"
}'
It's important to note that the 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:
Copy
Copied
{
 "custom_data": {
 	"billing_schedule_id": "B-890xyz",
 	"payer_user_id": "P-nbjd8573"
 	}
}