How It Works
Your server requests a session token
POST to the SHC session endpoint with your API key. The response returns a one-time token scoped to this checkout.
Your server returns the token to the browser
The token is passed back to the browser as JSON. Your API key never leaves the server.
The browser calls shc() β the iframe appears
The browser passes the token to the global shc() function. The library renders a secure iframe containing the card form inside your #shc-fields div.
The cardholder fills in the form and clicks Pay
Card data is submitted directly from the iframe to PayFacto. Your page never sees the raw card data.
PayFacto fires the callback with the result
Your callback function receives a response object. Check response.success first, then verify the HMAC server-side before fulfilling the order.
API Key
PayFacto provides you with an API key β a username and password pair. Base64-encode username:password and put it in the Authorization: Basic ... header on every server-side session request. Never put it in client-side JavaScript or a public repository.
HTTPS server
Your server must support HTTPS. All PayFacto endpoints require a secure connection.
UAT environment
Use UAT during development: https://uat.ca.shc.payfacto.cloud. Your PayFacto contact will provide the production URL once you are ready to go live.
A page you control
SHC works on any HTML page. You add one <script> tag and one <div> β SHC handles the rest.
Call the session endpoint from your server, not the browser. The Authorization header contains your API secret. If you call it from the browser, anyone can steal your key.
The session token is a one-time token that expires in 5 minutes by default (configurable via expires). Request it fresh for each checkout β never cache or reuse tokens.
Required session fields
Optional session fields
Webhooks are a window into your system. Care must be taken that third parties are unable to send false or misleading information. The following tips can greatly reduce the possibility of bad actors introducing false information into your system.
Randomize the Endpoints
When sending an endpoint to SHC, add a random element to it (i.e. /webhook/{randomId}). Map the random element (randomId) to the secureId in the token. When a message is received, compare the randomId and the secureId received to the stored pair to ensure they match, otherwise reject the message.
Always Verify the HMAC
When the message is received, verify the HMAC as shown in the Verifying the HMAC section to ensure the message has not been tampered with.
Treat the Message as a Notification
The message sent to your webhook is a notification, not a source of truth. Reconcile your transactions with data provided securely by PayFacto.
Acknowledge Quickly
Send an acknowledgement as soon as you receive a notification β this will greatly reduce the probability of getting multiple notifications for the same transaction. Ensure that a 2XX response, such as a 200, is sent to avoid confusion.
Add the SHC library script tag to your page <head> and an empty <div> wherever you want the card form to appear. The default container id is shc-fields β you can use a different id but must tell SHC about it via the sourceElement option.
Your server returns the session token to the browser as JSON. The browser then calls the global shc() function with the token as the first argument. The second argument is a callback. The callback fires when the cardholder clicks Pay. The third argument is optional and is an object containing browser-side options.
Third argument β browser-side options
These options are different from session options β they control how the iframe behaves once it is created. Pass them as the third argument to shc(). Each entry in fields must have both visibility and value or SHC throws an error.
Never fulfil an order based on the callback alone. Always verify the HMAC on your server (Step 5) before releasing goods or services.
Successful response (Pay by card)
Successful response (Pay by konek)
Additional response fields
Error response
3D Secure error codes
Always verify HMACs on your server, never in the browser. The check only proves anything if your API secret stays secret.
Run JSON.stringify(response.response) β the inner response object, not the full envelope β through HMAC-SHA256 keyed with your API secret. Compare the result against metadata.HMAC. If they differ, discard the response and do not fulfil the order.
If the default styling options are not enough, you can build your own form. Wrap it in a <div> with an id, and pass that id to shc() as sourceElement. Give any input the matching SHC field id to activate validation, formatting, and secure submission for that field.
Before SHC copies your custom form into the secure iframe, it strips <script>, <iframe>, <object>, <a> tags, any <input type=submit> or <button type=submit>, the action and method attributes from <form> tags, and all inline JavaScript event handlers. This prevents code injection.
3DS hidden fields β required if your account uses 3D Secure
Sending messages from custom buttons
Add a data-message attribute to any button inside your custom form. When clicked, SHC sends the message to the parent page. Listen with a message event listener:
SHC reads a <style> tag with the id shc-style and injects it into the iframe. This is the only way to style the iframe β normal CSS on your page does not reach inside it.
Common style recipes
Available CSS ids and classes
shc() returns an shcMessenger object. Use .on() to listen for events from the form, and the send methods to control the form programmatically.
If you need to retrieve the result of a session after the callback fires β for example, to reconcile server-side β use these GET endpoints. Plug the secureId from the response into the URL.
Use these card numbers in UAT to test every 3DS outcome. For all scenarios: Cardholder Name = Test Card, CVV = 123 (or 1234 for Amex).
ignoreInitAuthTimeout β Before 3DS starts, SHC collects device information. This can occasionally time out, failing the transaction. Setting ignoreInitAuthTimeout: true in the session request tells SHC to continue anyway. Use only if your failure rate from this timeout is high β bypassing it may shift fraud liability to you.