Add a Debit Card
Overview
You can provide the ability for workers to have payments made to an existing debit card, instead of the Branch Wallet, by embedding the Branch-customized TabaPay SSO Card Widget. This will let a worker securely input card details, returning a token to access the card data in a PCI-compliant manner.
Security
Review the recommendations for Application Security before proceeding with this integration.
Implementation
Backend Server Implementation
Develop a new endpoint called AddDebitCard for your backend server.
- Accept a
POSTrequest containing the worker's details (see JavaScript Web Implementation step 3 for example request). - Forward the worker's details to Branch's Add External Card endpoint.
- Save the returned External Card's
IDto the company database, to be used for future API calls.
Select the iFrame URL
Improved iFrameWorker names are now automatically linked to Debit Cards using verified roster records. This reduces friction to onboard, and ensures the appropriate name is used. The improved iFrame implements this by omitting the
First NameandLast Namefields, and producing blank values in the event data for these fields. Corresponding with this change, Branch's Add External Card endpoint now accepts blank values for these fields.
- Improved iFrame (Example)
- Production URL: https://tabapay-iframe.branchapp.com/
- Sandbox URL: https://tabapay-iframe-sandbox.branchapp.com/
- Legacy iFrame (Example)
- Production URL: https://direct-embed.branchapp.com/card-widget.html
- Sandbox URL: https://direct-embed-sandbox.branchapp.com/card-widget.html
JavaScript Web Implementation
- Add HTML to contain the Card Widget iFrame.
<div><iframe id="card-widget"></iframe></div>- Add JavaScript to load the Card Widget into the iFrame.
// The URL below is for the Debit Card Sandbox, choose the production or sandbox URL accordingly
var iFrameURL = "https://tabapay-iframe-sandbox.branchapp.com/";
document.getElementById("card-widget").src = iFrameURL;- Create a JavaScript function to extract the Card Widget iFrame data upon completion and forward them to your backend server endpoint.
function extractCardWidgetData( event ) {
if ( event.data != "Close" ) {
if ( event.data.slice( 0, 7 ) == "Error: " ) {
// Error
} else {
var asData = event.data.split( "|" );
if ( asData.length == 9 ) {
// asData[ 0 ] contains the First Name
// asData[ 1 ] contains the Last Name
// asData[ 2 ] contains the Card BIN+Last4
// asData[ 3 ] contains the expiration in YYYYMM format
// asData[ 4 ] contains the token
// asData[ 5 ] contains the address
// asData[ 6 ] contains the city
// asData[ 7 ] contains the state 2 char ISO code
// asData[ 8 ] contains the zip code
const firstName = asData[0]; // "John"
const lastName = asData[1]; // "Larson"
const cardBinAndLast4 = asData[2]; // "4111111111"
const expiration = asData[3]; // "202605"
const token = asData[4]; // "80BLD07rSYbG6u..."
const address = asData[5]; // "1234 Any Street"
const city = asData[6]; // "Kalispell"
const state = asData[7]; // "MT"
const zipCode = asData[8]; // "59901"
// Forward the extracted worker details to your backend server endpoint
fetch("https://www.your-backend-server.com/add-debit-card", {
method: "POST",
body: JSON.stringify({
firstName: firstName,
lastName: lastName,
cardBinAndLast4: cardBinAndLast4,
expiration: expiration,
token: token,
address: address,
city: city,
state: state,
zipCode: zipCode
}),
headers: {
"Content-type": "application/json; charset=UTF-8"
}
});
} else {
// Data Error
}
}
} else {
// Close or Cancel
}
}- Use JavaScript to bind the data extraction function to a listener on the Card Widget iFrame completion event.
window.addEventListener( "message", extractCardWidgetData, false );iOS Swift Implementation
import UIKit
import WebKit
class ViewController: UIViewController {
// The URL below is for the Branch Sandbox, choose the production or sandbox URL accordingly
let cardWidgetURL = URL(string: "https://tabapay-iframe-sandbox.branchapp.com/")!
lazy var webView: WKWebView = {
let contentController = WKUserContentController()
contentController.add(self, name: "ios")
let jsScript = """
window.addEventListener("message", (event) => {
window.webkit.messageHandlers.ios.postMessage(event.data);
}, false);
"""
let userScript = WKUserScript(source: jsScript, injectionTime: .atDocumentEnd, forMainFrameOnly: false)
contentController.addUserScript(userScript)
let config = WKWebViewConfiguration()
config.userContentController = contentController
let webView = WKWebView(frame: self.view.bounds, configuration: config)
webView.load(URLRequest(url: cardWidgetURL))
return webView
}()
override func viewDidLoad() {
super.viewDidLoad()
self.view.addSubview(webView)
}
}
extension ViewController: WKScriptMessageHandler {
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard let messageBody = message.body as? String else { return }
if messageBody == "Close" {
// Close or cancel
} else if messageBody.starts(with: "Error: ") {
// Error
} else {
let data = messageBody.split(separator: "|")
if data.count == 9 {
let cardData = [
"firstName": data[0], // "John"
"lastName": data[1], // "Larson"
"cardNumber": data[2], // "4111111111"
"expiration": data[3], // "202605"
"token": data[4], // "80BLD07rSYbG6u..."
"address": data[5], // "1234 Any Street"
"city": data[6], // "Kalispell"
"state": data[7], // "MT"
"zipCode": data[8] // "59901"
]
// Forward the extracted worker details to your backend server endpoint
} else {
// Invalid data format
}
}
}
}
Android Kotlin Implementation
// The URL below is for the Branch Sandbox, choose the production or sandbox URL accordingly
val cardWidgetUrl = "https://tabapay-iframe-sandbox.branchapp.com/"
val webView = findViewById<WebView>(R.id.webView)
webView.settings.javaScriptEnabled = true
webView.addJavascriptInterface(AndroidBridgeInterface(), "android")
webView.webViewClient = MyWebViewClient()
webView.loadUrl(cardWidgetUrl)
class MyWebViewClient : WebViewClient() {
override fun onPageFinished(view: WebView, url: String) {
super.onPageFinished(view, url)
view.loadUrl(
"javascript:(function() {" +
"window.parent.addEventListener ('message', function(event) {" +
" android.extractCardWidgetData(event.data);});" +
"})()"
)
}
}
class AndroidBridgeInterface {
@JavascriptInterface
fun extractCardWidgetData(data: String) {
if (data != "Close") {
if (data.startsWith("Error: ")) {
// Error handling
} else {
val asData = data.split("|")
if (asData.size == 9) {
val firstName = asData[0] // "John"
val lastName = asData[1] // "Larson"
val cardBinAndLast4 = asData[2] // "4111111111"
val expiration = asData[3] // "202605"
val token = asData[4] // "80BLD07rSYbG6u..."
val address = asData[5] // "1234 Any Street"
val city = asData[6] // "Kalispell"
val state = asData[7] // "MT"
val zipCode = asData[8] // "59901"
// Forward the extracted worker details to your backend server endpoint
} else {
// Data Error
}
}
} else {
// Close or Cancel
}
}
}Testing Cards
- Enter sample card numbers from here to test the functionality of
extractCardWidgetData. - Card type must be debit for a successful response.
- Using a CVV of 999 will generate an invalid CVV response.
Example Improved Debit Card iFrame - Sandbox
Example Legacy Card Widget iFrame - Sandbox
Updated 22 days ago
