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

  1. Add <script src="https://widgets-sandbox.synctera.com/assets/activate/activate_v1.0.1.js"></script>
    to your page.
  2. 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>
    
  3. Add your own submit button under the Card Activation widgets.
  4. 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;
    

  5. 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


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.

BrowserMinimum tested version
Chrome29 (2013)
Firefox27 (2014)
Edge79 (2020), 15 (2017)
Safari12 (2018)
Opera20 (2014)
IE11 (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:

  1. On your backend, request a widget token from Synctera for the particular card you wish to use.
  2. Make sure the Synctera Activation widget Javascript has been added to your website.
  3. 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.
  4. You can style these fields however you like (as explained below in Custom Styling).
  5. Listen for the "validity" event from the controller widget.
  6. When valid, enable your button.
  7. When the button is clicked, call the submit() function on the controller widget.
  8. The submit function will activate the card.
  9. It also returns a promise which resolves when successful, or rejects when there's a failure.
  10. Once submitted, the widgets will auto-destroy and you can now remove them.

Widget API

Element Attributes:

NameValueDefaultDetailsExample
tokenwidget token ID-Required
<card-pan token="[widget token from Synctera]" ...>
classclass name (string)OmittedOptional
If present, it will activate custom styling
<card-pan ... class="customStyles" ...><card-cvv ... class="customStyles" ...>`

Events:

NameCalled when...Why?addEventListeneron
loadThe widgets have are fully loadedFor best user experience, show the widgets only when this event is triggeredcardPanEl.addEventListener('load', () => ...);cardPanEl.onLoad = () => ...
validityThe widgets are now (in)validOnly allow submit() to be called when valid
To get the status, check the "isValid" property
cardPanEl.addEventListener('validity', () => {
␠ buttonEl.disabled = !cardPanEl.isValid;
});
cardPanEl.onValidity = (e, isValid) => {
␠ buttonEl.disabled = !isValid;
};
errorThe widgets failed to loadNon-recoverable error states
To get the error, check the "error" property
cardPanEl.addEventListener('error', () => {
␠ console.log(cardPanEl.error);
});
cardPanEl.onError = () => {
␠ console.log(cardPanEl.error);
};
successThe widget submitted successfullyKnow 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 = () => ...
failureThe widget submitted unsuccessfullyKnow 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:

NameValue / ParametersDefault / ReturnsDetailsExample
isValidtrue
false
falsetrue if both fields are valid and form is ready to submitcardPanEl.isValid
error{
errorType:'...',
error: *
}
undefinedError details if an error or failure occurscardPanEl.error
submit()No parametersReturns: PromiseSubmits 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 or card-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 selectorInput field equivalentDescription
.customStyles[_required]input:requiredTrue as soon as the widget has rendered
(Useful to know when the widget is ready to be shown)
.customStyles[_hover]input:hoverTrue when the field is hovered over by the mouse
.customStyles[_focus]input:focusTrue when the field is focused
.customStyles[_active]input:activeTrue when the mouse or touch is pressing down on the field
.customStyles[_blank]input:blankTrue when there is no text in the field
.customStyles[_invalid]input:invalidTrue when the text in the field is not yet valid
.customStyles[_valid]input:validTrue when the text in the field is now valid
.customStyles[_user-invalid]input:user-invalidLike :invalid, but only after the user first interacted with the field
.customStyles[_user-valid]input:user-validLike :valid, but only after the user first interacted with the field
.customStyles[_out-of-range]input:out-of-rangeTrue 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-rangeTrue 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 nameAllowed values
colorrgb(<R>, <G>, <B>) or rgba(<R>, <G>, <B>, <Alpha>)
font-familyOne 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: