ACH PaymentFields Integration
Securely collect bank account details using the client-side PaymentFields library
The PaymentFields client-side JavaScript library enables secure collection and tokenization of bank account data directly in the browser. This approach eliminates the need for your servers to handle sensitive banking information, reducing your data security burden and simplifying compliance with NACHA data protection requirements.
How It Works
- Customer enters bank account details into your form
- PaymentFields encrypts the data client-side
- The encrypted data is sent directly to Preczn
- A secure token is returned for use in transactions
Integration Steps
Step 1: Include the PaymentFields Script
Add the PaymentFields library to your page's <head> section:
<head>
<script src="https://api.preczn.com/v1/clients/paymentFields.min.js"></script>
</head>Step 2: Create the Payment Form
Create a form with the required fields. Each field must use data-preczn attributes to identify the field type.
<form id="paymentForm">
<!-- Account Type -->
<label for="accountType">Account Type</label>
<select data-preczn="accountType">
<option value="">Select account type</option>
<option value="personalChecking">Personal Checking</option>
<option value="personalSavings">Personal Savings</option>
<option value="corporateChecking">Corporate Checking</option>
<option value="corporateSavings">Corporate Savings</option>
</select>
<!-- Routing Number -->
<label for="routingNumber">Routing Number</label>
<input type="text" data-preczn="routingNumber" placeholder="9 digits" maxlength="9">
<!-- Account Number -->
<label for="accountNumber">Account Number</label>
<input type="text" data-preczn="accountNumber" placeholder="4-17 digits">
<!-- Bank Country (hidden or visible) -->
<input type="hidden" data-preczn="bankCountry" value="USA">
<button type="button" onclick="tokenize()">Submit Payment</button>
</form>Security Requirement: Form controls with
data-precznattributes must NOT haveidornameattributes. This prevents sensitive data from being captured by form serialization or logging.
Additional Required Fields
PaymentFields only tokenizes bank account data. You must separately collect and submit these fields with your transaction request:
| Account Type | Required Fields | Notes |
|---|---|---|
Personal (personalChecking, personalSavings) | firstName, lastName | Collect using standard form inputs |
Corporate (corporateChecking, corporateSavings) | accountBusinessName | Business name on the account |
| Braintree processor | achMandate | Customer authorization text (required) |
These fields should use standard name attributes since they're submitted to your server, not to PaymentFields:
<!-- For personal accounts -->
<input type="text" name="firstName" placeholder="First Name">
<input type="text" name="lastName" placeholder="Last Name">
<!-- For corporate accounts -->
<input type="text" name="accountBusinessName" placeholder="Business Name">
<!-- For Braintree (display authorization text and capture acceptance) -->
<label>
<input type="checkbox" name="achMandateAccepted" required>
I authorize [Your Company] to debit my bank account for the amount specified.
</label>Step 3: Define the Callback Function
Create a callback function to handle the tokenization response:
function tokenCallback(result) {
if (result.errors) {
// Handle validation errors
result.errors.forEach(function(error) {
console.error('Validation error:', error.field, error.message);
});
displayErrors(result.errors);
return;
}
// Success - use the token
var token = result.token;
console.log('Token received:', token);
// Send token to your server for processing
submitToServer({
token: token,
type: result.type,
last4: result.accountNumber // Last 4 digits only
});
}Step 4: Initiate Tokenization
Call the PaymentFields library with your public API key:
function tokenize() {
Preczn.PaymentFields.getAchToken(
"pk_your_public_api_key", // Your public API key
"paymentForm", // Form element ID
tokenCallback // Callback function
);
}Response Format
Successful Tokenization
{
"type": "personalChecking",
"accountNumber": "6789",
"routingNumber": "987654321",
"bankCountry": "USA",
"token": "tkn_apkwm89dr8br9zvqw4b3xgktk"
}| Field | Description |
|---|---|
type | Account type selected by the customer |
accountNumber | Last 4 digits of the account number (masked) |
routingNumber | Full routing number |
bankCountry | Bank country code |
token | Secure token for use in transactions |
Note: The PaymentFields client library returns
accountNumbercontaining the last 4 digits. API transaction responses uselast4for the same data.
Error Response
{
"errors": [
{
"field": "routingNumber",
"message": "Routing number must be exactly 9 digits"
},
{
"field": "accountNumber",
"message": "Account number must be between 4 and 17 digits"
}
]
}Field Validation Requirements
| Field | Requirement | Error Message |
|---|---|---|
accountType | Must be one of the valid account types | "Account type must be one of: PersonalChecking, PersonalSavings, CorporateChecking, CorporateSavings" |
routingNumber | Exactly 9 numeric digits | "Routing number must be exactly 9 digits" |
accountNumber | 4-17 numeric digits | "Account number must be between 4 and 17 digits" |
bankCountry | Must be "USA" | "Bank country must be one of: USA" |
Content Security Policy
If your site uses Content Security Policy headers, add these directives:
script-src: https://api.preczn.com
connect-src: https://api.preczn.com
Complete Example
<!DOCTYPE html>
<html>
<head>
<title>ACH Payment</title>
<script src="https://api.preczn.com/v1/clients/paymentFields.min.js"></script>
<style>
.error { color: red; font-size: 12px; }
.form-group { margin-bottom: 15px; }
input, select { width: 100%; padding: 8px; margin-top: 4px; }
</style>
</head>
<body>
<h2>Pay with Bank Account</h2>
<form id="paymentForm">
<div class="form-group">
<label>Account Type</label>
<select data-preczn="accountType" required>
<option value="">Select account type</option>
<option value="personalChecking">Personal Checking</option>
<option value="personalSavings">Personal Savings</option>
<option value="corporateChecking">Business Checking</option>
<option value="corporateSavings">Business Savings</option>
</select>
<div class="error" data-error="accountType"></div>
</div>
<div class="form-group">
<label>Routing Number</label>
<input type="text" data-preczn="routingNumber"
placeholder="9-digit routing number" maxlength="9" required>
<div class="error" data-error="routingNumber"></div>
</div>
<div class="form-group">
<label>Account Number</label>
<input type="text" data-preczn="accountNumber"
placeholder="Account number" required>
<div class="error" data-error="accountNumber"></div>
</div>
<input type="hidden" data-preczn="bankCountry" value="USA">
<button type="button" onclick="tokenize()">Pay Now</button>
</form>
<div id="result"></div>
<script>
function clearErrors() {
document.querySelectorAll('.error').forEach(function(el) {
el.textContent = '';
});
}
function displayErrors(errors) {
errors.forEach(function(error) {
var el = document.querySelector('[data-error="' + error.field + '"]');
if (el) {
el.textContent = error.message;
}
});
}
function tokenCallback(result) {
clearErrors();
if (result.errors) {
displayErrors(result.errors);
return;
}
// Token received successfully - use safe DOM methods
var resultEl = document.getElementById('result');
resultEl.textContent = 'Token received: ' + result.token;
resultEl.style.color = 'green';
// Send to your server
fetch('/api/process-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: result.token,
accountType: result.type,
accountLast4: result.accountNumber
})
});
}
function tokenize() {
clearErrors();
Preczn.PaymentFields.getAchToken(
"pk_your_public_api_key",
"paymentForm",
tokenCallback
);
}
</script>
</body>
</html>Best Practices
- Always validate client-side first - Check that all required fields are filled before calling
getAchToken() - Display clear error messages - Map validation errors to user-friendly messages near the relevant fields
- Never store the token in local storage - Send it directly to your server
- Use HTTPS - Always serve your payment pages over HTTPS
- Handle network errors - Wrap the tokenization call in try-catch for network failure handling
Updated 8 days ago
