Skip to content
Last updated

SDK Integration Guide

NPS JavaScript SDK

Detailed instructions for integrating the NPS JavaScript SDK into your web application


Integration Steps

1
Install SDK

Include the NPS SDK directly from our CDN:

<script src="https://cdn.nelnetpay.com/sdk/v1.0.0/nps.js"></script>

2
Setup Backend Authentication

Before using the SDK, your backend must obtain a session token from the NPS API.

Step 2.1: Obtain Credentials

  • Obtain your secret from NPS
  • Store credentials securely

Step 2.2: Create JWT Authentication Token

All NPS API requests require JWT (JSON Web Token) authentication with:

  • Algorithm: HS512 (HMAC-SHA512)
  • Header: Authorization: Bearer <JWT_TOKEN>
  • Required Claims:
    • sub: Your API Key ID
    • iat: Issued at timestamp (current time)
    • exp: Expiration timestamp
const jwt = require('jsonwebtoken');

function createAuthToken() {
    const payload = {
        sub: process.env.NPS_API_KEY_ID,
        iat: Math.floor(...),
        exp: Math.floor(...)
    };
    
    return jwt.sign(payload, process.env.NPS_API_KEY, { 
        algorithm: 'HS512' 
    });
}
3
Create Payment Session Endpoint

Create a backend endpoint that requests a payment session from the NPS API:

app.post('<YOUR BACKEND API>', async (req, res) => {
    const authToken = createAuthToken();
    
    const response = await fetch('<NPS API>', {
        method: 'POST',
        headers: {
            'Authorization': `Bearer ${authToken}`,
            'Content-Type': 'application/json'
        }
    });
    
    const data = await response.json();
    res.json({
        sessionId: data.session.id,
        sessiontoken: data.session.token,
        expiresAt: data.session.expiresAt
    });
});

4
Initialize SDK and Mount Payment Form
<!DOCTYPE html>
<html>
<head>
    <script src="https://cdn.nelnetpay.com/sdk/v1.0.0/nps.js"></script> 
</head>
<body>
    <!-- Your checkout form collects name, billing address, and amount -->
    <form id="checkout-form">
        <!-- Payer Information -->
        <h2>Payer information</h2>
        <input type="email" name="email" placeholder="Email" required />
        <input type="text" name="firstName" placeholder="First name" required />
        <input type="text" name="lastName" placeholder="Last name" required />
        <input type="tel" name="phone" placeholder="Phone" required />
        
        <!-- Payment Method Selection -->
        <h2>Payment method</h2>
        <input type="number" name="amount" placeholder="Amount" step="0.01" value="49.99" required />
        
        <label>
            <input type="radio" name="paymentMethod" value="applepay">
            Apple Pay
        </label>
        <label>
            <input type="radio" name="paymentMethod" value="card" checked>
            Credit/Debit Card
        </label>
        <label>
            <input type="radio" name="paymentMethod" value="ach">
            Bank Account
        </label>
        
        <!-- ACH Account Type (shown only when ACH is selected) -->
        <div id="ach-account-type" style="display: none;">
            <label>
                <input type="radio" name="achAccountType" value="checking" checked>
                Checking
            </label>
            <label>
                <input type="radio" name="achAccountType" value="savings">
                Savings
            </label>
        </div>
        
        <!-- SDK iframe mounts here and collects card/bank details -->
        <div id="payment-form"></div>
        
        <!-- Billing Address -->
        <h2>Billing address</h2>
        <input type="text" name="streetAddress" placeholder="Street Address" required />
        <input type="text" name="apt" placeholder="Apt, suite, etc." />
        <input type="text" name="city" placeholder="City" required />
        <input type="text" name="state" placeholder="State" required />
        <input type="text" name="zipCode" placeholder="ZIP Code" required />
        <select name="country" required>
            <option value="US">United States</option>
            <option value="CA">Canada</option>
        </select>
        
        <button type="submit">Pay Now</button>
    </form>
    
    <script>
    let nps;
    
    async function initializePayment() {
        // STEP 4.1: Get session token from your backend
        const response = await fetch('<YOUR BACKEND API>', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' }
        });
        const { sessionToken } = await response.json();
        
        // STEP 4.2: Initialize NPS SDK
        nps = new NPS({
            sessionId: sessionId
            sessionToken: sessionToken,
            onReady: handleReady,
            onTokenizationComplete: handleTokenization,
            onError: handleError
        });
        

        const selectedMethod = document.querySelector('input[name="paymentMethod"]:checked').value;


        // STEP 4.3: Mount payment form with styling options
        nps.mount('#payment-form', {
            paymentMethod: selectedMethod,
            displayOptions: {
                showLabels: true,
                showIcons: true,
                showErrors: true
            },
            styling: {
                theme: 'light', // or 'dark'
                labelStyle: 'stacked', // or 'inline' or 'inline-split'
                fieldStyle: 'outlined', // or 'filled' or 'underlined'
                fontFamily: 'Inter, sans-serif',
                fontSize: '16px',
                colors: {
                    primary: '#3B82F6',
                    error: '#DC2626',
                    success: '#10B981',
                    label: '#374151',
                    border: '#D1D5DB',
                    text: '#111827',
                    background: '#FFFFFF',
                    focusBorder: '#3B82F6',
                    helpText: '#6B7280'
                },
                spacing: {
                    baseUnit: 8,
                    fieldHeight: 48,
                    fieldPadding: 12
                },
                borderRadius: 6,
                borderWidth: 1
            }
        });
        
        // STEP 4.4: Setup payment method switching
        document.querySelectorAll('input[name="paymentMethod"]').forEach(radio => {
            radio.addEventListener('change', (e) => {
                const method = e.target.value;
                // Show/hide ACH account type
                document.getElementById('ach-account-type').style.display = 
                    method === 'ach' ? 'block' : 'none';
                // Disable Pay Now button for Apple Pay
                document.querySelector('button[type="submit"]').disabled = 
                    method === 'applepay';
                // Update payment method in iframe
                switchPaymentMethod(method);
            });
        });
        
        // Listen for ACH account type changes
        document.querySelectorAll('input[name="achAccountType"]').forEach(radio => {
            radio.addEventListener('change', () => switchPaymentMethod('ach'));
        });
    }
    
    // Switch payment method
    function switchPaymentMethod(method) {
        let options = {};
        if (method === 'ach') {
            const accountType = document.querySelector('input[name="achAccountType"]:checked')?.value;
            options.accountType = accountType || 'checking';
        }
        nps.updatePaymentMethod(method, options);
    }
    
    // Handle form submission
    document.getElementById('checkout-form').addEventListener('submit', async (e) => {
        e.preventDefault();
        
        const formData = new FormData(e.target);
        const firstName = formData.get('firstName');
        const lastName = formData.get('lastName');
        
        // Tokenize with amount, name and billing address from your form
        try {
            const result = await nps.tokenize({
                amount: parseFloat(formData.get('amount')),
                cardholderName: `${firstName} ${lastName}`,
                billingAddress: {
                    name: `${firstName} ${lastName}`,
                    street: formData.get('streetAddress'),
                    city: formData.get('city'),
                    state: formData.get('state'),
                    postalCode: formData.get('zipCode'),
                    country: formData.get('country')
                },
                metadata: {
                }
            });
            
            // Token received - send to your backend
            console.log('Token:', result.token);
        } catch (error) {
            console.error('Payment failed:', error);
        }
    });
    
    function handleReady() {
        console.log('Payment form ready');
    }
    
    function handleTokenization(result) {
        console.log('Token received:', result.token);
        // Send token to your backend for processing
    }
    
    function handleError(error) {
        console.error('Payment error:', error);
    }
    
    // Initialize on page load
    initializePayment();
    </script>
</body>
</html>

What Merchants Should Already Have:

  • Existing checkout form with amount and billing fields (name, address, etc)
  • Form submission handler
  • Payment method buttons (card, ACH, Apple Pay)
  • ACH account type selector (checking/savings)

What Merchants Need to Add:

  1. NPS SDK script tag in <head>
  2. Pass amount and billing fields (name, address, etc)
  3. Pass ACH account type
  4. Handle payment method switching
  5. Container div <div id="payment-form"></div> where SDK iframe mounts
  6. Styling
  7. Backend endpoint (created in Step 3)
  8. Initialize NPS SDK code
  9. Update form submission to call nps.tokenize()

Key Features:

  • Multiple Payment Methods: Card, ACH, Apple Pay with selection
  • Payment Method Switching: SDK updates iframe content when user selects different method
  • ACH Account Type: Checking/Savings selection on parent page, passed to iframe
  • Apple Pay Handling: Pay Now button disabled when Apple Pay selected (Apple Pay has own button)
  • Full Styling Control: Theme, colors, fonts, spacing all customizable
  • Amount Collection: Amount field on parent page, passed during tokenization
  • Name Handling: Full name combined for cardholderName
  • Metadata: Anything else related to payment passed in metadata object in a systematic/similar way
5
Process Payment Token

After tokenization succeeds, send the payment token to your backend:

function handleTokenization(result) {
    // Send token to your backend
    fetch(<YOUR PACKEND API>, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
            token: result.token,
            // ... other payment details
        })
    });
}

Configuration Options

Configure the SDK with various options to customize behavior and appearance.

SDK Constructor Options

OptionTypeRequiredDescription
sessionTokenstringYessessionToken from backend
onReadyfunctionNoCallback when SDK is initialized
onTokenizationCompletefunctionNoCallback when tokenization succeeds
onErrorfunctionNoCallback for error handling

Mount Options

nps.mount('#payment-form', {
    paymentMethod: 'card', 
    displayOptions: {
        showLabels: true,
        showIcons: true,
        showErrors: true
    },
    styling: {
        theme: 'light',
        labelStyle: 'stacked',
        fieldStyle: 'outlined',
        fontFamily: 'Inter, sans-serif',
        fontSize: '16px',
        colors: {
            primary: '#3B82F6',
            error: '#DC2626',
            success: '#10B981'
        }
    }
});

Important: The styling options are applied to the iframe / iframe content (payment fields), not the container element. You would need to add your CSS styling to the #payment-form container but make sure to test it thoroughly .

Styling Customization

Refer the styling guide documentation

The following styling options customize the iframe payment form fields:

const styling = {
    theme: 'light', // 'light' or 'dark'
    labelStyle: 'stacked', // 'stacked' or 'inline' or 'inline-split'
    fieldStyle: 'outlined', // 'outlined' or 'filled' or 'underlined'
    fontFamily: 'Inter, system-ui, sans-serif',...
    fontSize: '16px',
    colors: {
        label: '#374151',
        border: '#D1D5DB',
        text: '#111827',
        background: '#FFFFFF',
        focusBorder: '#3B82F6',
        error: '#DC2626',
        errorBackground: '#FEF2F2',
        success: '#10B981',
        helpText: '#6B7280'
    },
    spacing: {
        baseUnit: 8,
        fieldHeight: 48,
        fieldPadding: 12
    },
    borderRadius: 6,
    borderWidth: 1
};

// Apply styling to iframe content
nps.mount('#payment-form', { styling });

Container Styling

Apply CSS as needed:

/* iFrame Container */
.payment-iframe-container {
    margin-top: 10px;
    min-height: 280px;
    height: auto;
    background: #e8ebee;
    border-radius: 8px;
    padding: 20px;
    border: 1px solid #e5e7eb;
    overflow: visible; 
}

/* Compact container for Apple Pay - fits tightly around button */
.payment-iframe-container.applepay-active {
    min-height: 80px !important;
    height: 80px !important;
    padding: 4px !important;
    margin-top: 22px !important;
    display: flex;
    background: transparent !important;
    border: none !important;
}

Payment Methods

Credit/Debit Card

nps.mount('#payment-form', {
    paymentMethod: 'card',
    cardOptions: {
        supportedBrands: ['visa', 'mastercard', 'amex', 'discover'],
        requireCvv: true,
        showCardIcon: true
    }
});

ACH Bank Transfer

nps.mount('#payment-form', {
    paymentMethod: 'ach'
});

Apple Pay

// Check if Apple Pay is available
if (nps.isApplePayAvailable()) {
    nps.mount('#payment-form', {
        paymentMethod: 'applepay',     
    });
}

Features

Update Payment Method

Switch between payment methods without remounting:

// Switch to ACH
await nps.updatePaymentMethod('ach');

// Switch back to card
await nps.updatePaymentMethod('card');

Tokenization

When tokenizing, you must pass the amount , cardholder name and billing address. The iframe only collects card, bank details, while name, amount and billing address are passed during tokenization:

const result = await nps.tokenize({
    amount: 49.99,                
    cardholderName: 'John Doe',  
    billingAddress: {
        name: 'John Doe',
        street: '123 Main St',
        city: 'Anytown',
        state: 'CA',
        postalCode: '90210',
        country: 'US'
    },
    metadata: {
       
    }
});

// Response includes the payment token
console.log(result.token);        // Payment token to send to backend       

For example-Important:

  • The iframe (mounted form) collects: card number, expiration date, CVV
  • You collect separately: amount, cardholder name, billing address
  • All are combined during tokenize() call

Destroy SDK Instance

Clean up when done:

// Remove iframe and clean up resources
nps.destroy();

Error Handling

Error Types

function handleError(error) {
    switch (error.code) {
        case 'VALIDATION_ERROR':
            // Invalid input in payment fields
            console.error('Validation failed:', error.fields);
            break;
            
        case 'SESSION_EXPIRED':
            // Session token has expired
            console.error('Session expired, please refresh');
            break;
            
        case 'NETWORK_ERROR':
            // Network connectivity issue
            console.error('Network error, please try again');
            break;
            
        case 'TOKENIZATION_FAILED':
            // Tokenization request failed
            console.error('Failed to tokenize:', error.message);
            break;
            
        default:
            console.error('Unknown error:', error);
    }
}

Migration from Legacy SDK

If migrating from an older NPS SDK version:

1.Update script URL to new version
2.Update constructor syntax (now uses single config object)
3.Update event handlers to new callback names
4.Test thoroughly before production deployment

Support Resources

Need Help?

Technical Support
NPSTechSupport@nelnet.net