Passage.Js
Passage.js is a JavaScript library for Merchants to collect sensitive payment data from the users and send directly to Valor. Merchants can integrate the script and customize the checkout form as per their requirements. The authentication is done by a Client Token generated by GetClientToken API, which is discussed in the later section.
You can integrate Valor Payment Gateway using Passage.js with these simple steps:
- Generate APP ID, APP Key and EPI required for integration.
- Retrieve the client token through GetClientToken API.
- Integrate the required Passage.js script and pass the received token from the API to the “data-clientToken” attribute.
- Create a form with required fields. Set action of the form to the API which calls Valor's Sale API.
- Handle the response received from the Sale API.
Getting ID and Keys
In order to integrate and use Passage.js, the merchants will need to use their APP ID, APP Key and EPI to generate a Client Token.
You can take the following steps to generate or retrieve your keys:
Step 1: Login to the Valor portal
Step 2: Click on "Manage" option in "Virtual Terminal" in sidemenu
Step 3: Under "API KEYS" you can find your APP ID, APP Key and EPI
Generating Client Token
The merchant can now generate a Client Token to handle merchant authentication in place of APP ID, APP Key. The Token should then be used in Passage.js script with “data-clientToken” attribute.
Example Client Token: 7b9e2a55-720d-4533-bb70-9376a378eae4
Client Token can be generated by using the following GetClientToken API.
https://securelink-staging.valorpaytech.com:4430/?
https://securelink.valorpaytech.com:4430/?
<?php
require_once('vendor/autoload.php');
$client = new \GuzzleHttp\Client();
$response = $client->request('POST', 'https://securelink-staging.valorpaytech.com:4430/?appid=WaJeJErcv5xpqZa2UZz6LZod5MSyyfJw&appkey=53PWdki5U0PGSVhRnVoFsfVSbuDutsA8&epi=2203082193&txn_type=sale&token=26F9A99643197174FE11B29A4A76145773C0B93D&amount=5.00&surchargeIndicator=0&surchargeAmount=5.00&phone=5628398878&address1=2%20Jericho%20Plz&city=Jericho&state=NY&shipping_country=US&billing_country=US&zip=50001&saleAPI=', [
'headers' => [
'accept' => 'application/json',
],
]);
echo $response->getBody();
import requests
url = "https://securelink-staging.valorpaytech.com:4430/?appid=WaJeJErcv5xpqZa2UZz6LZod5MSyyfJw&appkey=53PWdki5U0PGSVhRnVoFsfVSbuDutsA8&epi=2203082193&txn_type=sale&token=26F9A99643197174FE11B29A4A76145773C0B93D&amount=5.00&surchargeIndicator=0&surchargeAmount=5.00&phone=5628398878&address1=2%20Jericho%20Plz&city=Jericho&state=NY&shipping_country=US&billing_country=US&zip=50001&saleAPI="
headers = {"accept": "application/json"}
response = requests.post(url, headers=headers)
print(response.text)
const sdk = require('api')('@valorapi/v1.0#2lhelnbcau0v');
sdk.saleApi({
appid: 'WaJeJErcv5xpqZa2UZz6LZod5MSyyfJw',
appkey: '53PWdki5U0PGSVhRnVoFsfVSbuDutsA8',
epi: '2203082193',
txn_type: 'sale',
token: '26F9A99643197174FE11B29A4A76145773C0B93D',
amount: '5.00',
surchargeIndicator: '0',
surchargeAmount: '5.00',
phone: '5628398878',
address1: '2%20Jericho%20Plz',
city: 'Jericho',
state: 'NY',
shipping_country: 'US',
billing_country: 'US',
zip: '50001',
saleAPI: ''
})
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
CURL *hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(hnd, CURLOPT_WRITEDATA, stdout);
curl_easy_setopt(hnd, CURLOPT_URL, "https://securelink-staging.valorpaytech.com:4430/?appid=WaJeJErcv5xpqZa2UZz6LZod5MSyyfJw&appkey=53PWdki5U0PGSVhRnVoFsfVSbuDutsA8&epi=2203082193&txn_type=sale&token=26F9A99643197174FE11B29A4A76145773C0B93D&amount=5.00&surchargeIndicator=0&surchargeAmount=5.00&phone=5628398878&address1=2%20Jericho%20Plz&city=Jericho&state=NY&shipping_country=US&billing_country=US&zip=50001&saleAPI=");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "accept: application/json");
curl_easy_setopt(hnd, CURLOPT_HTTPHEADER, headers);
CURLcode ret = curl_easy_perform(hnd);
using RestSharp;
var options = new RestClientOptions("https://securelink-staging.valorpaytech.com:4430/?appid=WaJeJErcv5xpqZa2UZz6LZod5MSyyfJw&appkey=53PWdki5U0PGSVhRnVoFsfVSbuDutsA8&epi=2203082193&txn_type=sale&token=26F9A99643197174FE11B29A4A76145773C0B93D&amount=5.00&surchargeIndicator=0&surchargeAmount=5.00&phone=5628398878&address1=2%20Jericho%20Plz&city=Jericho&state=NY&shipping_country=US&billing_country=US&zip=50001&saleAPI=");
var client = new RestClient(options);
var request = new RestRequest("");
request.AddHeader("accept", "application/json");
var response = await client.PostAsync(request);
Console.WriteLine("{0}", response.Content);
package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://securelink-staging.valorpaytech.com:4430/?appid=WaJeJErcv5xpqZa2UZz6LZod5MSyyfJw&appkey=53PWdki5U0PGSVhRnVoFsfVSbuDutsA8&epi=2203082193&txn_type=sale&token=26F9A99643197174FE11B29A4A76145773C0B93D&amount=5.00&surchargeIndicator=0&surchargeAmount=5.00&phone=5628398878&address1=2%20Jericho%20Plz&city=Jericho&state=NY&shipping_country=US&billing_country=US&zip=50001&saleAPI="
req, _ := http.NewRequest("POST", url, nil)
req.Header.Add("accept", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}
require 'uri'
require 'net/http'
url = URI("https://securelink-staging.valorpaytech.com:4430/?appid=WaJeJErcv5xpqZa2UZz6LZod5MSyyfJw&appkey=53PWdki5U0PGSVhRnVoFsfVSbuDutsA8&epi=2203082193&txn_type=sale&token=26F9A99643197174FE11B29A4A76145773C0B93D&amount=5.00&surchargeIndicator=0&surchargeAmount=5.00&phone=5628398878&address1=2%20Jericho%20Plz&city=Jericho&state=NY&shipping_country=US&billing_country=US&zip=50001&saleAPI=")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["accept"] = 'application/json'
response = http.request(request)
puts response.read_body
{"error_no":"S00","error_code":"00","clientToken":"7b9e2a55-720d-4533-bb70-9376a378eae4","validity":"2023-01-05 12:44:01"}
Field Type Length Mandatory / Optional Decription
appid String 32 Mandatory Contact valorpaytech
appkey String 32 Mandatory Contact valorpaytech
txn_type String 15 Mandatory clientToken
epi Numeric 10 Mandatory Epi number
Integrating The Script
After getting the token, integrate the Passage.js Script in your checkout page where you want to process the card details and payments. Pass the received token in the script with data-clientToken attribute.
You can integrate it using following script:
<script src="https://js.valorpaytech.com/V1/js/Passage.min.js" data-name="valor_passage" data-clientToken="YOUR TOKEN" data-epi="YOUR EPI"></script>
This script would call the card fields (card number, card expiry and cvv) by default when you integrate the form. But, we offer a list of other optional parameters that you can directly configure into the script itself for more flexibility and customizability over the form:
Name Example Value Description
data-clientToken 7b9e2a55-720d-4533-bb70-9376a378eae4 Client Token required to pass for authentication.
data-epi 2104704629 Client EPI
data-demo true To process transaction in demo use this attribute or else remove this attribute to process with live.
data-variant inline/lightbox Default value is inline, set it lightbox to display
card details as popup instead on page.
data-submitText Pay $5 Customize Submit Payment button text
data-submitBg #000 Color of the submit button background.
data-submitColor #fff Color of the submit button text.
data-valorLogo false Default true. Pass false to hide the logo.
data-cardholderName true Calls for Valor's Name field if true
data-defaultCardholderName John Doe Default value is empty, can assign a value to autofill
data-email true Calls for Valor's email field if true
data-defaultEmail [email protected] Default value is empty, can assign a value to autofill
data-phone true Calls for Valor's phone field if true
data-defaultPhone (123) 123-1234 Default value is empty, can assign a value to autofill
data-billingAddress true Calls for Valor's address fields (Address, City, State) if true
data-defaultAddress1 3636 Default value is empty, can assign a value to autofill
data-defaultAddress2 33rd st Default value is empty, can assign a value to autofill
data-defaultCity New York City Default value is empty, can assign a value to autofill
data-defaultState New York Default value is empty, can assign a value to autofill
date-epi 2104704629 Client EPI required to pass for authentication
data-demo https://securelink-staging.valorpaytech.com:4430 To use the demo URL
data-name valor_passage Default value is empty, can assign a value to autofill
Integrating The Form
After you're done with selecting and finalizing your form style and fields, it's time to integrate it into a form and display it all on the page.
For the Form Layout you can choose one of the 2 approaches:
- Inline: Which integrates all the fields including the card field into the checkout page. This is the default behavior while integrating Passage.js. You can pass the attribute "data-variant" as "inline" or not use the attribute at all to enable this option.
- Lightbox: Which opens up the card fields as a popup on clicking the Submit button. To enable this layout, you will have to pass the attribute "data-variant" as "lightbox" in the Script in the previous step.
After that you can take following steps to integrate the form to capture card details:
- Create a form element in the view with id "valor-checkout-form" and set the action of the form to call the Sale API from your backend.
- You can first add any additional fields of your choice that you require in the form and then call a div with the id "valor-checkout-fields". This will call all the data input fields from Passage.js such as card details and the ones you may have enabled in the script tag.
Here's an Example:
<form action="https://path-to-your-api-call" method="post" id="valor-checkout-form">
<input type="hidden" name="orderId" value="1"/>
<div id="valor-fields"></div>
</form>
To capture the form submit event of passage.js use the below code snippet.
document.addEventListener("passageHiddenFormAdded", function(event) {
const form = event.detail.form;
form.addEventListener("submit", function(event) {
event.preventDefault();
});
});
Vault API – Add Payment Profile Token
This document outlines the integration details for adding a new endpoint to the Vault API that allows storing a card token in the process of adding a payment profile.
End Point: POST https://demo.valorpaytech.com/api/valor-vault/addpaymentprofiletoken/{vault_id}
- {vault_id} – The unique Vault ID associated with the customer profile (received from the "Create Customer Profile" API).
Sample Request Payload
{
"token": "<TOKEN>",
}
Field Type Required Description
token string Yes The secure token representing the card
cardholder_name string No Cardholder name is a optional
Integration Steps
Generate Card Token:
- The frontend application collects the payment information.
- Calls the Create Card Token API to securely generate a token.
Create Vault Customer Profile:
- Call the Vault API to create a new customer profile.
- Save the returned vault_id.
Add Payment Profile Token:
Use the new endpoint (/addpaymentprofiletoken/{vault_id}) to associate the token with the newly created Vault ID.
Inline Integration Example:
Lightbox Integration Example:
Handling The Response
The form submission will be calling the Sale API to complete the payment. After the the payment has completed it will return the response that you can integrate into a Thank You/Error page or a popup.
Details about the request/response structure, parameters for Sale API can be found here and information about Error codes can be found here
PassageJS v2.0 Documentation
A comprehensive payment form library supporting Credit Cards and ACH payments with secure tokenization and seamless integration.
Table of Contents
- Overview
- Features
- Installation
- Quick Start
- Configuration
- Payment Methods
- Events & Callbacks
- Custom Data
- API Reference
- Integration Examples
- Security
- Troubleshooting
Overview
PassageJS v2.0 is a vanilla JavaScript payment library that provides secure, PCI-compliant payment processing for both credit cards and ACH (bank account) payments. It features automatic card tokenization, real-time validation, and a comprehensive event system for seamless integration.
Key Benefits
🔒 Secure: Credit card tokenization ensures sensitive data never touches your servers
🎨 Customizable: Flexible UI with inline and lightbox modes
📱 Responsive: Mobile-optimized design that works on all devices
⚡ Fast: Vanilla JavaScript with no dependencies
🔧 Flexible: Comprehensive event system and custom data support
Features
Payment Processing
✅ Credit card tokenization via Valor PayTech API
✅ Direct ACH payment submission
✅ Real-time form validation
✅ Automatic field formatting
✅ Session management
UI/UX
✅ Inline and lightbox display modes
✅ Responsive design
✅ Custom styling options
✅ Card type detection with icons
✅ Loading states and error messages
Integration
✅ Comprehensive event system
✅ Custom data injection
✅ Parent form integration
✅ Multiple callback options
✅ Easy configuration updates
Installation
Option 1: Direct Script Include
<script src="path/to/passage-v2.js"></script>
Option 2: Module Import
import PassageJS from './passage-v2.js';
HTML Setup
Add a container element where the payment form will be rendered:
<div id="valor-fields"></div>
Quick Start
Basic Credit Card Setup
const passage = new PassageJS({
clientToken: 'your_valor_client_token',
epi: 'your_valor_epi',
formAction: '/process-payment',
onSuccess: (result) => {
console.log('Payment successful:', result);
// Redirect to success page
window.location.href = '/success';
},
onError: (error) => {
console.error('Payment failed:', error);
alert('Payment failed. Please try again.');
}
});
Lightbox Mode
const passage = new PassageJS({
clientToken: 'your_valor_client_token',
epi: 'your_valor_epi',
formAction: '/process-payment',
variant: 'lightbox',
submitText: 'Pay Now'
});
Configuration
Required Settings
Option | Type | Description |
---|---|---|
clientToken | string | Your Valor PayTech client token |
epi | string | Your Valor PayTech EPI identifier |
formAction | string | URL where payment data will be submitted |
Core Settings
const config = {
// Required
clientToken: 'your_client_token',
epi: 'your_epi',
formAction: '/process-payment',
// Optional
isDemo: false, // Use demo environment
formMethod: 'POST', // Form submission method
customData: {}, // Additional data to submit
// UI Settings
variant: 'inline', // 'inline' | 'lightbox'
theme: 'default',
submitText: 'Pay Now',
submitBg: '#005cb9',
submitColor: '#fff',
// Payment Methods
enableCreditCard: true,
enableACH: true,
defaultPaymentMethod: 'credit-card',
// Form Fields
showLogo: false,
showCardholderName: true,
showEmail: false,
showPhone: false,
showBillingAddress: false,
// Session
sessionExpiryMinutes: 5
};
Default Values
const passage = new PassageJS({
// ... other config
defaults: {
cardholderName: 'John Doe',
email: '[email protected]',
phone: '(555) 123-4567',
address1: '123 Main St',
city: 'New York',
state: 'New York',
zip: '10001'
}
});
Payment Methods
Credit Card Processing
Credit cards are automatically tokenized for security:
- User enters card details → Real-time validation
- Form submission → Card data sent to Valor for tokenization
- Token received → Sensitive card data is replaced with secure token
- Form submitted → Only token and metadata sent to your server
Your server receives:
card_token
- Secure payment tokenpayment_method
- "credit-card"cardholder_name
- If enabled- Customer and custom data
ACH (Bank Account) Processing
ACH payments are submitted directly without tokenization:
Your server receives:
payment_method
- "ach"routing_number
- Bank routing numberaccount_number
- Bank account numberaccount_type
- "checking" or "savings"account_holder_name
- Account holder name- Customer and custom data
Events & Callbacks
Event System
PassageJS provides a comprehensive event system for integration:
// Listen to events
passage.on('tokenReceived', (data) => {
console.log('Card tokenized:', data.token);
});
passage.on('formSubmitting', (data) => {
console.log('Submitting to:', data.action);
console.log('Form data:', data.formData);
});
passage.on('validationChanged', (data) => {
console.log('Form valid:', data.isValid);
updateCheckoutButton(data.isValid);
});
Available Events
Event | Description | Data |
---|---|---|
initialized | Library loaded and ready | {version, config} |
lightboxOpened | Lightbox modal opened | {} |
lightboxClosed | Lightbox modal closed | {} |
paymentMethodChanged | User switched payment method | {method} |
fieldChanged | Form field value changed | {fieldType, value, isValid} |
fieldBlurred | Form field lost focus | {fieldType, value, isValid} |
validationChanged | Form validation state changed | {isValid, validation, paymentMethod} |
beforeSubmit | Before payment processing starts | {paymentMethod} |
tokenReceived | Credit card token received | {token, paymentMethod} |
formSubmitting | Form being submitted to server | {formData, action, method} |
afterSubmit | After form submission | {formData} |
success | Payment completed successfully | {success, paymentMethod, token} |
error | Payment processing failed | {error} |
sessionExpired | Payment session expired | {} |
Legacy Callbacks
For backward compatibility, you can also use callback functions:
const passage = new PassageJS({
// ... config
onSuccess: (result) => {
console.log('Payment successful:', result);
},
onError: (error) => {
console.error('Payment failed:', error);
},
onValidationChange: (isValid, validation) => {
console.log('Form validation:', isValid);
},
onTokenReceived: (token, paymentMethod) => {
console.log('Token received:', token);
},
onFormSubmit: (formData, action) => {
console.log('Form submitting to:', action);
}
});
Custom Data
Adding Order Information
Include order IDs, amounts, and other data with your payment submissions:
During Initialization
const passage = new PassageJS({
clientToken: 'your_token',
epi: 'your_epi',
formAction: '/process-payment',
customData: {
order_id: 'ORDER-12345',
amount: '99.99',
currency: 'USD',
customer_id: 'CUST-789'
}
});
Dynamically
// Set custom data anytime
passage.setCustomData({
order_id: generateOrderId(),
promo_code: 'SUMMER20',
discount_amount: '10.00'
});
// Add more data (merges with existing)
passage.setCustomData({
shipping_method: 'express',
gift_message: 'Happy Birthday!'
});
Using Parent Form
<form id="checkout-form">
<input type="hidden" name="order_id" value="ORDER-12345">
<input type="hidden" name="product_id" value="PROD-001">
<!-- PassageJS renders here and automatically includes parent form data -->
<div id="valor-fields"></div>
</form>
Event-Based Data
// Add data right before submission
passage.on('beforeSubmit', () => {
passage.setCustomData({
timestamp: new Date().toISOString(),
session_id: getSessionId(),
user_agent: navigator.userAgent
});
});
API Reference
Constructor
new PassageJS(config)
Public Methods
setCustomData(data)
setCustomData(data)
Add or update custom data to be included with form submission.
passage.setCustomData({
order_id: 'ORDER-123',
amount: '50.00'
});
getCustomData()`
Get current custom data.
const customData = passage.getCustomData();
console.log(customData);
updateConfig(newConfig)`
Update configuration after initialization.
passage.updateConfig({
submitText: 'Pay $99.99',
submitBg: '#28a745'
});
getValidationState()`
Get current form validation state.
const validation = passage.getValidationState();
console.log('Form is valid:', validation.isValid);
reset()`
Reset form to initial state.
passage.reset();
destroy()`
Clean up and remove PassageJS instance.
passage.destroy();
Event Methods
on(eventName, callback)`
Listen to events.
passage.on('success', (result) => {
console.log('Payment successful:', result);
});
off(eventName, callback)`
Remove event listener.
const handler = (result) => console.log(result);
passage.on('success', handler);
passage.off('success', handler);
once(eventName, callback)`
Listen to event once.
passage.once('initialized', () => {
console.log('PassageJS is ready!');
});
Integration Examples
E-commerce Checkout
// Complete e-commerce integration
function initializeCheckout(cart) {
const passage = new PassageJS({
clientToken: 'your_token',
epi: 'your_epi',
formAction: '/process-payment',
variant: 'lightbox',
customData: {
order_id: generateOrderId(),
subtotal: cart.subtotal,
tax: cart.tax,
shipping: cart.shipping,
total: cart.total,
items_count: cart.items.length
}
});
// Update total when payment method changes
passage.on('paymentMethodChanged', (data) => {
const fee = data.method === 'ach' ? 0 : 2.99;
updateOrderTotal(cart.total + fee);
});
// Track successful payments
passage.on('success', (result) => {
analytics.track('payment_completed', {
order_id: passage.getCustomData().order_id,
payment_method: result.paymentMethod,
amount: cart.total
});
window.location.href = '/order-confirmation';
});
}
Test Cards
Address - 8320
Zip - 85284
