script src="https://uat.ca.shc.payfacto.cloud/secure-hosted-checkout/v1/browser/shc.js"></script>).<div id="shc-fields"></div>).https://uat.ca.shc.payfacto.cloud/secure-hosted-checkout/v1/sessions endpoint from your server application.A fully functional example application can be found in our public Bitbucket repository.

A merchant will need the following information to get started:
This information listed above is provided to you when you create a new developer account with PayFacto.
/secure-hosted-checkout/v1/sessions endpoint./secure-hosted-checkout/v1/sessions endpoint, requires secret information that could be stolen if it was available to the client application. The call to /secure-hosted-checkout/v1/sessions should be done by the merchant’s server, with the result passed to the client.
Note: All the examples provided use JavaScript.SHC tokens are obtained by having the merchant’s server call the shc.titan.uat.ca.payfacto.cloud/secure-hosted-checkout/v1/sessions endpoint. This endpoint is RESTful in that it expects a JSON object as input and returns a JSON object as output. An example of a request is given below:
const endpoint = 'https://uat.ca.shc.payfacto.cloud/secure-hosted-checkout/v1/sessions';
const payload = {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Access-Control-Allow-Origin': '*',
'Authorization': `Basic ${apikey}`
},
body: JSON.stringify({ transactionType:'VERIFY' })
};
fetch(endpoint, payload)
.then(response => response.json())
.then(response => console.log(response))
.catch(response => console.error(response));
{
success: true,
response: {
authCode: "426186",
avs: "U",
brand: "Visa",
card: "411111******1111",
cvv2Cvc2Status: "M",
email: "test@example.com",
expiry: "1226",
invoiceNumber: "abc-123",
isoResponseCode: "00",
issuerMessage: "AP",
lastFour: "1111",
name: "Test Card",
processorAvsResultCode: "",
purchaseAmount: 1025,
purchaseCurrency: "CAD",
purchaseDate: "2026-01-26 17:47:44 EDT",
secureId: "34fd08eb-cdf4-42bb-983d-ef0a386ce856",
status: "SUCCEEDED",
store: {
address: "123 Some Street, Toronto, ON, A1A 1A1, CA",
email: "contact@merchant-store.com",
name: "Merchant Store",
phone: "(123) 456-7890",
website: "www.merchant.com"
},
success: true,
token: "5k46v51j238tpt5v7v4u4a18hc4f04m9926",
transactionId: "da5a34e0-793c-4c21-9fb2-f03b670eb2f8",
transactionType: "PURCHASE",
type: "CREDIT"
},
metadata: {
algorithm: "sha256",
HMAC: "3f7878f6b6e5e5f4e5d6c7b8a9b0c1d2e3f4g5h6i7j8k9l0m1n2o3p4q5r6s7t8",
timestamp: "2024-06-01T12:47:44Z"
}
}
success: boolean indicating success or failure of the transactionauthCode: the authorization codeavs: the AVS response codebrand: card brandcard: the partial number of the card for display purposescvv2Cvc2Status: the CVV response. Valid values are ‘M' for PASS and 'N’ for FAILemail: the cardholder's e-mail addressexpiry: expiry date of the cardinvoiceNumber: passed invoice number. If no invoice number is passed then one is generated on the flyisoResponseCode: ISO response code from issuerissuerMessage: message from the issuerlastFour: last four digits of the card numbername: cardholder nameprocessorAvsResultCode: the AVS response code returned from the processor. Value varies by card brand and processorpurchaseAmount: the amount of the transactionpurchaseCurrency: the currency used to conduct the transactionpurchaseDate: the date and time stamp when the transaction was processedsecureId: the session IDstatus: PayFacto payment platform status messagestore.address: store address as single linestore.email: store support contact e-mail addressstore.name: name of the store the merchant account is associated withstore.phone: store support contact phone numberstore.website: store Websitetoken: card token automatically generated as part of the processtransactionId: the unique identifier of the transaction that was createdtransactionType: the type of requested transaction. Valid values are 'PREAUTHORIZATION', PURCHASE, and 'VERIFY'type: card type. Valid values are CREDIT' and 'DEBIT'algorithm: the algorithm used to generate an HMACHMAC: the contents of the response converted to a string and then encrypted using the sha256 algorithm and the merchant account's private API passwordtimestamp: the time the transaction was generated.receipt: an HTML receipt that can be displayed on the screen or embedded in an e-mailA | Street address matches, ZIP/postal code does not |
M | Street address and ZIP/postal code match |
N | Street address and ZIP/postal code do not match |
U | Address information is unavailable or AVS is not supported by downstream provider |
Y | 5-Digit ZIP and street address match |
Z | 5-Digit ZIP matches, street address does not |
{
success: false,
response: {
code: "INVALID_NUMBER",
message: "card number is incorrect",
type: "CARD_DECLINED"
}
}
code: the subclass of error that was returned. The valid values aremessage: A message that briefly describes the nature of the error.success: A boolean value indicating if the request was successful or not. This property will always be set to false for an error response.type: The class of error that was returned. The valid values are:| HTTP Code | Error Type | Error Code |
400 | CARD_DECLINED | INVALID_CARD_NUMBER |
400 | CARD_DECLINED | AVS_DECLINED |
400 | CARD_DECLINED | CARD_BRAND_NOT_SUPPORTED |
400 | CARD_DECLINED | CVV_DECLINED |
400 | CARD_DECLINED | RISK_DECLINED |
400 | CARD_DECLINED | ISSUER_DECLINED |
400 | AMOUNT_DECLINED | AMOUNT_TOO_LARGE |
400 | AMOUNT_DECLINED | AMOUNT_TOO_SMALL |
| 400 | UNAUTHORIZED | |
400 | BATCH_CLOSING | BATCH_CLOSING |
400 | RECAPTCHA_VERIFICATION_FAILED | |
429 | TOO_MANY_REQUESTS | |
500 | INTERNAL_ERROR | |
504 | INTERNAL_ERROR | ISSUER_TIMEOUT |
| Error Type | Error Code | Description |
| CARD_ERROR | NOT_VERIFIED | Could not verify card number |
| CARD_ERROR | NOT_AUTHENTICATED | Issuer rejected card |
| DOWNSTREAM_ERROR | NOT_VERIFIED | 3DS provider is having technical issues |
The HMAC is calulated using the following:
// JavaScript example
function generateHmacDigest(algorithm, key, message) {
const hmac = crypto.createHmac(algorithm, key);
hmac.update(JSON.stringify(message));
return hmac.digest('hex');
}
generateHmacDigest("sha256", "my-secret-key", transaction.response);
"my-secret-key" is the API secret for the merchant account. To verify the HMAC simply repeat the above calulation and compare the returned HMAC witht he generated HMAC.By default, SCH displays the minimum number of fields needed to validate a credit card online. These are the cardholder name, card number, expiry date, and CVV fields. SCH can also display fields for address, postal code, email address, as well as change the display behavior of the Pay button. By default, the Pay button's behavior changes from the word Pay to a spinner; you can choose to disable this functionality.
To include these fields, you need to supply the optional values when creating the secure token.
const body = {
avs: 'both',
amount: 'editable',
disableSubmitIndicator: true,
email: true,
expires: '2025-06-24T13:50:00.0Z',
ignoreInitAuthTimedOut: true,
invoice: 'disabled',
invoiceNumber: 'abc-123',
language: language,
purchaseAmount: 100,
transactionType: 'PURCHASE',
useRecaptcha: false
}
avs: display the address and postal fields.
Valid values are 'address', 'postal', or 'both'.
If full AVS is enabled in the merchant account, ignore these values. For partial or optional AVS, pass the correct value to show the appropriate fields.
amount: display the amount field. Valid values are ‘disabled', ‘editable’, and 'hidden’.
If the transaction type is 'PURCHASE' or 'PREAUTHORIZATION' and purchaseAmount is not passed then the amount field will be displayed.
If purchaseAmount is not empty and amount is not passed then the amount field will be hidden.
disableSubmitIndicator: hide the submit indicator
When set to true the submit indicator on the Pay button will not be displayed
email: display the e-mail address field
When set to true the the e-mail field will be displayed.
If 3DS is active then this value is ignored
expires: set the expiry date and time for the secure token
The date and time the token will expire in ISO-8601 format.
The default is five minutes from creation time
ignoreInitAuthTimeout: ignore 3DS authentication timeout errors
Set to true to ignore 3DS authentication initialization errors
invoice: display the invoice number field.
Valid values are ‘disabled', ‘editable’, and 'hidden’.
invoiceNumber: an invoice number, maximum 25 characters long.
If a value is passed and the invoice field is not set, then invoiceNumber will be displayed as a read only field.
language: language to display fields in.
Valid values are 'en' and 'fr'.
This field is mandatory.
purchaseAmount: value of the transaction to be performed
if the transaction is a PURCHASE or PREAUTHORIZATION this field can contain the amount in lowest ordinal format (i.e. 1 dollar is passed in as 100)
NOTE: If the transaction type is 'PREAUTHORIZATION' or 'PURCHASE', then purchaseAmount is a mandatory value.
transactionType: type of transaction to perform
Valid values are 'PURCHASE', 'PREAUTHORIZATION', and 'VERIFY'.
This field is mandatory
useRecaptcha: disable reCAPTCHA
Is set to true by default
Set to false to turn off reCAPTCHA
When the purchaseAmount is part of the session request then that is the value used when the transaction is processed rather than the value passed down by the form. This means that setting purchaseAmount as an option will have no effect.
If a purchase or preauthorization is required after a verify, the response contains a token which can be used. See below for an example of how to perform a purchase or preauthorization.
Payment tokens generated by SHC can be used in subsequent calls to generate a purchase or a pre-authorization.
function postCharge(amount, invoiceNumber, token, isPurchase) {
const capture = isPurchase === true; // if capture is true then it is a purchase,
// else it is a pre-authorization
const endpoint = `https://uat.ca.api.payfacto.cloud/payments/v1/charges`;
const body = {
amount: amount,
cature: capture,
invoiceNumber: invoiceNumber,
paymentMethod: {
type: "PAYMENT_TOKEN",
paymentToken: { storedCredential: { type: "CIT_INITIAL", tokenId: token } }
}
};
const payload = {
method: 'POST',
headers: {
Authorization: 'Basic YOUR API KEY HERE',
Accept: 'application/json',
'Content-Type': 'application/json; charset=utf-8',
'idempotency-key': crypto.randomBytes(16).toString('base64')
},
body: JSON.stringify(body)
}
fetch(endpoint, payload)
.then(response => {console.log( response.status); return response.json() })
.then(data => console.log(JSON.stringify(data, null, 2)))
.catch(error => console.error(error));
}
useRecaptcha
SHC uses Google's reCAPTCHA to prevent some automated attacks. For security purposes, the useRecaptcha option is set to true by default.
However, some merchants have reported that using Google's reCAPTCHA interferes with their site. In these rare instances, SHC allows you to disable this security feature.
ignoreInitAuthTimeoutinitAuthTimeout error which can cause the transaction to fail. Setting ignoreInitAuthTimeout to true will ignore the the timeout error and allow the rest of the 3D Secure process to continue.cardholderName
when the cardholder's name is passed in the name field is hidden and the value is preserved in the hidden field
fields
An object containing values to add to the form and how to display them
invoiceNumber
when passed in the value is preserved in a hidden field.
If the invoice flag is set then the value is displayed in the field
purchaseAmount
when passed in the amount field is hidden and the value is preserved in a hidden field. If the transaction type is 'PREAUTHORIZATION' or 'PURCHASE' then this value is ignored when processing the transaction in favour of the value passed on the session create call.
sourceElement
override shc-fields as the default location to add the fields in
useOldStyleResponse
use the older style response objects. Used for backwards compatibility with older versions of SHC
shc function includes the fields object, which contains values to be passed to the server on submit. The keys will be the names of the fields and the values are the content to be loaded in the fields and their visibility.const options = {
fields: {
invoiceNumber: { visibility: "", "value": "" },
purchaseAmount: { visibility: "", "value": "" },
cardholderName: { visibility: "", "value": "" },
email: { visibility: "", "value": "" },
address: { visibility: "", "value": "" },
postal: { visibility: "", "value": "" }
}
}
Only the fields to be pre-loaded are required. The visibility and value properties are mandatory. If one of the properties is missing an exception will be thrown. The visibility property can contain one of the following three values: hidden, disabled, or enabled. The contents of the value field are not tested for correctness.
There are already options in place for passing purchaseAmount, invoiceNumber, and cardholderName. The old methods will work by default but will be overridden by the options in fields if they exist.
sourceElement property in the options parameter.The following example shows how to use the sourceElement property as a third argument:
const options = { sourceElement: ‘custom-form’ };
shc(shcToken, response => handleResponse(response), options);
To create a custom form, the merchant creates the form inside a div tag and then passes the id of that div tag to the shc function using the sourceElement property in the options object (i.e.: shc(secureToken, callback, { sourceElement: merchantForm }).)
The function will then use this form instead of generating its own. As part of the setup, all of the listeners will be stripped from the copied fields. To make use of the shc listeners add the id of the listener you want to emulate to the field.
For example, to take advantage of shc's card formatting, add id="shc-card-input" to the custom card field. If a field is marked with the required attribute the Pay button will not be enabled until the field contains a value.
When the form is submitted the contents of all the user defined fields will be part of the response in the callback.
In a custom form, buttons that contain the attribute data-message will send the contents of that message in a message to the parent form via a message. You can use a message event listener (i.e.: window.addEventListener('message', messageEventHandler);) to listen for the event. The message will use the format { message: 'data-message contents' }.
A field's generic layout resembles the following:
<label for="${name}" id="shc-${name}-label" class="confidante-field-label">
<div id="shc-${name}-img" class="confidante-field-img"></div>
<input id="shc-${name}-input" required="required" type="text" class="confidante-field-input shc-field-${name}" name="${name}" placeholder="${placeholder}" />
<span id="shc-${name}-span">${label}</span>
<div id="shc-${name}-validate" class="confidante-field-validate"></div>
</label>
${name} represents the field name. Valid field name values are:shc-style id in a style tag, as shown in the following example:<style id="shc-style">
/* place the custom styles here */
</style>
If you want to hide all the images at the start of the field, use the following CSS code:
.confidante-field-img svg {
visibility: collapse;
}
To hide the image, use the following CSS code:
#shc-card-img {
visibility: collapse;
}
.confidante-field-img svg {
visibility: collapse;
}
.confidante-field-validate svg {
visibility: collapse;
}
/* this style moves the label to the area the image icon used to cover */
label > span.confidante-field-span {
transform: translate(16px,34px);
}
/* this style starts the input text in the area the image icon used to cover */
input {
padding: 10px 0px 10px 16px;
}

To move the images to the right side of the input fields, use the following CSS code:
.confidante-field-img svg {
left: auto;
right: 5px;
}
.confidante-field-validate svg {
display: none;
}

/* increase the border to encompass the label */
input {
padding: 24px 16px 16px 40px;
}
/* freeze the icons in their locations */
.confidante-field-img svg {
margin-top: 14px;
}
.confidante-field-validate svg {
margin-top: 14px;
}
/* move the labels to a new location */
label > span.confidante-field-span {
position:absolute;
top: 0px;
left: 10px;
font-size:0.825em;
transform: translate(-4px, 6px);
}
/* prevent the labels from moving */
label:focus-within > span.confidante-field-span,
input:not(:placeholder-shown) + span.confidante-field-span {
transform: translate(-4px, 6px);
font-style: initial;
}
/* keep the card number mask in place over the card number */
.confidante-field-mask {
top: 25px;
}

/* restyle the label */
#shc label {
margin-bottom:15px;
position:relative;
border: 0px;
border-bottom: 1px solid #ddd;
box-shadow: none;
}
/* move the input field to align with the label */
#shc input:not(.shc-hidden-fields) {
width:100%;
padding: 20px 0px 10px 0px;
margin-top:20px;
border:none;
outline:none;
}
/* adjust the position of the label */
#shc span.confidante-field-span {
position:absolute;
top:0;
left:0;
transform:translateY(40px);
font-size:0.825em;
transition-duration:400ms;
}
/* restyle the button */
#shc button {
padding:15px 0px;
margin-top:20px;
background:purple;
color:#fff;
border:1px solid purple;
cursor:pointer;
border-radius:3px;
}
/* change the colour and position of the label when the input is focused or has text */
#shc label:focus-within > span.confidante-field-span,
#shc input:not(:placeholder-shown) + span.confidante-field-span {
color:purple;
transform:translate(32px, 12px);
}
/* make sure the mask is over the input field */
.confidante-field-mask {
top: 40px;
left: 5px;
}
/* change the colour of the svg icon when the input is focused or valid */
label:focus-within > .confidante-field-img svg,
.confidante-field-label.valid > .confidante-field-img svg {
fill: purple;
}

<button id="shc-pay-button" type="button" class="disabled">Pay</button>
#shc-pay-button CSS identifier, you can add different styles to the Pay button.To remove the border around SHC, use the following CSS:
#target {
border:0;
padding: 0px;
padding-top: 20px;
}

If a field has an SHC field id, all the formatting and listeners will be applied to that field.
When the Pay button is clicked, the values in the user fields will be collected and returned to the caller.
<div id="custom-form">
<form style="display: flex;">
<input id="secureId" name="secureId" type="hidden" value="bonJeton" />
<input type="hidden" name="name" value="JOHN DOE" />
<input type="text" id="shc-card-input" name="card" placeholder="1234 1234 1234 1234" required="required" autocomplete="cc-number" />
<div style="display: flex; flex-direction: row;">
<input type="text" id="shc-expiry-input" name="expiry" placeholder="MM / YY" required="required" />
<input type="text" id="shc-cvv-input" name="cvv" placeholder="123" required="required" autocomplete="cc-csc" />
</div>
<button id="shc-pay-button" type="button">Pay</button>
</form>
</div>
In order to use your custom form you will need to pass the form's id to shc as an option in the third argument.
If you need to add a required custom field, you must set the required attribute on the field in order to prevent the Pay button from being enabled until that custom field contains a value.
When working with custom forms the merchant is responsible for adding the hidden 3DS fields.
purchaseAmount: the monetary amount of the transaction denoted in minor units. purchaseCurrency: the currency that the transaction will be conducted in. purchaseDate: the date and time the transaction is taking place in extended ISO-8601 format (YYYY-MM-DDTHH:MM:SS.000Z)The fields will be treated as read only by SHC so the required values can be safely pre-loaded before SHC is called.
To protect against the possible injection of fraudulent code, SHC prevents the transfer of the following HTML tags to the SHC secure iframe:
<SCRIPT><IFRAME><OBJECT><A> (the anchor tag)<INPUT TYPE=”SUBMIT”><BUTTON TYPE=”SUBMIT”>As an added measure of security. the ACTION and METHOD attributes are removed from the <FORM> tag.
In addition to disallowing certain tags and attributes, no JavaScript is transferred to the SHC secure iframe. This includes JavaScript that is part of a permissible HTML tag or any events that were attached to an HTML tag before transferring the form to the SHC secure iframe.
data-message attribute will send the contents of that message in a message to the parent form via a message.You can use a message event listener (i.e.: window.addEventListener('message', messageEventHandler);) to listen for the event. The message will use the { message: 'data-message contents' } format.
shcMessenger object allows the shc form to communicate with the calling application. The shcMessenger is created when the shc function is called.let shcMessenger;
getShcToken(shcToken => {
shcMessenger = shc(shcToken, response => processResponse(response), options);
});
shcMessenger.on method. This method takes two arguments:The resulting call resembles the following:
shcMessenger.on('shc-event', optionalData => handleEvent(optionalData));
{ brand : cardBrand }.shc callback. Please refer to the callback documentation for details on what is sent in the data object.{ isReady: true }.{ isReady: false }.sendUnblockSubmit() message is sent. sendBlockSubmit() and allow the shc form to be ready to submit after all of the fields are valid.If your merchant account is configured for 3DS2, PayFacto will
automatically trigger the 3DS2 validation on every SHC transaction.
const options = {
purchaseAmount: amountAsInteger,
};
merchantGetShcToken(shcToken => {
shc(shcToken, response => merchantProcessResponse(response), options);
});
To test your 3D Secure implementation there are several card numbers that will trigger different 3D Secure responses. Below are the different test scenarios and the card numbers that will trigger them in PayFacto's test environment:
Frictionless Authentication without 3DS2
This scenario will return success without engaging 3D Secure.
Cardholder Name: Test Card
Card numbers:
Expiry Date: 08/27
CVV: 123 or 1234
Failed Authentication with 3DS2
This scenario will display a challenge page that will fail when the password “111111” to simulate a failure.
Cardholder Name: Test Card
Card numbers:
Expiry Date: 08/27
CVV: 123 or 1234
Authentication Unavailable
This scenario will provide an authentication unavailable.
Cardholder Name: Test Card
Card numbers:
Expiry Date: 08/27
CVV: 123 or 1234
Authentication Rejected
This scenario results in the authentication being rejected.
Cardholder Name: Test Card
Card numbers:
Expiry Date: 08/27
CVV: 123 or 1234
If the e-mail field is present in the SHC Token request, SHC will forward an e-receipt to the e-mail address in the field.
The legacy SHC solution used a combination of an api key in the Authorization header, plus a companyNumber and merchantNumber in the body. This new version of SHC requires the merchant api key username and password, base 64 encoded, in the Authorization header only.
The new payload is much simpler than the old payload.
In the new payload the following parameters are mandatory:
transactionType: the type of transactions SHC is to processlanguage: the language the form is to be displayed in{
transactionType: "VERIFY",
language: "fr"
}With the addition of the new transactionType parameter, SHC can now process purchases and preauthorizations directly instead of having to do additional calls to the API.
This allows the collection of card information and the required transaction to be handled as a single step with the results of the transaction being returned to the caller.
The three valid transaction types are now:
SHC now supports performing pre-authorization and purchases as well as verifications.
This eliminates the extra calls to the API.
transactionType to PURCHASE.transactionType to PREAUTHORIZATION. transactionType to VERIFY.If the request type is a CHARGE or a PREAUTHORIZATION the authCode will be returned as part of the response.
The successful response virtually the same as the response of Legacy SHC, with the exception being that a purchase or preauthorization will also return an authorization code (authCode.)
The HTTP response codes for error conditions remain the same, but an expanded set of error messages are now available.