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.

Note
For recurring ACH transactions, use the same payment_method_id in the POST /payments call for each recurring transaction. Also note that initiated_by is only used for recurring credit card payments so this will not be required for recurring ACH payments.

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 ACH Payment

As mentioned in the note above, for recurring ACH transactions, use the same payment_method_id in the POST /payments call for each recurring transaction. Also note that initiated_by is only used for recurring credit card payments so this will not be required for recurring ACH payments.

Recurring ACH Payments Policy

In order for your application to support recurring Pay With Bank (ACH) payments, your application must support certain mandatory compliance requirements, outlined in this section. Your application must use our custom checkout APIs in order to support recurring Pay With Bank (ACH) payments. It is critical that your application is compliant. Violations of this policy will result in termination of your application.

Agreement to use bank account for future payments

To support the storage of payer bank account credentials and recurring use of them for payment, your application must present proper language in order to be compliant with the National Automated Clearinghouse Association (NACHA) network rules. NACHA regulations govern all bank transfers in the United States.

Display the following language before the point of payment submission: “I authorize [application name] to use my bank account for future payments. I understand that I may cancel this authorization at any time.

Your application must store electronic proof that the payer agreed to the use of their bank account for future payments. Adequate proof constitutes the payer's IP address and a timestamp of when they agreed to above statement. WePay or its bank may request this proof from you at any time. For additional reference, see Section 2.3 in the NACHA Operating Rules and Guidelines.

Ability to opt out for recurring paymentsThe NACHA rules mandate that payers who sign up for recurring bank debits must also have a way to opt out of them. These rules state that payers must be able to opt out of any recurring bank debit up to 10 calendar days in advance of the scheduled debit (for additional reference, see Subsection 2.3.2.6 Notices of Variable Debits to Consumer Accounts of the NACHA Operating Rules and Guidelines). There are two ways to satisfy this requirement:
  • Payer accounts: We strongly recommend that your application create an account for the payer if she or he wish to sign up for recurring payments. This is recommended because it provides payers with the easiest method of securely and repeatedly accessing your application to manage or opt out of recurring payments at her or his own discretion. Payers must be able to opt out of any scheduled payment 10 calendar days prior.
  • Notifications: We permit your application to manage the payer opt out requirement via notifications instead of creating payer accounts. If your application intends to implement a subscription model (automatic recurring debits to payer bank accounts), your application must send a notice 10 calendar days in advance of the debit that includes:
    • the date that the impending debit will occur
    • the amount of the debit
    • a link to your application so the payer can opt out of or manage the recurring payment

If your application intends to implement a bank-on-file model (your application stores the payment bank credentials, but the payer must approve each payment), your application still must include a way for the payer to opt out or manage the recurring payment. However, 10 days advanced notice is not required since the bank debit will not occur without the payer's consent.

NACHA rules for varying subscription payments

There are complex rules (Subsection 2.3.2.6 Notices of Variable Debits to Consumer Accounts) of the NACHA Operating Rules and Guidelines that are both challenging for partners to implement and for WePay to enforce. For this reason, WePay will only support subscription debits (of both fixed and variable amounts and intervals) on the condition that notice is sent 10 calendar days prior to the scheduled debit, as detailed above in the subsection “Notifications”.


Create a Recurring Credit Card 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.
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"
 	}
}