Appearance
Embedded Forms
Embedded forms allow you to collect payments directly on your website while keeping sensitive card data off your servers.
How It Works
- Load the GovPayPlan JavaScript SDK
- Create a payment form container
- Initialize the secure payment fields
- Handle form submission
- Process the payment
Benefits
- Seamless experience: Payers stay on your site
- Full customization: Match your design
- Reduced PCI scope: Card data handled securely
- Better conversion: No redirect friction
Quick Start
Step 1: Include the SDK
html
<script src="https://js.govpayplan.com/v1/sdk.js"></script>1
Step 2: Create Form Container
html
<form id="payment-form">
<div id="card-element"></div>
<div id="card-errors"></div>
<button type="submit">Pay $100.00</button>
</form>1
2
3
4
5
2
3
4
5
Step 3: Initialize the SDK
javascript
const gpp = GovPayPlan.init({
publishableKey: 'gpp_pub_abc123'
});
const cardElement = gpp.elements.create('card');
cardElement.mount('#card-element');1
2
3
4
5
6
2
3
4
5
6
Step 4: Handle Submission
javascript
const form = document.getElementById('payment-form');
form.addEventListener('submit', async (e) => {
e.preventDefault();
const { token, error } = await gpp.createToken(cardElement);
if (error) {
document.getElementById('card-errors').textContent = error.message;
return;
}
// Send token to your server
await fetch('/api/charge', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: token.id,
amount: 10000 // cents
})
});
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Step 5: Process on Server
javascript
// Your server endpoint
app.post('/api/charge', async (req, res) => {
const { token, amount } = req.body;
const payment = await govpayplan.payments.create({
amount: amount,
currency: 'usd',
source: token,
description: 'Permit Fee'
});
res.json({ success: true, payment });
});1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
Element Types
Card Element
All-in-one card input:
javascript
const card = gpp.elements.create('card');1
Split Elements
Individual fields for custom layouts:
javascript
const cardNumber = gpp.elements.create('cardNumber');
const cardExpiry = gpp.elements.create('cardExpiry');
const cardCvc = gpp.elements.create('cardCvc');1
2
3
2
3
Styling Elements
Using Options
javascript
const card = gpp.elements.create('card', {
style: {
base: {
fontSize: '16px',
color: '#333',
fontFamily: 'Arial, sans-serif',
'::placeholder': {
color: '#aab7c4'
}
},
invalid: {
color: '#dc3545',
iconColor: '#dc3545'
}
}
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Available Style Properties
| Property | Description |
|---|---|
color | Text color |
fontSize | Font size |
fontFamily | Font family |
fontWeight | Font weight |
letterSpacing | Letter spacing |
lineHeight | Line height |
::placeholder | Placeholder styles |
CSS Classes
The element container receives classes based on state:
| Class | When Applied |
|---|---|
.gpp-empty | No input |
.gpp-focus | Element focused |
.gpp-invalid | Validation error |
.gpp-complete | Valid and complete |
Event Handling
Change Events
javascript
cardElement.on('change', (event) => {
if (event.error) {
errorDiv.textContent = event.error.message;
} else {
errorDiv.textContent = '';
}
// Enable submit when complete
submitBtn.disabled = !event.complete;
});1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Focus Events
javascript
cardElement.on('focus', () => {
// Element received focus
});
cardElement.on('blur', () => {
// Element lost focus
});1
2
3
4
5
6
7
2
3
4
5
6
7
Form Validation
Built-in Validation
The SDK validates:
- Card number (Luhn check)
- Expiration date
- CVV format
Custom Validation
javascript
form.addEventListener('submit', async (e) => {
e.preventDefault();
// Custom validation
const amount = document.getElementById('amount').value;
if (amount < 1) {
showError('Amount must be at least $1');
return;
}
// Proceed with payment
const { token, error } = await gpp.createToken(cardElement);
// ...
});1
2
3
4
5
6
7
8
9
10
11
12
13
14
2
3
4
5
6
7
8
9
10
11
12
13
14
ACH/Bank Payments
Bank Account Element
javascript
const bankAccount = gpp.elements.create('bankAccount');
bankAccount.mount('#bank-element');1
2
2
Collecting Bank Info
javascript
const { token, error } = await gpp.createToken(bankAccount, {
accountHolderName: 'John Doe',
accountHolderType: 'individual' // or 'company'
});1
2
3
4
2
3
4
Error Handling
Common Errors
| Code | Description |
|---|---|
invalid_number | Card number invalid |
invalid_expiry | Expiration date invalid |
invalid_cvc | CVV invalid |
card_declined | Card was declined |
processing_error | Temporary error |
Display Errors
javascript
cardElement.on('change', (event) => {
const errorElement = document.getElementById('card-errors');
if (event.error) {
errorElement.textContent = event.error.message;
errorElement.style.display = 'block';
} else {
errorElement.style.display = 'none';
}
});1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
Security
Tokenization
Card data is tokenized client-side. Tokens:
- Are single-use
- Expire after 10 minutes
- Cannot be used to retrieve card details
PCI Compliance
Using embedded forms reduces your PCI scope to SAQ A-EP:
- Card data never touches your servers
- Secure iframe handles sensitive input
- All data encrypted in transit
Related Topics
- Hosted Payment Page - Simpler integration
- Authentication - API keys
- Testing - Test cards
