Card Collect
Paybyrd Card Collect API documentation
This guide will provide you with the necessary steps to start using Paybyrd card collect widget.
Overview
Card Collect is a javascript plugin that allows your company to create credit card payments without the need to be PCI-compliant as you do not handle credit card-related data on your side.
We provide fully customizable secured fields for the cardholder to enter his information and translate it to a temporary token that can be used to consume any Paybyrd API that requires credit card data.
Installation
To get started you just have to run
npm install @paybyrd/card-collect
or
yarn add @paybyrd/card-collect
and then
import CardCollect from "@paybyrd/card-collect";
on your project.
For usage in the browser please visit github, download dist/cardCollect-web.js and include it in your HTML file
Quick Start
This is a simple and easy library to integrate. You just need to designate the places where your fields will be placed and initialize the library.
First, include the library in your application as explained above, and then, initialize it.
const form = await CardCollect({ options });
or for web
const form = await cardCollect({ options });
You can pass the following options when initializing the library:
Property | Description |
---|---|
onStageChanged | This handler will be called whenever the form state changes. The only argument passed is a state object with the current status of the form fields, for example:{ card_cvv: { errorMessages: ['is not a valid security code'], isDirty: true, isEmpty: false, isFocused: false, isTouched: true, isValid: false, name: "card_cvv" } } ```You can use this handler to enable/disable the submit button to prevent the user from misusing your form. |
Finally, you can create fields and configure the submit handler.
form.cardCollect_field({
id: '#cc-number',
type: 'card-number',
name: 'card_number',
placeholder: 'Card number',
showCardIcon: true,
validations: ['required', 'validCardNumber'],
});
const submitButton = document.getElementById("submit-button");
submitButton.onclick = handleSubmit;
function handleSubmit() {
form.cardCollect_submit().then(({ status, response }) => {
console.log(response);
}).catch((error) => console.log(error));
}
You should have at least one field with the name card_number
and one with card_exp
. These are mandatory.
The response
is a JSON object that will contain the TokenId
. Please do not confuse this token with the token generated in the tokenization API. The token generated by the card collect is available only for a few minutes and it will be discarded after usage.
{
"tokenId": "ecf4a873-59fd-4300-a6e6-330d267ebbb2",
"correlationId": "5c9b4c3a-9602-4c4e-9a3d-4e4af8a3d872"
}
With the TokenId
, you can call any Paybyrd API that requires card data. Inside the Card
node, instead of sending the raw card data, you will send the TokenId
as shown in the sample below:
curl --request POST \
--url https://gateway.paybyrd.com/api/v2/payment \
--header 'Accept: application/json' \
--header 'Content-Type: application/json' \
--header 'x-api-key: 5E37D19C-F99C-445F-8B77-1463EFC66C7B' \
--data '
{
"type": "Card",
"amount": "8.15",
"currency": "EUR",
"orderRef": "ABC12345",
"redirectUrl": "https://your-shop-url?orderRef=ABC12345",
"card": {
"tokenId": "ecf4a873-59fd-4300-a6e6-330d267ebbb2"
}
}'
{
"transactionId": "0e443bff-9052-4eec-a5f1-9db474f2077a",
"type": "Card",
"currency": "EUR",
"orderRef": "ABC12345",
"brand": "VISA",
"fingerprint": "b53b68c8-43af-4acc-bc79-e892dd6a9a38",
"amount": "8.15",
"isPreAuth": false,
"redirectUrl": "https://your-shop-url?orderRef=ABC12345",
"action": {
"type": "redirect",
"url": "https://link-s.paybyrd.com/3ds_Q44clBT77"
},
"card": {
"number": "420000******0000",
"expiration": "12/25",
"cvv": "***",
"holder": "Peter Parker"
},
"code": "BYRD207",
"description": "Pending redirect",
}
Full integration example
<div id="cardCollect">
<div id="cc-holder" class="form-field"></div>
<div id="cc-number" class="form-field"></div>
<div class="form-field-group">
<div id="cc-expiration-date" class="form-field"></div>
<div id="cc-cvc" class="form-field"></div>
</div>
<button class="form-button" id="submit-form" disabled>Submit</button>
</div>
.form-field {
width: 100%;
height: 40px;
position: relative;
background: white;
margin-bottom: 10px;
border-radius: 4px;
box-shadow: 0 0 3px 0px rgba(0, 0, 0, .3);
padding: 0 10px;
}
iframe {
width: 100%;
height: 100%;
}
.form-field-group {
display: flex;
flex-flow: wrap;
}
.form-field-group div {
flex: 0 0 50%;
box-sizing: border-box;
}
.form-field-group div:first-child {
border-radius: 4px 0 0 4px;
}
.form-field-group div:last-child {
border-radius: 0 4px 4px 0;
}
.form-button {
border: 1px solid #1f8ab0;
background-color: #3b495c;
border-color: #3b495c;
color: #ced5e0;
font-family: inherit;
border-radius: 4px;
font-size: 16px;
height: 35px;
width: 100%;
}
async function init() {
// Handler setup
const handleSubmit = () => {
cardCollect_submit()
.then(({ status, data }) => console.log("Success:", status, data)) // Handle paybyrd's response here
.catch((error) => console.log("Error:", error)); // Handle any errors here
};
const handleStateChanged = (state) => {
console.log(state);
};
// Paybyrd elements initialization
const {
cardCollect_field,
cardCollect_submit,
} = await cardCollect({
onStateChanged: handleStateChanged
});
// Form setup
const submitButton = document.getElementById("submit-form");
submitButton.onclick = handleSubmit;
cardCollect_field({
id: '#cc-holder',
type: 'text',
name: 'card_holder',
placeholder: 'Card holder',
validations: ['required'],
});
cardCollect_field({
id: '#cc-number',
type: 'card-number',
name: 'card_number',
placeholder: 'Card number',
validations: ['required', 'validCardNumber'],
});
cardCollect_field({
id: '#cc-expiration-date',
type: 'card-expiration-date',
name: 'card_exp',
placeholder: 'MM/YY',
validations: ['required', 'validCardExpirationDate'],
serializers: [{ name: 'replace', options: { old: ' ', new: '' } }],
yearLength: 2,
});
cardCollect_field({
id: '#cc-cvc',
type: 'card-security-code',
name: 'card_cvv',
placeholder: 'CVV',
validations: ['required', 'validCardSecurityCode'],
});
}
init();
The CSS included in this example is the default CSS. It's embedded in the library, you don't have to include it. However, you can customize the look and feel of your form as you see fit.
<div id="cardCollect">
<div id="cc-holder" class="my-field"></div>
<div id="cc-number" class="form-field"></div>
<div class="form-field-group">
<div id="cc-expiration-date" class="form-field"></div>
<div id="cc-cvc" class="form-field"></div>
</div>
<button class="form-button" id="submit-form" disabled>Submit</button>
</div>
.myfield {
width: 100%;
height: 60px;
position: relative;
background: purple;
margin-bottom: 10px;
border-radius: 7px;
box-shadow: 0 0 3px 0px rgba(0, 0, 0, .3);
padding: 0 10px;
}
Integration
You should create each field using the code below.
form.cardCollect_field(properties);
Where properties
is an Object that can contain the following properties.
Property | Description |
---|---|
name | required name of the input field. Will be shown in the form state and used as a data key in the request payload. |
type | required type of the input field. Available types are: text , card-number , card-expiration-date and card-security-code . |
validations | array of validations that will be used to calculate field isValid state. You can find more information below. |
autoComplete | allows to control how the browser should populate a given form field. The most common autocomplete attributes: cc-name , cc-number , cc-exp . |
css | an object of styles you can apply to the field. |
classes | CSS classes applied to the container element when the field is in a particular state.dirty - true if a user typed in the fieldempty - the field is emptyfocused - the field is focusedvalid - the field is validinvalid - the field is invalidtouched - true if this field has ever gained and lost focusExample: { "invalid": "form**input--invalid", "empty": "form**input--empty", "focused": "form**input--focused", "dirty": "form**input--dirty", "touched": "form__input--touched" } |
autoFocus | specifies that the input field should automatically get focus when the page loads. |
disabled | specifies that the input field is disabled. disabled: 'disabled' |
readOnly | specifies that the input field is read only (cannot be changed). readOnly: 'readonly' |
ariaLabel | is used to define a string that labels the current element. By default, each field has own aria-label value, but you can redefine it and specify the purpose for better accessibility. |
serializers | you could use this to format how you want to receive the data. Example: maybe you want to take the date and remove the spaces. You can find more information down bellow in the Formating section. |
placeholder | text displayed when the field is empty. |
showCardIcon | Only available for type card-number and card-security-code property available for credit-card-number and card-security-code field types. Icon changes based on the detected card number. |
icons | Only available for type card-number and card-security-code Override default icons with your images. unfortunately, we cannot use regular HTTP(s) URLs for security reasons. To customize an icon you need to pass a Data URL with an icon. Check the example below. cardPlaceholder - card icon for empty and undefined card brand states.cvvFront - card icon for the front (amex) CVV.cvvBack - card icon for the back CVV.visa|amex|maestro|... - card icons for particular brands. Full list of types below. |
addCardBrands | Only available for type card-number use it if you would like to extend the list of supported card brands or redefine existing card brand pattern. You can find more information below. |
hideValue | Only available for type card-number and card-security-code Boolean. Use it if you would like to hide entered value to prevent shoulder surfing attacks. |
yearLength | Only available for type card-expiration-date The value can be either '2' or '4'. By default date format - MM/YYYY. |
separator | Only available for type card-expiration-date separator to use between the month and year values. Default: " / " . |
Validations
The validation rule can be passed as a string or an object to pass additional parameters (it's required for some validation types).
Array<string | { type: string, params: any }>
required
- use it for required fields.validCardExpirationDate
- use it for the card expiration date field.validCardNumber
- use it for the card number field. It checks that the card number is formatted correctly and passes the Luhn check.validCardSecurityCode
- use it for the card security code field. Please be aware cvc field doesn't validate value based on the typed card by default. To do so, please check out how to configure smart cvv below./^(0[1-9]|1[0-2])\s\/?\s([0-9]{4})$/
- you can specify any RegExp to validate your field value. Example of usage:validations: ['validCardExpirationDate', 'required', '/^(0[1-9]|1[0-2])\s\/?\s([0-9]{4})$/']
.
Error messages associated with the validations.
Validation | Error message |
---|---|
required | is required |
validCardExpirationDate | is not a valid expiration date |
validCardNumber | is not a valid card number |
validCardSecurityCode | is not a valid security code |
regExp | the value doesn't match a pattern |
Formating
Serializers
These are used to change the format of the data being sent to the server.
Replace
Returns a new string with some or all matches of an old value replaced by the new value.
{ name: 'replace', options: { old:' ', new:'-'', count: '2' }}
old
- string is to be replaced with new value.new
- string that replaces the specified substring.count
- optional, defines how many times a certain string should be replaced.
Separate
Split expiration date month and year as 2 separate values.
{name: 'separate', options: {monthName: '<custom-name>', yearName: '<custom-name>'}
monthName
- expiration date month field name you would like to define.yearName
- expiration date year field name you would like to define.
Convert to base64
{ name: 'toBase64' }
Examples:
form.pbelement_field({
serializers: [{ name: 'replace', options: { old:' ', new:'-' }}],
serializers: [{ name: 'replace', options: { old:' ', new:'-', count: '2' }}]
});
form.pbelement_field({
serializers: [{ name: 'separate', options: { monthName: 'month', yearName: 'year' }}]
});
form.pbelement_field({
serializers: [{ name: 'toBase64'}]
});
How to style?
To customize your secure fields with styles you can add a css
object into your field initialization method to generate a standalone CSS or add your custom CSS to your page.
What is supported:
- Regular CSS properties
- Placeholders
- Generic Web Fonts and
@font-face
property - Pseudo-classes (eg.
:hover
,:focus
) - Media queries (media query condition is calculated based on the iframe width, not on the parent window)
You can style any of the field states by adding a selector to the css
object:
& .invalid
- applied when the field has invalid value.& .valid
- applied when the field has a valid value.& .empty
- applied when the field doesn't have any value.& .dirty
- applied once the user changed the value in the watched field.& .touched
- indicates that the field has been touched, applied after the first blur event.
form.cardCollect_field({
id: '#my-text-field-id',
type: 'text',
name: 'my-text-field',
placeholder: 'placeholder text',
validations: ['required'],
css: {
'color': '#1b1d1f',
'border': 'solid 1px #1b1d1f',
'transition': 'border-color .15s ease-in-out',
'border-radius': '5px',
'padding': '0 10px',
'box-sizing': 'border-box',
'&:focus': {
'border-color': '#11bef5',
},
'&.invalid.touched': {
'color': 'red',
},
'&.valid': {
'color': 'green',
},
'@media (min-width: 420px)': {
'border-color': 'red',
},
'@font-face': {
'font-family': 'PT Mono',
'font-style': 'normal',
'font-weight': '400',
'font-display': 'swap',
'src': 'local("PT Mono"), local("PTMono-Regular") url(https://fonts.gstatic.com/s/ptmono/v7/9oRONYoBnWILk-9AnCszM_HxEcn7Hg.woff2) format("woff2")',
'unicode-range': 'U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116'
},
'font-family': '"PT Mono", monospace',
}
});
Web Fonts support
To perfectly match the font of your form with the font on your site you can choose one of the following options:
- Use Web safe CSS and HTML fonts (such as Arial, Verdana, Courier, etc).
- Set @font-face CSS property. The font can be either loaded from the remote server or a locally-installed font.
Examples:
{
'color': '#1b1d1f',
'font-family': 'Arial, Helvetica, sans-serif',
}
{
'@font-face': {
'font-family': 'PT Mono',
'font-style': 'normal',
'font-weight': '400',
'font-display': 'swap',
'src': 'local("PT Mono"), local("PTMono-Regular") url(https://fonts.gstatic.com/s/ptmono/v7/9oRONYoBnWILk-9AnCszM_HxEcn7Hg.woff2) format("woff2")',
'unicode-range': 'U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116'
},
'color': '#1b1d1f',
'font-family': '"PT Mono", monospace',
}
{
'@font-face': {
'font-family': 'CustomFont',
'src': 'url(data:application/x-font-woff;charset=utf-8;base64,<base64 encoded string>,format("woff"))',
},
'font-family': '"CustomFont", sans-serif',
}
Card brand identification
Will automatically determine the type of the credit card and show the desired icon. If you would like to show a card brand icon or icon for CVV inside your field just set showCardIcon: true
inside the field initialization method.
form.cardCollect_field({
id: '#cc-number',
type: 'card-number',
name: 'cc-number',
placeholder: 'Card number',
validations: ['required', 'validCardNumber'],
showCardIcon: true,
}
});
form.cardCollect_field({
id: '#cc-cvv',
type: 'card-security-code',
name: 'cc-cvv',
placeholder: 'CVV',
validations: ['required', 'validCardSecurityCode'],
showCardIcon: true,
});
The following card brands are supported:
Card Brand | State cardType |
---|---|
Visa | visa |
Visa Electron | visaelectron |
Maestro | maestro |
Mastercard | mastercard |
Amex | amex |
Discover | discover |
Dankort | dankort |
Diners Club | dinersclub |
JCB | jcb |
UnionPay | unionpay |
Forbrugsforeningen | forbrugsforeningen |
Elo | elo |
Hipercard | hipercard |
By default, the icon is 31px width image positioned on the right side of the input, but you can overwrite these styles as shown in the examples below:
form.cardCollect_field({
id: '#cc-number',
type: 'card-number',
name: 'cc-number',
placeholder: 'Card number',
validations: ['required', 'validCardNumber'],
showCardIcon: true,
css: {
color: '#1b1d1f',
border: 'solid 1px #1b1d1f',
transition: 'border-color .15s ease-in-out',
borderRadius: '5px',
padding: '0 10px',
boxSizing: 'border-box',
'&:focus': {
borderColor: '#11bef5',
},
}
});
form.cardCollect_field({
id: '#cc-number',
type: 'card-number',
name: 'cc-number',
placeholder: 'Card number',
validations: ['required', 'validCardNumber'],
showCardIcon: {
left: '5px',
},
css: {
boxSizing: 'border-box',
padding-left: '45px',
padding-right: '0',
}
});
form.cardCollect_field({
id: '#cc-number',
type: 'card-number',
name: 'cc-number',
placeholder: 'Card number',
validations: ['required', 'validCardNumber'],
showCardIcon: {
width: '37px',
height: '25px',
},
});
Smart CVC validation
You can set the CVC field as a dependency on the card number field and it would validate CVC value according to the card brand.
Please make sure your fields were initialized before .setCVCDependency(...)
method call.
const cardNumber = form.cardCollect_field({
id: '#card-number',
type: 'card-number',
name: 'card-number',
validations: ['required', 'validCardNumber'],
autoComplete: 'cc-number',
showCardIcon: 'true',
css: css,
placeholder: '1234 1234 1234 1234',
});
const cvc = form.cardCollect_field({
id: '#card-cvc',
elementId: 'cc-cvc-field',
type: 'card-security-code',
name: 'card-cvc',
validations: ['required', 'validCardSecurityCode'],
autoComplete: 'cc-csc',
css: css,
placeholder: 'CVC',
});
cardNumber.setCVCDependency(cvc);
Updated about 2 years ago