← Domain guides

Bill Pay Guide

How do we gather bill pay information?

How do we add a new bill pay payee?

How are permissions handled?

What should I look for in Kibana?

How does the enrollment process work?

How do we add or update payments?

Bill Pay Guide

A walk-through on bill pay flow and operations to help understand bill pay and debug issues

How do we gather bill pay information?

Step 1: Determine the common login id

In order to interact with iPay (our bill pay provider), we (Banno mobile data services) need to properly identify the user on whose behalf we’re making requests. Each financial institution (FI) with the iPay bill pay product sets a “common login id” with iPay. This id serves as a link between the FI’s and iPay’s representation of a user (or member, in the case of credit unions).

Core

For core FIs with NetTeller online banking (JHA’s OLB), the common login id is the user’s NetTeller id (NTID). For FIs without NetTeller, different values are used, such as a person’s username in the FI’s OLB. Today (June 2017), we don’t have any live core institutions without NetTeller, but we soon will. Right now, we don’t have a common way to determine the common login id for users of non-NT core FIs.

Online Banking Aggregation (OLB Agg)

To get the common login id for an agg institution, we scrape a hidden, encoded value (an iBNO) off of a web page during a bill pay fetch request (billPayFetchRequest in fetch-reporting). We decode the value using the secret_key and iv_param in the isb_bill_pay_configs table. This decoded value is the common login id.

There is a caveat for DSO (dual sign-on), i.e. when the FI has a separate sign-on form (and sometimes even a separate webpage) for bill pay. For all regular non-DSO FIs, the user logs into OLB, then clicks an SSO link directly into their online bill pay without entering a new set of credentials. DSO users have to submit separate bill-pay specific credentials into their bill pay sign-on form online. They have a similar step with Banno Mobile/Online: they enter their bill-pay credentials into our app after signing in with their regular OLB credentials. DSO FIs have separate_bill_pay_accounts set to true in the institution_abilities table.

The other caveat is that some FIs’ websites can’t handle a user being signed in more than once at a time. For other OLB agg FIs, we start the bill pay request in parallel, part-way through the regular request. For these, we wait until the entire regular fetch request is finished, then do the bill pay request afterward. These FIs have run_requests_concurrently set to false in the institution_abilities table.

Step 2: Get the iPay subscriber id(s)

All of the iPay operations we use to make bill payments, add payees, etc. for a user require a unique iPay identifier called a subscriber id to regulate each user’s iPay permissions. In addition, NetTeller Cash Management (NT business) users need another unique identifier, called the sub associated user id, since their subscriber id is shared among all members of their company. The company would be the bill pay “subscriber” in this case, and it would have sub-users, each with their own set of permissions, which iPay distinguishes and enforces with the sub associated user id. Both subscriber ids and sub associated user ids are unique integers across all FIs.

When a user kicks off a creation fetch request, once we’ve verified their credentials are valid, we’ll try to find their subscriber id using their common login id, described above. If we don’t find their subscriber id(s) on creation, we’ll try again each time the user syncs (does an online fetch request) or does another creation. To get a subscriber id, we make a BilPaySubConsmCustInq request to iPay via jXchange with the common login id in the SubComId field. The subscriber id is marked as the SubId in the response.

In the case of a NetTeller Cash Management (NTCM) user, we instead use the NetTeller BSL (Business Service Layer) to find the ids. We send along their cash management (CM) user id with the NTID in the GetNetTellerCustomerAccountRequest operation call so that BSL can tell the user apart from other members of their company, who would share their company NTID. In return, we receive back the sub associated user id (SubAssocUsrId in the response) as well as the subscriber id.

A note on login accounts

For core and non-DSO agg FIs, the bill pay accounts (Checking, Savings, etc.) will be associated with the primary login account for the user. For DSO FIs, they will have their own bill-pay-only secondary login account. In fetch-reporting, you’ll see a “Has Billpay” flag. This corresponds to is_billpay in the login_accounts table. It is set to true when we find and save a subscriber id for the user/login (user and login are essentially equivalent in this context since a Banno user is only allowed to have one bill pay set-up no matter the number of logins they have).

Step 3: Use the subscriber id(s) to find bill pay accounts, payees, and payments

If we successfully find a user’s subscriber id(s), we use it/them in jXchange requests to find bill pay accounts, payees, and payments. This discovery phase happens each time a user syncs or does a creation and also whenever we run their login account in batch (if they haven’t opened the app for a while, we update their information behind the scenes).

How do we add a new bill pay payee?

The model for creating a new payee only has the name and the nickname as common fields for each type of payee. Each type of payee has different fields in order to avoid creating incorrect payees or those with incomplete information. The types of payee are:

  • PersonCheck
  • CompanyCheck
  • PersonElectronic
  • CompanyElectronic
  • P2PSMS
  • P2PEmail

Step 1: Get the Banno User and Subscriber Id

Given a Banno user identifier, the payee flow tries to get the Banno user and SubscriberId associated. A user must be enrolled and has an associated SubscriberId to be able to add payees. If a user doesn’t have User/SubscriberId, the add payees flow will fail by returning an error.

Step 2: Call BillPayPayeeAdd Jx operation

Before calling the jX call for adding the payee, the payee flow checks the type of the payee to be added. At this moment only Personal and Company payees are supported, meanwhile, FinancialInstitution payee won’t be processed and the call will return an error. If the payee has a valid type, it will call the operation addPayeeV2 in jxchange-api-rpc (BilPayPayeeAdd) returning the PayeeId for the new payee.

Step 3: Recover the created payee from iPay

There are some fields in a payee (like the amount, PayeeId…) that are generated by iPay. That’s why after adding the payee it is necessary to recover it from iPay. To recover the payee we call the getPayee operation of jxchange-api-rpc (BilPayPayeeInq).

Step 4: Get the Banno account for the user

The following steps require the banno id of the account associated with the payee. To get this account we need to make a query against the endpoint users/{userId}/accounts of banno-users and find the account associated with the payee using the iPayAccountId field.

Step 5: Create a new payee in the cache

We make a request against the endpoint payees / v2 of consumer-bill-pay-cache with the new payee. This endpoint will update the bill_pay database and return the payeeId.

Step 6: Create a new bill with the payee created

The add payee flow calls the endpoint (POST) bills to create a new Bill. For creating the bill we need the PayeeId of the payee created, the banno account and the UserId. The endpoint will return the BillId for the bill created.

Step 7: Register the operation in the history

Before returning the payee created, we record this operation with the history service first to keep it up to date. We use the event PayeeAddedViaText. This event needs the BillId, the PayeeId, and the nickname of the payee created.

Step 8: Return the new payee created with the BillId as the PayeeId

If there wasn’t any failure in the payee creation flow, we will return the Payee created with the iPay fields (that we retrieved from iPay). However, we will use the BillId as the PayeeId.

How are permissions handled?

Ability to see bill pay in the app

In order to see the bill pay section of the app, the user must have permission from their institution (in the form of the user specific ability or, in the absence of one, the FI ability). Additionally, if they are a NetTeller Cash Management user, they also must have permission on the iPay side to schedule bill payments.

Can my user see bill pay?

Go in order down the list of checks. If the answer is ever no, they shouldn’t see bill pay. On checks that have options A and B, use A if the user has a cash_management_user_id in the core_login_details table (NTCM business user); otherwise, use B (individual user).

Check 1.

Is the bill_pay flag in the user_specific_abilities table set to true or is the ability non-existent for this user (the user has no row in the db or that field is empty)? If it’s set to true, skip down to check 3. Else, continue to 2.

Check 2.

  1. Does the user's FI have `business_bill_pay` set to true in the `institution_abilities` table? If yes, continue to 3A.
  2. Does the user's FI have `bill_pay` set to true in the `institution_abilities` table? If yes, continue to 3B.

Check 3.

  1. Does iPay's `BilPaySubInq` response say they `CanScheduleBillPayments`? If the value is true, the user should see bill pay, else, not.
  2. The user should see bill pay.

Ability to see payee creation (the + button) in the app

The user should be able to see payee creation if they have the ability (whether specially, as a user specific ability, or generally as an FI ability). We check the payee_creation ability field in both the user_specific_abilities and institution_abilities tables, regardless of whether they’re a NTCM user. However, if the user is NTCM, they also need to have permission on the iPay side: the CanManagePayees permission that comes back from the BilPaySubInq call must also be true for that user to see the + button.

Ability to see bill pay accounts in the app

The user should be able to see all accounts that come back in the BilPaySubInq, with a few exceptions. Accounts are filtered out if they fail to meet any of the following criteria on the BilPaySubInq response:

  • PayFromId and PayFromAcctId must be present on the account’s PayFromAcctInfo
  • PayFromAcctStat isn’t “Approved” (case insensitive)
  • For business bill pay users only: There exists a SubAssocUsrPerInfo with a PerCode of ExcludedPayFromAccountIdThatTheSubUserCannotDesignate and the Rstr attribute on the PerCode isn’t “Hid” (all values case insensitive)

What should I look for in Kibana?

Log lines that stand out for various success and error cases

Operations

One thing to look for is the bill pay operation call (request/response) for the user around the time the case occurred. The good news is that bill pay interactions, unlike core-fetch jXchange interactions, are always logged, regardless of the log_interaction_always FI flag. The data services stack makes bill pay requests to iPay via jXchange, which passes the responses back from iPay to us.

DS -> jX -> iPay -> jX -> DS

BilPaySubConsmCustInq

To get the user’s subscriber id(s)

BilPaySubInq

To get the following:

  • permissions to limit a NTCM user’s access to bill pay and payee creation in the app
  • accounts and NTCM excluded accounts
  • payees and NTCM excluded payees

BilPayPayeeSrch

To get payees

BilPayPayeeAdd

To add payees

BilPayPayeeMod

To edit and delete payees, but this isn’t currently supported in the app

BilPayPmtHistSrch

To get past payments, as far back as the FI’s number of bill_payment_history_days in the isb_bill_pay_configs table

BilPaySchedPmtSrch

To get future scheduled payments

BilPaySchedPmtAdd

To create payments

BilPaySchedPmtMod

To edit and cancel payments

BilPayPayeeInq

To look up a single payee by its discriminator, PayeeId (we call it a discriminator because it uniquely identifies a payee for a particular user)

We call this when we get available delivery options for payment creations, get the primary address for a payee, after creating a payee, and when looking up payees. (It would also come before modifying and deleting payees, if we supported those actions.)

BilPayChanInq

To get information about the FI

We currently use it to get non-processing dates in order to calculate the available delivery dates during payment creations. We will soon use it to determine the FI’s funding and date models.

BilPaySchedPmtInq

To look up a scheduled payment by its payment id (PmtId)

We call this after scheduling a payment with the standard date option (not a rush option), after updating a scheduled payment, and before cancelling a payment.

BilPayPmtHistInq

To look up a payment by its payment id (PmtId)

We call this after scheduling a payment with a rush option.

Other search items

To find iPay requests for a particular FI, use its routing number. For a specific user, look for their subscriber id (SubscriberId in the Login Details view in fetch-reporting and subscriber_id in the bill_pay.bill_pay_users table). For NTCM users, you can look for their sub_assoc_user_id from the bill_pay.bill_pay_business_users table. We submit it in many of the bill pay requests’ headers, such as payment creation and editing and payee creation, as well as in the body of the subscriber id lookup request.

To find BSL requests for CM users, use the user’s NTID and their CM user id along with app_name:"netteller-bsl-service" in Kibana.

Please note that payee creation is considered to be a high-risk activity because it would enable someone who stole a user’s credentials to move money out of that user’s accounts. If you can’t find logs for adding payees or other risky behaviors, check the FI’s/user’s 2-factor auth (2FA) or MFA setup.

How does the enrollment process work?

The bill pay enrollment process enrolls a user in the iPay Bill Pay product with all eligible accounts. If no accounts are available or the user doesn’t have the Banno ability, then, the user cannot be enrolled. The enrollment process can be seen as a five-step process:

  • Retrieve the userId
  • Get the banno user with its userType
  • Determine whether the user is already enrolled in iPay by finding the user’s SubscriberId (and SubAssocUsrId)
  • Enroll the user (Jx/Symx)
  • Retrieve all the bill pay accounts related to the SubscriberId

Step 1: Get the Banno user and determine the user type

The enrollment process requires a Banno user id to retrieve the Banno user from the endpoint /users/{userId}. A Banno User has the following information:

  • Personal data: Username, first/last name, phone or email.
  • All the Ids associated to this user. A user may only have some of these ids available.
    • NetTellerId
    • CashManagementUserId
    • CustomerId
    • MemberNumber
    • SubscriberId
    • SubAssocUsrId
  • The raw user type. The raw user type defines with the ids of the user, the user type for that user.

The user type is determined using the ids associated with the user and the core type. Here’s the logic used to determine the type:

UserType \ IdsRaw User TypeNetTellerIdCashManagementUserIdCustomerIdMemberNumber
NetTellerJxNetTellerRequiredMust notRequired
BusinessNetTellerRequiredRequiredRequired
BusinessNetTellerRequiredMust notRequired
NetTellerSymxSymXchangeRequired
NonNetTellerSymXSymXchangeMust not
OnlinBankingSymXchange

The SubscriberId for a BusinessUser is optional, but if it is present, it should also have the SubAssocUsrId. Other combinations of Ids and Raw User Type will fail the enrollment process.

Step 2: Determine whether the user is already enrolled

Before attempting to enroll the user, we need to check that the user is not already enrolled.

Identify ther user type

There are two types of user, business or personal. A Business user requires a SubscriberId (to identify the company) and a SubAssocUsrId (to identify the individual employee). A Personal (Retail) user only requires a SubscriberId, not a SubAssocUsrId. Although each user type calls a different endpoint, both types have a similar model of retrieving the id.

User Type Diagram

Get the SubscriberId from the bill_pay_cache

The enrollment process will try to get the subscribedId from the bill_pay_cache. To get the SubscriberId we make a request to the endpoint personalsubscribers/{userId} for personal users. The endpoint for business users is businesssubscribers/{userId} to get the SubscriberId and the SubAssocUsrId.

Enrollment SubscriberId

Get the SubscriberId from banno_all/banno-users (fallback)

If there was no subscriber in the bill_pay_cache, it tries to get the SubscriberId from banno_all/banno-users. The endpoint is v0/institution/{institutionId}/users/{userId}/subscriber.

Update bill_pay_cache if needed

If the enrollment process did not find an SubscribedId in the bill_pay_cache, but there was a SubscriberId in banno_all/banno-users, it will update the cache with that identifier. To update the cache, the enrollment process will call the endpoint personalsubscribers/{userId} and businesssubscribers/{userId} with a POST method, for personal users and retail users respectively.


Step 3: Filter non-enrollment users

The enrollment process difers if the user is from Jx (NetTellerJx) or Symx (NetTellerSymx, NonNetTellerSymX). Today (2019), Business and OnlinBanking users don’t support the enrollment process. For non supported users, the enrollment process will return an error.

Step 4: Enroll users

As we said in the previous section, a user that does not have a SubscriberId and it is not a Bussiness/Online type is eligible for enrollment. The enrollment process for jX users (NetTellerJx) and SymX (NetTellerSymX and NonNetTellerSymXUser) users is the same. The only difference in the enrollment process happens after having the accounts eligible. SymX users do not need to retrieve channel settings and the filter accounts, They use all the eligible accounts.

Get common Id

Because there are SymX users that do not have NettellerId they use the operation getCommonIdForNTSymX / getCommonIdForNonNTSymX to get the commonId (common login id/subComId) for enrolling the user in iPay.

Get personal info

Given the customerId and the institutionId, we get the personal information for a specific user. The personal info is retrieved from the v1/institutions/{institutionId}/customers/{customerId} endpoint. If some of the personal information is not present we use the default value for that user. We refer as personal info to email, phone number or address.

Get eligible accounts for a user

Given the NetTellerId (that all the NetTellerJx users have) and the institutionId and using the endpoint institution/{institutionId}/nettelleruser/{NetTellerId}, We return all the eligible accounts for that user. An eligible account has the basic information for an account: the account number, the type and its name.

Get the channel setting for an institution

We can get the channel settings for a user calling the operation billPayChanInq and the institutionId for a user. The channel settings have information related to the institutionId such as: if the institution can add or manage recurring payments or it can have pay from savings. This step is not done for Symx users.

Get all the actives accounts for a user

We use all the eligible accounts from the previous step look for all the actives accounts of a user. If the channel setting payFromSavings is true we use the eligible accounts otherwise we use only the eligible accounts that are checking. Because Symx users did not recover the channel settings, they don’t filter the eligible accounts. Then, using the operation acctInq we get the status for each account and filter those accounts that are not eligible for enrollment.

Enroll SubscriberId

If getExistingSubscriber comes empty the enrollment process will try to enroll the user. If the enrollment process found a SubscriberId it will look bill pay for accounts and end the enrollment process (because the user is already enrolled) returning a Created. We enroll the subscriberId with the operation BilPaySubAdd. After that we call the endpoint personalsubscribers/{userId} with a POST. Lastly, we record the enrollment into the history and return all the personal accounts using the operation BilPaySubInq.

Step 5: Get all banno accounts for a user

The last step of the enrollment process is to get all the banno accounts for that user through the endpoint v1 / users / {userId} / accounts / all.

#How do we add or update payments? In the process for making/updating payments, we (Banno mobile data services) can identify two steps:

  • Retrieve all the information related the payments and filter thoses payments that cannot be made/updated.
  • Then for each payment, we will make or update the payment. The only limitation on this process is that an user can only make/update a single payment of payee.

Step 1: Retrieve and filter process

The retrieve and filter processes have two main functions, get the information for making/updating each payment and filter those payments that have incorrect information or can’t be processed. This step will return:

  • A list of payments that cannot be processed and the reason behind it.
  • A list of payments that can be processed with their information. This step may return an error if some of the general information for all the payments (get the user, subscriber, …) cannot be retrieved.

Step 1.1: Get the user

The payment process requires a Banno user to make the payments. To retrieve the Banno user the process will make a call to the endpoint /users/{userId}.

Step 1.2: Get the settings

For processing all the payments we need some user/institution settings.

Get the abilities for the user

The abilities define what can and cannot do a user. The relevant abilities for a user in the payment process are:

  • addRecurringPayments
  • manageRecurringPayments
  • p2pEnabled

Get channel settings for the user’s institution

Give the user type (Personal or Business) and the institution, we recover the channel settings from the cache. The channel settings defines what can be done in an institution for that user type (ex: the institution supports recurring payment) or extra information of the institution.

Calculate payment settings

The payment settings defines what can be done in the payment process for a user given the combination of his abilities and the channel settings. For a given user, the following payment settings are allowed if they allowed in the abilities and channel settings:

  • addRecurringPayments
  • manageRecurringPayments
  • p2pEnabled

Step 1.3: Filter payments by abilities

We will filter all the payments that are set by the user as recurring when the payment setting does not allow recurring payments.

Step 1.4: Get the subscriber

We get the subscriber associated for this user. Depending of the user type the payment process will get the subscriber from two different endpoints, personalsubscribers/{userId} for personal users and businesssubscribers/{userId} for business users.

Step 1.5: Get payees from the cache and jx

We will use the endpoint v0/users/{userId}/payees get all the payees associated with the user in the cache. Then we will do the same against jx to get all the payees associated with the user.

Step 1.6: Filter payment without a payee

Using the payees from the previous step, we filter those payments that are related with a payee that does not exists in the cache and in iPay.

Step 1.7: Filter payment with incorrect address

We filter all the payments that has an incorrect address. All the address should have a type Prim and an id.

Step 1.8: Filter incorrect P2P payments

We filter all the payments that are P2P (they are Person type or p2p type is defined) but the payment settings for that user does not allow P2P payments.

Step 1.9: Get all the accounts for the user

The payment process will call the endpoint users/{userId}/accounts to retrieve all the bill pay accounts of the user. If there is an error as a fallback, the process will call the endpoint v1/users/{userId}/accounts/all.

Step 1.10: Calculate and filter by delivery options

For each payment we calculate its delivery options. Then, we filter all the payments that could not calculate their delivery options.

Step 1.11: Filter by account

We filter all the payments that does not have a banno account (retrieved before).

Step 1.12: Calculate and filter by estimated arrival date

We use the payment settings and delivery options of each payment to calculate their estimated arrival date. We filter all the payments that could not calculate their estimated arrival date.

Step 1.13: Make/Update each payment

For each payment that has not been filtered, we call the function to make/update the payment (Explained in the steps 2.1 and 2.2). After that we will return:

  • A list with each payment that was filtered/has an error with their associated payeeId.
  • A list with the information of each payment after being make/update and their associated payeeId.

Step 2.A: Make payment

Step 2.A.1: Add the payment to iPay

We call the jx operation BilPaySchedPmtAdd to add the payment into iPay. If this operation worked correctly we receive the confirmationId for that payment.

Step 2.A.2: Get past or future payments

We make the jx call BilPayPmtHistSrch to recover the past payment with the confirmationId obtained in the previous step. This step validates that the payment was successfully added into iPay.

Step 2.A.3: Add the payment to the cache

We call the endpoint v0/schedpayments to add the previous payment into the cache.

Step 2.A.4: Recover the payment from cache

In a similar way that we did in the previous step, this step validates that we added the payment into the cache correctly. We call the endpoint v0/schedpayments/{paymentId} to recover the payment from the cache.

Step 2.A.5: Record the operation into the history

Finally we record the operation into the cache using a PaymentCreatedChange event.

Step 2.B: Update payment

TBD