Skip to content
Trustfac
Developers

The integration, in one page.

A custom store needs one package on the page, one call from the server and a webhook endpoint. The WooCommerce and Shopify plugins do all three for you.

Two engineers at a standing desk sharing a laptop, smiling.

Card data

The card number is entered into fields served by the vault, not by your page or ours.

The package mounts the card number, expiry and security code as hosted fields inside your checkout. When the shopper submits, those fields tokenize the card on the shopper’s own device and hand your page a token, the last four digits and the brand. That token is what your server sends us to charge, save or refund. Because the number itself never passes through your code or your server, your PCI questionnaire stays at SAQ A.

Saved cards, subscription renewals, invoices and the thank-you page offer all charge the same token. There is no second place where card data is collected.

Taking a payment

Mount the fields, tokenize, and send the token from your server with an idempotency key.

Every write accepts an idempotency key. If a request times out and your server sends it again with the same key, you receive the original result rather than a second charge. The plugins do this automatically; a custom integration should do it from the start.

The response tells you whether the charge was approved or declined and, for a decline, a reason you can show the shopper in plain language.

checkout.jsExample
import { Checkout } from "@trustfac/checkout";

// Card fields render inside hosted iframes on your page.
const checkout = await Checkout.mount("#card", { session });

// Tokenized on the customer's device. Your code and your
// server only ever see the token, the last four and the brand.
const { token } = await checkout.tokenize();

await fetch("/api/orders/pay", {
  method: "POST",
  headers: { "Idempotency-Key": orderId },
  body: JSON.stringify({ orderId, token }),
});

Webhooks

Signed events for everything that changes money, with replay from the dashboard.

Each account has its own webhook secret, which you can rotate from the dashboard. Every delivery is signed with it, and every delivery and your endpoint’s response are listed so you can see what was sent and resend it if your side was down.

verify.tsExample
// Verify a webhook before trusting it.
import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(rawBody: string, header: string, secret: string) {
  const expected = createHmac("sha256", secret).update(rawBody).digest("hex");
  return timingSafeEqual(Buffer.from(header), Buffer.from(expected));
}
EventCovers
paymentsucceeded, declined, refunded
disputeopened, evidence due, won, lost
subscriptionrenewed, renewal failed, paused, cancelled
payoutsent, with the orders and fees inside it

Test mode and going live

Every account starts in test mode with its own keys and a set of test cards that produce an approval, a decline and a dispute. Test and live keys are separate, and nothing written in test mode can reach a live charge.

Live mode is switched on by our team after review and your sign-off. It is not an API call and it is not a setting in the dashboard. The full reference, including request and response shapes for every endpoint, is issued with the account.

Scope the integration with us.

Tell us what the store runs on and we will say what the work is, usually in one email. Custom stores most often take a day.