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:

PropertyDescription
onStageChangedThis 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.

PropertyDescription
namerequired name of the input field. Will be shown in the form state and used as a data key in the request payload.
typerequired type of the input field. Available types are: text, card-number, card-expiration-date and card-security-code.
validationsarray of validations that will be used to calculate field isValid state. You can find more information below.
autoCompleteallows to control how the browser should populate a given form field.
The most common autocomplete attributes:
cc-name, cc-number, cc-exp.
cssan object of styles you can apply to the field.
classesCSS classes applied to the container element when the field is in a particular state.

dirty - true if a user typed in the field
empty - the field is empty
focused - the field is focused
valid - the field is valid
invalid - the field is invalid
touched - true if this field has ever gained and lost focus

Example:

{ "invalid": "form**input--invalid", "empty": "form**input--empty", "focused": "form**input--focused", "dirty": "form**input--dirty", "touched": "form__input--touched" }
autoFocusspecifies that the input field should automatically get focus when the page loads.
disabledspecifies that the input field is disabled. disabled: 'disabled'
readOnlyspecifies that the input field is read only (cannot be changed). readOnly: 'readonly'
ariaLabelis 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.
serializersyou 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.
placeholdertext displayed when the field is empty.
showCardIconOnly 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.
iconsOnly 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.
addCardBrandsOnly 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.
hideValueOnly 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.
yearLengthOnly available for type card-expiration-date

The value can be either '2' or '4'. By default date format - MM/YYYY.
separatorOnly 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.

ValidationError message
requiredis required
validCardExpirationDateis not a valid expiration date
validCardNumberis not a valid card number
validCardSecurityCodeis not a valid security code
regExpthe 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 BrandState cardType
Visavisa
Visa Electronvisaelectron
Maestromaestro
Mastercardmastercard
Amexamex
Discoverdiscover
Dankortdankort
Diners Clubdinersclub
JCBjcb
UnionPayunionpay
Forbrugsforeningenforbrugsforeningen
Eloelo
Hipercardhipercard

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);