Card Activation Widget
Using this widget you can add card activation to your website. It requires a Synctera widget vault token to
initialize it with. The user will have 5 minutes to complete the activation submission.
The Card Activation Widget injects a configurable set of iframes into your app, allowing your user to
securely enter a PAN & CVV in a PCI compliant manner. This helps remove some (but not all) of the PCI
compliance requirements you would otherwise need to handle.
The iframes injected by Synctera allow you complete control over the styling over the widget using
only CSS.
Quick start
- Add
<script src="https://widgets-sandbox.synctera.com/assets/activate/activate_v1.0.1.js"></script>
to your page. - Embed the Card Activation widgets when and as needed (both the card-pan and card-cvv widgets are
needed):<!-- Controller widget: --> <card-pan id="synctera-activate" token="[insert the token here]"></card-pan> <card-cvv></card-cvv>
- Add your own submit button under the Card Activation widgets.
- Listen for the
validity
event on the Controller Card Activation widget (the one with the id):const activationWidget = document.getElementById('synctera-activate); activationWidget.onValidity = (e, isValid) => button.disabled = !isValid;
- Have the button call
activationWidget.submit()
to activate the card.
It returns a promise, which
resolves if the activation submission was successful, or rejects if it failed.
Basic Example:
<html>
<head>
<script src="https://widgets-sandbox.synctera.com/assets/activate/activate_v1.0.1.js"></script>
</head>
<body>
<div>PAN</div>
<card-pan id="synctera-activate" token="[insert the token here]"></card-pan>
<div>CVV</div>
<card-cvv></card-cvv>
<button id="synctera-submit-button" disabled>Submit</button>
<script type="application/javascript">
const activate = document.getElementById('synctera-activate');
const button = document.getElementById('synctera-submit-button');
activate.addEventListener('validity', () => button.disabled = !activate.isValid);
button.addEventListener('click', () => {
activate.submit()
.then(() => alert('Card Activated!'))
.catch((e) => console.error('Card failed to Activate', e));
});
</script>
</body>
</html>
Styling: If you add a custom class name to the Card Activation widget, custom styling will be activated
(see Custom Styling). By default, the widgets use the browser's inbuilt
styling for the Card PAN and Card CVV input text fields (note that without custom styling the widget iframe is
4px bigger than the input field inside to allow for any browser outline effects).
See Custom Styling Example for a complete working example.
Environments
- Sandbox: https://widgets-sandbox.synctera.com/assets/activate/activate_v1.0.1.js
- Production: https://widgets.synctera.com/assets/activate/activate_v1.0.1.js
Browser support
The widgets work on both mobile and desktop, and we ensure support for all modern browsers. It also
works in many older browsers, which we try to support where feasible.
Browser | Minimum tested version |
---|---|
Chrome | 29 (2013) |
Firefox | 27 (2014) |
Edge | 79 (2020), 15 (2017) |
Safari | 12 (2018) |
Opera | 20 (2014) |
IE | 11 (2013) |
Card Activation flow
Summary
Fetch widget token from backend → Render widgets with token → Listen for "validity" event → User
submits controller widget → Widget submits PAN & CVV to Synctera → And returns success or failure →
Widget auto-destroys
Note: It is recommended to also add 'load' and 'error' listeners for UI management
(see Widget API below).
The flow for using the widgets:
- On your backend, request a widget token from Synctera for the particular card you wish to use.
- Make sure the Synctera Activation widget Javascript has been added to your website.
- Render the two specialized Card PAN and Card CVV HTML tags as above, setting the token attribute, and your own
button to submit the widget. - You can style these fields however you like (as explained below in Custom Styling).
- Listen for the "validity" event from the controller widget.
- When valid, enable your button.
- When the button is clicked, call the
submit()
function on the controller widget. - The submit function will activate the card.
- It also returns a promise which resolves when successful, or rejects when there's a failure.
- Once submitted, the widgets will auto-destroy and you can now remove them.
Widget API
Element Attributes:
Name | Value | Default | Details | Example |
---|---|---|---|---|
token | widget token ID | - | Required | <card-pan token="[widget token from Synctera]" ...> |
class | class name (string) | Omitted | Optional If present, it will activate custom styling | <card-pan ... class="customStyles" ...> <card-cvv ... class="customStyles" ...>` |
Events:
Name | Called when... | Why? | addEventListener | on |
---|---|---|---|---|
load | The widgets have are fully loaded | For best user experience, show the widgets only when this event is triggered | cardPanEl.addEventListener('load', () => ...); | cardPanEl.onLoad = () => ... |
validity | The widgets are now (in)valid | Only allow submit() to be called when validTo get the status, check the "isValid" property | cardPanEl.addEventListener('validity', () => { ␠ buttonEl.disabled = !cardPanEl.isValid; }); | cardPanEl.onValidity = (e, isValid) => { ␠ buttonEl.disabled = !isValid; }; |
error | The widgets failed to load | Non-recoverable error states To get the error, check the "error" property | cardPanEl.addEventListener('error', () => { ␠ console.log(cardPanEl.error); }); | cardPanEl.onError = () => { ␠ console.log(cardPanEl.error); }; |
success | The widget submitted successfully | Know when the widget is done and the card was activated Alternatively: The "submit()" method returns a promise resolving when done | cardPanEl.addEventListener('success', () => ...); | cardPanEl.onSuccess = () => ... |
failure | The widget submitted unsuccessfully | Know if the card was not activated and the user will need to try again Alternatively: The "submit()" method returns a promise rejecting on failure To get the failure, check the "error" property | cardPanEl.addEventListener('failure', () => { ␠ console.log(cardPanEl.error); }); | cardPanEl.onFailure = (e, errorDetails) => ... |
Fields:
Name | Value / Parameters | Default / Returns | Details | Example |
---|---|---|---|---|
isValid | true false | false | true if both fields are valid and form is ready to submit | cardPanEl.isValid |
error | { errorType:'...', error: * } | undefined | Error details if an error or failure occurs | cardPanEl.error |
submit() | No parameters | Returns: Promise | Submits the PAN & CVV to Synctera's servers Alternatively: The widget fires "success" and "failure" events | cardPanEl.submit() ␠ .then(// success) ␠ .catch(// error) |
Custom styling
Summary
- Add a class name to
card-pan
orcard-cvv
tags to activate Custom Styling:<card-pan class='customStyles' ...
- Style as desired (i.e. border), but Font Styles are special
- For pseudo-selectors, e.g.
:hover
,:focus
, etc - use pseudo-attributes instead:
Example:.customStyles[_hover] { border: 1px solid #616161; }
- Font styles are auto-forwarded, but only certain values are allowed (see below)
- Optional: You can use
.customStyles[_required]
to show the widgets once they have loaded
By default, without custom styling, the widgets use the browser's inbuilt styling for the PAN and CVV
input text fields (note that the widget iframe is 4px bigger than the input field inside to allow
for any browser outline effects).
You may want to style the widget to match your webapp design or to add things like placeholders.
This can be done entirely through css styling. When a class
attribute is added to the widget,
the 4px spacing is removed, the input box styling is stripped and the background is made transparent
such that any elements placed behind the widget will be visible (i.e. a placeholder element). The
text input is set to always take up 100% of the height and width of the iframe, and likewise for the
iframe in the widget tag.
Input text field pseudo selectors such as :hover
, :focus
and :blank
are indirectly supported
through css-like attributes instead of actual pseudo selectors. As the user hovers, focuses and
types in the field, attributes will be added/removed on the card-pan
and card-cvv
tags automatically. Supported
"pseudo attributes" are inspired from: https://developer.mozilla.org/en-US/docs/Web/CSS/Pseudo-classes#input_pseudo-classes
Where customStyles
is the class name added to widget tags, e.g. <card-pan class='customStyles'...
:
Supported selector | Input field equivalent | Description |
---|---|---|
.customStyles[_required] | input:required | True as soon as the widget has rendered (Useful to know when the widget is ready to be shown) |
.customStyles[_hover] | input:hover | True when the field is hovered over by the mouse |
.customStyles[_focus] | input:focus | True when the field is focused |
.customStyles[_active] | input:active | True when the mouse or touch is pressing down on the field |
.customStyles[_blank] | input:blank | True when there is no text in the field |
.customStyles[_invalid] | input:invalid | True when the text in the field is not yet valid |
.customStyles[_valid] | input:valid | True when the text in the field is now valid |
.customStyles[_user-invalid] | input:user-invalid | Like :invalid, but only after the user first interacted with the field |
.customStyles[_user-valid] | input:user-valid | Like :valid, but only after the user first interacted with the field |
.customStyles[_out-of-range] | input:out-of-range | True when the pan field is less than 13 or greater than 16 numbers and the cvv isn't 3 numbers |
.customStyles[_in-range] | input:in-range | True when the pan in the field is between 13 and 16 numbers and the cvv is 3 numbers |
See Font Styles for information on acceptable font style values.
src="https://widgets-sandbox.synctera.com/assets/activate/activate_v1.0.1.js"
Custom Styling Example:
<html>
<head>
<script
type="application/javascript"
src="https://widgets-sandbox.synctera.com/assets/activate/activate_v1.0.1.js"
></script>
<style>
.ct {
/* Setting the container to relative allows us to control the placement of absolutely positioned children */
position: relative;
margin: 5px;
}
.customStyles {
/* Set on the widget <card-actvivation> tag */
box-sizing: border-box;
border: 1px solid #b7b7b7;
width: 193px;
height: 41px;
border-radius: 4px;
padding: 0 8px;
}
/* Rather than using pseudo selectors (e.g. .customStyles:hover), a "pseudo attribute" is
* added to the card-actvivation tag, you can select using attribute selectors like this */
.customStyles[_hover] {
border: 1px solid #616161;
}
.customStyles[_focus] {
border: 2px solid #2564eb;
padding: 0 7px;
}
.customStyles[_disabled] {
background: #d3d3d3;
}
.customStyles[_user-invalid] {
border-color: #e31b0c;
}
.customStyles,
.placeholder {
/* These fonts will automatically be sent to the iframe (after sanitization) */
font-family: Arial, sans-serif;
font-size: 1rem;
line-height: 1.4375em;
font-weight: 400;
color: rgba(0, 0, 0, 0.87);
letter-spacing: 0.15px;
}
.placeholder {
/* You can absolutely position a placeholder behind the card-pan or card-cvv tag */
position: absolute;
display: none;
top: 9px;
left: 10px;
color: rgba(0, 0, 0, 0.4);
z-index: -1;
}
.customStyles[_blank] + .placeholder {
/* This will show the placeholder if the field is blank */
display: block;
}
.customStyles[_focus] + .placeholder {
/* But hide the placeholder again when the card-pan or card-cvv tag indicates it has focus */
display: none;
}
/* Hide the container until the component is ready to show */
.ct:has(.customStyles:not([_required])) {
display: none;
}
</style>
</head>
<body>
<!-- Remove "customStyles" to see default styling -->
<div class="ct">
<card-pan id="synctera-activation" class="customStyles" token="[insert the token here]"></card-pan>
<div class="placeholder">PAN</div>
</div>
<div class="ct">
<card-cvv class="customStyles" isconfirm></card-cvv>
<div class="placeholder">CVV</div>
</div>
<div class="ct">
<button id="synctera-submit-button" disabled="">Submit</button>
</div>
<script>
var activation = document.getElementById('synctera-activation');
var button = document.getElementById('synctera-submit-button');
activation.addEventListener('load', () => console.log('LOADED'));
activation.addEventListener('validity', () => button.disabled = !activation.isValid);
button.addEventListener('click', () => {
activation.submit()
.then(() => alert('Card Activated!'))
.catch((e) => console.error('Card failed to activate', e));
});
</script>
</body>
</html>
Font Styles
You can style the or tag as you see fit (border, background, etc). Css font properties
are handled in a special way to forward them to the iframe for styling the input, in a secure and
sanitized manner. As such only certain css font properties are supported and only with certain
values (all other values may be ignored, if they work they are not guaranteed across all browsers):
Font css property name | Allowed values |
---|---|
color | rgb(<R>, <G>, <B>) or rgba(<R>, <G>, <B>, <Alpha>) |
font-family | One of: courier: Courier New, Courier, Lucida Console, Lucida Sans Typewriter, monospace arial: Arial, Helvetica, sans-serif georgia: Georgia, Times New Roman, Times, serif helvetica: Helvetica, Arial, sans-serif lucida: Lucida Console, Lucida Sans Typewriter, Courier New, Courier, monospace times: Times New Roman, Times, Georgia, serif tahoma: Tahoma, Verdana, sans-serif verdana: Verdana, Tahoma, sans-serif |
font-size | <N>px |
font-weight | <N>00 (a number, not 'bold' etc) |
line-height | <N>px |
letter-spacing | <N>px |
Note that with the font-family
property, we look for a keyword in the first font in the comma
separated list of fonts you supply. If there's a match, we use the font-family strings in the above
table and not the font-family specified (for security). The above list of fonts are designed to
ensure maximum coverage across different operating systems for similar style fonts. Custom fonts are
not supported at this time.
Additional Resources
For examples showing the Card Activation & Set PIN widget implementation please see the following:
Updated about 1 month ago