PayFacto API - v2.0 - Solution : Secure Hosted Pages (SHP)

PayFacto API - v2.0 - Solution : Secure Hosted Pages (SHP)

PayFacto API - v2.0 - Solution : Secure Hosted Pages (SHP)

Secure Hosted Pages (SHP) is a full payment page hosted by PayFacto. Your server creates a session link, you redirect the customer to PayFacto's hosted page, and PayFacto sends them back to your successUrl or declineUrl when the payment is done. You never render the form β€” PayFacto handles all the card UI, PCI compliance, and 3D Secure.

How It Works

πŸ”‘

  Your server creates a link

POST to the SHP session endpoint with your transaction type and optional parameters. The response returns a linkUrl β€” the full URL of the PayFacto-hosted payment page.

πŸ”—

  Redirect the customer

Send the customer's browser to the linkUrl. This can be a server-side redirect, a client-side redirect, a button link, or a QR code.

πŸ’³

  Customer pays on the PayFacto-hosted page

The customer enters their card details on a PayFacto-hosted page. Your server never sees raw card data. 3D Secure runs automatically if your account is configured for it.

βœ…

 PayFacto redirects the customer back

After payment, PayFacto redirects the customer to your successUrl or declineUrl. The linkId is included as a query parameter so your server can retrieve the transaction result.

πŸ“‹

  Your server retrieves the transaction result

Call GET /links/{{linkId}}/responses or verify the HMAC from the webhook payload to confirm the transaction outcome before fulfilling the order.

1

  Prerequisites

πŸ”‘

  API Key

PayFacto provides you with an API key β€” a username and password pair. Base64-encode username:password and pass it as the Authorization: Basic ... header on every session request. Never put it in client-side JavaScript or a public repository.

🌐

  HTTPS server

All PayFacto endpoints require HTTPS. Your server must be able to make outbound HTTPS requests to the SHP session endpoint.

πŸ’§

  UAT environment

Use the UAT base URL during development: https://uat.ca.shc.payfacto.cloud. Your PayFacto contact will provide the production URL when you are ready to go live.

βœ…

  successUrl and declineUrl

You must have two HTTPS URLs on your server β€” one to handle successful payments and one for failures. Pass them in the session request body as successUrl and declineUrl.

2

  Endpoints

ℹ️

SHP uses two endpoints: one to create the session link (your server calls this), and one that is the hosted payment page itself (the customer's browser visits this).

UAT / Integration

Create a session link β€” call from your server

The hosted payment page β€” redirect the customer's browser here

Production

Create a session link β€” call from your server

The hosted payment page β€” redirect the customer's browser here

3
ℹ️

Call POST /secure-hosted-checkout/v1/links from your server. The only required field is transactionType. The response includes a linkUrl β€” this is the full URL of the hosted payment page you will redirect the customer to.

⚠️

This call must be made from your server, not the browser. The Authorization header contains your API secret. Never expose it in client-side code.

Required field

FieldTypeDescription
transactionTypestring Β· requiredThe type of transaction to process. Accepted values: PURCHASE (charge immediately), PREAUTHORIZATION (reserve funds, capture later), VERIFY (validate the card only, no money moves). For PURCHASE and PREAUTHORIZATION you must also send purchaseAmount.

Optional fields

FieldType / DefaultDescription
purchaseAmountintegerAmount in the smallest currency unit (cents). $10.25 = 1025. Mandatory when transactionType is PURCHASE or PREAUTHORIZATION. The amount on the session is the amount charged β€” any value the customer types into the form is ignored.
languagestring Β· default enLanguage displayed on the hosted page. en = English, fr = French.
successUrlstring (URL)Where to redirect the customer after a successful payment. Should be an HTTPS URL on your server.
declineUrlstring (URL)Where to redirect the customer after a failed payment or decline.
amountstringHow to display the amount field on the hosted page. disabled, editable, or hidden.
avsstringWhether to show address verification fields. postal (postal code only) or both (street address + postal code).
descriptionstring Β· max 60 charsA short description of the payment link, shown on the hosted page.
emailboolean Β· default falseWhether to show an email address field. If the customer fills it in, PayFacto sends them a receipt automatically.
expiresstring (ISO-8601)When the link stops working. Format: YYYY-MM-DDTHH:MM:SS. After this time the hosted page shows an expiry error.
invoicestringHow to display the invoice number field. disabled, editable, or hidden.
invoiceNumberstring Β· max 25 charsPre-fill the invoice number on the hosted page.
sendEmailboolean Β· default falseWhether to send the payment link to the customer by email.
transactionDescriptionstringText shown in the description field of the generated receipt.
usesinteger Β· default 1Maximum number of times the link can be used. Set to a higher value for reusable payment links (e.g. repeat invoice payments).
webhookUrlstring (URL)An additional URL that PayFacto will POST the transaction result to, in addition to the browser redirect.
JSON β€” Minimal link request
{
"transactionType": "PURCHASE",
"purchaseAmount": 1025,
"language": "en"
}
JSON β€” Full link request (all optional fields)
{
"transactionType": "PURCHASE",
"purchaseAmount": 1025,
"language": "en",
"invoiceNumber": "INV-2024-001",
"invoice": "hidden",
"amount": "hidden",
"description": "Order #2024-001 β€” 2x Widget Pro",
"email": true,
"avs": "both",
"successUrl": "https://your-site.com/paid",
"declineUrl": "https://your-site.com/declined",
"expires": "2024-06-30T23:59:59",
"uses": 1,
"sendEmail": false,
"transactionDescription": "Receipt description",
"webhookUrl": "https://your-site.com/webhook"
}
JavaScript β€” Server-side link request
// Server-side β€” Node.js / fetch example
const response = await fetch(
'https://uat.ca.shc.payfacto.cloud/secure-hosted-checkout/v1/links',
{
method: 'POST',
headers: {
'Authorization': `Basic ${Buffer.from('username:password').toString('base64')}`,
'Content-Type': 'application/json; charset=utf-8',
'Accept': 'application/json'
},
body: JSON.stringify({
transactionType: 'PURCHASE',
purchaseAmount: 1025, // $10.25 in cents
language: 'en',
successUrl: 'https://your-site.com/paid',
declineUrl: 'https://your-site.com/declined'
})
}
);

const data = await response.json();
// data.linkUrl is the URL to redirect the customer to
console.log(data.linkUrl);

link response

JSON β€” Link response
{
"id": "59e36fcb-ff9d-48be-972e-8960a4c8d4ac",
"description": null,
"expires": "2026-11-04T14:34:14.667Z",
"language": "fr",
"uses": "1",
"usesUsed": "0",
"purchaseAmount": 1025,
"transactionType": "PURCHASE",
"linkUrl": "https://uat.ca.shc.payfacto.cloud/secure-hosted-checkout/v1/browser/hosted-pages?link=59e36fcb-ff9d-48be-972e-8960a4c8d4ac"
}
Response fieldDescription
idThe unique identifier of the link. Also called linkId. Use this to look up responses and transactions.
linkUrlThe full URL of the PayFacto-hosted payment page. Redirect the customer here.
expiresWhen the link expires in ISO-8601 format.
usesMaximum number of times the link can be used.
usesUsedHow many times the link has been used so far.
purchaseAmountThe amount that will be charged, in cents.
transactionTypeEcho of the requested transaction type.
4

  Step 2 β€” Redirect the Customer

ℹ️

Once your server has the linkUrl, send the customer's browser to it. You can do this with a server-side HTTP redirect, a client-side JavaScript redirect, a link in an email, or by generating a QR code. See the Helper Endpoints section for QR code generation.

JavaScript β€” Redirect the customer
// After your server creates the session and returns linkUrl to the browser:
window.location.href = data.linkUrl;

// Or server-side redirect (e.g. Express):
res.redirect(data.linkUrl);

// The URL looks like:
// https://uat.ca.shc.payfacto.cloud/secure-hosted-checkout/v1/browser/hosted-pages
// ?link=59e36fcb-ff9d-48be-972e-8960a4c8d4ac
⏳

  Session token expiry

Links expire after the time set in expires (default: 5 minutes from creation). Create a new session link for each checkout attempt β€” do not cache or reuse session links across customers or sessions.

πŸ”—

  Reusable links

Set uses to a value greater than 1 to create a payment link that can be used multiple times β€” useful for invoice emails or in-person QR codes at a point of sale. Each use creates a separate transaction.

πŸ“§

  Email delivery

Set sendEmail: true in the session request to have PayFacto email the linkUrl directly to the customer. The email address must be collected separately or passed as part of the session.

5

  Step 3 β€” Handle the Customer Return

ℹ️

After the customer pays (or fails), PayFacto redirects them to your successUrl or declineUrl. The linkId is appended as a query parameter. Use it to retrieve the transaction result from PayFacto before fulfilling the order.

⚠️

Never fulfil an order based on the browser redirect alone. The redirect only tells you the customer returned β€” it does not prove the payment succeeded. Always verify the result server-side using the linkId or HMAC webhook before releasing goods or services.

JavaScript β€” Retrieve transaction result on successUrl
// PayFacto redirects the customer to your successUrl after payment.
// Example: https://your-site.com/paid?linkId=59e36fcb-ff9d-48be-972e-8960a4c8d4ac

// On your server, retrieve the transaction result using the linkId:
const result = await fetch(
`https://uat.ca.shc.payfacto.cloud/secure-hosted-checkout/v1/links/${linkId}/responses`,
{
headers: { 'Authorization': `Basic ${apiKey}` }
}
).then(r => r.json());
EndpointWhat it returns
GET /links/{linkId}/responsesAll response objects recorded against this link.
GET /links/{linkId}/transactionsAll transactions created from this link.
GET /sessions/{secureId}/responseThe full response from a specific session.
GET /sessions/{secureId}/transactionThe underlying transaction data.
GET /sessions/{secureId}/receiptThe HTML receipt, if one was generated.
6

  Step 4 β€” Verify the HMAC

ℹ️

Every PayFacto response includes a metadata.HMAC field β€” a SHA-256 fingerprint of the response body, signed with your API secret. Recalculate it on your server to confirm the response came from PayFacto and was not tampered with in transit.

⚠️

Always verify HMACs on your server, never in the browser. The check only proves anything if your API secret stays secret.

The HMAC is generated by running 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.

JavaScript β€” HMAC verification
const crypto = require('crypto');

function verifyHmac(response, apiSecret) {
const computed = crypto
.createHmac(response.metadata.algorithm, apiSecret)
.update(JSON.stringify(response.response))
.digest('hex');

return computed === response.metadata.HMAC;
}

if (!verifyHmac(shpResponse, process.env.API_SECRET)) {
throw new Error('HMAC mismatch β€” do not process this response');
}
metadata fieldDescription
algorithmThe hashing algorithm used. Currently always sha256.
HMACThe hex-encoded HMAC of the response object.
timestampISO-8601 timestamp of when the response was generated.
7

  Helper Endpoints

ℹ️

These endpoints let you manage links after creation β€” look up their state, cancel them, retrieve results, or generate a QR code for in-person or invoice use.

Endpoints β€” Link management
// Get the hosted-page URL as plain text
GET /browser/links/{linkId}/url

// Get a QR code image (PNG) of the link β€” embed directly in an tag
GET /browser/links/{linkId}/qrcode

// Look up the current state of a link
GET /links/{linkId}

// Cancel / expire a link immediately
POST /links/{linkId}/cancel

// Get all responses recorded against a link
GET /links/{linkId}/responses

// Get all transactions created from a link
GET /links/{linkId}/transactions
EndpointMethodDescription
/links/{linkId}GETRetrieve the current state of a link β€” status, uses remaining, expiry.
/links/{linkId}/cancelPOSTExpire a link immediately. Useful if a customer abandons checkout.
/links/{linkId}/responsesGETGet all response objects recorded against this link. Use to retrieve the transaction result after the customer returns.
/links/{linkId}/transactionsGETGet all transactions created from this link.
/browser/links/{linkId}/urlGETGet the hosted-page URL as plain text. Useful for embedding in emails or SMS.
/browser/links/{linkId}/qrcodeGETGet a QR code image (PNG) that opens the hosted payment page. Embed directly in an img tag or print.