Validating custom Stripe form
← ejemplos
Stripe is a popular payment platform. It's quite easy for developers to use and integrate its helpful APIs in a payment, checkout form.
This example covers steps to help you create a payment form with Bootstrap framework, validate it with FormValidation. The credit card data is then processed by Stripe API.
Step 1: Creating a payment form
It's easy to use your favorite framework to create a standard payment form as following:
<form id="paymentForm" class="form-horizontal">
...
<div class="form-group">
<label class="col-xs-3 control-label">Credit card number</label>
<div class="col-xs-5">
<input type="text" class="form-control" data-stripe="number" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Expiration</label>
<div class="col-xs-3">
<input type="text" class="form-control" placeholder="Month" data-stripe="exp-month" />
</div>
<div class="col-xs-3">
<input type="text" class="form-control" placeholder="Year" data-stripe="exp-year" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">CVV</label>
<div class="col-xs-2">
<input type="text" class="form-control" data-stripe="cvc" />
</div>
</div>
<input type="hidden" name="token" value="" />
...
</form>
As you see, all fields for filling the credit card information don't have the
name
attribute. Instead, they use the data-stripe
attribute
which are defined by Stripe. The Stripe API then will collects the credit card data from
fields using this attribute.
The form also includes a hidden field named token
. Instead of storing the
credit card data which are very sensitive, the form stores an equivalent token that is
determined and returned by Stripe API.
Step 2: Adding validation rules
All credit card fields are nameless elements. How we can apply the validation rules for them?
Fortunately, FormValidation provides the selector option to support indicating fields via a CSS selector.
We can use the built in validators for the credit card fields
via their data-stripe
attribute as following:
$('#paymentForm').formValidation({
fields: {
ccNumber: {
// The credit card number field can be retrieved
// by [data-stripe="number"] attribute
selector: '[data-stripe="number"]',
validators: {
notEmpty: {
...
},
creditCard: {
...
}
}
},
expMonth: {
selector: '[data-stripe="exp-month"]',
row: '.col-xs-3',
validators: {
notEmpty: {
...
},
digits: {
...
},
callback: {
...
}
}
},
expYear: {
selector: '[data-stripe="exp-year"]',
row: '.col-xs-3',
validators: {
notEmpty: {
...
},
digits: {
...
},
callback: {
...
}
}
},
cvvNumber: {
selector: '[data-stripe="cvc"]',
validators: {
notEmpty: {
...
},
cvv: {
...
creditCardField: 'ccNumber'
}
}
}
}
});
The table below list validators used for validating credit card data:
Validator | Purpose |
---|---|
creditCard | Validate a credit card number |
cvv | Validate a CVV number |
callback | Validate expiration month and year. For more details, see the Validating credit card expiration date example. |
Step 3: Using Stripe API to collect credit card data
When the form passes our validation rules, it's time to send credit card data to Stripe and get back the token. It can be done by triggering the success.form.fv event:
// Change the key to your one
Stripe.setPublishableKey('pk_test_IrimHhYZzZiCmaNo5riP9buX');
$('#paymentForm')
.formValidation({
...
})
.on('success.form.fv', function(e) {
// Prevent default form submission
e.preventDefault();
// Get the form element
var $form = $(e.target);
// Reset the token first
$form.find('[name="token"]').val('');
Stripe.card.createToken($form, function(status, response) {
if (response.error) {
// Show the error message
bootbox.alert(response.error.message);
} else {
// Set the token value
$form.find('[name="token"]').val(response.id);
// You can submit the form to back-end as usual
// $form.get(0).submit();
// Or using Ajax
$.ajax({
url: '/path/to/your/back-end/',
data: $form.serialize(),
dataType: 'json'
}).success(function(data) {
// Handle the response
bootbox.alert(data.message);
// Reset the form
$form.formValidation('resetForm', true);
});
}
});
});
Inside the handler of Stripe.card.createToken
, we use bootboxjs to show the error message from Stripe if
there's something wrong with credit card data. Otherwise, we set the token value
returned by Stripe API. This token then can be used to charge the customer.
Optionally, you can use the resetForm() method to reset entire form in case you use Ajax to send the form data to server.
You can see how all the steps are implemented in the working example below. We also provide some fake credit card numbers for testing:
Card type | Example |
---|---|
American Express | 340653705597107 |
Diners Club | 30130708434187 |
Diners Club (US) | 5517479515603901 |
Discover | 6011734674929094 |
JCB | 3566002020360505 |
Maestro | 6762835098779303 |
Mastercard | 5303765013600904 |
Visa | 4929248980295542 |
<form id="paymentForm" class="form-horizontal">
<div class="form-group">
<label class="col-xs-3 control-label">Product name</label>
<div class="col-xs-5">
<input type="text" class="form-control" name="productName" value="T-Shirt" readonly="readonly" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Price</label>
<div class="col-xs-3 inputGroupContainer">
<div class="input-group">
<input type="text" class="form-control" name="price" value="25" readonly="readonly" />
<span class="input-group-addon">$</span>
</div>
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Your full name</label>
<div class="col-xs-5">
<input type="text" class="form-control" name="fullName" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Credit card number</label>
<div class="col-xs-5">
<input type="text" class="form-control" data-stripe="number" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">Expiration</label>
<div class="col-xs-3">
<input type="text" class="form-control" placeholder="Month" data-stripe="exp-month" />
</div>
<div class="col-xs-3">
<input type="text" class="form-control" placeholder="Year" data-stripe="exp-year" />
</div>
</div>
<div class="form-group">
<label class="col-xs-3 control-label">CVV</label>
<div class="col-xs-2">
<input type="text" class="form-control" data-stripe="cvc" />
</div>
</div>
<div class="form-group">
<div class="col-xs-9 col-xs-offset-3">
<button type="submit" class="btn btn-primary">Purchase</button>
</div>
</div>
<input type="hidden" name="token" value="" />
</form>
<script src="https://js.stripe.com/v2/"></script>
<script src="//oss.maxcdn.com/bootbox/4.2.0/bootbox.min.js"></script>
<script>
$(document).ready(function() {
// Change the key to your one
Stripe.setPublishableKey('pk_test_IrimHhYZzZiCmaNo5riP9buX');
$('#paymentForm')
.formValidation({
framework: 'bootstrap',
icon: {
valid: 'glyphicon glyphicon-ok',
invalid: 'glyphicon glyphicon-remove',
validating: 'glyphicon glyphicon-refresh'
},
fields: {
fullName: {
validators: {
notEmpty: {
message: 'The full name is required'
}
}
},
ccNumber: {
selector: '[data-stripe="number"]',
validators: {
notEmpty: {
message: 'The credit card number is required'
},
creditCard: {
message: 'The credit card number is not valid'
}
}
},
expMonth: {
selector: '[data-stripe="exp-month"]',
row: '.col-xs-3',
validators: {
notEmpty: {
message: 'The expiration month is required'
},
digits: {
message: 'The expiration month can contain digits only'
},
callback: {
message: 'Expired',
callback: function(value, validator) {
value = parseInt(value, 10);
var year = validator.getFieldElements('expYear').val(),
currentMonth = new Date().getMonth() + 1,
currentYear = new Date().getFullYear();
if (value < 0 || value > 12) {
return false;
}
if (year == '') {
return true;
}
year = parseInt(year, 10);
if (year > currentYear || (year == currentYear && value >= currentMonth)) {
validator.updateStatus('expYear', 'VALID');
return true;
} else {
return false;
}
}
}
}
},
expYear: {
selector: '[data-stripe="exp-year"]',
row: '.col-xs-3',
validators: {
notEmpty: {
message: 'The expiration year is required'
},
digits: {
message: 'The expiration year can contain digits only'
},
callback: {
message: 'Expired',
callback: function(value, validator) {
value = parseInt(value, 10);
var month = validator.getFieldElements('expMonth').val(),
currentMonth = new Date().getMonth() + 1,
currentYear = new Date().getFullYear();
if (value < currentYear || value > currentYear + 100) {
return false;
}
if (month == '') {
return false;
}
month = parseInt(month, 10);
if (value > currentYear || (value == currentYear && month >= currentMonth)) {
validator.updateStatus('expMonth', 'VALID');
return true;
} else {
return false;
}
}
}
}
},
cvvNumber: {
selector: '[data-stripe="cvc"]',
validators: {
notEmpty: {
message: 'The CVV number is required'
},
cvv: {
message: 'The value is not a valid CVV',
creditCardField: 'ccNumber'
}
}
}
}
})
.on('success.form.fv', function(e) {
e.preventDefault();
var $form = $(e.target);
// Reset the token first
$form.find('[name="token"]').val('');
Stripe.card.createToken($form, function(status, response) {
if (response.error) {
bootbox.alert(response.error.message);
} else {
// Set the token value
$form.find('[name="token"]').val(response.id);
// You can submit the form to back-end as usual
// $form.get(0).submit();
// Or using Ajax
$.ajax({
// You need to change the url option to your back-end endpoint
url: 'response.json',
data: $form.serialize(),
dataType: 'json'
}).success(function(data) {
// Handle the response
bootbox.alert(data.message);
// Reset the form
$form.formValidation('resetForm', true);
});
}
});
});
});
</script>